source: roaraudio/roard/streams.c @ 1842:8c8a003773ca

Last change on this file since 1842:8c8a003773ca was 1842:8c8a003773ca, checked in by phi, 15 years ago

support for names on server streams, added roar_stream_get_name()

File size: 27.5 KB
Line 
1//streams.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008
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, 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25#include "roard.h"
26
27int streams_init (void) {
28 int i;
29
30 for (i = 0; i < ROAR_STREAMS_MAX; i++)
31  g_streams[i] = NULL;
32
33 return 0;
34}
35
36int streams_free (void) {
37 int i;
38
39 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
40  if ( g_streams[i] != NULL ) {
41   streams_delete(i);
42  }
43 }
44
45 return 0;
46}
47
48
49int streams_new    (void) {
50 int i, j;
51 struct roar_stream        * n = NULL;
52 struct roar_stream_server * s = NULL;
53
54#ifdef ROAR_SUPPORT_LISTEN
55 if ( g_terminate && !g_no_listen ) // don't accept new streams in case of termination state
56  return -1;
57#else
58 if ( g_terminate )                 // don't accept new streams in case of termination state
59  return -1;
60#endif
61
62 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
63  if ( g_streams[i] == NULL ) {
64   s = ROAR_STREAM_SERVER(n = ROAR_STREAM(malloc(sizeof(struct roar_stream_server))));
65   if ( n == NULL ) {
66    ROAR_ERR("streams_new(void): can not allocate memory for new stream: %s", strerror(errno));
67    ROAR_DBG("streams_new(void) = -1");
68    return -1;
69   }
70
71   n->id         = i;
72   n->fh         = -1;
73//   n->pos_rel_id = i;
74/*
75   n->database   = NULL;
76   n->dataoff    = NULL;
77   n->datalen    = 0;
78   n->offset     = 0;
79*/
80   n->pos        = 0;
81
82   s->name            = NULL;
83
84   s->client          = -1;
85   s->socktype        = ROAR_SOCKET_TYPE_UNKNOWN;
86   s->buffer          = NULL;
87   s->need_extra      =  0;
88   s->output          = NULL;
89   s->is_new          =  1;
90   s->codecfilter     = -1;
91   s->pre_underruns   =  0;
92   s->post_underruns  =  0;
93   s->delay           =  0;
94   s->codec_orgi      = -1;
95   s->primary         =  0;
96
97   s->mixer.scale     = 65535;
98   s->mixer.rpg_mul   = 1;
99   s->mixer.rpg_div   = 1;
100   for (j = 0; j < ROAR_MAX_CHANNELS; j++)
101    s->mixer.mixer[j] = 65535;
102
103#ifdef ROAR_SUPPORT_META
104   for (j = 0; j < ROAR_META_MAX_PER_STREAM; j++) {
105    s->meta[j].type   = ROAR_META_TYPE_NONE;
106    s->meta[j].key[0] = 0;
107    s->meta[j].value  = NULL;
108   }
109#endif
110
111   roar_vio_init_calls(&(s->vio));
112   s->driver_id = -1;
113   s->flags     =  ROAR_FLAG_NONE;
114
115   roardsp_fchain_init(&(s->fc));
116
117   g_streams[i] = s;
118   ROAR_DBG("streams_new(void): n->id=%i", n->id);
119   ROAR_DBG("streams_new(void) = %i", i);
120   return i;
121  }
122 }
123
124 return -1;
125}
126
127int streams_delete (int id) {
128 struct roar_stream_server * s;
129 int prim;
130 int no_vio_close = 0;
131 int i;
132
133 if ( (s = g_streams[id]) == NULL )
134  return 0;
135
136 ROAR_DBG("streams_delete(id=%i) = ?", id);
137 ROAR_DBG("streams_delete(id=%i): g_streams[id]->id=%i", id, ROAR_STREAM(s)->id);
138
139 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
140  if ( g_streams[i] != NULL && ROAR_STREAM(g_streams[i])->pos_rel_id == id ) {
141   if ( ROAR_STREAM(g_streams[i])->dir == ROAR_DIR_THRU ) {
142    streams_delete(i);
143   } else {
144    ROAR_STREAM(g_streams[i])->pos_rel_id = -1;
145   }
146  }
147 }
148
149#ifdef ROAR_SUPPORT_META
150 // delete meta data form other meta streams if needed
151 if ( streams_get_flag(id, ROAR_FLAG_META) == 1 ) {
152  ROAR_DBG("streams_delete(id=%i): deleting meta stream!", id);
153  stream_meta_clear(id);
154  stream_meta_finalize(id);
155 }
156#endif
157
158 if ( s->codecfilter != -1 ) {
159  codecfilter_close(s->codecfilter_inst, s->codecfilter);
160  s->codecfilter_inst = NULL;
161  s->codecfilter = -1;
162 }
163
164 if ( s->driver_id != -1 ) {
165  driver_closevio(&(s->vio), s->driver_id);
166  roar_vio_init_calls(&(s->vio));
167  s->driver_id = -1;
168  no_vio_close =  1;
169 }
170
171 roardsp_fchain_uninit(&(s->fc));
172
173 if ( s->client != -1 ) {
174  ROAR_DBG("streams_delete(id=%i): Stream is owned by client %i", id, g_streams[id]->client);
175  client_stream_delete(s->client, id);
176 }
177
178 if ( s->buffer != NULL )
179  roar_buffer_free(s->buffer);
180
181 if ( s->output != NULL )
182  free(s->output);
183
184/*
185 if ( ROAR_STREAM(s)->fh != -1 )
186  close(ROAR_STREAM(s)->fh);
187*/
188
189 if ( !no_vio_close )
190  roar_vio_close(&(s->vio));
191
192 prim = s->primary;
193
194 if ( s->name != NULL )
195  free(s->name);
196
197 free(s);
198
199 g_streams[id] = NULL;
200
201 if ( prim ) {
202  alive = 0;
203  clean_quit();
204 }
205
206 ROAR_DBG("streams_delete(id=%i) = 0", id);
207 return 0;
208}
209
210int streams_set_client (int id, int client) {
211 if ( g_streams[id] == NULL )
212  return -1;
213
214 ROAR_DBG("streams_set_client(id=%i): g_streams[id]->id=%i", id, ROAR_STREAM(g_streams[id])->id);
215 g_streams[id]->client = client;
216
217 return 0;
218}
219
220int streams_get_client (int id) {
221 if ( g_streams[id] == NULL )
222  return -1;
223
224 return g_streams[id]->client;
225}
226
227int streams_set_dir    (int id, int dir, int defaults) {
228 struct roar_stream_server * ss;
229
230 if ( (ss = g_streams[id]) == NULL )
231  return -1;
232
233 ROAR_STREAM(ss)->dir = dir;
234
235 if ( defaults ) {
236  if ( dir <= 0 || dir >= ROAR_DIR_DIRIDS )
237   return -1;
238
239  if ( streams_set_flag(id, g_config->streams[dir].flags) == -1 )
240   return -1;
241
242   ss->mixer.scale   = g_config->streams[dir].mixer.scale;
243   ss->mixer.rpg_mul = g_config->streams[dir].mixer.rpg_mul;
244   ss->mixer.rpg_div = g_config->streams[dir].mixer.rpg_div;
245 }
246
247 return 0;
248}
249
250int streams_set_fh     (int id, int fh) {
251 struct roar_stream_server * ss;
252 int dir;
253
254 if ( (ss = g_streams[id]) == NULL )
255  return -1;
256
257 ROAR_DBG("streams_set_fh(id=%i): g_streams[id]->id=%i", id, ROAR_STREAM(ss)->id);
258
259 ROAR_STREAM(g_streams[id])->fh = fh;
260
261 ROAR_DBG("streams_set_fh(id=%i, fh=%i): driverID=%i", id, fh, ss->driver_id);
262
263 if ( ss->driver_id == -1 && fh != -2 )
264  roar_vio_set_fh(&(ss->vio), fh);
265
266 if ( codecfilter_open(&(ss->codecfilter_inst), &(ss->codecfilter), NULL,
267                  ROAR_STREAM(ss)->info.codec, ss) == -1 ) {
268  return streams_delete(id);
269 }
270
271 if ( fh == -2 ) {
272  ROAR_DBG("streams_set_fh(id=%i, fh=%i) = ?", id, fh);
273  if ( roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_GET_READ_FH, &fh) == -1 ) {
274   fh = -2;
275  } else {
276   ROAR_DBG("streams_set_fh(id=%i, fh=%i) = ?", id, fh);
277   if ( fh < 0 ) {
278    fh = -2;
279   } else {
280    ROAR_STREAM(g_streams[id])->fh = fh;
281   }
282  }
283 }
284
285 if ( fh == -1 || fh == -2 ) { // yes, this is valid, indecats full vio!
286  return 0;
287 }
288
289// roar_socket_recvbuf(fh, ROAR_OUTPUT_CALC_OUTBUFSIZE( &(ROAR_STREAM(g_streams[id])->info) )); // set recv buffer to minimum
290
291 dir = ROAR_STREAM(ss)->dir;
292
293 if ( dir == ROAR_DIR_MONITOR || dir == ROAR_DIR_RECORD || dir == ROAR_DIR_OUTPUT ) {
294  ROAR_SHUTDOWN(fh, SHUT_RD);
295 }
296
297 if ( dir == ROAR_DIR_FILTER ) {
298  return 0;
299 } else {
300  return roar_socket_nonblock(fh, ROAR_SOCKET_NONBLOCK);
301 }
302}
303
304int streams_get_fh     (int id) {
305 if ( id < 0 )
306  return -1;
307
308 if ( g_streams[id] == NULL )
309  return -1;
310
311 return ROAR_STREAM(g_streams[id])->fh;
312}
313
314int streams_get    (int id, struct roar_stream_server ** stream) {
315 if ( g_streams[id] == NULL )
316  return -1;
317
318 *stream = g_streams[id];
319
320 return 0;
321}
322
323int streams_set_socktype (int id, int socktype) {
324 if ( g_streams[id] == NULL )
325  return -1;
326
327 g_streams[id]->socktype = socktype;
328
329 return 0;
330}
331
332int streams_get_socktype (int id) {
333 if ( g_streams[id] == NULL )
334  return -1;
335
336 return g_streams[id]->socktype;
337}
338
339int streams_set_primary (int id, int prim) {
340 if ( g_streams[id] == NULL )
341  return -1;
342
343 g_streams[id]->primary = prim;
344
345 return 0;
346}
347
348int streams_mark_primary (int id) {
349 return streams_set_primary(id, 1);
350}
351
352int streams_set_sync     (int id, int sync) {
353 int fh = streams_get_fh(id);
354
355 if ( fh != -1 ) {
356  if ( roar_socket_nonblock(fh, sync ? ROAR_SOCKET_BLOCK : ROAR_SOCKET_NONBLOCK) == -1 )
357   return -1;
358
359#ifdef ROAR_FDATASYNC
360  ROAR_FDATASYNC(fh);
361#endif
362
363  return 0;
364 } else {
365  return roar_vio_nonblock(&(g_streams[id]->vio), sync);
366 }
367}
368
369int streams_set_flag     (int id, int flag) {
370 if ( g_streams[id] == NULL )
371  return -1;
372
373 if ( flag & ROAR_FLAG_PRIMARY ) {
374  streams_set_primary(id, 1);
375  flag -= ROAR_FLAG_PRIMARY;
376 }
377
378 if ( flag & ROAR_FLAG_SYNC ) {
379  if ( streams_set_sync(id, 1) == -1 )
380   flag -= ROAR_FLAG_SYNC;
381 }
382
383 if ( flag & ROAR_FLAG_HWMIXER ) { // currently not supported -> ignored
384  g_streams[id]->flags |= flag;
385  if ( streams_set_mixer(id) == -1 ) {
386   g_streams[id]->flags -= flag;
387   return -1;
388  }
389 }
390
391 g_streams[id]->flags |= flag;
392
393#ifdef ROAR_SUPPORT_META
394 if ( flag & ROAR_FLAG_META )
395  stream_meta_finalize(id);
396#endif
397
398 return 0;
399}
400
401int streams_reset_flag   (int id, int flag) {
402 if ( g_streams[id] == NULL )
403  return -1;
404
405 if ( flag & ROAR_FLAG_PRIMARY ) {
406  streams_set_primary(id, 0);
407  flag -= ROAR_FLAG_PRIMARY;
408 }
409
410 if ( flag & ROAR_FLAG_SYNC ) {
411  streams_set_sync(id, 0);
412 }
413
414 g_streams[id]->flags |= flag;
415 g_streams[id]->flags -= flag;
416
417 return 0;
418}
419
420int streams_get_flag     (int id, int flag) {
421 if ( g_streams[id] == NULL )
422  return -1;
423
424 return g_streams[id]->flags & flag ? 1 : 0;
425}
426
427int streams_set_name     (int id, char * name) {
428 char * str;
429
430 if ( g_streams[id] == NULL )
431  return -1;
432
433 if ( (str = strdup(name)) == NULL )
434  return -1;
435
436 if ( g_streams[id]->name != NULL )
437  free(g_streams[id]->name);
438
439 g_streams[id]->name = str;
440}
441
442char * streams_get_name  (int id) {
443 if ( g_streams[id] == NULL )
444  return NULL;
445
446 return g_streams[id]->name;
447}
448
449
450int streams_calc_delay    (int id) {
451 struct roar_stream_server * ss;
452 struct roar_stream        * s;
453 register uint_least32_t d = 0;
454 uint_least32_t t[1];
455 uint64_t       tmp;
456
457 if ( (s = ROAR_STREAM(ss = g_streams[id])) == NULL )
458  return -1;
459
460 if ( ss->codecfilter != -1 ) {
461  if ( codecfilter_delay(ss->codecfilter_inst, ss->codecfilter, t) != -1 )
462   d += *t;
463 }
464
465 if ( ss->vio.ctl != NULL ) {
466  if ( roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_GET_DELAY, t) != -1 ) { // *t is in byte
467   ROAR_DBG("streams_calc_delay(id=%i): VIO delay in byte: %i", id, *t);
468   tmp = *t;
469   tmp *= 1000000; // musec per sec
470   tmp /= s->info.rate * s->info.channels * (s->info.bits/8);
471   ROAR_DBG("streams_calc_delay(id=%i): VIO delay in musec: %i", id, tmp);
472
473   d += tmp;
474  }
475 }
476
477 ROAR_DBG("streams_calc_delay(id=%i): delay in musec: %i", id, d);
478
479 ss->delay = d;
480
481 return 0;
482}
483
484int streams_set_mixer    (int id) {
485 struct roar_stream_server * ss;
486
487 if ( (ss = g_streams[id]) == NULL )
488  return -1;
489
490 if ( !streams_get_flag(id, ROAR_FLAG_HWMIXER) )
491  return 0;
492
493 if ( ss->driver_id == -1 )
494  return 0;
495
496 return driver_set_volume(id, &(ss->mixer));
497}
498
499int streams_ctl          (int id, int_least32_t cmd, void * data) {
500 struct roar_stream_server * ss;
501 int_least32_t comp;
502
503 if ( (ss = g_streams[id]) == NULL )
504  return -1;
505
506 comp = cmd & ROAR_STREAM_CTL_COMPMASK;
507
508 cmd &= ~comp;
509
510 ROAR_DBG("streams_ctl(id=%i, cmd=?, data=%p): comp=0x%.8x, cmd=0x%.4x", id, data, comp, cmd);
511
512 switch (comp) {
513  case ROAR_STREAM_CTL_COMP_BASE:
514   break;
515  case ROAR_STREAM_CTL_COMP_CF:
516    return codecfilter_ctl(ss->codecfilter_inst, ss->codecfilter, cmd, data);
517   break;
518  case ROAR_STREAM_CTL_COMP_DRV:
519   break;
520  default:
521   return -1;
522 }
523
524 return -1;
525}
526
527int streams_get_outputbuffer  (int id, void ** buffer, size_t size) {
528 if ( g_streams[id] == NULL )
529  return -1;
530
531 // output buffer size does never change.
532 if ( g_streams[id]->output != NULL ) {
533  *buffer = g_streams[id]->output;
534  return 0;
535 }
536
537 if ( (g_streams[id]->output = malloc(size)) == NULL ) {
538  ROAR_ERR("streams_get_outputbuffer(*): Can not alloc: %s", strerror(errno));
539  return -1;
540 }
541
542 *buffer = g_streams[id]->output;
543
544 return 0;
545}
546
547int streams_fill_mixbuffer (int id, struct roar_audio_info * info) {
548 // TODO: decide: is this the most complex, hacked, un-understadable,
549 //               un-writeable and even worse: un-readable
550 //               function in the whole project?
551 size_t todo = ROAR_OUTPUT_CALC_OUTBUFSIZE(info);
552 size_t needed = todo;
553 size_t todo_in;
554 size_t len, outlen;
555 size_t mul = 1, div = 1;
556 void * rest = NULL;
557 void * in   = NULL;
558 struct roar_buffer     * buf;
559 struct roar_audio_info * stream_info;
560 struct roar_stream_server * stream = g_streams[id];
561 int is_the_same = 0;
562
563 if ( g_streams[id] == NULL )
564  return -1;
565
566 if ( streams_get_outputbuffer(id, &rest, todo) == -1 ) {
567  return -1;
568 }
569
570 if ( rest == NULL ) {
571  return -1;
572 }
573
574 // set up stream_info
575
576 stream_info = &(ROAR_STREAM(stream)->info);
577
578 // calc todo_in
579 todo_in = ROAR_OUTPUT_CALC_OUTBUFSIZE(stream_info);
580
581 // calc mul and div:
582 mul = todo    / todo_in;
583 div = todo_in / todo;
584
585 if ( mul == 0 ) {
586  mul = 1;
587 } else {
588  div = 1;
589 }
590
591 ROAR_DBG("streams_fill_mixbuffer(*): mul=%i, div=%i", mul, div);
592
593 ROAR_DBG("streams_fill_mixbuffer(*): rest=%p, todo=%i->%i (in->out)", rest, todo_in, todo);
594 // are both (input and output) of same format?
595
596
597 ROAR_DBG("streams_fill_mixbuffer(*): stream_info:");
598 roar_debug_audio_info_print(stream_info);
599 ROAR_DBG("streams_fill_mixbuffer(*): info:");
600 roar_debug_audio_info_print(info);
601
602 is_the_same = stream_info->rate     == info->rate     && stream_info->bits  == info->bits &&
603               stream_info->channels == info->channels && stream_info->codec == info->codec;
604
605 ROAR_DBG("streams_fill_mixbuffer(*): is_the_same=%i", is_the_same);
606
607/* How it works:
608 *
609 * set a counter to the number of samples we need.
610 * loop until we have all samples done or no samples are
611 * left in our input buffer.
612 * If there a no samples left in the input buffer: fill the rest
613 * of the output buffer with zeros.
614 *
615 * The loop:
616 * get a buffer from the input.
617 * if it's bigger than needed, set an offset.
618 * The rest of the data:
619 * 0) convert endianness (codec) from remote to local...
620 * 1) change bits in of the samples
621 * 2) change sample rate
622 * 3) change the nummber of channels
623 * 4) insert into output buffer
624 */
625
626/*
627 // get our first buffer:
628
629 if ( stream_shift_buffer(id, &buf) == -1 ) {
630  return -1;
631 }
632
633 // first test for some basic simple cases...
634
635 if ( buf == NULL ) { // we habe nothing in input queue
636                      // we may memset() our output buffer OR
637                      // just return with -1 so we are going to
638                      // be ignored.
639  return -1;
640 }
641*/
642
643 while (todo) { // main loop
644  ROAR_DBG("streams_fill_mixbuffer(*): looping...");
645  // exit loop if nothing is left, even if we need more data..
646  if ( stream_shift_buffer(id, &buf) == -1 )
647   break;
648  if ( buf == NULL )
649   break;
650
651  // read the data for this loop...
652  roar_buffer_get_data(buf, &in);
653  roar_buffer_get_len(buf, &len);
654
655  ROAR_DBG("streams_fill_mixbuffer(*): len = %i", len);
656
657  if ( len > todo_in ) {
658   roar_buffer_set_offset(buf, todo_in);
659   len = todo_in;
660  } else {
661   roar_buffer_set_len(buf, 0); // queue for deletation
662  }
663
664  // we now have 'len' bytes in 'in'
665
666  // calc how much outlen this has...
667  outlen = (len * mul) / div;
668
669  ROAR_DBG("streams_fill_mixbuffer(*): outlen = %i, buf = %p, len = %i", outlen, in, len);
670
671  if ( is_the_same ) {
672/*
673 * 0) convert endianness (codec) from remote to local...
674 * 1) change bits in of the samples
675 * 2) change sample rate
676 * 3) change the nummber of channels
677   \\==> skiping,...
678 */
679   // * 4) insert into output buffer
680   ROAR_DBG("streams_fill_mixbuffer(*): memcpy: in->rest: %p -> %p", in, rest);
681   if ( memcpy(rest, in, len) != rest ) {
682    ROAR_ERR("streams_fill_mixbuffer(*): memcpy returned invalid pointer.");
683   }
684
685  } else {
686
687/*
688   // * 0) convert endianness (codec) from remote to local...
689   if ( stream_info->codec != info->codec ) {
690    // we neet to convert...
691    return -1;
692   }
693
694   // * 1) change bits in of the samples
695   if ( stream_info->bits != info->bits ) {
696    return -1;
697   }
698
699   // * 2) change sample rate
700   if ( stream_info->rate != info->rate ) {
701    return -1;
702   }
703
704   // * 3) change the nummber of channels
705   if ( stream_info->channels != info->channels ) {
706    return -1;
707   }
708
709   // * 4) insert into output buffer
710*/
711  // hey! we have roar_conv() :)
712
713  if ( roar_conv(rest, in, 8*len / stream_info->bits, stream_info, info) == -1 )
714   return -1;
715  }
716
717  if ( !streams_get_flag(id, ROAR_FLAG_HWMIXER) ) {
718   if ( change_vol(rest, info->bits, rest, 8*outlen / info->bits, info->channels, &(stream->mixer)) == -1 )
719    return -1;
720  }
721
722  // we habe outlen bytes more...
723  todo    -= outlen;
724  rest    += outlen;
725  todo_in -= len;
726
727  roar_buffer_get_len(buf, &len);
728  ROAR_DBG("streams_fill_mixbuffer(*): New length of buffer %p is %i", buf, len);
729  if ( len == 0 ) {
730   roar_buffer_delete(buf, NULL);
731  } else {
732   stream_unshift_buffer(id, buf);
733  }
734 }
735
736//len = 0;
737//roar_buffer_get_len(buf, &len);
738
739/*
740 if ( len > 0 ) // we still have some data in this buffer, re-inserting it to the input buffers...
741  stream_unshift_buffer(id, buf);
742 else
743  buffer_delete(buf, NULL);
744*/
745
746 ROAR_STREAM(g_streams[id])->pos =
747      ROAR_MATH_OVERFLOW_ADD(ROAR_STREAM(g_streams[id])->pos,
748          ROAR_OUTPUT_CALC_OUTBUFSAMP(info, needed-todo));
749 //ROAR_WARN("stream=%i, pos=%u", id, ((struct roar_stream*)g_streams[id])->pos);
750
751 if ( todo > 0 ) { // zeroize the rest of the buffer
752  memset(rest, 0, todo);
753
754  if ( todo != ROAR_OUTPUT_CALC_OUTBUFSIZE(info) ) {
755   if ( g_streams[id]->is_new ) {
756    stream->pre_underruns++;
757   } else {
758    ROAR_WARN("streams_fill_mixbuffer(*): Underrun in stream: %u bytes missing, filling with zeros", (unsigned int)todo);
759    stream->post_underruns++;
760   }
761
762   stream->is_new = 0;
763  }
764 } else {
765  stream->is_new = 0;
766 }
767
768 return 0;
769}
770
771
772int streams_get_mixbuffers (void *** bufferlist, struct roar_audio_info * info, unsigned int pos) {
773 static void * bufs[ROAR_STREAMS_MAX+1];
774 int i;
775 int have = 0;
776
777 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
778  if ( g_streams[i] != NULL ) {
779   if ( ROAR_STREAM(g_streams[i])->dir != ROAR_DIR_PLAY && ROAR_STREAM(g_streams[i])->dir != ROAR_DIR_BIDIR )
780    continue;
781
782   if ( streams_get_outputbuffer(i, &bufs[have], ROAR_OUTPUT_CALC_OUTBUFSIZE(info)) == -1 ) {
783    ROAR_ERR("streams_get_mixbuffer(*): Can not alloc output buffer for stream %i, BAD!", i);
784    ROAR_ERR("streams_get_mixbuffer(*): Ignoring stream for this round.");
785    continue;
786   }
787   if ( streams_fill_mixbuffer(i, info) == -1 ) {
788    ROAR_ERR("streams_get_mixbuffer(*): Can not fill output buffer for stream %i, this should not happen", i);
789    continue;
790   }
791
792//   printf("D: bufs[have=%i] = %p\n", have, bufs[have]);
793
794   ROAR_DBG("streams_get_mixbuffers(*):  bufs[have] = %p", bufs[have]);
795   ROAR_DBG("streams_get_mixbuffers(*): *bufs[have] = 0x%08x...", *(uint32_t*)bufs[have]);
796
797   have++; // we have a new stream!
798  }
799 }
800
801 bufs[have] = NULL;
802 //printf("D: bufs[have=%i] = %p\n", have, bufs[have]);
803
804 ROAR_DBG("streams_get_mixbuffers(*): have = %i", have);
805
806 *bufferlist = bufs;
807 return have;
808}
809
810
811int stream_add_buffer  (int id, struct roar_buffer * buf) {
812 ROAR_DBG("stream_add_buffer(id=%i, buf=%p) = ?", id, buf);
813
814 if ( g_streams[id] == NULL )
815  return -1;
816
817 if ( g_streams[id]->buffer == NULL ) {
818  g_streams[id]->buffer = buf;
819  ROAR_DBG("stream_add_buffer(id=%i, buf=%p) = 0", id, buf);
820  return 0;
821 }
822
823 ROAR_DBG("stream_add_buffer(id=%i, buf=%p) = ?", id, buf);
824 return roar_buffer_add(g_streams[id]->buffer, buf);
825}
826
827int stream_shift_buffer   (int id, struct roar_buffer ** buf) {
828 struct roar_buffer * next;
829
830 if ( g_streams[id] == NULL )
831  return -1;
832
833 if ( g_streams[id]->buffer == NULL ) {
834  *buf = NULL;
835  return 0;
836 }
837
838 roar_buffer_get_next(g_streams[id]->buffer, &next);
839
840 *buf                  = g_streams[id]->buffer;
841 g_streams[id]->buffer = next;
842
843 return 0;
844}
845int stream_unshift_buffer (int id, struct roar_buffer *  buf) {
846 if ( g_streams[id] == NULL )
847  return -1;
848
849 if ( g_streams[id]->buffer == NULL ) {
850  g_streams[id]->buffer = buf;
851  return 0;
852 }
853
854 buf->next = NULL;
855
856 roar_buffer_add(buf, g_streams[id]->buffer);
857
858 g_streams[id]->buffer = buf;
859
860 return 0;
861}
862
863int streams_check  (int id) {
864 int fh;
865 int i;
866 ssize_t req, realreq, done;
867 struct roar_stream        *   s;
868 struct roar_stream_server *  ss;
869 struct roar_buffer        *   b;
870 char                      * buf;
871
872 if ( g_streams[id] == NULL )
873  return -1;
874
875 ROAR_DBG("streams_check(id=%i) = ?", id);
876
877 s = ROAR_STREAM(ss = g_streams[id]);
878
879 if ( (fh = s->fh) == -1 )
880  return 0;
881
882 if ( streams_get_flag(id, ROAR_FLAG_PAUSE) )
883  return 0;
884
885 switch (s->dir) {
886  case ROAR_DIR_LIGHT_IN:
887    return light_check_stream(id);
888   break;
889  case ROAR_DIR_PLAY:
890  case ROAR_DIR_BIDIR:
891   break;
892  default:
893    return 0;
894   break;
895 }
896
897 ROAR_DBG("streams_check(id=%i): fh = %i", id, fh);
898
899 req  = ROAR_OUTPUT_BUFFER_SAMPLES * s->info.channels * s->info.bits / 8; // optimal size
900 req += ss->need_extra; // bytes left we sould get....
901
902 if ( roar_buffer_new(&b, req) == -1 ) {
903  ROAR_ERR("streams_check(*): Can not alloc buffer space!");
904  ROAR_DBG("streams_check(*) = -1");
905  return -1;
906 }
907
908 roar_buffer_get_data(b, (void **)&buf);
909
910 ROAR_DBG("streams_check(id=%i): buffer is up and ready ;)", id);
911
912 if ( ss->codecfilter == -1 ) {
913  realreq = req;
914/*
915  req = read(fh, buf, req);
916  if ( req < realreq ) { // we can do this as the stream is in nonblocking mode!
917   if ( (realreq = read(fh, buf+req, realreq-req)) > 0 )
918    req += realreq;
919  }
920*/
921  done = 0;
922  while (req > 0 && done != realreq) {
923   if ( (req = stream_vio_s_read(ss, buf+done, realreq-done)) > 0 )
924    done += req;
925  }
926  req = done;
927
928  roar_buffer_get_data(b, (void **)&buf);
929  for (i = 0; i < ROAR_STREAMS_MAX; i++) {
930   if ( g_streams[i] != NULL && ROAR_STREAM(g_streams[i])->pos_rel_id == id ) {
931    if ( ROAR_STREAM(g_streams[i])->dir == ROAR_DIR_THRU ) {
932     if ( stream_vio_write(i, buf, req) != req ) {
933      streams_delete(i);
934     }
935    }
936   }
937  }
938 } else {
939  req = codecfilter_read(ss->codecfilter_inst, ss->codecfilter, buf, req);
940 }
941
942 if ( req > 0 ) {
943  ROAR_DBG("streams_check(id=%i): got %i bytes", id, req);
944
945  roar_buffer_set_len(b, req);
946
947  if ( stream_add_buffer(id, b) != -1 )
948   return 0;
949
950  ROAR_ERR("streams_check(id=%i): something is wrong, could not add buffer to stream!", id);
951  roar_buffer_free(b);
952 } else {
953  ROAR_DBG("streams_check(id=%i): read() = %i // errno: %s", id, req, strerror(errno));
954#ifdef ROAR_HAVE_LIBVORBISFILE
955  if ( errno != EAGAIN && errno != ESPIPE ) { // libvorbis file trys to seek a bit ofen :)
956#else
957  if ( errno != EAGAIN ) {
958#endif
959   ROAR_DBG("streams_check(id=%i): EOF!", id);
960   streams_delete(id);
961   ROAR_DBG("streams_check(id=%i) = 0", id);
962  }
963  roar_buffer_free(b);
964  return 0;
965 }
966
967
968 ROAR_DBG("streams_check(id=%i) = -1", id);
969 return -1;
970}
971
972
973int streams_send_mon   (int id) {
974// int fh;
975 struct roar_stream        *   s;
976 struct roar_stream_server *  ss;
977 void  * obuf;
978 int     olen;
979 int     need_to_free = 0;
980 ssize_t ret;
981
982 if ( g_streams[id] == NULL )
983  return -1;
984
985 ROAR_DBG("streams_send_mon(id=%i) = ?", id);
986
987 s = ROAR_STREAM((ss = g_streams[id]));
988
989/*
990 if ( (fh = s->fh) == -1 )
991  return 0;
992*/
993
994
995 if ( streams_get_flag(id, ROAR_FLAG_PAUSE) )
996  return 0;
997
998 switch (s->dir) {
999  case ROAR_DIR_LIGHT_OUT:
1000    return light_send_stream(id);
1001   break;
1002  case ROAR_DIR_OUTPUT:
1003    if ( g_standby )
1004     return 0;
1005  case ROAR_DIR_MONITOR:
1006  case ROAR_DIR_BIDIR:
1007   break;
1008
1009  default:
1010    return 0;
1011   break;
1012 }
1013
1014
1015 ROAR_DBG("streams_send_mon(id=%i): fh = %i", id, s->fh);
1016
1017 if ( s->info.channels != g_sa->channels || s->info.bits  != g_sa->bits ||
1018      s->info.rate     != g_sa->rate     || s->info.codec != g_sa->codec  ) {
1019  olen = ROAR_OUTPUT_CALC_OUTBUFSIZE(&(s->info)); // we hope g_output_buffer_len
1020                                                  // is ROAR_OUTPUT_CALC_OUTBUFSIZE(g_sa) here
1021  if ( (obuf = malloc(olen)) == NULL )
1022   return -1;
1023
1024  need_to_free = 1;
1025
1026  ROAR_DBG("streams_send_mon(id=%i): obuf=%p, olen=%i", id, obuf, olen);
1027
1028  if ( roar_conv(obuf, g_output_buffer, ROAR_OUTPUT_BUFFER_SAMPLES*g_sa->channels, g_sa, &(s->info)) == -1 ) {
1029   free(obuf);
1030   return -1;
1031  }
1032 } else {
1033  obuf = g_output_buffer;
1034  olen = g_output_buffer_len;
1035 }
1036
1037 errno = 0;
1038
1039 if ( ss->codecfilter == -1 ) {
1040  ROAR_DBG("streams_send_mon(id=%i): not a CF stream", id);
1041  if ( s->fh == -1 && roar_vio_get_fh(&(ss->vio)) == -1 )
1042   return 0;
1043
1044  if ( (ret = stream_vio_s_write(ss, obuf, olen)) == olen ) {
1045   if ( need_to_free ) free(obuf);
1046   s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, ROAR_OUTPUT_CALC_OUTBUFSAMP(&(s->info), olen)*s->info.channels);
1047   return 0;
1048  }
1049
1050  if ( ret > 0 && errno == 0 ) {
1051   ROAR_WARN("streams_send_mon(id=%i): Overrun in stream: wrote %i of %i bytes, %i bytes missing", id, (int)ret, olen, olen-(int)ret);
1052   if ( need_to_free ) free(obuf);
1053   s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, ROAR_OUTPUT_CALC_OUTBUFSAMP(&(s->info), ret)*s->info.channels);
1054   return 0;
1055  }
1056 } else {
1057  errno = 0;
1058  if ( codecfilter_write(ss->codecfilter_inst, ss->codecfilter, obuf, olen)
1059            == olen ) {
1060   if ( need_to_free ) free(obuf);
1061   s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, ROAR_OUTPUT_CALC_OUTBUFSAMP(&(s->info), olen)*s->info.channels);
1062   return 0;
1063  } else { // we cann't retry on codec filetered streams
1064   if ( errno != EAGAIN ) {
1065    if ( need_to_free ) free(obuf);
1066    streams_delete(id);
1067    return -1;
1068   }
1069  }
1070 }
1071
1072 if ( errno == EAGAIN ) {
1073  // ok, the client blocks for a moment, we try to sleep a bit an retry in the hope not to
1074  // make any gapes in any output because of this
1075
1076#ifdef ROAR_HAVE_USLEEP
1077  usleep(100); // 0.1ms
1078#endif
1079
1080  if ( stream_vio_s_write(ss, obuf, olen) == olen ) {
1081   if ( need_to_free ) free(obuf);
1082   s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, ROAR_OUTPUT_CALC_OUTBUFSAMP(&(s->info), olen)*s->info.channels);
1083   return 0;
1084  } else if ( errno == EAGAIN ) {
1085   ROAR_WARN("streams_send_mon(id=%i): Can not send data to client: %s", id, strerror(errno));
1086   return 0;
1087  }
1088 }
1089
1090 // ug... error... delete stream!
1091
1092 if ( need_to_free ) free(obuf);
1093 streams_delete(id);
1094
1095 return -1;
1096}
1097
1098int streams_send_filter(int id) {
1099 int fh;
1100 int have = 0;
1101 int len;
1102 struct roar_stream        *   s;
1103 struct roar_stream_server *  ss;
1104
1105 if ( g_streams[id] == NULL )
1106  return -1;
1107
1108 ROAR_DBG("streams_send_filter(id=%i) = ?", id);
1109
1110 s = ROAR_STREAM(ss = g_streams[id]);
1111
1112 if ( (fh = s->fh) == -1 )
1113  return 0;
1114
1115 if ( s->dir != ROAR_DIR_FILTER )
1116  return 0;
1117
1118 if ( streams_get_flag(id, ROAR_FLAG_PAUSE) )
1119  return 0;
1120
1121
1122 ROAR_DBG("streams_send_filter(id=%i): fh = %i", id, fh);
1123
1124 if ( stream_vio_s_write(ss, g_output_buffer, g_output_buffer_len) == g_output_buffer_len ) {
1125  while ( have < g_output_buffer_len ) {
1126   if ( (len = stream_vio_s_read(ss, g_output_buffer+have, g_output_buffer_len-have)) < 1 ) {
1127    streams_delete(id);
1128    return -1;
1129   }
1130   have += len;
1131  }
1132  return 0;
1133 }
1134
1135 // ug... error... delete stream!
1136
1137 streams_delete(id);
1138
1139 return -1;
1140}
1141
1142
1143// VIO:
1144
1145ssize_t stream_vio_read (int stream, void *buf, size_t count) {
1146 struct roar_stream_server * s = g_streams[stream];
1147
1148 if ( !s )
1149  return -1;
1150
1151 return stream_vio_s_read(s, buf, count);
1152}
1153
1154ssize_t stream_vio_write(int stream, void *buf, size_t count) {
1155 struct roar_stream_server * s = g_streams[stream];
1156
1157 if ( !s )
1158  return -1;
1159
1160 return stream_vio_s_write(s, buf, count);
1161}
1162
1163
1164ssize_t stream_vio_s_read (struct roar_stream_server * stream, void *buf, size_t count) {
1165  size_t len =  0;
1166 ssize_t r   = -1;
1167
1168 errno = 0;
1169
1170 if ( !stream )
1171  return -1;
1172
1173 //roar_vio_set_fh(&(stream->vio), ROAR_STREAM(stream)->fh);
1174
1175 if ( ! stream->vio.read )
1176  return -1;
1177
1178 while ( (r = roar_vio_read(&(stream->vio), buf, count)) > 0 ) {
1179  len   += r;
1180  buf   += r;
1181  count -= r;
1182  if ( count == 0 )
1183   break;
1184 }
1185
1186 if ( len == 0 && r == -1 )
1187  return -1;
1188
1189 return len;
1190}
1191
1192ssize_t stream_vio_s_write(struct roar_stream_server * stream, void *buf, size_t count) {
1193 errno = 0;
1194
1195 if ( !stream )
1196  return -1;
1197
1198/*
1199 if ( roar_vio_get_fh(&(stream->vio)) == -1 && ROAR_STREAM(stream)->fh != -1 )
1200  roar_vio_set_fh(&(stream->vio), ROAR_STREAM(stream)->fh);
1201*/
1202
1203// ROAR_WARN("stream_vio_s_write(*): writing...");
1204
1205 return roar_vio_write(&(stream->vio), buf, count);
1206}
1207
1208//ll
Note: See TracBrowser for help on using the repository browser.