source: roaraudio/roard/output.c @ 5210:8eb738dee9d4

Last change on this file since 5210:8eb738dee9d4 was 5210:8eb738dee9d4, checked in by phi, 12 years ago

Updated ports to minimal, win32 and avr (pr2)

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