source: roaraudio/roard/driver_portaudio.c @ 5276:0eb24ca6810e

Last change on this file since 5276:0eb24ca6810e was 5276:0eb24ca6810e, checked in by phi, 12 years ago

merged VIO's _nonblock() into _ctl() (Closes: #135)

File size: 7.4 KB
Line 
1//driver_portaudio.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2011
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
123 inst->inst  = self;
124 inst->close = driver_portaudio_close;
125 inst->write = driver_portaudio_write;
126 inst->ctl   = driver_dummy_ctl;
127
128 Pa_Initialize();
129
130#ifdef ROAR_HAVE_LIBPABLIO
131 switch (info->channels) {
132  case 1: flags |= PABLIO_MONO;   break;
133  case 2: flags |= PABLIO_STEREO; break;
134  default:
135    if ( autoconfig ) {
136     info->channels = 2;
137     flags |= PABLIO_STEREO;
138    } else {
139     roar_mm_free(self);
140     Pa_Terminate();
141     return -1;
142    }
143 }
144
145 err = OpenAudioStream(&(self->ostream), info->rate, fmt, flags);
146
147 if ( err != paNoError && autoconfig ) {
148  if ( (flags & PABLIO_MONO) == PABLIO_MONO ) {
149   flags -= PABLIO_MONO;
150   flags |= PABLIO_STEREO;
151   info->channels = 2;
152  }
153  fmt         = paInt16;
154  info->codec = ROAR_CODEC_DEFAULT;
155  info->bits  = 16;
156
157  err = OpenAudioStream(&(self->ostream), info->rate, fmt, flags);
158 }
159
160 if ( err != paNoError ) {
161  roar_mm_free(self);
162  Pa_Terminate();
163  return -1;
164 }
165
166 return 0;
167#elif defined(ROAR_HAVE_PA19_VERSION_19)
168 err                              = paNoError;
169
170 params.device                    = Pa_GetDefaultOutputDevice();
171 params.channelCount              = info->channels;
172 params.sampleFormat              = fmt;
173
174 if ( params.device != paNoDevice )
175  dev_info = Pa_GetDeviceInfo(params.device);
176
177 if ( dev_info != NULL ) {
178  params.suggestedLatency = dev_info->defaultLowOutputLatency;
179 } else {
180  err = paNoDevice;
181 }
182
183 params.hostApiSpecificStreamInfo = NULL;
184
185 // TODO: FIXME: use libroar for this.
186 self->framesize = info->bits * info->channels / 8;
187
188 // Sets up blocking I/O stream.
189 if ( err == paNoError ) {
190  err = Pa_OpenStream(&(self->stream),
191                      NULL,
192                      &params,
193                      info->rate,
194                      128 /*FIXME:frames*/,
195                      paClipOff,
196                      NULL,
197                      NULL
198                     );
199 }
200
201 if ( err != paNoError && err != paNoDevice && autoconfig ) {
202  params.sampleFormat = paInt16;
203  params.channelCount = 2;
204  info->codec         = ROAR_CODEC_DEFAULT;
205  info->bits          = 16;
206  info->channels      = 2;
207
208  err = Pa_OpenStream(&(self->stream),
209                      NULL,
210                      &params,
211                      info->rate,
212                      128 /*FIXME:frames*/,
213                      paClipOff,
214                      NULL,
215                      NULL
216                     );
217 }
218
219 if ( err != paNoError ) {
220  ROAR_ERR("driver_portaudio_open(*): Could not open PortAudio device: \"%s\".", Pa_GetErrorText(err));
221  roar_mm_free(self);
222  return -1;
223 }
224
225 err = Pa_StartStream(self->stream);
226
227 if ( err != paNoError ) {
228  ROAR_ERR("driver_portaudio_open(*): Could not start stream: \"%s\".", Pa_GetErrorText(err));
229  roar_mm_free(self);
230  return -1;
231 }
232
233 return 0;
234#else
235 return -1;
236#endif
237}
238
239int     driver_portaudio_close        (struct roar_vio_calls * vio) {
240 struct driver_portaudio * self = vio->inst;
241
242 // TODO: cleanup common code.
243
244#ifdef ROAR_HAVE_LIBPABLIO
245 CloseAudioStream(self->ostream);
246
247 Pa_Terminate();
248
249 roar_mm_free(self);
250
251 return 0;
252#elif defined(ROAR_HAVE_PA19_VERSION_19)
253 if ( (self != NULL) && (self->stream != NULL) ) {
254  Pa_StopStream(self->stream);
255  Pa_CloseStream(self->stream);
256 }
257
258 roar_mm_free(self);
259
260 Pa_Terminate();
261
262 return 0;
263#else
264 return -1;
265#endif
266}
267
268ssize_t driver_portaudio_write        (struct roar_vio_calls * vio, void *buf, size_t count) {
269 struct driver_portaudio * self = vio->inst;
270#ifdef ROAR_HAVE_PA19_VERSION_19
271 size_t write_frames = count / self->framesize;
272 PaError err;
273#endif
274
275 ROAR_DBG("driver_portaudio_write(vio=%p, buf=%p, count=%llu) = ?", vio, buf, (long long unsigned int)count);
276
277#ifdef ROAR_HAVE_LIBPABLIO
278 count /= self->ostream->bytesPerFrame; // TODO: FIXME: do not access private members
279 ROAR_DBG("driver_portaudio_write(vio=%p, buf=%p, count=%llu) = ? // PABLIO mode", vio, buf, (long long unsigned int)count);
280 return WriteAudioStream(self->ostream, buf, count) * self->ostream->bytesPerFrame;
281#elif defined(ROAR_HAVE_PA19_VERSION_19)
282
283 ROAR_DBG("driver_portaudio_write(vio=%p, buf=%p, size=%llu) = ?", vio, buf, (long long unsigned int)size);
284
285 // I'm not 100% sure if you could write arbitrary number of frames to Pa_WriteStream(), but it seems to be backend dependent.
286 err = Pa_WriteStream(self->stream, buf, write_frames);
287
288 if ( err < 0 && err != paOutputUnderflowed )
289  return -1;
290
291 // PA always seems to write requested size, or it will error out.
292 return count;
293#else
294 return -1;
295#endif
296}
297
298#endif
299
300//ll
Note: See TracBrowser for help on using the repository browser.