source: roaraudio/roard/output.c @ 5045:bbba9c469731

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

default_flags needs to be inited.

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 = 0;
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  ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
205  default_flags = ROAR_FLAG_AUTOCONF|ROAR_FLAG_RECSOURCE;
206  sync = 1;
207  prim = 1; // if ( prim == 0 ) prim = 1; -> prim allways = 1
208 }
209
210 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
211
212 if ( (stream = streams_new()) == -1 ) {
213  ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = -1", drv, dev, opts);
214  if ( prim ) alive = 0;
215  return -1;
216 }
217
218 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
219
220 streams_get(stream, &ss);
221 s = ROAR_STREAM(ss);
222
223 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
224
225 memset(&(s->info), 0xFF, sizeof(struct roar_audio_info)); // set everything to -1
226
227 s->pos_rel_id = -1;
228// s->info.codec = codec;
229
230 // seting default flags:
231 streams_set_flag(stream, default_flags);
232
233 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
234
235 if ( opts == NULL ) {
236  k = NULL;
237 } else {
238  k = strtok(opts, ",");
239 }
240
241 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s'): initial k='%s'(%p)", drv, dev, opts, k, k);
242
243 while (k != NULL) {
244//  ROAR_WARN("add_output(*): opts: %s", k);
245
246  if ( (v = strstr(k, "=")) != NULL ) {
247   *v++ = 0;
248  }
249
250  ROAR_DBG("add_output(*): opts: k='%s', v='%s'", k, v);
251  if ( strcmp(k, "rate") == 0 ) {
252   _CKPARAM()
253    s->info.rate = atoi(v);
254  } else if ( strcmp(k, "channels") == 0 ) {
255   _CKPARAM()
256    s->info.channels = atoi(v);
257  } else if ( strcmp(k, "bits") == 0 ) {
258   _CKPARAM()
259    s->info.bits = atoi(v);
260  } else if ( strcmp(k, "codec") == 0 ) {
261   _CKPARAM()
262    if ( (s->info.codec = roar_str2codec(v)) == -1 ) {
263     ROAR_ERR("add_output(*): unknown codec '%s'", v);
264     error++;
265    }
266  } else if ( strcmp(k, "q") == 0 ) {
267   _CKPARAM()
268    q = atof(v);
269  } else if ( strcmp(k, "blocks") == 0 ) {
270   _CKPARAM()
271    blocks = atoi(v);
272  } else if ( strcmp(k, "blocksize") == 0 ) {
273   _CKPARAM()
274    blocksize = atoi(v);
275  } else if ( strcmp(k, "mmap") == 0 ) {
276   _CKPARAM(!)
277    f_mmap = 1;
278  } else if ( strcmp(k, "subsystem") == 0 ) {
279   _CKPARAM() {
280    if ( !strcasecmp(v, "wave") || !strcasecmp(v, "waveform") ) {
281     dir = ROAR_DIR_OUTPUT;
282#ifndef ROAR_WITHOUT_DCOMP_MIDI
283    } else if ( !strcasecmp(v, "midi") ) {
284     dir = ROAR_DIR_MIDI_OUT;
285#endif
286#ifndef ROAR_WITHOUT_DCOMP_LIGHT
287    } else if ( !strcasecmp(v, "light") ) {
288     dir = ROAR_DIR_LIGHT_OUT;
289#endif
290#ifndef ROAR_WITHOUT_DCOMP_RAW
291    } else if ( !strcasecmp(v, "raw") ) {
292     dir = ROAR_DIR_RAW_OUT;
293#endif
294    } else if ( !strcasecmp(v, "complex") ) {
295     dir = ROAR_DIR_COMPLEX_OUT;
296    } else {
297     ROAR_ERR("add_output(*): unknown/unsupported subsystem '%s'", k);
298     error++;
299    }
300   }
301  // DMX:
302  } else if ( strcmp(k, "channel") == 0 ) {
303   _CKPARAM() {
304    channel  = atoi(v);
305    if ( channel < 0 || channel > 65535 ) {
306     ROAR_ERR("add_output(*): Invalide channel (not within 0..65535): %i", channel);
307     channel = -1;
308     error++;
309    }
310   }
311  } else if ( strcmp(k, "universe") == 0 ) {
312   _CKPARAM() {
313    universe = atoi(v);
314    if ( universe < 0 || universe > 255 ) {
315     ROAR_ERR("add_output(*): Invalide universe (not within 0..255): %i", universe);
316     universe = -1;
317     error++;
318    }
319   }
320
321  } else if ( strcmp(k, "name") == 0 ) {
322   _CKPARAM() {
323    if ( streams_set_name(stream, v) == -1 ) {
324     ROAR_ERR("add_output(*): Can not set Stream name");
325     error++;
326    }
327   }
328
329  } else if ( strcmp(k, "meta") == 0 ) {
330   _CKPARAM(!)
331    streams_set_flag(stream, ROAR_FLAG_META);
332  } else if ( strcmp(k, "sync") == 0 ) {
333   _CKPARAM(!)
334    sync = 1;
335  } else if ( strcmp(k, "primary") == 0 ) {
336   _CKPARAM(!)
337    prim = 1;
338
339  } else if ( strcmp(k, "cleanmeta") == 0 ) {
340   _CKPARAM(!)
341    streams_set_flag(stream, ROAR_FLAG_CLEANMETA);
342  } else if ( strcmp(k, "autoconf") == 0 ) {
343   _CKPARAM(!)
344    streams_set_flag(stream, ROAR_FLAG_AUTOCONF);
345  } else if ( strcmp(k, "recsource") == 0 ) {
346   _CKPARAM(!)
347    streams_set_flag(stream, ROAR_FLAG_RECSOURCE);
348  } else if ( strcmp(k, "passmixer") == 0 ) {
349   _CKPARAM(!)
350    streams_set_flag(stream, ROAR_FLAG_PASSMIXER);
351  } else if ( strcmp(k, "recsource") == 0 ) {
352   _CKPARAM(!)
353    streams_set_flag(stream, ROAR_FLAG_RECSOURCE);
354  } else {
355   ROAR_ERR("add_output(*): unknown option '%s'", k);
356   error++;
357  }
358
359  if ( error ) {
360   streams_delete(stream);
361   if ( prim ) alive = 0;
362#ifdef ROAR_DRIVER_CODEC
363   if ( to_free != NULL )
364    free(to_free);
365#endif
366   return -1;
367  }
368
369  k = strtok(NULL, ",");
370 }
371
372 ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = ?", drv, dev, opts);
373
374 // set audio info...
375 switch (dir) {
376  case ROAR_DIR_LIGHT_OUT:
377    switch (s->info.codec) {
378     case ROAR_CODEC_DMX512:
379     case -1:
380       if ( s->info.rate == -1 )
381        s->info.rate = ROAR_OUTPUT_CFREQ;
382
383       s->info.channels =   0;
384       s->info.bits     =   8;
385       s->info.codec    = ROAR_CODEC_DMX512; // in case codec == -1
386      break;
387    }
388   break;
389  case ROAR_DIR_MIDI_OUT:
390    switch (s->info.codec) {
391     case ROAR_CODEC_MIDI:
392     case -1:
393       if ( s->info.rate == -1 )
394        s->info.rate    = ROAR_MIDI_TICKS_PER_BEAT;
395
396       s->info.channels = ROAR_MIDI_CHANNELS_DEFAULT;
397       s->info.bits     = ROAR_MIDI_BITS;
398       s->info.codec    = ROAR_CODEC_MIDI; // in case codec == -1
399      break;
400    }
401   break;
402  case ROAR_DIR_RAW_OUT:
403    if ( s->info.rate == -1 )
404     s->info.rate = 0;
405    if ( s->info.bits == -1 )
406     s->info.bits = 0;
407    if ( s->info.channels == -1 )
408     s->info.channels = 0;
409    if ( s->info.codec == -1 )
410     s->info.codec = 0;
411   break;
412 }
413
414 if ( s->info.rate == -1 )
415  s->info.rate = g_sa->rate;
416 if ( s->info.bits == -1 )
417  s->info.bits = g_sa->bits;
418 if ( s->info.channels == -1 )
419  s->info.channels = g_sa->channels;
420 if ( s->info.codec == -1 )
421  s->info.codec = g_sa->codec;
422
423 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);
424
425 if ( streams_set_dir(stream, dir, 1) == -1 ) {
426  streams_delete(stream);
427  return -1;
428 }
429
430#ifdef ROAR_DRIVER_CODEC
431 if ( to_free != NULL )
432  free(to_free);
433#endif
434
435 if ( s->info.codec == ROAR_CODEC_ALAW || s->info.codec == ROAR_CODEC_MULAW )
436  s->info.bits = 8; // needed to open OSS driver, will be overriden by codecfilter
437
438 ROAR_STREAM_SERVER(s)->codec_orgi = s->info.codec;
439
440 if ( driver_openvio(&(ss->vio), &(ss->driver_id), drv, dev, &(s->info), -1, ss) == -1 ) {
441  ss->driver_id = -1; // don't close a driver not opened...
442  memset(&(ss->vio), 0, sizeof(struct roar_vio_calls));
443  streams_delete(stream);
444  if ( prim ) alive = 0;
445  ROAR_ERR("add_output(drv='%s', dev='%s', opts='%s'): can not open output driver.", drv, dev, opts);
446  ROAR_DBG("add_output(drv='%s', dev='%s', opts='%s') = -1", drv, dev, opts);
447  return -1;
448 }
449
450 roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_SSTREAMID, &stream); // ignore errors here
451 roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_SSTREAM,   s); // ignore errors here
452
453 if ( blocks != -1 )
454  roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_DBLOCKS, &blocks);
455
456 if ( blocksize != -1 )
457  roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_DBLKSIZE, &blocksize);
458
459 // TODO: we shoudld *really* check for errors here...
460 if ( channel != -1 ) {
461  tu16 = channel;
462  roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_DMXSCHAN, &tu16);
463 }
464 if ( universe != -1 ) {
465  tu16 = universe;
466  roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_DMXUNIV, &tu16);
467 }
468
469 ROAR_DBG("add_output(*): ss->driver_id=%i", ss->driver_id);
470
471 streams_set_fh(stream, -1); // update some internal structures
472
473 if ( q > -1e6 ) {
474  ROAR_DBG("add_output(*): setting q=%f", q);
475  streams_ctl(stream, ROAR_CODECFILTER_CTL_SET_Q|ROAR_STREAM_CTL_TYPE_FLOAT, &q);
476 }
477
478 client_stream_add(g_self_client, stream);
479
480 if ( prim ) {
481  streams_mark_primary(stream);
482  s->pos_rel_id = stream;
483 }
484
485 if ( sync ) {
486  streams_set_flag(stream, ROAR_FLAG_SYNC);
487 } else {
488  streams_reset_flag(stream, ROAR_FLAG_SYNC);
489 }
490
491 if ( f_mmap )
492  streams_set_flag(stream, ROAR_FLAG_MMAP);
493
494 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);
495 return 0;
496}
497
498//ll
Note: See TracBrowser for help on using the repository browser.