zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
portaudio.c
Go to the documentation of this file.
1 
21 #include "config.h"
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "alMain.h"
28 #include "alu.h"
29 
30 #include <portaudio.h>
31 
32 
33 static const ALCchar pa_device[] = "PortAudio Default";
34 
35 
36 #ifdef HAVE_DYNLOAD
37 static void *pa_handle;
38 #define MAKE_FUNC(x) static typeof(x) * p##x
39 MAKE_FUNC(Pa_Initialize);
40 MAKE_FUNC(Pa_Terminate);
41 MAKE_FUNC(Pa_GetErrorText);
42 MAKE_FUNC(Pa_StartStream);
43 MAKE_FUNC(Pa_StopStream);
44 MAKE_FUNC(Pa_OpenStream);
45 MAKE_FUNC(Pa_CloseStream);
46 MAKE_FUNC(Pa_GetDefaultOutputDevice);
47 MAKE_FUNC(Pa_GetStreamInfo);
48 #undef MAKE_FUNC
49 
50 #define Pa_Initialize pPa_Initialize
51 #define Pa_Terminate pPa_Terminate
52 #define Pa_GetErrorText pPa_GetErrorText
53 #define Pa_StartStream pPa_StartStream
54 #define Pa_StopStream pPa_StopStream
55 #define Pa_OpenStream pPa_OpenStream
56 #define Pa_CloseStream pPa_CloseStream
57 #define Pa_GetDefaultOutputDevice pPa_GetDefaultOutputDevice
58 #define Pa_GetStreamInfo pPa_GetStreamInfo
59 #endif
60 
61 static ALCboolean pa_load(void)
62 {
63  PaError err;
64 
65 #ifdef HAVE_DYNLOAD
66  if(!pa_handle)
67  {
68 #ifdef _WIN32
69 # define PALIB "portaudio.dll"
70 #elif defined(__APPLE__) && defined(__MACH__)
71 # define PALIB "libportaudio.2.dylib"
72 #elif defined(__OpenBSD__)
73 # define PALIB "libportaudio.so"
74 #else
75 # define PALIB "libportaudio.so.2"
76 #endif
77 
78  pa_handle = LoadLib(PALIB);
79  if(!pa_handle)
80  return ALC_FALSE;
81 
82 #define LOAD_FUNC(f) do { \
83  p##f = GetSymbol(pa_handle, #f); \
84  if(p##f == NULL) \
85  { \
86  CloseLib(pa_handle); \
87  pa_handle = NULL; \
88  return ALC_FALSE; \
89  } \
90 } while(0)
91  LOAD_FUNC(Pa_Initialize);
92  LOAD_FUNC(Pa_Terminate);
93  LOAD_FUNC(Pa_GetErrorText);
94  LOAD_FUNC(Pa_StartStream);
95  LOAD_FUNC(Pa_StopStream);
96  LOAD_FUNC(Pa_OpenStream);
97  LOAD_FUNC(Pa_CloseStream);
98  LOAD_FUNC(Pa_GetDefaultOutputDevice);
99  LOAD_FUNC(Pa_GetStreamInfo);
100 #undef LOAD_FUNC
101 
102  if((err=Pa_Initialize()) != paNoError)
103  {
104  ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err));
105  CloseLib(pa_handle);
106  pa_handle = NULL;
107  return ALC_FALSE;
108  }
109  }
110 #else
111  if((err=Pa_Initialize()) != paNoError)
112  {
113  ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err));
114  return ALC_FALSE;
115  }
116 #endif
117  return ALC_TRUE;
118 }
119 
120 
121 typedef struct {
122  PaStream *stream;
123  PaStreamParameters params;
124  ALuint update_size;
125 
126  RingBuffer *ring;
127 } pa_data;
128 
129 
130 static int pa_callback(const void *inputBuffer, void *outputBuffer,
131  unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
132  const PaStreamCallbackFlags statusFlags, void *userData)
133 {
134  ALCdevice *device = (ALCdevice*)userData;
135 
136  (void)inputBuffer;
137  (void)timeInfo;
138  (void)statusFlags;
139 
140  aluMixData(device, outputBuffer, framesPerBuffer);
141  return 0;
142 }
143 
144 static int pa_capture_cb(const void *inputBuffer, void *outputBuffer,
145  unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo,
146  const PaStreamCallbackFlags statusFlags, void *userData)
147 {
148  ALCdevice *device = (ALCdevice*)userData;
149  pa_data *data = (pa_data*)device->ExtraData;
150 
151  (void)outputBuffer;
152  (void)timeInfo;
153  (void)statusFlags;
154 
155  WriteRingBuffer(data->ring, inputBuffer, framesPerBuffer);
156  return 0;
157 }
158 
159 
160 static ALCenum pa_open_playback(ALCdevice *device, const ALCchar *deviceName)
161 {
162  pa_data *data;
163  PaError err;
164 
165  if(!deviceName)
166  deviceName = pa_device;
167  else if(strcmp(deviceName, pa_device) != 0)
168  return ALC_INVALID_VALUE;
169 
170  data = (pa_data*)calloc(1, sizeof(pa_data));
171  data->update_size = device->UpdateSize;
172 
173  data->params.device = -1;
174  if(!ConfigValueInt("port", "device", &data->params.device) ||
175  data->params.device < 0)
176  data->params.device = Pa_GetDefaultOutputDevice();
177  data->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) /
178  (float)device->Frequency;
179  data->params.hostApiSpecificStreamInfo = NULL;
180 
181  data->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2);
182 
183  switch(device->FmtType)
184  {
185  case DevFmtByte:
186  data->params.sampleFormat = paInt8;
187  break;
188  case DevFmtUByte:
189  data->params.sampleFormat = paUInt8;
190  break;
191  case DevFmtUShort:
192  /* fall-through */
193  case DevFmtShort:
194  data->params.sampleFormat = paInt16;
195  break;
196  case DevFmtUInt:
197  /* fall-through */
198  case DevFmtInt:
199  data->params.sampleFormat = paInt32;
200  break;
201  case DevFmtFloat:
202  data->params.sampleFormat = paFloat32;
203  break;
204  }
205 
206 retry_open:
207  err = Pa_OpenStream(&data->stream, NULL, &data->params, device->Frequency,
208  device->UpdateSize, paNoFlag, pa_callback, device);
209  if(err != paNoError)
210  {
211  if(data->params.sampleFormat == paFloat32)
212  {
213  data->params.sampleFormat = paInt16;
214  goto retry_open;
215  }
216  ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
217  free(data);
218  return ALC_INVALID_VALUE;
219  }
220 
221  device->ExtraData = data;
222  device->DeviceName = strdup(deviceName);
223 
224  return ALC_NO_ERROR;
225 }
226 
227 static void pa_close_playback(ALCdevice *device)
228 {
229  pa_data *data = (pa_data*)device->ExtraData;
230  PaError err;
231 
232  err = Pa_CloseStream(data->stream);
233  if(err != paNoError)
234  ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
235 
236  free(data);
237  device->ExtraData = NULL;
238 }
239 
241 {
242  pa_data *data = (pa_data*)device->ExtraData;
243  const PaStreamInfo *streamInfo;
244 
245  streamInfo = Pa_GetStreamInfo(data->stream);
246  device->Frequency = streamInfo->sampleRate;
247  device->UpdateSize = data->update_size;
248 
249  if(data->params.sampleFormat == paInt8)
250  device->FmtType = DevFmtByte;
251  else if(data->params.sampleFormat == paUInt8)
252  device->FmtType = DevFmtUByte;
253  else if(data->params.sampleFormat == paInt16)
254  device->FmtType = DevFmtShort;
255  else if(data->params.sampleFormat == paInt32)
256  device->FmtType = DevFmtInt;
257  else if(data->params.sampleFormat == paFloat32)
258  device->FmtType = DevFmtFloat;
259  else
260  {
261  ERR("Unexpected sample format: 0x%lx\n", data->params.sampleFormat);
262  return ALC_FALSE;
263  }
264 
265  if(data->params.channelCount == 2)
266  device->FmtChans = DevFmtStereo;
267  else if(data->params.channelCount == 1)
268  device->FmtChans = DevFmtMono;
269  else
270  {
271  ERR("Unexpected channel count: %u\n", data->params.channelCount);
272  return ALC_FALSE;
273  }
274  SetDefaultChannelOrder(device);
275 
276  return ALC_TRUE;
277 }
278 
280 {
281  pa_data *data = (pa_data*)device->ExtraData;
282  PaError err;
283 
284  err = Pa_StartStream(data->stream);
285  if(err != paNoError)
286  {
287  ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err));
288  return ALC_FALSE;
289  }
290 
291  return ALC_TRUE;
292 }
293 
294 static void pa_stop_playback(ALCdevice *device)
295 {
296  pa_data *data = (pa_data*)device->ExtraData;
297  PaError err;
298 
299  err = Pa_StopStream(data->stream);
300  if(err != paNoError)
301  ERR("Error stopping stream: %s\n", Pa_GetErrorText(err));
302 }
303 
304 
305 static ALCenum pa_open_capture(ALCdevice *device, const ALCchar *deviceName)
306 {
307  ALuint frame_size;
308  pa_data *data;
309  PaError err;
310 
311  if(!deviceName)
312  deviceName = pa_device;
313  else if(strcmp(deviceName, pa_device) != 0)
314  return ALC_INVALID_VALUE;
315 
316  data = (pa_data*)calloc(1, sizeof(pa_data));
317  if(data == NULL)
318  return ALC_OUT_OF_MEMORY;
319 
320  frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
321  data->ring = CreateRingBuffer(frame_size, device->UpdateSize*device->NumUpdates);
322  if(data->ring == NULL)
323  goto error;
324 
325  data->params.device = -1;
326  if(!ConfigValueInt("port", "capture", &data->params.device) ||
327  data->params.device < 0)
328  data->params.device = Pa_GetDefaultOutputDevice();
329  data->params.suggestedLatency = 0.0f;
330  data->params.hostApiSpecificStreamInfo = NULL;
331 
332  switch(device->FmtType)
333  {
334  case DevFmtByte:
335  data->params.sampleFormat = paInt8;
336  break;
337  case DevFmtUByte:
338  data->params.sampleFormat = paUInt8;
339  break;
340  case DevFmtShort:
341  data->params.sampleFormat = paInt16;
342  break;
343  case DevFmtInt:
344  data->params.sampleFormat = paInt32;
345  break;
346  case DevFmtFloat:
347  data->params.sampleFormat = paFloat32;
348  break;
349  case DevFmtUInt:
350  case DevFmtUShort:
351  ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
352  goto error;
353  }
354  data->params.channelCount = ChannelsFromDevFmt(device->FmtChans);
355 
356  err = Pa_OpenStream(&data->stream, &data->params, NULL, device->Frequency,
357  paFramesPerBufferUnspecified, paNoFlag, pa_capture_cb, device);
358  if(err != paNoError)
359  {
360  ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err));
361  goto error;
362  }
363 
364  device->DeviceName = strdup(deviceName);
365 
366  device->ExtraData = data;
367  return ALC_NO_ERROR;
368 
369 error:
370  DestroyRingBuffer(data->ring);
371  free(data);
372  return ALC_INVALID_VALUE;
373 }
374 
375 static void pa_close_capture(ALCdevice *device)
376 {
377  pa_data *data = (pa_data*)device->ExtraData;
378  PaError err;
379 
380  err = Pa_CloseStream(data->stream);
381  if(err != paNoError)
382  ERR("Error closing stream: %s\n", Pa_GetErrorText(err));
383 
384  free(data);
385  device->ExtraData = NULL;
386 }
387 
388 static void pa_start_capture(ALCdevice *device)
389 {
390  pa_data *data = device->ExtraData;
391  PaError err;
392 
393  err = Pa_StartStream(data->stream);
394  if(err != paNoError)
395  ERR("Error starting stream: %s\n", Pa_GetErrorText(err));
396 }
397 
398 static void pa_stop_capture(ALCdevice *device)
399 {
400  pa_data *data = (pa_data*)device->ExtraData;
401  PaError err;
402 
403  err = Pa_StopStream(data->stream);
404  if(err != paNoError)
405  ERR("Error stopping stream: %s\n", Pa_GetErrorText(err));
406 }
407 
409 {
410  pa_data *data = device->ExtraData;
411  ReadRingBuffer(data->ring, buffer, samples);
412  return ALC_NO_ERROR;
413 }
414 
416 {
417  pa_data *data = device->ExtraData;
418  return RingBufferSize(data->ring);
419 }
420 
421 
422 static const BackendFuncs pa_funcs = {
437 };
438 
440 {
441  if(!pa_load())
442  return ALC_FALSE;
443  *func_list = pa_funcs;
444  return ALC_TRUE;
445 }
446 
447 void alc_pa_deinit(void)
448 {
449 #ifdef HAVE_DYNLOAD
450  if(pa_handle)
451  {
452  Pa_Terminate();
453  CloseLib(pa_handle);
454  pa_handle = NULL;
455  }
456 #else
457  Pa_Terminate();
458 #endif
459 }
460 
462 {
463  switch(type)
464  {
465  case ALL_DEVICE_PROBE:
467  break;
470  break;
471  }
472 }
static void pa_start_capture(ALCdevice *device)
Definition: portaudio.c:388
static const ALCchar pa_device[]
Definition: portaudio.c:33
static void pa_stop_capture(ALCdevice *device)
Definition: portaudio.c:398
#define ALC_TRUE
Definition: alc.h:84
static int pa_capture_cb(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags, void *userData)
Definition: portaudio.c:144
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum type
Definition: gl2ext.h:845
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
Definition: glew.h:1824
char * strdup(const char *inStr)
Definition: strdup.c:6
int ConfigValueInt(const char *blockName, const char *keyName, int *ret)
Definition: alcConfig.c:325
#define NULL
Definition: ftobjs.h:61
void alc_pa_deinit(void)
Definition: portaudio.c:447
GLuint GLuint stream
Definition: glew.h:6573
SDL_EventEntry * free
Definition: SDL_events.c:80
ALuint Frequency
Definition: alMain.h:569
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
Definition: ALu.c:970
static const BackendFuncs pa_funcs
Definition: portaudio.c:422
ALint64 ALCdevice_GetLatencyDefault(ALCdevice *device)
Definition: ALc.c:1285
ALsizei RingBufferSize(RingBuffer *ring)
Definition: alcRing.c:67
void SetDefaultChannelOrder(ALCdevice *device)
Definition: ALc.c:1352
void AppendCaptureDeviceList(const ALCchar *name)
static void pa_close_capture(ALCdevice *device)
Definition: portaudio.c:375
unsigned int ALCuint
Definition: alc.h:60
#define calloc
Definition: SDL_malloc.c:636
char ALCchar
Definition: alc.h:42
GLenum GLvoid ** params
Definition: gl2ext.h:806
static ALCenum pa_open_playback(ALCdevice *device, const ALCchar *deviceName)
Definition: portaudio.c:160
static void pa_stop_playback(ALCdevice *device)
Definition: portaudio.c:294
struct RingBuffer RingBuffer
Definition: alMain.h:750
EGLContext EGLenum EGLClientBuffer buffer
Definition: eglext.h:87
void * ExtraData
Definition: alMain.h:630
ALCboolean alc_pa_init(BackendFuncs *func_list)
Definition: portaudio.c:439
#define ALC_FALSE
Definition: alc.h:81
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
FT_Error error
Definition: cffdrivr.c:407
GLsizei samples
Definition: gl2ext.h:970
RingBuffer * CreateRingBuffer(ALsizei frame_size, ALsizei length)
Definition: alcRing.c:41
#define LOAD_FUNC(f)
unsigned int ALuint
Definition: al.h:59
static ALCenum pa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
Definition: portaudio.c:408
static ALCboolean pa_reset_playback(ALCdevice *device)
Definition: portaudio.c:240
enum DevFmtChannels FmtChans
Definition: alMain.h:572
static ALCuint pa_available_samples(ALCdevice *device)
Definition: portaudio.c:415
static void pa_close_playback(ALCdevice *device)
Definition: portaudio.c:227
static ALCboolean pa_load(void)
Definition: portaudio.c:61
void alc_pa_probe(enum DevProbe type)
Definition: portaudio.c:461
#define ALC_NO_ERROR
Definition: alc.h:102
void ALCdevice_LockDefault(ALCdevice *device)
Definition: ALc.c:1277
char ALCboolean
Definition: alc.h:39
void ALCvoid
Definition: alc.h:75
#define ERR(...)
Definition: alMain.h:816
ALuint UpdateSize
Definition: alMain.h:570
static ALCboolean pa_start_playback(ALCdevice *device)
Definition: portaudio.c:279
static ALCenum pa_open_capture(ALCdevice *device, const ALCchar *deviceName)
Definition: portaudio.c:305
ALuint NumUpdates
Definition: alMain.h:571
enum DevFmtType FmtType
Definition: alMain.h:573
ALCchar * DeviceName
Definition: alMain.h:575
#define ALC_INVALID_VALUE
Definition: alc.h:114
#define ALC_OUT_OF_MEMORY
Definition: alc.h:117
void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len)
Definition: alcRing.c:108
int ALCenum
Definition: alc.h:66
const ALCchar * DevFmtTypeString(enum DevFmtType type)
Definition: ALc.c:1136
void DestroyRingBuffer(RingBuffer *ring)
Definition: alcRing.c:58
void ALCdevice_UnlockDefault(ALCdevice *device)
Definition: ALc.c:1281
void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len)
Definition: alcRing.c:78
ALuint ChannelsFromDevFmt(enum DevFmtChannels chans)
Definition: ALc.c:1179
void AppendAllDevicesList(const ALCchar *name)
DevProbe
Definition: alMain.h:383
static __inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type)
Definition: alMain.h:523
static int pa_callback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, const PaStreamCallbackFlags statusFlags, void *userData)
Definition: portaudio.c:130