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 ALCportPlayback_lock(self
);
181 aluMixData(STATIC_CAST(ALCbackend
, self
)->mDevice
, outputBuffer
, framesPerBuffer
);
182 ALCportPlayback_unlock(self
);
187 static ALCenum
ALCportPlayback_open(ALCportPlayback
*self
, const ALCchar
*name
)
189 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
194 else if(strcmp(name
, pa_device
) != 0)
195 return ALC_INVALID_VALUE
;
197 self
->update_size
= device
->UpdateSize
;
199 self
->params
.device
= -1;
200 if(!ConfigValueInt(NULL
, "port", "device", &self
->params
.device
) ||
201 self
->params
.device
< 0)
202 self
->params
.device
= Pa_GetDefaultOutputDevice();
203 self
->params
.suggestedLatency
= (device
->UpdateSize
*device
->NumUpdates
) /
204 (float)device
->Frequency
;
205 self
->params
.hostApiSpecificStreamInfo
= NULL
;
207 self
->params
.channelCount
= ((device
->FmtChans
== DevFmtMono
) ? 1 : 2);
209 switch(device
->FmtType
)
212 self
->params
.sampleFormat
= paInt8
;
215 self
->params
.sampleFormat
= paUInt8
;
220 self
->params
.sampleFormat
= paInt16
;
225 self
->params
.sampleFormat
= paInt32
;
228 self
->params
.sampleFormat
= paFloat32
;
233 err
= Pa_OpenStream(&self
->stream
, NULL
, &self
->params
,
234 device
->Frequency
, device
->UpdateSize
, paNoFlag
,
235 ALCportPlayback_WriteCallback
, self
239 if(self
->params
.sampleFormat
== paFloat32
)
241 self
->params
.sampleFormat
= paInt16
;
244 ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err
));
245 return ALC_INVALID_VALUE
;
248 alstr_copy_cstr(&device
->DeviceName
, name
);
254 static void ALCportPlayback_close(ALCportPlayback
*self
)
256 PaError err
= Pa_CloseStream(self
->stream
);
258 ERR("Error closing stream: %s\n", Pa_GetErrorText(err
));
262 static ALCboolean
ALCportPlayback_reset(ALCportPlayback
*self
)
264 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
265 const PaStreamInfo
*streamInfo
;
267 streamInfo
= Pa_GetStreamInfo(self
->stream
);
268 device
->Frequency
= streamInfo
->sampleRate
;
269 device
->UpdateSize
= self
->update_size
;
271 if(self
->params
.sampleFormat
== paInt8
)
272 device
->FmtType
= DevFmtByte
;
273 else if(self
->params
.sampleFormat
== paUInt8
)
274 device
->FmtType
= DevFmtUByte
;
275 else if(self
->params
.sampleFormat
== paInt16
)
276 device
->FmtType
= DevFmtShort
;
277 else if(self
->params
.sampleFormat
== paInt32
)
278 device
->FmtType
= DevFmtInt
;
279 else if(self
->params
.sampleFormat
== paFloat32
)
280 device
->FmtType
= DevFmtFloat
;
283 ERR("Unexpected sample format: 0x%lx\n", self
->params
.sampleFormat
);
287 if(self
->params
.channelCount
== 2)
288 device
->FmtChans
= DevFmtStereo
;
289 else if(self
->params
.channelCount
== 1)
290 device
->FmtChans
= DevFmtMono
;
293 ERR("Unexpected channel count: %u\n", self
->params
.channelCount
);
296 SetDefaultChannelOrder(device
);
301 static ALCboolean
ALCportPlayback_start(ALCportPlayback
*self
)
305 err
= Pa_StartStream(self
->stream
);
308 ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err
));
315 static void ALCportPlayback_stop(ALCportPlayback
*self
)
317 PaError err
= Pa_StopStream(self
->stream
);
319 ERR("Error stopping stream: %s\n", Pa_GetErrorText(err
));
323 typedef struct ALCportCapture
{
324 DERIVE_FROM_TYPE(ALCbackend
);
327 PaStreamParameters params
;
329 ll_ringbuffer_t
*ring
;
332 static int ALCportCapture_ReadCallback(const void *inputBuffer
, void *outputBuffer
,
333 unsigned long framesPerBuffer
, const PaStreamCallbackTimeInfo
*timeInfo
,
334 const PaStreamCallbackFlags statusFlags
, void *userData
);
336 static void ALCportCapture_Construct(ALCportCapture
*self
, ALCdevice
*device
);
337 static void ALCportCapture_Destruct(ALCportCapture
*self
);
338 static ALCenum
ALCportCapture_open(ALCportCapture
*self
, const ALCchar
*name
);
339 static void ALCportCapture_close(ALCportCapture
*self
);
340 static DECLARE_FORWARD(ALCportCapture
, ALCbackend
, ALCboolean
, reset
)
341 static ALCboolean
ALCportCapture_start(ALCportCapture
*self
);
342 static void ALCportCapture_stop(ALCportCapture
*self
);
343 static ALCenum
ALCportCapture_captureSamples(ALCportCapture
*self
, ALCvoid
*buffer
, ALCuint samples
);
344 static ALCuint
ALCportCapture_availableSamples(ALCportCapture
*self
);
345 static DECLARE_FORWARD(ALCportCapture
, ALCbackend
, ClockLatency
, getClockLatency
)
346 static DECLARE_FORWARD(ALCportCapture
, ALCbackend
, void, lock
)
347 static DECLARE_FORWARD(ALCportCapture
, ALCbackend
, void, unlock
)
348 DECLARE_DEFAULT_ALLOCATORS(ALCportCapture
)
350 DEFINE_ALCBACKEND_VTABLE(ALCportCapture
);
353 static void ALCportCapture_Construct(ALCportCapture
*self
, ALCdevice
*device
)
355 ALCbackend_Construct(STATIC_CAST(ALCbackend
, self
), device
);
356 SET_VTABLE2(ALCportCapture
, ALCbackend
, self
);
361 static void ALCportCapture_Destruct(ALCportCapture
*self
)
364 Pa_CloseStream(self
->stream
);
368 ll_ringbuffer_free(self
->ring
);
371 ALCbackend_Destruct(STATIC_CAST(ALCbackend
, self
));
375 static int ALCportCapture_ReadCallback(const void *inputBuffer
, void *UNUSED(outputBuffer
),
376 unsigned long framesPerBuffer
, const PaStreamCallbackTimeInfo
*UNUSED(timeInfo
),
377 const PaStreamCallbackFlags
UNUSED(statusFlags
), void *userData
)
379 ALCportCapture
*self
= userData
;
380 size_t writable
= ll_ringbuffer_write_space(self
->ring
);
382 if(framesPerBuffer
> writable
)
383 framesPerBuffer
= writable
;
384 ll_ringbuffer_write(self
->ring
, inputBuffer
, framesPerBuffer
);
389 static ALCenum
ALCportCapture_open(ALCportCapture
*self
, const ALCchar
*name
)
391 ALCdevice
*device
= STATIC_CAST(ALCbackend
, self
)->mDevice
;
392 ALuint samples
, frame_size
;
397 else if(strcmp(name
, pa_device
) != 0)
398 return ALC_INVALID_VALUE
;
400 samples
= device
->UpdateSize
* device
->NumUpdates
;
401 samples
= maxu(samples
, 100 * device
->Frequency
/ 1000);
402 frame_size
= FrameSizeFromDevFmt(device
->FmtChans
, device
->FmtType
, device
->AmbiOrder
);
404 self
->ring
= ll_ringbuffer_create(samples
, frame_size
);
405 if(self
->ring
== NULL
) return ALC_INVALID_VALUE
;
407 self
->params
.device
= -1;
408 if(!ConfigValueInt(NULL
, "port", "capture", &self
->params
.device
) ||
409 self
->params
.device
< 0)
410 self
->params
.device
= Pa_GetDefaultInputDevice();
411 self
->params
.suggestedLatency
= 0.0f
;
412 self
->params
.hostApiSpecificStreamInfo
= NULL
;
414 switch(device
->FmtType
)
417 self
->params
.sampleFormat
= paInt8
;
420 self
->params
.sampleFormat
= paUInt8
;
423 self
->params
.sampleFormat
= paInt16
;
426 self
->params
.sampleFormat
= paInt32
;
429 self
->params
.sampleFormat
= paFloat32
;
433 ERR("%s samples not supported\n", DevFmtTypeString(device
->FmtType
));
434 return ALC_INVALID_VALUE
;
436 self
->params
.channelCount
= ChannelsFromDevFmt(device
->FmtChans
, device
->AmbiOrder
);
438 err
= Pa_OpenStream(&self
->stream
, &self
->params
, NULL
,
439 device
->Frequency
, paFramesPerBufferUnspecified
, paNoFlag
,
440 ALCportCapture_ReadCallback
, self
444 ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err
));
445 return ALC_INVALID_VALUE
;
448 alstr_copy_cstr(&device
->DeviceName
, name
);
453 static void ALCportCapture_close(ALCportCapture
*self
)
455 PaError err
= Pa_CloseStream(self
->stream
);
457 ERR("Error closing stream: %s\n", Pa_GetErrorText(err
));
460 ll_ringbuffer_free(self
->ring
);
465 static ALCboolean
ALCportCapture_start(ALCportCapture
*self
)
467 PaError err
= Pa_StartStream(self
->stream
);
470 ERR("Error starting stream: %s\n", Pa_GetErrorText(err
));
476 static void ALCportCapture_stop(ALCportCapture
*self
)
478 PaError err
= Pa_StopStream(self
->stream
);
480 ERR("Error stopping stream: %s\n", Pa_GetErrorText(err
));
484 static ALCuint
ALCportCapture_availableSamples(ALCportCapture
*self
)
486 return ll_ringbuffer_read_space(self
->ring
);
489 static ALCenum
ALCportCapture_captureSamples(ALCportCapture
*self
, ALCvoid
*buffer
, ALCuint samples
)
491 ll_ringbuffer_read(self
->ring
, buffer
, samples
);
496 typedef struct ALCportBackendFactory
{
497 DERIVE_FROM_TYPE(ALCbackendFactory
);
498 } ALCportBackendFactory
;
499 #define ALCPORTBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCportBackendFactory, ALCbackendFactory) } }
501 static ALCboolean
ALCportBackendFactory_init(ALCportBackendFactory
*self
);
502 static void ALCportBackendFactory_deinit(ALCportBackendFactory
*self
);
503 static ALCboolean
ALCportBackendFactory_querySupport(ALCportBackendFactory
*self
, ALCbackend_Type type
);
504 static void ALCportBackendFactory_probe(ALCportBackendFactory
*self
, enum DevProbe type
);
505 static ALCbackend
* ALCportBackendFactory_createBackend(ALCportBackendFactory
*self
, ALCdevice
*device
, ALCbackend_Type type
);
507 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory
);
510 static ALCboolean
ALCportBackendFactory_init(ALCportBackendFactory
* UNUSED(self
))
517 static void ALCportBackendFactory_deinit(ALCportBackendFactory
* UNUSED(self
))
531 static ALCboolean
ALCportBackendFactory_querySupport(ALCportBackendFactory
* UNUSED(self
), ALCbackend_Type type
)
533 if(type
== ALCbackend_Playback
|| type
== ALCbackend_Capture
)
538 static void ALCportBackendFactory_probe(ALCportBackendFactory
* UNUSED(self
), enum DevProbe type
)
542 case ALL_DEVICE_PROBE
:
543 AppendAllDevicesList(pa_device
);
545 case CAPTURE_DEVICE_PROBE
:
546 AppendCaptureDeviceList(pa_device
);
551 static ALCbackend
* ALCportBackendFactory_createBackend(ALCportBackendFactory
* UNUSED(self
), ALCdevice
*device
, ALCbackend_Type type
)
553 if(type
== ALCbackend_Playback
)
555 ALCportPlayback
*backend
;
556 NEW_OBJ(backend
, ALCportPlayback
)(device
);
557 if(!backend
) return NULL
;
558 return STATIC_CAST(ALCbackend
, backend
);
560 if(type
== ALCbackend_Capture
)
562 ALCportCapture
*backend
;
563 NEW_OBJ(backend
, ALCportCapture
)(device
);
564 if(!backend
) return NULL
;
565 return STATIC_CAST(ALCbackend
, backend
);
571 ALCbackendFactory
*ALCportBackendFactory_getFactory(void)
573 static ALCportBackendFactory factory
= ALCPORTBACKENDFACTORY_INITIALIZER
;
574 return STATIC_CAST(ALCbackendFactory
, &factory
);