source: roaraudio/roard/driver_portaudio.c @ 5056:b31e60545552

Last change on this file since 5056:b31e60545552 was 5056:b31e60545552, checked in by phi, 13 years ago

support auto reconf bits=32->16 in case not supported (See: #48)

File size: 7.2 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#endif
39 PaError err;
40 int autoconfig = 0;
41
42 if ( fh != -1 )
43  return -1;
44
45 if ( sstream != NULL ) {
46  autoconfig = streams_get_flag(ROAR_STREAM(sstream)->id, ROAR_FLAG_AUTOCONF);
47 }
48
49 switch (info->bits) {
50  case 8:
51    switch (info->codec) {
52     case ROAR_CODEC_PCM_S_LE:
53     case ROAR_CODEC_PCM_S_BE:
54     case ROAR_CODEC_PCM_S_PDP:
55       fmt = paInt8;
56      break;
57     case ROAR_CODEC_PCM_U_LE:
58     case ROAR_CODEC_PCM_U_BE:
59     case ROAR_CODEC_PCM_U_PDP:
60       fmt = paUInt8;
61      break;
62     default:
63       if ( autoconfig ) {
64        info->codec = ROAR_CODEC_DEFAULT;
65        fmt = paInt8;
66       } else {
67        return -1;
68       }
69      break;
70    }
71   break;
72  case 16:
73    if ( info->codec != ROAR_CODEC_DEFAULT ) {
74     if ( autoconfig ) {
75      info->codec = ROAR_CODEC_DEFAULT;
76     } else {
77      return -1;
78     }
79    }
80    fmt = paInt16;
81   break;
82#ifdef paPackedInt24
83  case 24:
84    if ( info->codec != ROAR_CODEC_DEFAULT ) {
85     if ( autoconfig ) {
86      info->codec = ROAR_CODEC_DEFAULT;
87     } else {
88      return -1;
89     }
90    }
91    fmt = paPackedInt24;
92   break;
93#endif
94  case 32:
95    if ( info->codec != ROAR_CODEC_DEFAULT ) {
96     if ( autoconfig ) {
97      info->codec = ROAR_CODEC_DEFAULT;
98     } else {
99      return -1;
100     }
101    }
102    fmt = paInt32;
103   break;
104  default:
105    if ( autoconfig ) {
106     info->codec = ROAR_CODEC_DEFAULT;
107     info->bits  = 16;
108     fmt = paInt16;
109    } else {
110     return -1;
111    }
112   break;
113 }
114
115 if ( (self = roar_mm_malloc(sizeof(struct driver_portaudio))) == NULL )
116  return -1;
117
118 memset(self, 0, sizeof(struct driver_portaudio));
119
120 memset(inst, 0, sizeof(struct roar_vio_calls));
121
122 inst->inst  = self;
123 inst->close = driver_portaudio_close;
124 inst->write = driver_portaudio_write;
125 inst->nonblock = driver_dummy_nonblock;
126
127 Pa_Initialize();
128
129#ifdef ROAR_HAVE_LIBPABLIO
130 switch (info->channels) {
131  case 1: flags |= PABLIO_MONO;   break;
132  case 2: flags |= PABLIO_STEREO; break;
133  default:
134    if ( autoconfig ) {
135     info->channels = 2;
136     flags |= PABLIO_STEREO;
137    } else {
138     roar_mm_free(self);
139     Pa_Terminate();
140     return -1;
141    }
142 }
143
144 err = OpenAudioStream(&(self->ostream), info->rate, fmt, flags);
145
146 if ( err != paNoError && autoconfig ) {
147  if ( (flags & PABLIO_MONO) == PABLIO_MONO ) {
148   flags -= PABLIO_MONO;
149   flags |= PABLIO_STEREO;
150   info->channels = 2;
151  }
152  fmt         = paInt16;
153  info->codec = ROAR_CODEC_DEFAULT;
154  info->bits  = 16;
155
156  err = OpenAudioStream(&(self->ostream), info->rate, fmt, flags);
157 }
158
159 if ( err != paNoError ) {
160  roar_mm_free(self);
161  Pa_Terminate();
162  return -1;
163 }
164
165 return 0;
166#elif defined(ROAR_HAVE_PA19_VERSION_19)
167 params.device                    = Pa_GetDefaultOutputDevice();
168 params.channelCount              = info->channels;
169 params.sampleFormat              = fmt;
170 params.suggestedLatency          = Pa_GetDeviceInfo(params.device)->defaultLowOutputLatency;
171 params.hostApiSpecificStreamInfo = NULL;
172
173 // TODO: FIXME: use libroar for this.
174 self->framesize = info->bits * info->channels / 8;
175
176 // Sets up blocking I/O stream.
177 err = Pa_OpenStream(&(self->stream),
178                     NULL,
179                     &params,
180                     info->rate,
181                     128 /*FIXME:frames*/,
182                     paClipOff,
183                     NULL,
184                     NULL
185                    );
186
187 if ( err != paNoError && autoconfig ) {
188  params.sampleFormat = paInt16;
189  params.channelCount = 2;
190  info->codec         = ROAR_CODEC_DEFAULT;
191  info->bits          = 16;
192  info->channels      = 2;
193
194  err = Pa_OpenStream(&(self->stream),
195                      NULL,
196                      &params,
197                      info->rate,
198                      128 /*FIXME:frames*/,
199                      paClipOff,
200                      NULL,
201                      NULL
202                     );
203 }
204
205 if ( err != paNoError ) {
206  ROAR_ERR("driver_portaudio_open(*): Could not open PortAudio device: \"%s\".", Pa_GetErrorText(err));
207  roar_mm_free(self);
208  return -1;
209 }
210
211 err = Pa_StartStream(self->stream);
212
213 if ( err != paNoError ) {
214  ROAR_ERR("driver_portaudio_open(*): Could not start stream: \"%s\".", Pa_GetErrorText(err));
215  roar_mm_free(self);
216  return -1;
217 }
218
219 return 0;
220#else
221 return -1;
222#endif
223}
224
225int     driver_portaudio_close        (struct roar_vio_calls * vio) {
226 struct driver_portaudio * self = vio->inst;
227
228 // TODO: cleanup common code.
229
230#ifdef ROAR_HAVE_LIBPABLIO
231 CloseAudioStream(self->ostream);
232
233 Pa_Terminate();
234
235 roar_mm_free(self);
236
237 return 0;
238#elif defined(ROAR_HAVE_PA19_VERSION_19)
239 if ( (self != NULL) && (self->stream != NULL) ) {
240  Pa_StopStream(self->stream);
241  Pa_CloseStream(self->stream);
242 }
243
244 roar_mm_free(self);
245
246 Pa_Terminate();
247
248 return 0;
249#else
250 return -1;
251#endif
252}
253
254ssize_t driver_portaudio_write        (struct roar_vio_calls * vio, void *buf, size_t count) {
255 struct driver_portaudio * self = vio->inst;
256#ifdef ROAR_HAVE_PA19_VERSION_19
257 size_t write_frames = count / self->framesize;
258 PaError err;
259#endif
260
261 ROAR_DBG("driver_portaudio_write(vio=%p, buf=%p, count=%llu) = ?", vio, buf, (long long unsigned int)count);
262
263#ifdef ROAR_HAVE_LIBPABLIO
264 count /= self->ostream->bytesPerFrame; // TODO: FIXME: do not access private members
265 ROAR_DBG("driver_portaudio_write(vio=%p, buf=%p, count=%llu) = ? // PABLIO mode", vio, buf, (long long unsigned int)count);
266 return WriteAudioStream(self->ostream, buf, count) * self->ostream->bytesPerFrame;
267#elif defined(ROAR_HAVE_PA19_VERSION_19)
268
269 ROAR_DBG("driver_portaudio_write(vio=%p, buf=%p, size=%llu) = ?", vio, buf, (long long unsigned int)size);
270
271 // I'm not 100% sure if you could write arbitrary number of frames to Pa_WriteStream(), but it seems to be backend dependent.
272 err = Pa_WriteStream(self->stream, buf, write_frames);
273
274 if ( err < 0 && err != paOutputUnderflowed )
275  return -1;
276
277 // PA always seems to write requested size, or it will error out.
278 return count;
279#else
280 return -1;
281#endif
282}
283
284#endif
285
286//ll
Note: See TracBrowser for help on using the repository browser.