source: roaraudio/roard/sources.c @ 4807:c29f46728c76

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

Added source radionoise to roard. This is used to generate low energy noise so codecs do not drop to (near) zero bitrate.

File size: 13.3 KB
Line 
1//sources.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#ifndef ROAR_WITHOUT_DCOMP_SOURCES
29
30#define ROAR_SOURCE_DEFAULT "cf"
31
32struct roar_source g_source[] = {
33 {"raw",  "Raw source",                  "/some/file",     SRC_FLAG_FHSEC, ROAR_SUBSYS_WAVEFORM, NULL,  sources_add_raw},
34#ifdef ROAR_HAVE_IO_POSIX
35 {"wav",  "Old RIFF/WAVE source",        "/some/file.wav", SRC_FLAG_NONE,  ROAR_SUBSYS_WAVEFORM, sources_add_wav,  NULL},
36#endif
37 {"cf",   "Old CF source",               "/some/file.ext", SRC_FLAG_NONE,  ROAR_SUBSYS_WAVEFORM, sources_add_cf,   NULL},
38 {"roar", "Old simple RoarAudio source", "some.host",      SRC_FLAG_NONE,  ROAR_SUBSYS_WAVEFORM, sources_add_roar, NULL},
39#ifndef ROAR_WITHOUT_DCOMP_CDRIVER
40 {"oss",  "OSS CDriver",                 "/dev/audio",     SRC_FLAG_NONE,  ROAR_SUBSYS_WAVEFORM, NULL, sources_add_cdriver},
41#endif
42 {"radionoise", "Noise source at -102dB", NULL,            SRC_FLAG_NONE, ROAR_SUBSYS_WAVEFORM, NULL, sources_add_radionoise},
43 {NULL, NULL, NULL, SRC_FLAG_NONE, 0, NULL, NULL} // EOL
44};
45
46int sources_init (void) {
47 g_source_client = -1;
48 return 0;
49}
50
51void print_sourcelist (void) {
52 int i;
53 char subsys[7] = "      ";
54
55 printf("  Source    Flag Subsys - Description (devices)\n");
56 printf("-------------------------------------------------------\n");
57
58 for (i = 0; g_source[i].name != NULL; i++) {
59  strncpy(subsys, "      ", 6);
60
61  if ( g_source[i].subsystems & ROAR_SUBSYS_WAVEFORM )
62   subsys[0] = 'W';
63  if ( g_source[i].subsystems & ROAR_SUBSYS_MIDI )
64   subsys[1] = 'M';
65  if ( g_source[i].subsystems & ROAR_SUBSYS_CB )
66   subsys[2] = 'C';
67  if ( g_source[i].subsystems & ROAR_SUBSYS_LIGHT )
68   subsys[3] = 'L';
69  if ( g_source[i].subsystems & ROAR_SUBSYS_RAW )
70   subsys[4] = 'R';
71  if ( g_source[i].subsystems & ROAR_SUBSYS_COMPLEX )
72   subsys[5] = 'X';
73
74  if ( g_source[i].devices != NULL ) {
75   printf("  %-10s %c%c%c %6s - %s (devices: %s)\n", g_source[i].name,
76                 g_source[i].flags & SRC_FLAG_FHSEC      ? 's' : ' ',
77                 g_source[i].old_open != NULL            ? 'S' : ' ',
78                 g_source[i].new_open != NULL            ? 'N' : ' ',
79                 subsys,
80                 g_source[i].desc, g_source[i].devices);
81  } else {
82   printf("  %-9s %c%c%c %6s - %s\n", g_source[i].name,
83                 g_source[i].flags & SRC_FLAG_FHSEC      ? 's' : ' ',
84                 g_source[i].old_open != NULL            ? 'S' : ' ',
85                 g_source[i].new_open != NULL            ? 'N' : ' ',
86                 subsys,
87                 g_source[i].desc);
88  }
89 }
90}
91
92
93int sources_set_client (int client) {
94 if ( client >= 0 ) {
95  g_source_client = client;
96  return 0;
97 } else {
98  return -1;
99 }
100}
101
102int sources_free (void) {
103 return 0;
104}
105
106int sources_add (char * driver, char * device, char * container, char * options, int primary) {
107 int i;
108
109 if ( driver == NULL )
110  driver = ROAR_SOURCE_DEFAULT;
111
112 for (i = 0; g_source[i].name != NULL; i++) {
113  if ( !strcmp(g_source[i].name, driver) ) {
114   if ( g_source[i].new_open != NULL ) {
115    return sources_add_new(&(g_source[i]), driver, device, container, options, primary);
116   } else if ( g_source[i].old_open != NULL ) {
117    return g_source[i].old_open(driver, device, container, options, primary);
118   } else {
119    ROAR_ERR("sources_add(driver='%s', ...): Found source but did not find any open rutine", driver);
120    return -1;
121   }
122  }
123 }
124
125 ROAR_ERR("sources_add(driver='%s', ...): Source not found", driver);
126 return -1;
127}
128
129int sources_add_new (struct roar_source * source,
130                     char * driver, char * device,
131                     char * container,
132                     char * options, int primary) {
133 int  stream;
134 int  fh = -1;
135 struct roar_stream        *  s;
136 struct roar_stream_server * ss;
137 char * k, * v;
138 int error = 0;
139 int f_sync = 0, f_mmap = 0;
140 int codec;
141
142 if ( source == NULL )
143  return -1;
144
145 if ( (stream = streams_new()) == -1 ) {
146  return -1;
147 }
148
149 if ( streams_get(stream, &ss) == -1 ) {
150  streams_delete(stream);
151  return -1;
152 }
153
154 s = ROAR_STREAM(ss);
155
156 memcpy(&(s->info), g_sa, sizeof(struct roar_audio_info));
157
158 codec = s->info.codec;
159
160 if ( streams_set_dir(stream, ROAR_DIR_PLAY, 1) == -1 ) {
161  streams_delete(stream);
162  return -1;
163 }
164
165 s->pos_rel_id = -1;
166
167 k = strtok(options, ",");
168 while (k != NULL) {
169  if ( (v = strstr(k, "=")) != NULL ) {
170   *v++ = 0;
171  }
172
173  if ( strcmp(k, "rate") == 0 ) {
174   s->info.rate = atoi(v);
175  } else if ( strcmp(k, "channels") == 0 ) {
176   s->info.channels = atoi(v);
177  } else if ( strcmp(k, "bits") == 0 ) {
178   s->info.bits = atoi(v);
179  } else if ( strcmp(k, "codec") == 0 ) {
180   if ( (codec = roar_str2codec(v)) == -1 ) {
181    ROAR_ERR("sources_add_new(*): unknown codec '%s'", v);
182    error++;
183   }
184
185  } else if ( strcmp(k, "name") == 0 ) {
186   if ( streams_set_name(stream, v) == -1 ) {
187    ROAR_ERR("add_output(*): Can not set Stream name");
188    error++;
189   }
190
191  } else if ( strcmp(k, "mmap") == 0 ) {
192   f_mmap = 1;
193  } else if ( strcmp(k, "sync") == 0 ) {
194   f_sync = 1;
195  } else if ( strcmp(k, "primary") == 0 ) {
196   primary = 1;
197  } else if ( strcmp(k, "meta") == 0 ) {
198   streams_set_flag(stream, ROAR_FLAG_META);
199  } else if ( strcmp(k, "cleanmeta") == 0 ) {
200   streams_set_flag(stream, ROAR_FLAG_CLEANMETA);
201  } else if ( strcmp(k, "autoconf") == 0 ) {
202   streams_set_flag(stream, ROAR_FLAG_AUTOCONF);
203
204  } else {
205   ROAR_ERR("sources_add_new(*): unknown option '%s'", k);
206   error++;
207  }
208
209  if ( error ) {
210   streams_delete(stream);
211   if ( primary ) alive = 0;
212   return -1;
213  }
214
215  k = strtok(NULL, ",");
216 }
217
218 if ( primary )
219  streams_mark_primary(stream);
220
221 streams_set_flag(stream, ROAR_FLAG_SOURCE);
222 client_stream_add(g_source_client, stream);
223
224 if ( codec == ROAR_CODEC_ALAW || codec == ROAR_CODEC_MULAW )
225  s->info.bits = 8; // needed to open OSS driver, will be overriden by codecfilter
226
227 s->info.codec = codec;
228 ROAR_STREAM_SERVER(s)->codec_orgi = codec;
229
230 if ( source->new_open(stream, device, fh, driver) == -1 ) {
231  streams_delete(stream);
232  return -1;
233 }
234
235 roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_SSTREAMID, &stream); // ignore errors here
236 roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_SET_SSTREAM,   s); // ignore errors here
237
238 if ( f_sync ) {
239  streams_set_flag(stream, ROAR_FLAG_SYNC);
240 } else {
241  streams_reset_flag(stream, ROAR_FLAG_SYNC);
242 }
243
244 if ( f_mmap )
245  streams_set_flag(stream, ROAR_FLAG_MMAP);
246
247 return 0;
248}
249
250int sources_add_raw  (int stream   , char * device, int fh, char * driver) {
251 struct roar_stream_server * ss;
252
253 if ( fh > -1 )
254  return streams_set_fh(stream, fh);
255
256 streams_get(stream, &ss);
257
258 if ( roar_vio_open_file(&(ss->vio), device, O_RDONLY, 0644) == -1 )
259  return -1;
260
261 return streams_set_fh(stream, -2);
262}
263
264#ifdef ROAR_HAVE_IO_POSIX
265int sources_add_wav (char * driver, char * device, char * container, char * options, int primary) {
266 int stream;
267 int fh;
268 char buf[44];
269 struct roar_stream * s;
270
271 ROAR_WARN("sources_add_raw(*): The wav(e) source is obsolete, use source 'cf' (default)!");
272
273 if ( (fh = open(device, O_RDONLY, 0644)) == -1 ) {
274  return -1;
275 }
276
277 if (read(fh, buf, 44) != 44) {
278  close(fh);
279  return -1;
280 }
281
282 if ( (stream = streams_new()) == -1 ) {
283  close(fh);
284  return -1;
285 }
286
287 streams_get_clientobj(stream, &s);
288
289 memcpy(&(s->info), g_sa, sizeof(struct roar_audio_info));
290
291 memcpy(&(s->info.rate    ), buf+24, 4);
292 memcpy(&(s->info.channels), buf+22, 2);
293 memcpy(&(s->info.bits    ), buf+34, 2);
294
295 if ( streams_set_dir(stream, ROAR_DIR_PLAY, 1) == -1 ) {
296  streams_delete(stream);
297  close(fh);
298  return -1;
299 }
300 s->pos_rel_id = -1;
301
302 streams_set_fh(stream, fh);
303
304 streams_set_flag(stream, ROAR_FLAG_SOURCE);
305 client_stream_add(g_source_client, stream);
306
307 return 0;
308}
309#endif
310
311#define _ret(x) streams_delete(stream); return (x)
312
313int sources_add_cf (char * driver, char * device, char * container, char * options, int primary) {
314 int  stream;
315 int  codec;
316 int  len;
317 char buf[64];
318 struct roar_stream    * s;
319 struct roar_vio_calls * vio;
320 struct roar_vio_defaults def;
321
322 if ( roar_vio_dstr_init_defaults(&def, ROAR_VIO_DEF_TYPE_NONE, O_RDONLY, 0644) == -1 )
323  return -1;
324
325 if ( (stream = streams_new()) == -1 ) {
326  return -1;
327 }
328
329 streams_get_clientobj(stream, &s);
330
331 memcpy(&(s->info), g_sa, sizeof(struct roar_audio_info));
332
333 if ( streams_set_dir(stream, ROAR_DIR_PLAY, 1) == -1 ) {
334  streams_delete(stream);
335  return -1;
336 }
337
338 s->pos_rel_id = -1;
339
340/*
341 if ( (fh = open(device, O_RDONLY, 0644)) == -1 ) {
342  return -1;
343 }
344*/
345
346 vio = &(ROAR_STREAM_SERVER(s)->vio);
347
348 //if ( roar_vio_open_file(vio, device, O_RDONLY, 0644) == -1 ) {
349 if ( roar_vio_open_dstr(vio, device, &def, 1) == -1 ) {
350  roar_vio_init_calls(vio); // clear the VIO object again
351                            // from things roar_vio_open_dstr() left.
352  _ret(-1);
353 }
354
355 ROAR_DBG("sources_add_cf(*) = ?");
356
357 // TODO: finy out a better way of doing auto detetion without need for seek!
358 if ( options == NULL ) {
359  if ( (len = roar_vio_read(vio, buf, 64)) < 1 ) {
360   _ret(-1);
361  }
362
363  if ( roar_vio_lseek(vio, -len, SEEK_CUR) == (off_t)-1 ) {
364   _ret(-1);
365  }
366
367  if ( (codec = roar_file_codecdetect(buf, len)) == -1 ) {
368   _ret(-1);
369  }
370 } else {
371  if ( !strncmp(options, "codec=", 6) )
372   options += 6;
373
374  if ( (codec = roar_str2codec(options)) == -1 ) {
375   _ret(-1);
376  }
377 }
378
379 s->info.codec = codec;
380
381 ROAR_STREAM_SERVER(s)->codec_orgi = codec;
382
383 ROAR_DBG("sources_add_cf(*) = ?");
384 streams_set_fh(stream, -2);
385 ROAR_DBG("sources_add_cf(*) = ?");
386 streams_set_socktype(stream, ROAR_SOCKET_TYPE_FILE);
387
388 if ( primary )
389  streams_mark_primary(stream);
390
391 streams_set_flag(stream, ROAR_FLAG_SOURCE);
392 client_stream_add(g_source_client, stream);
393
394 return 0;
395}
396
397#undef _ret
398
399
400int sources_add_roar (char * driver, char * device, char * container, char * options, int primary) {
401 int  stream;
402 int  fh;
403 int  codec = ROAR_CODEC_DEFAULT;
404 struct roar_stream * s;
405
406 if ( options != NULL && *options ) {
407  if ( !strncmp(options, "codec=", 6) )
408   options += 6;
409
410  if ( (codec = roar_str2codec(options)) == -1 ) {
411   return -1;
412  }
413 }
414
415 if ( (fh = roar_simple_monitor(g_sa->rate, g_sa->channels, g_sa->bits, codec, device, "roard")) == -1 ) {
416  return -1;
417 }
418
419 if ( (stream = streams_new()) == -1 ) {
420  close(fh);
421  return -1;
422 }
423
424 streams_get_clientobj(stream, &s);
425
426 memcpy(&(s->info), g_sa, sizeof(struct roar_audio_info));
427
428 if ( streams_set_dir(stream, ROAR_DIR_PLAY, 1) == -1 ) {
429  streams_delete(stream);
430  close(fh);
431  return -1;
432 }
433
434 s->pos_rel_id = -1;
435 s->info.codec = codec;
436
437 ROAR_STREAM_SERVER(s)->codec_orgi = codec;
438
439 streams_set_fh(stream, fh);
440
441 if ( primary )
442  streams_mark_primary(stream);
443
444 streams_set_flag(stream, ROAR_FLAG_SOURCE);
445 client_stream_add(g_source_client, stream);
446
447 return 0;
448}
449
450#ifndef ROAR_WITHOUT_DCOMP_CDRIVER
451int sources_add_cdriver (int stream   , char * device, int fh, char * driver) {
452 struct roar_stream_server * ss;
453
454 if ( fh > -1 )
455  return -1;
456
457 if ( streams_get(stream, &ss) == -1 )
458  return -1;
459
460 if ( !strncmp(driver, "cdriver:", 8) )
461  driver += 8;
462
463 ROAR_DBG("sources_add_cdriver(stream=%i, device='%s', fh=%i, driver='%s') = ?", stream, device, fh, driver);
464
465 if ( roar_cdriver_open(&(ss->vio), driver, device, &(ROAR_STREAM(ss)->info), ROAR_DIR_RECORD) == -1 )
466  return -1;
467
468 return streams_set_fh(stream, -2);
469}
470#endif
471
472static ssize_t sources_radionoise_read (struct roar_vio_calls * vio, void *buf, size_t count) {
473 int32_t * pcm = buf;
474 int16_t noise;
475 size_t len, i;
476
477 ROAR_DBG("sources_radionoise_read(vio=%p, buf=%p, count=%llu) = 0", vio, buf, (long long unsigned int)count);
478
479 // ensure size is a multiple of 4.
480 count -= count & 0x03LLU;
481
482 if ( count == 0 )
483  return 0;
484
485 if ( buf == NULL )
486  return -1;
487
488 roar_random_gen_nonce(buf, count);
489
490 len = count / 4;
491
492 for (i = 0; i < len; i++) {
493  noise  = pcm[i] & 0xFFFF;
494  pcm[i] = ((int32_t)noise << 16) >> 17;
495 }
496
497 ROAR_DBG("sources_radionoise_read(vio=%p, buf=%p, count=?) = %llu", vio, buf, (long long unsigned int)count);
498 return count;
499}
500
501static int     sources_radionoise_return_zero (struct roar_vio_calls * vio) {
502 (void)vio;
503
504 ROAR_DBG("sources_radionoise_return_zero(vio=%p) = 0", vio);
505
506 return 0;
507}
508
509int sources_add_radionoise (int stream, char * device, int fh, char * driver) {
510 struct roar_stream_server * ss;
511 struct roar_audio_info    * info;
512
513 if ( fh > -1 )
514  return -1;
515
516 if ( streams_get(stream, &ss) == -1 )
517  return -1;
518
519 info = &(ROAR_STREAM(ss)->info);
520
521 info->codec = ROAR_CODEC_DEFAULT;
522 info->bits  = 32;
523
524 memset(&(ss->vio), 0, sizeof(struct roar_vio_calls));
525 ss->vio.read     = sources_radionoise_read;
526 ss->vio.close    = sources_radionoise_return_zero;
527 ss->vio.sync     = sources_radionoise_return_zero;
528 ss->vio.nonblock = (int (*)(struct roar_vio_calls * vio, int state))sources_radionoise_return_zero;
529
530 return streams_set_fh(stream, -2);
531}
532
533#endif
534
535//ll
Note: See TracBrowser for help on using the repository browser.