source: roaraudio/roard/driver_portaudio.c

tip
Last change on this file was 6052:d48765b2475e, checked in by phi, 8 years ago

updated copyright headers

File size: 7.5 KB
Line 
1//driver_portaudio.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2015
5 *      Copyright (C) Hans-Kristian 'maister' Arntzen - 2010-2011
6 *
7 *  This file is part of roard a part of RoarAudio,
8 *  a cross-platform sound system for both, home and professional use.
9 *  See README for details.
10 *
11 *  This file is free software; you can redistribute it and/or modify
12 *  it under the terms of the GNU General Public License version 3
13 *  as published by the Free Software Foundation.
14 *
15 *  RoarAudio is distributed in the hope that it will be useful,
16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 *  GNU General Public License for more details.
19 *
20 *  You should have received a copy of the GNU General Public License
21 *  along with this software; see the file COPYING.  If not, write to
22 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23 *  Boston, MA 02110-1301, USA.
24 *
25 */
26
27#include "roard.h"
28
29#ifdef _DRIVER_PORTAUDIO_CAN_OPERATE
30
31int driver_portaudio_open(struct roar_vio_calls * inst, char * device, struct roar_audio_info * info, int fh, struct roar_stream_server * sstream) {
32 struct driver_portaudio * self;
33 PaSampleFormat fmt;
34#ifdef ROAR_HAVE_LIBPABLIO
35 long flags = PABLIO_WRITE;
36#elif defined(ROAR_HAVE_PA19_VERSION_19)
37 PaStreamParameters params;
38 const PaDeviceInfo * dev_info = NULL;
39#endif
40 PaError err;
41 int autoconfig = 0;
42
43 if ( fh != -1 )
44  return -1;
45
46 if ( sstream != NULL ) {
47  autoconfig = streams_get_flag(ROAR_STREAM(sstream)->id, ROAR_FLAG_AUTOCONF);
48 }
49
50 switch (info->bits) {
51  case 8:
52    switch (info->codec) {
53     case ROAR_CODEC_PCM_S_LE:
54     case ROAR_CODEC_PCM_S_BE:
55     case ROAR_CODEC_PCM_S_PDP:
56       fmt = paInt8;
57      break;
58     case ROAR_CODEC_PCM_U_LE:
59     case ROAR_CODEC_PCM_U_BE:
60     case ROAR_CODEC_PCM_U_PDP:
61       fmt = paUInt8;
62      break;
63     default:
64       if ( autoconfig ) {
65        info->codec = ROAR_CODEC_DEFAULT;
66        fmt = paInt8;
67       } else {
68        return -1;
69       }
70      break;
71    }
72   break;
73  case 16:
74    if ( info->codec != ROAR_CODEC_DEFAULT ) {
75     if ( autoconfig ) {
76      info->codec = ROAR_CODEC_DEFAULT;
77     } else {
78      return -1;
79     }
80    }
81    fmt = paInt16;
82   break;
83#ifdef paPackedInt24
84  case 24:
85    if ( info->codec != ROAR_CODEC_DEFAULT ) {
86     if ( autoconfig ) {
87      info->codec = ROAR_CODEC_DEFAULT;
88     } else {
89      return -1;
90     }
91    }
92    fmt = paPackedInt24;
93   break;
94#endif
95  case 32:
96    if ( info->codec != ROAR_CODEC_DEFAULT ) {
97     if ( autoconfig ) {
98      info->codec = ROAR_CODEC_DEFAULT;
99     } else {
100      return -1;
101     }
102    }
103    fmt = paInt32;
104   break;
105  default:
106    if ( autoconfig ) {
107     info->codec = ROAR_CODEC_DEFAULT;
108     info->bits  = 16;
109     fmt = paInt16;
110    } else {
111     return -1;
112    }
113   break;
114 }
115
116 if ( (self = roar_mm_malloc(sizeof(struct driver_portaudio))) == NULL )
117  return -1;
118
119 memset(self, 0, sizeof(struct driver_portaudio));
120
121 memset(inst, 0, sizeof(struct roar_vio_calls));
122 inst->flags = ROAR_VIO_FLAGS_NONE;
123 inst->refc  = 1;
124
125 inst->inst  = self;
126 inst->close = driver_portaudio_close;
127 inst->write = driver_portaudio_write;
128 inst->ctl   = driver_dummy_ctl;
129
130 Pa_Initialize();
131
132#ifdef ROAR_HAVE_LIBPABLIO
133 switch (info->channels) {
134  case 1: flags |= PABLIO_MONO;   break;
135  case 2: flags |= PABLIO_STEREO; break;
136  default:
137    if ( autoconfig ) {
138     info->channels = 2;
139     flags |= PABLIO_STEREO;
140    } else {
141     roar_mm_free(self);
142     Pa_Terminate();
143     return -1;
144    }
145 }
146
147 err = OpenAudioStream(&(self->ostream), info->rate, fmt, flags);
148
149 if ( err != paNoError && autoconfig ) {
150  if ( (flags & PABLIO_MONO) == PABLIO_MONO ) {
151   flags -= PABLIO_MONO;
152   flags |= PABLIO_STEREO;
153   info->channels = 2;
154  }
155  fmt         = paInt16;
156  info->codec = ROAR_CODEC_DEFAULT;
157  info->bits  = 16;
158
159  err = OpenAudioStream(&(self->ostream), info->rate, fmt, flags);
160 }
161
162 if ( err != paNoError ) {
163  roar_mm_free(self);
164  Pa_Terminate();
165  return -1;
166 }
167
168 return 0;
169#elif defined(ROAR_HAVE_PA19_VERSION_19)
170 err                              = paNoError;
171
172 params.device                    = Pa_GetDefaultOutputDevice();
173 params.channelCount              = info->channels;
174 params.sampleFormat              = fmt;
175
176 if ( params.device != paNoDevice )
177  dev_info = Pa_GetDeviceInfo(params.device);
178
179 if ( dev_info != NULL ) {
180  params.suggestedLatency = dev_info->defaultLowOutputLatency;
181 } else {
182  err = paNoDevice;
183 }
184
185 params.hostApiSpecificStreamInfo = NULL;
186
187 // TODO: FIXME: use libroar for this.
188 self->framesize = info->bits * info->channels / 8;
189
190 // Sets up blocking I/O stream.
191 if ( err == paNoError ) {
192  err = Pa_OpenStream(&(self->stream),
193                      NULL,
194                      &params,
195                      info->rate,
196                      128 /*FIXME:frames*/,
197                      paClipOff,
198                      NULL,
199                      NULL
200                     );
201 }
202
203 if ( err != paNoError && err != paNoDevice && autoconfig ) {
204  params.sampleFormat = paInt16;
205  params.channelCount = 2;
206  info->codec         = ROAR_CODEC_DEFAULT;
207  info->bits          = 16;
208  info->channels      = 2;
209
210  err = Pa_OpenStream(&(self->stream),
211                      NULL,
212                      &params,
213                      info->rate,
214                      128 /*FIXME:frames*/,
215                      paClipOff,
216                      NULL,
217                      NULL
218                     );
219 }
220
221 if ( err != paNoError ) {
222  ROAR_ERR("driver_portaudio_open(*): Could not open PortAudio device: \"%s\".", Pa_GetErrorText(err));
223  roar_mm_free(self);
224  return -1;
225 }
226
227 err = Pa_StartStream(self->stream);
228
229 if ( err != paNoError ) {
230  ROAR_ERR("driver_portaudio_open(*): Could not start stream: \"%s\".", Pa_GetErrorText(err));
231  roar_mm_free(self);
232  return -1;
233 }
234
235 return 0;
236#else
237 return -1;
238#endif
239}
240
241int     driver_portaudio_close        (struct roar_vio_calls * vio) {
242 struct driver_portaudio * self = vio->inst;
243
244 // TODO: cleanup common code.
245
246#ifdef ROAR_HAVE_LIBPABLIO
247 CloseAudioStream(self->ostream);
248
249 Pa_Terminate();
250
251 roar_mm_free(self);
252
253 return 0;
254#elif defined(ROAR_HAVE_PA19_VERSION_19)
255 if ( (self != NULL) && (self->stream != NULL) ) {
256  Pa_StopStream(self->stream);
257  Pa_CloseStream(self->stream);
258 }
259
260 roar_mm_free(self);
261
262 Pa_Terminate();
263
264 return 0;
265#else
266 return -1;
267#endif
268}
269
270ssize_t driver_portaudio_write        (struct roar_vio_calls * vio, void *buf, size_t count) {
271 struct driver_portaudio * self = vio->inst;
272#ifdef ROAR_HAVE_PA19_VERSION_19
273 size_t write_frames = count / self->framesize;
274 PaError err;
275#endif
276
277 ROAR_DBG("driver_portaudio_write(vio=%p, buf=%p, count=%llu) = ?", vio, buf, (long long unsigned int)count);
278
279#ifdef ROAR_HAVE_LIBPABLIO
280 count /= self->ostream->bytesPerFrame; // TODO: FIXME: do not access private members
281 ROAR_DBG("driver_portaudio_write(vio=%p, buf=%p, count=%llu) = ? // PABLIO mode", vio, buf, (long long unsigned int)count);
282 return WriteAudioStream(self->ostream, buf, count) * self->ostream->bytesPerFrame;
283#elif defined(ROAR_HAVE_PA19_VERSION_19)
284
285 ROAR_DBG("driver_portaudio_write(vio=%p, buf=%p, size=%llu) = ?", vio, buf, (long long unsigned int)size);
286
287 // I'm not 100% sure if you could write arbitrary number of frames to Pa_WriteStream(), but it seems to be backend dependent.
288 err = Pa_WriteStream(self->stream, buf, write_frames);
289
290 if ( err < 0 && err != paOutputUnderflowed )
291  return -1;
292
293 // PA always seems to write requested size, or it will error out.
294 return count;
295#else
296 return -1;
297#endif
298}
299
300#endif
301
302//ll
Note: See TracBrowser for help on using the repository browser.