source: roaraudio/roard/output.c @ 5209:8f10bdede5a6

Last change on this file since 5209:8f10bdede5a6 was 5192:4237437ca526, checked in by phi, 13 years ago

declare some stuff 'extern', this saves like 5.3KB of diskspace in plugin files and make them more resistant against changes in roard

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