source: roaraudio/roard/output.c @ 5063:3cc39a3c39a8

Last change on this file since 5063:3cc39a3c39a8 was 5063:3cc39a3c39a8, checked in by phi, 13 years ago

give wmm driver more prio on win32

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