Merge pull request #204 from jhasse/android-byte-order
[openal-soft.git] / Alc / backends / portaudio.c
blob9b0d34878967ba0a114ef4099261502d0463ec63
1 /**
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
21 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "alMain.h"
28 #include "alu.h"
29 #include "alconfig.h"
30 #include "ringbuffer.h"
31 #include "compat.h"
33 #include "backends/base.h"
35 #include <portaudio.h>
38 static const ALCchar pa_device[] = "PortAudio Default";
41 #ifdef HAVE_DYNLOAD
42 static void *pa_handle;
43 #define MAKE_FUNC(x) static __typeof(x) * p##x
44 MAKE_FUNC(Pa_Initialize);
45 MAKE_FUNC(Pa_Terminate);
46 MAKE_FUNC(Pa_GetErrorText);
47 MAKE_FUNC(Pa_StartStream);
48 MAKE_FUNC(Pa_StopStream);
49 MAKE_FUNC(Pa_OpenStream);
50 MAKE_FUNC(Pa_CloseStream);
51 MAKE_FUNC(Pa_GetDefaultOutputDevice);
52 MAKE_FUNC(Pa_GetDefaultInputDevice);
53 MAKE_FUNC(Pa_GetStreamInfo);
54 #undef MAKE_FUNC
56 #define Pa_Initialize pPa_Initialize
57 #define Pa_Terminate pPa_Terminate
58 #define Pa_GetErrorText pPa_GetErrorText
59 #define Pa_StartStream pPa_StartStream
60 #define Pa_StopStream pPa_StopStream
61 #define Pa_OpenStream pPa_OpenStream
62 #define Pa_CloseStream pPa_CloseStream
63 #define Pa_GetDefaultOutputDevice pPa_GetDefaultOutputDevice
64 #define Pa_GetDefaultInputDevice pPa_GetDefaultInputDevice
65 #define Pa_GetStreamInfo pPa_GetStreamInfo
66 #endif
68 static ALCboolean pa_load(void)
70 PaError err;
72 #ifdef HAVE_DYNLOAD
73 if(!pa_handle)
75 #ifdef _WIN32
76 # define PALIB "portaudio.dll"
77 #elif defined(__APPLE__) && defined(__MACH__)
78 # define PALIB "libportaudio.2.dylib"
79 #elif defined(__OpenBSD__)
80 # define PALIB "libportaudio.so"
81 #else
82 # define PALIB "libportaudio.so.2"
83 #endif
85 pa_handle = LoadLib(PALIB);
86 if(!pa_handle)
87 return ALC_FALSE;
89 #define LOAD_FUNC(f) do { \
90 p##f = GetSymbol(pa_handle, #f); \
91 if(p##f == NULL) \
92 { \
93 CloseLib(pa_handle); \
94 pa_handle = NULL; \
95 return ALC_FALSE; \
96 } \
97 } while(0)
98 LOAD_FUNC(Pa_Initialize);
99 LOAD_FUNC(Pa_Terminate);
100 LOAD_FUNC(Pa_GetErrorText);
101 LOAD_FUNC(Pa_StartStream);
102 LOAD_FUNC(Pa_StopStream);
103 LOAD_FUNC(Pa_OpenStream);
104 LOAD_FUNC(Pa_CloseStream);
105 LOAD_FUNC(Pa_GetDefaultOutputDevice);
106 LOAD_FUNC(Pa_GetDefaultInputDevice);
107 LOAD_FUNC(Pa_GetStreamInfo);
108 #undef LOAD_FUNC
110 if((err=Pa_Initialize()) != paNoError)
112 ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err));
113 CloseLib(pa_handle);
114 pa_handle = NULL;
115 return ALC_FALSE;
118 #else
119 if((err=Pa_Initialize()) != paNoError)
121 ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err));
122 return ALC_FALSE;
124 #endif
125 return ALC_TRUE;
129 typedef struct ALCportPlayback {
130 DERIVE_FROM_TYPE(ALCbackend);
132 PaStream *stream;
133 PaStreamParameters params;
134 ALuint update_size;
135 } ALCportPlayback;
137 static int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer,
138 unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
139 const PaStreamCallbackFlags statusFlags, void *userData);
141 static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device);
142 static void ALCportPlayback_Destruct(ALCportPlayback *self);
143 static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name);
144 static ALCboolean ALCportPlayback_reset(ALCportPlayback *self);
145 static ALCboolean ALCportPlayback_start(ALCportPlayback *self);
146 static void ALCportPlayback_stop(ALCportPlayback *self);
147 static DECLARE_FORWARD2(ALCportPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
148 static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALCuint, availableSamples)
149 static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ClockLatency, getClockLatency)
150 static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, lock)
151 static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, unlock)
152 DECLARE_DEFAULT_ALLOCATORS(ALCportPlayback)
154 DEFINE_ALCBACKEND_VTABLE(ALCportPlayback);
157 static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device)
159 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
160 SET_VTABLE2(ALCportPlayback, ALCbackend, self);
162 self->stream = NULL;
165 static void ALCportPlayback_Destruct(ALCportPlayback *self)
167 PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError;
168 if(err != paNoError)
169 ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
170 self->stream = NULL;
172 ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
176 static int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputBuffer,
177 unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
178 const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
180 ALCportPlayback *self = userData;
182 ALCportPlayback_lock(self);
183 aluMixData(STATIC_CAST(ALCbackend, self)->mDevice, outputBuffer, framesPerBuffer);
184 ALCportPlayback_unlock(self);
185 return 0;
189 static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name)
191 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
192 PaError err;
194 if(!name)
195 name = pa_device;
196 else if(strcmp(name, pa_device) != 0)
197 return ALC_INVALID_VALUE;
199 self->update_size = device->UpdateSize;
201 self->params.device = -1;
202 if(!ConfigValueInt(NULL, "port", "device", &self->params.device) ||
203 self->params.device < 0)
204 self->params.device = Pa_GetDefaultOutputDevice();
205 self->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) /
206 (float)device->Frequency;
207 self->params.hostApiSpecificStreamInfo = NULL;
209 self->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2);
211 switch(device->FmtType)
213 case DevFmtByte:
214 self->params.sampleFormat = paInt8;
215 break;
216 case DevFmtUByte:
217 self->params.sampleFormat = paUInt8;
218 break;
219 case DevFmtUShort:
220 /* fall-through */
221 case DevFmtShort:
222 self->params.sampleFormat = paInt16;
223 break;
224 case DevFmtUInt:
225 /* fall-through */
226 case DevFmtInt:
227 self->params.sampleFormat = paInt32;
228 break;
229 case DevFmtFloat:
230 self->params.sampleFormat = paFloat32;
231 break;
234 retry_open:
235 err = Pa_OpenStream(&self->stream, NULL, &self->params,
236 device->Frequency, device->UpdateSize, paNoFlag,
237 ALCportPlayback_WriteCallback, self
239 if(err != paNoError)
241 if(self->params.sampleFormat == paFloat32)
243 self->params.sampleFormat = paInt16;
244 goto retry_open;
246 ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
247 return ALC_INVALID_VALUE;
250 alstr_copy_cstr(&device->DeviceName, name);
252 return ALC_NO_ERROR;
256 static ALCboolean ALCportPlayback_reset(ALCportPlayback *self)
258 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
259 const PaStreamInfo *streamInfo;
261 streamInfo = Pa_GetStreamInfo(self->stream);
262 device->Frequency = streamInfo->sampleRate;
263 device->UpdateSize = self->update_size;
265 if(self->params.sampleFormat == paInt8)
266 device->FmtType = DevFmtByte;
267 else if(self->params.sampleFormat == paUInt8)
268 device->FmtType = DevFmtUByte;
269 else if(self->params.sampleFormat == paInt16)
270 device->FmtType = DevFmtShort;
271 else if(self->params.sampleFormat == paInt32)
272 device->FmtType = DevFmtInt;
273 else if(self->params.sampleFormat == paFloat32)
274 device->FmtType = DevFmtFloat;
275 else
277 ERR("Unexpected sample format: 0x%lx\n", self->params.sampleFormat);
278 return ALC_FALSE;
281 if(self->params.channelCount == 2)
282 device->FmtChans = DevFmtStereo;
283 else if(self->params.channelCount == 1)
284 device->FmtChans = DevFmtMono;
285 else
287 ERR("Unexpected channel count: %u\n", self->params.channelCount);
288 return ALC_FALSE;
290 SetDefaultChannelOrder(device);
292 return ALC_TRUE;
295 static ALCboolean ALCportPlayback_start(ALCportPlayback *self)
297 PaError err;
299 err = Pa_StartStream(self->stream);
300 if(err != paNoError)
302 ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err));
303 return ALC_FALSE;
306 return ALC_TRUE;
309 static void ALCportPlayback_stop(ALCportPlayback *self)
311 PaError err = Pa_StopStream(self->stream);
312 if(err != paNoError)
313 ERR("Error stopping stream: %s\n", Pa_GetErrorText(err));
317 typedef struct ALCportCapture {
318 DERIVE_FROM_TYPE(ALCbackend);
320 PaStream *stream;
321 PaStreamParameters params;
323 ll_ringbuffer_t *ring;
324 } ALCportCapture;
326 static int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer,
327 unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
328 const PaStreamCallbackFlags statusFlags, void *userData);
330 static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device);
331 static void ALCportCapture_Destruct(ALCportCapture *self);
332 static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name);
333 static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset)
334 static ALCboolean ALCportCapture_start(ALCportCapture *self);
335 static void ALCportCapture_stop(ALCportCapture *self);
336 static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples);
337 static ALCuint ALCportCapture_availableSamples(ALCportCapture *self);
338 static DECLARE_FORWARD(ALCportCapture, ALCbackend, ClockLatency, getClockLatency)
339 static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, lock)
340 static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, unlock)
341 DECLARE_DEFAULT_ALLOCATORS(ALCportCapture)
343 DEFINE_ALCBACKEND_VTABLE(ALCportCapture);
346 static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device)
348 ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
349 SET_VTABLE2(ALCportCapture, ALCbackend, self);
351 self->stream = NULL;
352 self->ring = NULL;
355 static void ALCportCapture_Destruct(ALCportCapture *self)
357 PaError err = self->stream ? Pa_CloseStream(self->stream) : paNoError;
358 if(err != paNoError)
359 ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
360 self->stream = NULL;
362 ll_ringbuffer_free(self->ring);
363 self->ring = NULL;
365 ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
369 static int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuffer),
370 unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo),
371 const PaStreamCallbackFlags UNUSED(statusFlags), void *userData)
373 ALCportCapture *self = userData;
374 size_t writable = ll_ringbuffer_write_space(self->ring);
376 if(framesPerBuffer > writable)
377 framesPerBuffer = writable;
378 ll_ringbuffer_write(self->ring, inputBuffer, framesPerBuffer);
379 return 0;
383 static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name)
385 ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
386 ALuint samples, frame_size;
387 PaError err;
389 if(!name)
390 name = pa_device;
391 else if(strcmp(name, pa_device) != 0)
392 return ALC_INVALID_VALUE;
394 samples = device->UpdateSize * device->NumUpdates;
395 samples = maxu(samples, 100 * device->Frequency / 1000);
396 frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
398 self->ring = ll_ringbuffer_create(samples, frame_size, false);
399 if(self->ring == NULL) return ALC_INVALID_VALUE;
401 self->params.device = -1;
402 if(!ConfigValueInt(NULL, "port", "capture", &self->params.device) ||
403 self->params.device < 0)
404 self->params.device = Pa_GetDefaultInputDevice();
405 self->params.suggestedLatency = 0.0f;
406 self->params.hostApiSpecificStreamInfo = NULL;
408 switch(device->FmtType)
410 case DevFmtByte:
411 self->params.sampleFormat = paInt8;
412 break;
413 case DevFmtUByte:
414 self->params.sampleFormat = paUInt8;
415 break;
416 case DevFmtShort:
417 self->params.sampleFormat = paInt16;
418 break;
419 case DevFmtInt:
420 self->params.sampleFormat = paInt32;
421 break;
422 case DevFmtFloat:
423 self->params.sampleFormat = paFloat32;
424 break;
425 case DevFmtUInt:
426 case DevFmtUShort:
427 ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
428 return ALC_INVALID_VALUE;
430 self->params.channelCount = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
432 err = Pa_OpenStream(&self->stream, &self->params, NULL,
433 device->Frequency, paFramesPerBufferUnspecified, paNoFlag,
434 ALCportCapture_ReadCallback, self
436 if(err != paNoError)
438 ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
439 return ALC_INVALID_VALUE;
442 alstr_copy_cstr(&device->DeviceName, name);
444 return ALC_NO_ERROR;
448 static ALCboolean ALCportCapture_start(ALCportCapture *self)
450 PaError err = Pa_StartStream(self->stream);
451 if(err != paNoError)
453 ERR("Error starting stream: %s\n", Pa_GetErrorText(err));
454 return ALC_FALSE;
456 return ALC_TRUE;
459 static void ALCportCapture_stop(ALCportCapture *self)
461 PaError err = Pa_StopStream(self->stream);
462 if(err != paNoError)
463 ERR("Error stopping stream: %s\n", Pa_GetErrorText(err));
467 static ALCuint ALCportCapture_availableSamples(ALCportCapture *self)
469 return ll_ringbuffer_read_space(self->ring);
472 static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples)
474 ll_ringbuffer_read(self->ring, buffer, samples);
475 return ALC_NO_ERROR;
479 typedef struct ALCportBackendFactory {
480 DERIVE_FROM_TYPE(ALCbackendFactory);
481 } ALCportBackendFactory;
482 #define ALCPORTBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCportBackendFactory, ALCbackendFactory) } }
484 static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory *self);
485 static void ALCportBackendFactory_deinit(ALCportBackendFactory *self);
486 static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory *self, ALCbackend_Type type);
487 static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type);
488 static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
490 DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory);
493 static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory* UNUSED(self))
495 if(!pa_load())
496 return ALC_FALSE;
497 return ALC_TRUE;
500 static void ALCportBackendFactory_deinit(ALCportBackendFactory* UNUSED(self))
502 #ifdef HAVE_DYNLOAD
503 if(pa_handle)
505 Pa_Terminate();
506 CloseLib(pa_handle);
507 pa_handle = NULL;
509 #else
510 Pa_Terminate();
511 #endif
514 static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory* UNUSED(self), ALCbackend_Type type)
516 if(type == ALCbackend_Playback || type == ALCbackend_Capture)
517 return ALC_TRUE;
518 return ALC_FALSE;
521 static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type)
523 switch(type)
525 case ALL_DEVICE_PROBE:
526 AppendAllDevicesList(pa_device);
527 break;
528 case CAPTURE_DEVICE_PROBE:
529 AppendCaptureDeviceList(pa_device);
530 break;
534 static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
536 if(type == ALCbackend_Playback)
538 ALCportPlayback *backend;
539 NEW_OBJ(backend, ALCportPlayback)(device);
540 if(!backend) return NULL;
541 return STATIC_CAST(ALCbackend, backend);
543 if(type == ALCbackend_Capture)
545 ALCportCapture *backend;
546 NEW_OBJ(backend, ALCportCapture)(device);
547 if(!backend) return NULL;
548 return STATIC_CAST(ALCbackend, backend);
551 return NULL;
554 ALCbackendFactory *ALCportBackendFactory_getFactory(void)
556 static ALCportBackendFactory factory = ALCPORTBACKENDFACTORY_INITIALIZER;
557 return STATIC_CAST(ALCbackendFactory, &factory);