source: roaraudio/roard/driver_sndio.c @ 5439:7950543cabbc

Last change on this file since 5439:7950543cabbc was 5388:e5cc8e03a3e1, checked in by phi, 12 years ago

Added support for refcount based VIOs as well as dynamically allocated VIOs (non-stack or global VIOs) (Closes: #127)

File size: 7.0 KB
Line 
1//driver_sndio.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2009-2012
5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 */
25
26#include "roard.h"
27#ifdef ROAR_HAVE_LIBSNDIO
28
29int driver_sndio_init_vio(struct roar_vio_calls * vio, struct driver_sndio * inst) {
30 if ( vio == NULL )
31  return -1;
32
33 memset(vio, 0, sizeof(struct roar_vio_calls));
34 vio->flags    = ROAR_VIO_FLAGS_NONE;
35 vio->refc     = 1;
36
37 vio->close    = driver_sndio_close_vio;
38 vio->write    = driver_sndio_write;
39 vio->sync     = driver_sndio_sync;
40 vio->ctl      = driver_sndio_ctl;
41
42 vio->inst     = (void*) inst;
43
44 return 0;
45}
46
47#define _err() if ( self->shandle != NULL ) sio_close(self->shandle);   \
48               if ( self->mhandle != NULL ) mio_close(self->mhandle);   \
49               if ( self->device  != NULL ) roar_mm_free(self->device); \
50               roar_mm_free(self);                              \
51               return -1
52
53int driver_sndio_open(struct roar_vio_calls * inst, char * device, struct roar_audio_info * info, int fh, struct roar_stream_server * sstream) {
54 struct driver_sndio * self = NULL;
55
56 if ( (self = roar_mm_malloc(sizeof(struct driver_sndio))) == NULL ) {
57  ROAR_ERR("driver_sndio_open(*): Can not roar_mm_malloc() instance data: %s", strerror(errno));
58  return -1;
59 }
60
61 memset(self, 0, sizeof(struct driver_sndio));
62 memcpy(&(self->info), info, sizeof(struct roar_audio_info));
63
64 self->ssid = -1;
65
66 if ( sstream == NULL ) {
67  self->stream = NULL;
68  self->dir    = ROAR_DIR_OUTPUT;
69 } else {
70  self->stream = sstream;
71  self->dir    = ROAR_STREAM(sstream)->dir;
72
73  switch (self->dir) {
74   case ROAR_DIR_OUTPUT:
75   case ROAR_DIR_MONITOR:
76     self->dir = ROAR_DIR_OUTPUT;
77    break;
78   case ROAR_DIR_MIDI_OUT:
79     info->channels = 16;
80     info->codec    = ROAR_CODEC_MIDI;
81     info->bits     = 8;
82    break;
83   default:
84     _err();
85  }
86 }
87
88 if ( device != NULL )
89  self->device = roar_mm_strdup(device);
90
91 if ( driver_sndio_init_vio(inst, self) == -1 ) {
92  ROAR_ERR("driver_sndio_open(*): Can not init vio interface");
93  _err();
94 }
95
96 if ( driver_sndio_open_device(self) == -1 ) {
97  ROAR_ERR("driver_sndio_open(*): Can not open audio device");
98  _err();
99 }
100
101 ROAR_DBG("driver_sndio_open(*): sndio devices opened :)");
102
103 return 0;
104}
105#undef er
106
107int     driver_sndio_close_vio    (struct roar_vio_calls * vio) {
108 struct driver_sndio * self = vio->inst;
109
110 if ( self->shandle != NULL )
111  sio_close(self->shandle);
112
113 if ( self->mhandle != NULL )
114  mio_close(self->mhandle);
115
116 if ( self->device != NULL )
117  roar_mm_free(self->device);
118
119 roar_mm_free(self);
120
121 return 0;
122}
123
124int     driver_sndio_open_device  (struct driver_sndio * self) {
125
126 ROAR_DBG("driver_sndio_open_device(*) = ?");
127 switch (self->dir) {
128  case ROAR_DIR_OUTPUT:
129    if ( (self->shandle = sio_open(self->device, SIO_PLAY, 0)) == NULL ) {
130     ROAR_ERR("driver_sndio_open_device(*): Can not open sndio audio device");
131     return -1;
132    }
133   self->need_config = 1;
134   break;
135  case ROAR_DIR_MIDI_OUT:
136    if ( (self->mhandle = mio_open(self->device, MIO_OUT, 0)) == NULL ) {
137     ROAR_ERR("driver_sndio_open_device(*): Can not open sndio MIDI device");
138     return -1;
139    }
140   break;
141  default:
142    return -1;
143 }
144
145 ROAR_DBG("driver_sndio_open_device(*) = ?");
146 return 0;
147}
148
149int     driver_sndio_config_device(struct driver_sndio * self) {
150 struct sio_par par;
151
152 sio_initpar(&par);
153
154 par.bits  = self->info.bits;
155 par.rate  = self->info.rate;
156 par.pchan = self->info.channels;
157
158 switch (self->info.codec) {
159  case ROAR_CODEC_PCM_S_LE:
160    par.le  = 1;
161    par.sig = 1;
162   break;
163  case ROAR_CODEC_PCM_S_BE:
164    par.le  = 0;
165    par.sig = 1;
166   break;
167  case ROAR_CODEC_PCM_U_LE:
168    par.le  = 1;
169    par.sig = 0;
170   break;
171  case ROAR_CODEC_PCM_U_BE:
172    par.le  = 0;
173    par.sig = 0;
174   break;
175  default:
176    return -1;
177   break;
178 }
179
180 if ( sio_setpar(self->shandle, &par) == 0 ) {
181  ROAR_ERR("driver_sndio_config_device(*): Can not set stream parameters");
182  return -1;
183 }
184
185 if ( sio_start(self->shandle) == 0 ) {
186  ROAR_ERR("driver_sndio_config_device(*): Can not start stream");
187  return -1;
188 }
189
190 self->need_config = 0;
191
192 return 0;
193}
194
195int     driver_sndio_reopen_device(struct driver_sndio * self) {
196 return -1;
197}
198
199ssize_t driver_sndio_write        (struct roar_vio_calls * vio, void *buf, size_t count) {
200 struct driver_sndio * self = vio->inst;
201
202 ROAR_DBG("driver_sndio_write(*) = ?");
203
204 if ( self->need_config ) {
205  if ( driver_sndio_config_device(vio->inst) == -1 ) {
206   return -1;
207  }
208 }
209
210 ROAR_DBG("driver_sndio_write(*) = ?");
211
212 switch (self->dir) {
213  case ROAR_DIR_OUTPUT:
214    return sio_write(self->shandle, buf, count);
215   break;
216  case ROAR_DIR_MIDI_OUT:
217    return mio_write(self->mhandle, buf, count);
218   break;
219 }
220
221 ROAR_WARN("driver_sndio_write(*): Driver changed direction to something not supported, this should not happen");
222
223 return -1;
224}
225
226int     driver_sndio_sync         (struct roar_vio_calls * vio) {
227 return -1;
228}
229
230#define data(x) x: if ( data == NULL ) return -1;
231#define no_data(x) x: if ( data != NULL ) return -1;
232
233int     driver_sndio_ctl          (struct roar_vio_calls * vio, roar_vio_ctl_t cmd, void * data) {
234 struct driver_sndio * self = vio->inst;
235 unsigned d;
236
237 switch (cmd) {
238  case data(ROAR_VIO_CTL_SET_SSTREAMID)
239    self->ssid = *(int *)data;
240   break;
241  case data(ROAR_VIO_CTL_SET_SSTREAM)
242    // FIXME: we should do some better error handling here:
243    if ( ROAR_STREAM(data)->dir != self->dir ) return -1;
244    self->stream = data;
245   break;
246  case data(ROAR_VIO_CTL_GET_AUINFO)
247    memcpy(data, &(self->info), sizeof(struct roar_audio_info));
248   break;
249  case data(ROAR_VIO_CTL_SET_AUINFO)
250    memcpy(&(self->info), data, sizeof(struct roar_audio_info));
251    return driver_sndio_reopen_device(self);
252   break;
253  case ROAR_VIO_CTL_SET_VOLUME:
254    switch (self->info.channels) {
255     case 1:
256       d = ROAR_MIXER(data)->mixer[0] * SIO_MAXVOL / ROAR_MIXER(data)->scale;
257      break;
258     case 2:
259       if ( ROAR_MIXER(data)->mixer[0] != ROAR_MIXER(data)->mixer[1] )
260        return -1;
261       d = ROAR_MIXER(data)->mixer[0] * SIO_MAXVOL / ROAR_MIXER(data)->scale;
262      break;
263     default:
264      return -1;
265    }
266    return sio_setvol(self->shandle, d) == 0 ? -1 : 0;
267   break;
268  case ROAR_VIO_CTL_NONBLOCK:
269    if ( *(int*)data == ROAR_SOCKET_BLOCK )
270     return 0;
271    roar_err_set(ROAR_ERROR_NOTSUP);
272    return -1;
273   break;
274  default:
275    return -1;
276   break;
277 }
278
279 return 0;
280}
281
282#endif
283
284//ll
Note: See TracBrowser for help on using the repository browser.