source: roaraudio/roard/output.c @ 5044:95b04c57ae49

Last change on this file since 5044:95b04c57ae49 was 5043:f3861009e400, checked in by phi, 13 years ago

updated list of drivers to test

File size: 13.0 KB
Line 
1//output.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2011
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
28int output_buffer_init   (struct roar_audio_info * info) {
29 size_t   size;
30 void   * buf;
31
32 g_output_buffer     = NULL;
33 g_input_buffer      = NULL;
34 g_output_buffer_len = 0;
35
36 size = ROAR_OUTPUT_CALC_OUTBUFSIZE(info);
37
38 ROAR_DBG("output_buffer_init(*): output buffer size is %i", size);
39
40 if ( (buf = roar_mm_malloc(size)) == NULL )
41  return -1;
42
43 g_output_buffer     = buf;
44 g_output_buffer_len = size;
45
46 if ( (buf = roar_mm_malloc(size)) == NULL ) {
47  g_output_buffer     = NULL;
48  g_output_buffer_len = 0;
49  roar_mm_free(g_output_buffer);
50  return -1;
51 }
52
53 g_input_buffer = buf;
54
55 ROAR_DBG("output_buffer_init(*): output buffer is at %p", buf);
56
57 memlock_register(MEMLOCK_LOW, g_output_buffer, size);
58 memlock_register(MEMLOCK_LOW, g_input_buffer,  size);
59
60 output_buffer_reinit();
61
62 return 0;
63}
64
65int output_buffer_reinit (void) {
66
67 if ( g_output_buffer != NULL )
68  memset(g_output_buffer, 0, g_output_buffer_len);
69
70 return 0;
71}
72
73int output_buffer_free   (void) {
74 ROAR_DBG("output_buffer_init(*): freeing output buffer at %p", g_output_buffer);
75
76 if ( g_output_buffer != NULL )
77  roar_mm_free(g_output_buffer);
78
79 if ( g_input_buffer != NULL )
80  roar_mm_free(g_input_buffer);
81
82 g_output_buffer     = NULL;
83 g_input_buffer      = NULL;
84 g_output_buffer_len = 0;
85
86 return 0;
87}
88
89
90
91
92
93
94#ifdef ROAR_DRIVER_DEFAULT
95int output_add_default (char * drv, char * dev, char * opts, int prim, int count) {
96 return output_add(drv, dev, opts, prim, count);
97}
98#else
99int output_add_default (char * drv, char * dev, char * opts, int prim, int count) {
100 char * drvs[] = {
101  // operating system depended things:
102#ifdef __OpenBSD__
103  /* OpenBSD use sndio natively, this check is discusses with upstream (See ML archive August 2010) */
104  "sndio",
105#endif
106  // native and pseudo-native interfaces:
107  "oss", "alsa", "sndio", "wmm",
108  // sound libs:
109  "ao", "portaudio",
110  // other sound systems:
111  "esd", "rsound", "artsc", "pulsesimple", "roar",
112  // libroareio's drivers:
113  "cdriver",
114  // specal buildins:
115  "sysclock", "null",
116  // terminator:
117  NULL
118 };
119 int i;
120 int ret;
121 int _alive;
122 char * _opts;
123
124 if ( drv != NULL )
125  return output_add(drv, dev, opts, prim, count);
126
127 if ( dev != NULL ) {
128  ROAR_WARN("add_default_output(drv=(none), dev='%s', opts='%s', prim=%i, count=%i): It's not recommended to use device name without driver name.", dev, opts, prim, count);
129 }
130
131 for (i = 0; drvs[i] != NULL; i++) {
132  ROAR_INFO("add_default_output(*): trying driver %s", ROAR_DBG_INFO_INFO, drvs[i]);
133  _alive = alive; // save global alive setting
134
135  if ( opts == NULL ) {
136   _opts = NULL;
137  } else {
138   _opts = roar_mm_strdup(opts);
139  }
140
141  ret = output_add(drvs[i], dev, _opts, prim, count);
142
143  if ( _opts != NULL )
144   roar_mm_free(_opts);
145
146  if ( ret != -1 )
147   return ret;
148
149  alive = _alive; // restore global alive setting
150  ROAR_INFO("add_default_output(*): Driver %s faild to load", ROAR_DBG_INFO_VERBOSE, drvs[i]);
151 }
152
153 return -1;
154}
155#endif
156
157
158#define _CKPARAM(n) if ( n (v == NULL) ) { \
159                     ROAR_WARN("add_output(drv='%s', dev='%s', opts=..., prim=%i, count=%i): " \
160                               "Parameter '%s' expects %s parameter.", \
161                               drv, dev, prim, count, k, (n 1) ? "a" : "no"); \
162                     error++; \
163                    } else
164
165int output_add (char * drv, char * dev, char * opts, int prim, int count) {
166 int stream;
167 int default_flags;
168 struct roar_stream * s;
169 struct roar_stream_server * ss;
170 char * k, * v;
171#ifdef ROAR_DRIVER_CODEC
172 char * to_free = NULL;
173#endif
174 int sync = 0, f_mmap = 0;
175 int32_t blocks = -1, blocksize = -1;
176 int dir = ROAR_DIR_OUTPUT;
177 int error = 0;
178 // DMX:
179 int32_t channel  = -1;
180 int32_t universe = -1;
181 uint16_t tu16;
182 float q = -32e6;
183
184 ROAR_INFO("add_output(drv='%s', dev='%s', opts='%s', prim=%i, count=%i): trying to add output driver", ROAR_DBG_INFO_INFO, drv, dev, opts, prim, count);
185
186 if ( drv == NULL && count == 0 ) {
187#ifdef ROAR_DRIVER_DEFAULT
188  drv  = ROAR_DRIVER_DEFAULT;
189  prim = 1;
190  sync = 1;
191
192#ifdef ROAR_DRIVER_CODEC
193  if ( opts == NULL ) {
194   opts = to_free = strdup("codec=" ROAR_DRIVER_CODEC);
195  }
196#endif
197#else
198  ROAR_ERR("add_output(*): Can not find default driver");
199  return -1;
200#endif
201 }
202
203 if ( opts == NULL && count == 0 ) {
204  default_flags = ROAR_FLAG_AUTOCONF|ROAR_FLAG_RECSOURCE;
205  sync = 1;
206  prim = 1; // if ( prim == 0 ) prim = 1; -> prim allways = 1
207 }
208
209 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
210
211 if ( (stream = streams_new()) == -1 ) {
212  ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = -1", drv, dev, opts);
213  if ( prim ) alive = 0;
214  return -1;
215 }
216
217 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
218
219 streams_get(stream, &ss);
220 s = ROAR_STREAM(ss);
221
222 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
223
224 memset(&(s->info), 0xFF, sizeof(struct roar_audio_info)); // set everything to -1
225
226 s->pos_rel_id = -1;
227// s->info.codec = codec;
228
229 // seting default flags:
230 streams_set_flag(stream, default_flags);
231
232 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
233
234 if ( opts == NULL ) {
235  k = NULL;
236 } else {
237  k = strtok(opts, ",");
238 }
239
240 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s'): initial k='%s'(%p)", drv, dev, opts, k, k);
241
242 while (k != NULL) {
243//  ROAR_WARN("add_output(*): opts: %s", k);
244
245  if ( (v = strstr(k, "=")) != NULL ) {
246   *v++ = 0;
247  }
248
249  ROAR_DBG("add_output(*): opts: k='%s', v='%s'", k, v);
250  if ( strcmp(k, "rate") == 0 ) {
251   _CKPARAM()
252    s->info.rate = atoi(v);
253  } else if ( strcmp(k, "channels") == 0 ) {
254   _CKPARAM()
255    s->info.channels = atoi(v);
256  } else if ( strcmp(k, "bits") == 0 ) {
257   _CKPARAM()
258    s->info.bits = atoi(v);
259  } else if ( strcmp(k, "codec") == 0 ) {
260   _CKPARAM()
261    if ( (s->info.codec = roar_str2codec(v)) == -1 ) {
262     ROAR_ERR("add_output(*): unknown codec '%s'", v);
263     error++;
264    }
265  } else if ( strcmp(k, "q") == 0 ) {
266   _CKPARAM()
267    q = atof(v);
268  } else if ( strcmp(k, "blocks") == 0 ) {
269   _CKPARAM()
270    blocks = atoi(v);
271  } else if ( strcmp(k, "blocksize") == 0 ) {
272   _CKPARAM()
273    blocksize = atoi(v);
274  } else if ( strcmp(k, "mmap") == 0 ) {
275   _CKPARAM(!)
276    f_mmap = 1;
277  } else if ( strcmp(k, "subsystem") == 0 ) {
278   _CKPARAM() {
279    if ( !strcasecmp(v, "wave") || !strcasecmp(v, "waveform") ) {
280     dir = ROAR_DIR_OUTPUT;
281#ifndef ROAR_WITHOUT_DCOMP_MIDI
282    } else if ( !strcasecmp(v, "midi") ) {
283     dir = ROAR_DIR_MIDI_OUT;
284#endif
285#ifndef ROAR_WITHOUT_DCOMP_LIGHT
286    } else if ( !strcasecmp(v, "light") ) {
287     dir = ROAR_DIR_LIGHT_OUT;
288#endif
289#ifndef ROAR_WITHOUT_DCOMP_RAW
290    } else if ( !strcasecmp(v, "raw") ) {
291     dir = ROAR_DIR_RAW_OUT;
292#endif
293    } else if ( !strcasecmp(v, "complex") ) {
294     dir = ROAR_DIR_COMPLEX_OUT;
295    } else {
296     ROAR_ERR("add_output(*): unknown/unsupported subsystem '%s'", k);
297     error++;
298    }
299   }
300  // DMX:
301  } else if ( strcmp(k, "channel") == 0 ) {
302   _CKPARAM() {
303    channel  = atoi(v);
304    if ( channel < 0 || channel > 65535 ) {
305     ROAR_ERR("add_output(*): Invalide channel (not within 0..65535): %i", channel);
306     channel = -1;
307     error++;
308    }
309   }
310  } else if ( strcmp(k, "universe") == 0 ) {
311   _CKPARAM() {
312    universe = atoi(v);
313    if ( universe < 0 || universe > 255 ) {
314     ROAR_ERR("add_output(*): Invalide universe (not within 0..255): %i", universe);
315     universe = -1;
316     error++;
317    }
318   }
319
320  } else if ( strcmp(k, "name") == 0 ) {
321   _CKPARAM() {
322    if ( streams_set_name(stream, v) == -1 ) {
323     ROAR_ERR("add_output(*): Can not set Stream name");
324     error++;
325    }
326   }
327
328  } else if ( strcmp(k, "meta") == 0 ) {
329   _CKPARAM(!)
330    streams_set_flag(stream, ROAR_FLAG_META);
331  } else if ( strcmp(k, "sync") == 0 ) {
332   _CKPARAM(!)
333    sync = 1;
334  } else if ( strcmp(k, "primary") == 0 ) {
335   _CKPARAM(!)
336    prim = 1;
337
338  } else if ( strcmp(k, "cleanmeta") == 0 ) {
339   _CKPARAM(!)
340    streams_set_flag(stream, ROAR_FLAG_CLEANMETA);
341  } else if ( strcmp(k, "autoconf") == 0 ) {
342   _CKPARAM(!)
343    streams_set_flag(stream, ROAR_FLAG_AUTOCONF);
344  } else if ( strcmp(k, "recsource") == 0 ) {
345   _CKPARAM(!)
346    streams_set_flag(stream, ROAR_FLAG_RECSOURCE);
347  } else if ( strcmp(k, "passmixer") == 0 ) {
348   _CKPARAM(!)
349    streams_set_flag(stream, ROAR_FLAG_PASSMIXER);
350  } else if ( strcmp(k, "recsource") == 0 ) {
351   _CKPARAM(!)
352    streams_set_flag(stream, ROAR_FLAG_RECSOURCE);
353  } else {
354   ROAR_ERR("add_output(*): unknown option '%s'", k);
355   error++;
356  }
357
358  if ( error ) {
359   streams_delete(stream);
360   if ( prim ) alive = 0;
361#ifdef ROAR_DRIVER_CODEC
362   if ( to_free != NULL )
363    free(to_free);
364#endif
365   return -1;
366  }
367
368  k = strtok(NULL, ",");
369 }
370
371 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
372
373 // set audio info...
374 switch (dir) {
375  case ROAR_DIR_LIGHT_OUT:
376    switch (s->info.codec) {
377     case ROAR_CODEC_DMX512:
378     case -1:
379       if ( s->info.rate == -1 )
380        s->info.rate = ROAR_OUTPUT_CFREQ;
381
382       s->info.channels =   0;
383       s->info.bits     =   8;
384       s->info.codec    = ROAR_CODEC_DMX512; // in case codec == -1
385      break;
386    }
387   break;
388  case ROAR_DIR_MIDI_OUT:
389    switch (s->info.codec) {
390     case ROAR_CODEC_MIDI:
391     case -1:
392       if ( s->info.rate == -1 )
393        s->info.rate    = ROAR_MIDI_TICKS_PER_BEAT;
394
395       s->info.channels = ROAR_MIDI_CHANNELS_DEFAULT;
396       s->info.bits     = ROAR_MIDI_BITS;
397       s->info.codec    = ROAR_CODEC_MIDI; // in case codec == -1
398      break;
399    }
400   break;
401  case ROAR_DIR_RAW_OUT:
402    if ( s->info.rate == -1 )
403     s->info.rate = 0;
404    if ( s->info.bits == -1 )
405     s->info.bits = 0;
406    if ( s->info.channels == -1 )
407     s->info.channels = 0;
408    if ( s->info.codec == -1 )
409     s->info.codec = 0;
410   break;
411 }
412
413 if ( s->info.rate == -1 )
414  s->info.rate = g_sa->rate;
415 if ( s->info.bits == -1 )
416  s->info.bits = g_sa->bits;
417 if ( s->info.channels == -1 )
418  s->info.channels = g_sa->channels;
419 if ( s->info.codec == -1 )
420  s->info.codec = g_sa->codec;
421
422 ROAR_DBG("add_output(*): s->info = {.rate=%i, .bits=%i, .channels=%i, .codec=%i}", s->info.rate, s->info.bits, s->info.channels, s->info.codec);
423
424 if ( streams_set_dir(stream, dir, 1) == -1 ) {
425  streams_delete(stream);
426  return -1;
427 }
428
429#ifdef ROAR_DRIVER_CODEC
430 if ( to_free != NULL )
431  free(to_free);
432#endif
433
434 if ( s->info.codec == ROAR_CODEC_ALAW || s->info.codec == ROAR_CODEC_MULAW )
435  s->info.bits = 8; // needed to open OSS driver, will be overriden by codecfilter
436
437 ROAR_STREAM_SERVER(s)->codec_orgi = s->info.codec;
438
439 if ( driver_openvio(&(ss->vio), &(ss->driver_id), drv, dev, &(s->info), -1, ss) == -1 ) {
440  ss->driver_id = -1; // don't close a driver not opened...
441  memset(&(ss->vio), 0, sizeof(struct roar_vio_calls));
442  streams_delete(stream);
443  if ( prim ) alive = 0;
444  ROAR_ERR("add_output(drv='%s', dev='%s', opts='%s'): can not open output driver.", drv, dev, opts);
445  ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = -1", drv, dev, opts);
446  return -1;
447 }
448
449 roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_SSTREAMID, &stream); // ignore errors here
450 roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_SSTREAM,   s); // ignore errors here
451
452 if ( blocks != -1 )
453  roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_DBLOCKS, &blocks);
454
455 if ( blocksize != -1 )
456  roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_DBLKSIZE, &blocksize);
457
458 // TODO: we shoudld *really* check for errors here...
459 if ( channel != -1 ) {
460  tu16 = channel;
461  roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_DMXSCHAN, &tu16);
462 }
463 if ( universe != -1 ) {
464  tu16 = universe;
465  roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_DMXUNIV, &tu16);
466 }
467
468 ROAR_DBG("add_output(*): ss->driver_id=%i", ss->driver_id);
469
470 streams_set_fh(stream, -1); // update some internal structures
471
472 if ( q > -1e6 ) {
473  ROAR_DBG("add_output(*): setting q=%f", q);
474  streams_ctl(stream, ROAR_CODECFILTER_CTL_SET_Q|ROAR_STREAM_CTL_TYPE_FLOAT, &q);
475 }
476
477 client_stream_add(g_self_client, stream);
478
479 if ( prim ) {
480  streams_mark_primary(stream);
481  s->pos_rel_id = stream;
482 }
483
484 if ( sync ) {
485  streams_set_flag(stream, ROAR_FLAG_SYNC);
486 } else {
487  streams_reset_flag(stream, ROAR_FLAG_SYNC);
488 }
489
490 if ( f_mmap )
491  streams_set_flag(stream, ROAR_FLAG_MMAP);
492
493 ROAR_DBG("add_output(*): s->info = {.rate=%i, .bits=%i, .channels=%i, .codec=%i}", s->info.rate, s->info.bits, s->info.channels, s->info.codec);
494 return 0;
495}
496
497//ll
Note: See TracBrowser for help on using the repository browser.