source: roaraudio/roard/driver_portaudio.c @ 5011:512edfc544df

Last change on this file since 5011:512edfc544df was 4858:ef003b336588, checked in by phi, 13 years ago

patch to make sync warnings go away, thanks to maister

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