source: roaraudio/roard/output.c @ 5012:b263759832f1

Last change on this file since 5012:b263759832f1 was 4852:166a9cc557c9, checked in by phi, 13 years ago

moved a lot stuff out of roard.c

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