source: roaraudio/roard/streams.c @ 4821:eb99f5b29f0d

Last change on this file since 4821:eb99f5b29f0d was 4819:bfe88a001985, checked in by phi, 13 years ago

avoid warning when record stream is not yet fully up

File size: 58.3 KB
RevLine 
[0]1//streams.c:
2
[668]3/*
[4708]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2011
[668]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
[3517]21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
[668]23 *
24 */
25
[0]26#include "roard.h"
27
[2734]28#define _CHECK_SID_RET(id,ret) if ( (id) < 0 || (id) > ROAR_STREAMS_MAX || g_streams[(id)] == NULL ) return (ret)
29#define _CHECK_SID(id)         _CHECK_SID_RET((id), -1)
30
[2417]31int streams_thru_num     =  0;
32int streams_recsource_id = -1;
[2254]33
[4336]34static void _streams_change_state(struct roar_stream_server * s, const int new, const char * func) {
35 register int id  = ROAR_STREAM(s)->id;
36 register int old = s->state;
37
38 s->state = new;
39
40 if ( func == NULL ) {
41  func = "(unknown)";
42 }
43
44 ROAR_INFO("_streams_change_state[by %s](id=%i): stream state: %s->%s", ROAR_DBG_INFO_VERBOSE,
45            func,
46            ROAR_STREAM(s)->id,
47            roar_streamstate2str(old), roar_streamstate2str(new));
48
49 roar_notify_core_emit_simple(ROAR_OE_BASICS_CHANGE_STATE, -1, id, ROAR_OT_STREAM, old, new, NULL, 0);
50}
51
[0]52int streams_init (void) {
53 int i;
54
55 for (i = 0; i < ROAR_STREAMS_MAX; i++)
56  g_streams[i] = NULL;
57
58 return 0;
59}
60
61int streams_free (void) {
62 int i;
63
64 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
65  if ( g_streams[i] != NULL ) {
66   streams_delete(i);
67  }
68 }
69
70 return 0;
71}
72
73
74int streams_new    (void) {
[16]75 int i, j;
[494]76 struct roar_stream        * n = NULL;
77 struct roar_stream_server * s = NULL;
[0]78
[1498]79#ifdef ROAR_SUPPORT_LISTEN
[1155]80 if ( g_terminate && !g_no_listen ) // don't accept new streams in case of termination state
[1148]81  return -1;
[1498]82#else
83 if ( g_terminate )                 // don't accept new streams in case of termination state
84  return -1;
85#endif
[1148]86
[0]87 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
88  if ( g_streams[i] == NULL ) {
[3063]89   s = ROAR_STREAM_SERVER(n = ROAR_STREAM(roar_mm_malloc(sizeof(struct roar_stream_server))));
[0]90   if ( n == NULL ) {
91    ROAR_ERR("streams_new(void): can not allocate memory for new stream: %s", strerror(errno));
92    ROAR_DBG("streams_new(void) = -1");
93    return -1;
94   }
95
[3671]96   memset(s, 0, sizeof(struct roar_stream_server));
97
[0]98   n->id         = i;
99   n->fh         = -1;
[2714]100   n->pos_rel_id = -1;
[1804]101/*
[0]102   n->database   = NULL;
103   n->dataoff    = NULL;
104   n->datalen    = 0;
105   n->offset     = 0;
[1804]106*/
[381]107   n->pos        = 0;
[0]108
[1842]109   s->name            = NULL;
110
[2611]111   s->state           = ROAR_STREAMSTATE_INITING;
112
[494]113   s->client          = -1;
114   s->socktype        = ROAR_SOCKET_TYPE_UNKNOWN;
115   s->buffer          = NULL;
116   s->need_extra      =  0;
117   s->output          = NULL;
118   s->is_new          =  1;
119   s->codecfilter     = -1;
[538]120   s->pre_underruns   =  0;
121   s->post_underruns  =  0;
[1137]122   s->delay           =  0;
[538]123   s->codec_orgi      = -1;
[643]124   s->primary         =  0;
[1913]125   s->ready           =  0;
[2151]126   s->outputbuffer    = NULL;
[2816]127   s->prethru         = NULL;
[3213]128   s->mixer_stream    = -1;
[3630]129   s->role            = ROAR_ROLE_UNKNOWN;
[4099]130   s->parent_stream   = -1;
[4541]131   s->single_sink_c   =  0;
[4553]132   s->single_sink_self_c =  0;
[494]133
134   s->mixer.scale     = 65535;
135   s->mixer.rpg_mul   = 1;
136   s->mixer.rpg_div   = 1;
[16]137   for (j = 0; j < ROAR_MAX_CHANNELS; j++)
[494]138    s->mixer.mixer[j] = 65535;
139
[1498]140#ifdef ROAR_SUPPORT_META
[90]141   for (j = 0; j < ROAR_META_MAX_PER_STREAM; j++) {
[494]142    s->meta[j].type   = ROAR_META_TYPE_NONE;
143    s->meta[j].key[0] = 0;
144    s->meta[j].value  = NULL;
[90]145   }
[1498]146#endif
[0]147
[592]148   roar_vio_init_calls(&(s->vio));
[3042]149   roar_vio_init_calls(&(s->jumbo));
150   s->viop      = &(s->vio);
[930]151   s->driver_id = -1;
[1030]152   s->flags     =  ROAR_FLAG_NONE;
[592]153
[4753]154#ifndef ROAR_WITHOUT_DCOMP_MIXER
[4361]155   s->mixerstream =  NULL;
[4753]156#endif
[4361]157
[1857]158   //roardsp_fchain_init(&(s->fc));
[981]159
[494]160   g_streams[i] = s;
[4101]161   counters_inc(streams, 1);
[4237]162   ROAR_INFO("streams_new(void): New stream %i created (state=initing)", ROAR_DBG_INFO_VERBOSE, i);
[491]163   ROAR_DBG("streams_new(void): n->id=%i", n->id);
[4346]164   roar_notify_core_emit_snoargs(ROAR_OE_BASICS_NEW, -1, i, ROAR_OT_STREAM);
[0]165   ROAR_DBG("streams_new(void) = %i", i);
166   return i;
167  }
168 }
169
170 return -1;
171}
172
173int streams_delete (int id) {
[643]174 struct roar_stream_server * s;
[645]175 int prim;
[1245]176 int no_vio_close = 0;
[1836]177 int i;
[2609]178 int client;
[645]179
[2734]180 _CHECK_SID(id);
181
[643]182 if ( (s = g_streams[id]) == NULL )
[0]183  return 0;
184
185 ROAR_DBG("streams_delete(id=%i) = ?", id);
[643]186 ROAR_DBG("streams_delete(id=%i): g_streams[id]->id=%i", id, ROAR_STREAM(s)->id);
[0]187
[2611]188 // in case we are allready closing it...
189 if ( s->state == ROAR_STREAMSTATE_CLOSING )
190  return 0;
191
[4336]192 _streams_change_state(s, ROAR_STREAMSTATE_CLOSING, "streams_delete");
[4346]193 roar_notify_core_emit_snoargs(ROAR_OE_BASICS_DELETE, -1, id, ROAR_OT_STREAM);
[2611]194
[4544]195 if ( s->flags & ROAR_FLAG_SINGLESINK )
196  streams_set_single_sink(id, 1);
197
[4101]198 counters_inc(streams, -1);
199
[2417]200 if ( streams_get_flag(id, ROAR_FLAG_RECSOURCE) == 1 )
201  streams_reset_flag(id, ROAR_FLAG_RECSOURCE);
202
[1836]203 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
204  if ( g_streams[i] != NULL && ROAR_STREAM(g_streams[i])->pos_rel_id == id ) {
[2239]205   switch (ROAR_STREAM(g_streams[i])->dir) {
206    case ROAR_DIR_THRU:
207    case ROAR_DIR_RAW_IN:
[2592]208      if ( i != id )
209       streams_delete(i);
[2239]210     break;
211    default:
[2592]212      if ( streams_get_flag(i, ROAR_FLAG_VIRTUAL) == 1 ) {
[2609]213       if ( i != id ) {
214        ROAR_DBG("streams_delete(id=%i): Deleting virtual child stream %i", id, i);
[2592]215        streams_delete(i);
[2609]216       }
[2592]217      } else {
218       ROAR_STREAM(g_streams[i])->pos_rel_id = -1;
219      }
[1836]220   }
221  }
222 }
223
[2255]224 if ( ROAR_STREAM(s)->dir == ROAR_DIR_THRU )
225  streams_thru_num--;
226
[2603]227 if ( streams_get_flag(id, ROAR_FLAG_VIRTUAL) == 1 ) {
[2605]228  // we un-group the stream here to avoid a client deleting the parent deleting the client deleting ...
[2609]229  i      = ROAR_STREAM(s)->pos_rel_id;
230  if ( i != -1 ) {
231   ROAR_STREAM(s)->pos_rel_id = -1;
232   client = streams_get_client(id);
233   streams_set_client(id, -1);
234   ROAR_DBG("streams_delete(id=%i): Stream has flag virtual, notifying parent stream %i", id, i);
[2612]235   streams_ctl(i, ROAR_CODECFILTER_CTL_VIRTUAL_DELETE|ROAR_STREAM_CTL_TYPE_INT, &id);
[2609]236   ROAR_DBG("streams_delete(id=%i): Notify send to stream %i", id, i);
237   streams_set_client(id, client);
238   ROAR_STREAM(s)->pos_rel_id = i;
239  }
[2603]240 }
241
[1498]242#ifdef ROAR_SUPPORT_META
[1045]243 // delete meta data form other meta streams if needed
244 if ( streams_get_flag(id, ROAR_FLAG_META) == 1 ) {
245  ROAR_DBG("streams_delete(id=%i): deleting meta stream!", id);
246  stream_meta_clear(id);
247  stream_meta_finalize(id);
248 }
[1498]249#endif
[1045]250
[643]251 if ( s->codecfilter != -1 ) {
252  codecfilter_close(s->codecfilter_inst, s->codecfilter);
253  s->codecfilter_inst = NULL;
254  s->codecfilter = -1;
255 }
256
[936]257 if ( s->driver_id != -1 ) {
[937]258  driver_closevio(&(s->vio), s->driver_id);
[936]259  roar_vio_init_calls(&(s->vio));
260  s->driver_id = -1;
[1245]261  no_vio_close =  1;
[936]262 }
263
[4753]264#ifndef ROAR_WITHOUT_DCOMP_MIXER
[4361]265 if ( s->mixerstream != NULL ) {
266  hwmixer_close(id);
267 }
[4753]268#endif
[4361]269
[1857]270 //roardsp_fchain_uninit(&(s->fc));
[981]271
[643]272 if ( s->client != -1 ) {
273  ROAR_DBG("streams_delete(id=%i): Stream is owned by client %i", id, g_streams[id]->client);
274  client_stream_delete(s->client, id);
[269]275 }
276
[2151]277 stream_outputbuffer_destroy(id);
[2816]278 stream_prethru_destroy(id);
[2151]279
[643]280 if ( s->buffer != NULL )
281  roar_buffer_free(s->buffer);
282
283 if ( s->output != NULL )
284  free(s->output);
285
[1243]286/*
[643]287 if ( ROAR_STREAM(s)->fh != -1 )
288  close(ROAR_STREAM(s)->fh);
[1243]289*/
290
[1245]291 if ( !no_vio_close )
[3042]292  roar_vio_close(s->viop);
[643]293
[645]294 prim = s->primary;
[0]295
[1842]296 if ( s->name != NULL )
297  free(s->name);
298
[3063]299 roar_mm_free(s);
[0]300
301 g_streams[id] = NULL;
302
[4102]303 if ( prim && alive ) {
[645]304  alive = 0;
305  clean_quit();
306 }
307
[4238]308 ROAR_INFO("streams_delete(id=%i): stream deleted", ROAR_DBG_INFO_VERBOSE, id);
[0]309 ROAR_DBG("streams_delete(id=%i) = 0", id);
310 return 0;
311}
312
313int streams_set_client (int id, int client) {
[2734]314
315 _CHECK_SID(id);
[0]316
[491]317 ROAR_DBG("streams_set_client(id=%i): g_streams[id]->id=%i", id, ROAR_STREAM(g_streams[id])->id);
[0]318 g_streams[id]->client = client;
319
320 return 0;
321}
322
[766]323int streams_get_client (int id) {
[2734]324 _CHECK_SID(id);
[766]325
326 return g_streams[id]->client;
327}
328
[1609]329int streams_set_dir    (int id, int dir, int defaults) {
330 struct roar_stream_server * ss;
[4543]331 int mixer;
[1609]332
[2734]333 _CHECK_SID(id);
334
[1609]335 if ( (ss = g_streams[id]) == NULL )
336  return -1;
337
338 ROAR_STREAM(ss)->dir = dir;
339
[2255]340 if ( dir == ROAR_DIR_THRU )
341  streams_thru_num++;
342
[1609]343 if ( defaults ) {
344  if ( dir <= 0 || dir >= ROAR_DIR_DIRIDS )
345   return -1;
346
[2387]347  ROAR_DBG("streams_set_dir(*): g_config->streams[dir=%i].flags = 0x%.4x", dir, g_config->streams[dir].flags);
[1906]348
349  if ( streams_set_flag(id, g_config->streams[dir].flags) == -1 ) {
350   ROAR_DBG("streams_set_dir(*) = -1 // can not set stream flags");
[1609]351   return -1;
[1906]352  }
[1609]353
354   ss->mixer.scale   = g_config->streams[dir].mixer.scale;
355   ss->mixer.rpg_mul = g_config->streams[dir].mixer.rpg_mul;
356   ss->mixer.rpg_div = g_config->streams[dir].mixer.rpg_div;
357 }
358
[3214]359 if ( dir != ROAR_DIR_MIXING ) {
360  switch (streams_get_subsys(id)) {
361   case ROAR_SUBSYS_WAVEFORM:
362     streams_set_mixer_stream(id, g_waveform_mixer.stream);
[3539]363     roardsp_chanlist_init(ss->chanmap.in,  ROAR_STREAM(ss)->info.channels, ROARDSP_CHANLIST_MAP_ROARAUDIO);
[3214]364    break;
365#ifndef ROAR_WITHOUT_DCOMP_MIDI
366   case ROAR_SUBSYS_MIDI:
[3544]367     roardsp_chanlist_init(ss->chanmap.in,  ROAR_STREAM(ss)->info.channels, ROARDSP_CHANLIST_MAP_MIDI);
[3214]368     streams_set_mixer_stream(id, g_midi_mixer.stream);
369    break;
370#endif
371#ifndef ROAR_WITHOUT_DCOMP_LIGHT
372   case ROAR_SUBSYS_LIGHT:
373     streams_set_mixer_stream(id, g_light_mixer.stream);
374    break;
375#endif
376  }
[3544]377
[4545]378  if ( streams_get_ssdir(id) & STREAM_DIR_OUT ) {
379   if ( (mixer = streams_get_mixer_stream(id)) != -1 ) {
380    if ( g_streams[mixer]->flags & ROAR_FLAG_SINGLESINK ) {
381     streams_set_mixer_stream(id, -1);
382     return -1;
383    }
[4543]384   }
385  }
386
[3544]387  memcpy(ss->chanmap.out, ss->chanmap.in, sizeof(ss->chanmap.out));
[3546]388  streams_set_map(id, NULL, 0);
[3214]389 } else {
390  streams_set_mixer_stream(id, id);
391 }
392
[1906]393 ROAR_DBG("streams_set_dir(*) = 0");
[1609]394 return 0;
395}
[766]396
[2251]397int streams_get_dir    (int id) {
398 struct roar_stream_server * ss;
399
[2734]400 _CHECK_SID(id);
401
[2251]402 if ( (ss = g_streams[id]) == NULL )
403  return -1;
404
405 return ROAR_STREAM(ss)->dir;
406}
407
[3213]408int streams_set_mixer_stream(int id, int mixer) {
409 struct roar_stream_server * ss;
410
411 _CHECK_SID(id);
412
413 if ( (ss = g_streams[id]) == NULL )
414  return -1;
415
416 ss->mixer_stream = mixer;
417
418 return 0;
419}
420
[4543]421int streams_get_mixer_stream(int id) {
[3213]422 struct roar_stream_server * ss;
423
424 _CHECK_SID(id);
425
426 if ( (ss = g_streams[id]) == NULL )
427  return -1;
428
429 return ss->mixer_stream;
430}
431
[3630]432int streams_set_role   (int id, int role) {
433 struct roar_stream_server * ss;
434
435 _CHECK_SID(id);
436
437 if ( (ss = g_streams[id]) == NULL )
438  return -1;
439
440 ss->role = role;
441
442 return 0;
443}
444
[2415]445int streams_get_subsys (int id) {
446 struct roar_stream_server * ss;
447
[2734]448 _CHECK_SID(id);
449
[2415]450 if ( (ss = g_streams[id]) == NULL )
451  return -1;
452
[4614]453 if ( ROAR_STREAM(ss)->dir == ROAR_DIR_THRU )
454  return streams_get_subsys(ROAR_STREAM(ss)->pos_rel_id);
455
456 return streams_dir2subsys(ROAR_STREAM(ss)->dir);
457}
458
459int streams_dir2subsys (int dir) {
460 switch (dir) {
[2415]461  case ROAR_DIR_PLAY:
462  case ROAR_DIR_RECORD:
463  case ROAR_DIR_MONITOR:
464  case ROAR_DIR_FILTER:
465  case ROAR_DIR_OUTPUT:
466  case ROAR_DIR_BIDIR:
467    return ROAR_SUBSYS_WAVEFORM;
468   break;
469  case ROAR_DIR_MIDI_IN:
470  case ROAR_DIR_MIDI_OUT:
471    return ROAR_SUBSYS_MIDI;
472   break;
473  case ROAR_DIR_LIGHT_IN:
474  case ROAR_DIR_LIGHT_OUT:
475    return ROAR_SUBSYS_LIGHT;
476   break;
477  case ROAR_DIR_RAW_IN:
478  case ROAR_DIR_RAW_OUT:
479    return ROAR_SUBSYS_RAW;
480   break;
[2681]481  case ROAR_DIR_COMPLEX_IN:
482  case ROAR_DIR_COMPLEX_OUT:
483    return ROAR_SUBSYS_COMPLEX;
484   break;
[4383]485  case ROAR_DIR_MIXING:
486    return ROAR_SUBSYS_NONE;
487   break;
[2415]488 }
489
490 return -1;
491}
492
[3542]493int streams_get_ssdir  (int id) {
494 struct roar_stream_server * ss;
495
496 _CHECK_SID(id);
497
498 if ( (ss = g_streams[id]) == NULL )
499  return -1;
500
501 switch (ROAR_STREAM(ss)->dir) {
502  case ROAR_DIR_PLAY:
503  case ROAR_DIR_MIDI_IN:
504  case ROAR_DIR_LIGHT_IN:
505  case ROAR_DIR_RAW_IN:
506  case ROAR_DIR_COMPLEX_IN:
507    return STREAM_DIR_IN;
508   break;
509  case ROAR_DIR_RECORD:
510  case ROAR_DIR_MONITOR:
511  case ROAR_DIR_OUTPUT:
512  case ROAR_DIR_MIDI_OUT:
513  case ROAR_DIR_LIGHT_OUT:
514  case ROAR_DIR_RAW_OUT:
515  case ROAR_DIR_COMPLEX_OUT:
516    return STREAM_DIR_OUT;
517   break;
518  case ROAR_DIR_MIXING:
519    return STREAM_DIR_NONE;
520   break;
521  case ROAR_DIR_FILTER:
522  case ROAR_DIR_BIDIR:
523    return STREAM_DIR_BIDIR;
524   break;
525  case ROAR_DIR_THRU:
526    return streams_get_ssdir(ROAR_STREAM(ss)->pos_rel_id);
527   break;
528 }
529
530 return -1;
531}
532
[2593]533#define _err() streams_delete(id); return -1;
[2594]534int streams_new_virtual (int parent, struct roar_stream_server ** stream) {
[2593]535 struct roar_stream_server * parent_ss, * ss;
536 struct roar_stream        * parent_s , *  s;
537 int id = -1;
538 int client, dir;
539
540 if ( streams_get(parent, &parent_ss) == -1 )
541  return -1;
542
543 if ( (client = streams_get_client(parent)) == -1 )
544  return -1;
545
546 if ( (dir = streams_get_dir(parent)) == -1 )
547  return -1;
548
549 if ( (id = streams_new()) == -1 ) {
550  return -1;
551 }
552
[2597]553 if ( client_stream_add(client, id) == -1 ) {
[2593]554  _err();
555 }
556
557 if ( streams_get(id, &ss) == -1 ) {
558  _err();
559 }
560
561 if ( streams_set_dir(id, dir, 1) == -1 ) {
562  _err();
563 }
564
565 s        = ROAR_STREAM(       ss);
566 parent_s = ROAR_STREAM(parent_ss);
567
[2596]568 s->pos_rel_id = parent;
[2593]569
[2625]570 if ( streams_set_rawflag(id, ROAR_FLAG_VIRTUAL) == -1 ) {
[2593]571  _err();
572 }
573
[2596]574 if ( stream != NULL )
[2594]575  *stream = ss;
576
[2593]577 return id;
578}
579#undef _err
580
[0]581int streams_set_fh     (int id, int fh) {
[1243]582 struct roar_stream_server * ss;
[1913]583 struct roar_stream        * s;
[51]584 int dir;
[2361]585 int nonblock = 1;
[51]586
[2734]587 _CHECK_SID(id);
588
[1913]589 if ( (s = ROAR_STREAM(ss = g_streams[id])) == NULL )
[0]590  return -1;
591
[4815]592 if ( ss->ready && !(s->fh == -1 && fh == -2) ) {
[4240]593  ROAR_DBG("streams_set_fh(id=%i, fh=%i) = -1 // try to set fh for stream which is already ready", id, fh);
[4229]594  return -1;
[4240]595 }
[4229]596
[4815]597 dir = s->dir;
[2816]598
[4240]599 ROAR_DBG("streams_set_fh(id=%i, fh=%i): g_streams[id]->id=%i", id, fh, s->id);
[491]600
[1913]601 s->fh = fh;
[0]602
[1243]603 ROAR_DBG("streams_set_fh(id=%i, fh=%i): driverID=%i", id, fh, ss->driver_id);
604
[2766]605 if ( ss->driver_id == -1 && fh != -2 ) {
606#ifndef ROAR_TARGET_WIN32
[1243]607  roar_vio_set_fh(&(ss->vio), fh);
[2766]608#else
609  roar_vio_open_fh_socket(&(ss->vio), fh);
610#endif
611 }
[1243]612
[2816]613 ROAR_DBG("streams_set_fh(id=%i, fh=%i) = ?", id, fh);
614
[2840]615 switch (dir) {
616  case ROAR_DIR_THRU:
617  case ROAR_DIR_RAW_IN:
618  case ROAR_DIR_RAW_OUT:
619   break;
620  default:
621    if ( codecfilter_open(&(ss->codecfilter_inst), &(ss->codecfilter), NULL,
622                     s->info.codec, ss) == -1 ) {
623     streams_delete(id); // TODO: FIXME: is this correct? shoudn't we return -1 in any case here?
624     return -1;
625    }
626   break;
[571]627 }
[268]628
[2816]629 ROAR_DBG("streams_set_fh(id=%i, fh=%i) = ?", id, fh);
630
[1610]631 if ( fh == -2 ) {
632  ROAR_DBG("streams_set_fh(id=%i, fh=%i) = ?", id, fh);
633  if ( roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_GET_READ_FH, &fh) == -1 ) {
634   fh = -2;
635  } else {
636   ROAR_DBG("streams_set_fh(id=%i, fh=%i) = ?", id, fh);
637   if ( fh < 0 ) {
638    fh = -2;
639   } else {
[1913]640    s->fh = fh;
[1610]641   }
642  }
643 }
644
[2816]645 ROAR_DBG("streams_set_fh(id=%i, fh=%i) = ?", id, fh);
646
[1610]647 if ( fh == -1 || fh == -2 ) { // yes, this is valid, indecats full vio!
[1913]648  ss->ready = 1;
[4336]649  //ROAR_INFO("streams_set_fh(id=%i, fh=%i): stream state: %s->new", ROAR_DBG_INFO_VERBOSE, id, fh, roar_streamstate2str(ss->state));
650  _streams_change_state(ss, ROAR_STREAMSTATE_NEW, "streams_set_fh");
[634]651  return 0;
652 }
653
[2816]654 ROAR_DBG("streams_set_fh(id=%i, fh=%i) = ?", id, fh);
[968]655
[2816]656// roar_socket_recvbuf(fh, ROAR_OUTPUT_CALC_OUTBUFSIZE( &(ROAR_STREAM(g_streams[id])->info) )); // set recv buffer to minimum
[51]657
[1912]658 switch (dir) {
659  case ROAR_DIR_MONITOR:
660  case ROAR_DIR_RECORD:
661  case ROAR_DIR_OUTPUT:
662  case ROAR_DIR_MIDI_OUT:
663  case ROAR_DIR_LIGHT_OUT:
[2248]664  case ROAR_DIR_RAW_OUT:
[1912]665    ROAR_SHUTDOWN(fh, SHUT_RD);
666   break;
[51]667 }
668
[2337]669 if ( dir >= ROAR_DIR_DIRIDS )
670  return -1;
671
672 if ( g_config->streams[dir].flags & ROAR_FLAG_SYNC ) {
[2361]673  switch (dir) {
674   case ROAR_DIR_BRIDGE:
675   case ROAR_DIR_MIDI_OUT:
676    break;
677   default:
678     nonblock = 0;
679    break;
680  }
681 }
682
683
684 if ( !nonblock ) {
[1913]685  ss->ready = 1;
[4336]686  //ROAR_INFO("streams_set_fh(id=%i, fh=%i): stream state: %s->new", ROAR_DBG_INFO_VERBOSE, id, fh, roar_streamstate2str(ss->state));
687  _streams_change_state(ss, ROAR_STREAMSTATE_NEW, "streams_set_fh");
[2816]688
689  ROAR_DBG("streams_set_fh(id=%i, fh=%i) = 0", id, fh);
[0]690  return 0;
691 } else {
[2764]692#ifndef ROAR_TARGET_WIN32
[1913]693  if ( roar_socket_nonblock(fh, ROAR_SOCKET_NONBLOCK) == -1 )
694   return -1;
[2764]695#endif
[1913]696
697  ss->ready = 1;
[4336]698  //ROAR_INFO("streams_set_fh(id=%i, fh=%i): stream state: %s->new", ROAR_DBG_INFO_VERBOSE, id, fh, roar_streamstate2str(ss->state));
699  _streams_change_state(ss, ROAR_STREAMSTATE_NEW, "streams_set_fh");
[2816]700
701  ROAR_DBG("streams_set_fh(id=%i, fh=%i) = 0", id, fh);
[1913]702  return 0;
[0]703 }
704}
705
[66]706int streams_get_fh     (int id) {
[2734]707 _CHECK_SID(id);
[66]708
[609]709 return ROAR_STREAM(g_streams[id])->fh;
[66]710}
[0]711
[2606]712int streams_set_null_io(int id) {
713 struct roar_stream_server * ss;
714 struct roar_stream        * s;
715
[2734]716 _CHECK_SID(id);
717
[2606]718 if ( (s = ROAR_STREAM(ss = g_streams[id])) == NULL )
719  return -1;
720
721 s->fh = -1;
722
723 return 0;
724}
725
[0]726int streams_get    (int id, struct roar_stream_server ** stream) {
[2734]727 _CHECK_SID(id);
[0]728
729 *stream = g_streams[id];
730
731 return 0;
732}
733
[4521]734int streams_get_clientobj (int id, struct roar_stream        ** stream) {
735 _CHECK_SID(id);
736
737 *stream = ROAR_STREAM(g_streams[id]);
738
739 return 0;
740}
741
[377]742int streams_set_socktype (int id, int socktype) {
[2734]743 _CHECK_SID(id);
[377]744
745 g_streams[id]->socktype = socktype;
746
747 return 0;
748}
749
750int streams_get_socktype (int id) {
[2734]751 _CHECK_SID(id);
[377]752
753 return g_streams[id]->socktype;
754}
[0]755
[3921]756int streams_is_ready     (int id) {
757 _CHECK_SID(id);
758
759 return g_streams[id]->ready;
760}
761
[4819]762int streams_is_new       (int id) {
763 _CHECK_SID(id);
764
765 return g_streams[id]->ready;
766}
767
[643]768int streams_set_primary (int id, int prim) {
[2734]769 _CHECK_SID(id);
[643]770
771 g_streams[id]->primary = prim;
772
773 return 0;
774}
775
776int streams_mark_primary (int id) {
777 return streams_set_primary(id, 1);
778}
[1029]779
[1116]780int streams_set_sync     (int id, int sync) {
[1117]781 int fh = streams_get_fh(id);
[1116]782
[2734]783 _CHECK_SID(id);
784
[1117]785 if ( fh != -1 ) {
786  if ( roar_socket_nonblock(fh, sync ? ROAR_SOCKET_BLOCK : ROAR_SOCKET_NONBLOCK) == -1 )
787   return -1;
[1116]788
[1498]789#ifdef ROAR_FDATASYNC
[1171]790  ROAR_FDATASYNC(fh);
[1498]791#endif
[1125]792
793  return 0;
[1117]794 } else {
795  return roar_vio_nonblock(&(g_streams[id]->vio), sync);
796 }
[1116]797}
798
[1928]799int streams_set_mmap (int id, int reset) {
800 int use = !reset;
801
[2734]802 _CHECK_SID(id);
[1928]803
804 return roar_vio_ctl(&(g_streams[id]->vio), ROAR_VIO_CTL_SET_UMMAP, &use);
805}
806
[4537]807int streams_set_single_sink(int id, int reset) {
[4543]808 struct roar_stream_server * self_ss, * ss;
809 struct roar_stream                   *  s;
810 int mixer;
811 size_t count = 0;
812 int i;
813 int ssdir;
814
815 /* FIXME: This code only uses one refc for the mixer shared with the inputs.
816  *        If the flag is unset on the mixer but got set by the sources the counter
817  *        may/will become corrupted.
818  */
819
[4537]820 _CHECK_SID(id);
821
[4543]822 self_ss = g_streams[id];
823
824 mixer = self_ss->mixer_stream;
825
[4547]826 ROAR_DBG("streams_set_single_sink(id=%i, reset=%i): mixer=%i", id, reset, mixer);
[4545]827
[4546]828 if ( !reset && id != mixer )
829  if ( self_ss->flags & ROAR_FLAG_SINGLESINK )
830   return 0;
831
[4543]832 if ( id == mixer ) {
833  if ( reset ) {
[4545]834   if ( self_ss->single_sink_self_c ) {
[4547]835    ROAR_DBG("streams_set_single_sink(id=%i, reset=%i): mixer=%i", id, reset, mixer);
[4545]836    self_ss->single_sink_self_c--;
[4543]837    self_ss->single_sink_c--;
[4545]838    if ( self_ss->single_sink_c == 0 ) {
[4547]839     ROAR_DBG("streams_set_single_sink(id=%i, reset=%i): mixer=%i", id, reset, mixer);
[4545]840     self_ss->flags |= ROAR_FLAG_SINGLESINK;
841     self_ss->flags -= ROAR_FLAG_SINGLESINK;
842    }
[4543]843    return 0;
[4545]844   } else {
845    return -1;
[4543]846   }
847  } else {
848   if ( self_ss->single_sink_c ) {
[4545]849    self_ss->single_sink_self_c++;
[4543]850    self_ss->single_sink_c++;
851    return 0;
852   }
853  }
854 } else if ( reset ) {
[4547]855  ROAR_DBG("streams_set_single_sink(id=%i, reset=%i): mixer=%i", id, reset, mixer);
[4545]856
[4689]857  if ( (ss = g_streams[mixer]) == NULL )
858   return -1;
859
860  if ( ss->single_sink_c == 0 )
[4543]861   return -1;
862  ss->single_sink_c--;
863
864  if ( ss->single_sink_c == 0 ) {
865    self_ss->flags |= ROAR_FLAG_SINGLESINK;
866    self_ss->flags -= ROAR_FLAG_SINGLESINK;
867         ss->flags |= ROAR_FLAG_SINGLESINK;
868         ss->flags -= ROAR_FLAG_SINGLESINK;
869  }
870
871  return 0;
872 }
873
874
875
876 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
877  if ( (s = ROAR_STREAM((ss = g_streams[i]))) != NULL ) {
878   if ( s->dir == ROAR_DIR_THRU )
[4544]879    if ( s->pos_rel_id == id || s->pos_rel_id == mixer || g_streams[s->pos_rel_id]->mixer_stream == mixer )
[4543]880     return -1;
881
882   if ( ss->mixer_stream != mixer )
883    continue;
884
885   ssdir = streams_get_ssdir(i);
886
[4544]887   if ( ssdir & STREAM_DIR_OUT )
[4543]888    count++;
889  }
890 }
891
892 if ( count > 1 )
893  return -1;
894
895 ss = g_streams[mixer];
896
[4545]897 if ( id == mixer )
898  ss->single_sink_self_c++;
899
[4543]900 ss->single_sink_c++;
901
902 self_ss->flags |= ROAR_FLAG_SINGLESINK;
903      ss->flags |= ROAR_FLAG_SINGLESINK;
904
905 return 0;
[4537]906}
907
[4550]908int streams_set_flag     (int id, uint32_t flag) {
[2626]909 int parent;
[4815]910 int tmp;
[2626]911
[2734]912 _CHECK_SID(id);
[1029]913
[2952]914 if ( flag & ROAR_FLAG_IMMUTABLE )
915  flag |= ROAR_FLAG_PRIMARY;
916
[4552]917
918 // check if flags we are going to change are protected:
919 if ( g_streams[id]->flags_protection & flag )
920  return -1;
921
922
[4540]923 if ( flag & ROAR_FLAG_MMAP ) {
924  if ( streams_set_mmap(id, 0) == -1 ) {
[1928]925   flag -= ROAR_FLAG_MMAP;
[4540]926   return -1;
927  }
928 }
[1926]929
[1043]930 if ( flag & ROAR_FLAG_PRIMARY ) {
931  streams_set_primary(id, 1);
932  flag -= ROAR_FLAG_PRIMARY;
933 }
934
[4537]935 if ( flag & ROAR_FLAG_SINGLESINK ) {
[4540]936  if ( streams_set_single_sink(id, 0) == -1 ) {
937   return -1;
938  }
[4545]939  flag -= ROAR_FLAG_SINGLESINK;
[4537]940 }
941
[2626]942 if ( flag & ROAR_FLAG_VIRTUAL ) {
943  if ( (parent = ROAR_STREAM(g_streams[id])->pos_rel_id) == -1 )
944   return -1;
945
946  if ( streams_ctl(parent, ROAR_CODECFILTER_CTL_VIRTUAL_NEW|ROAR_STREAM_CTL_TYPE_INT, &id) == -1 ) {
947//   flag -= ROAR_FLAG_VIRTUAL;
948   return -1;
949  }
[2705]950
951  if ( client_stream_move(streams_get_client(parent), id) == -1 ) {
952   return -1;
953  }
[2626]954 }
955
[1116]956 if ( flag & ROAR_FLAG_SYNC ) {
[1908]957  switch (ROAR_STREAM(g_streams[id])->dir) {
958   // for this stream types the flag is used in the subsystem:
959   case ROAR_DIR_BRIDGE:
960   case ROAR_DIR_MIDI_OUT:
961    break;
962
963   // normal behavor (vio blocking):
964   default:
[2341]965     // the fh is updated as soon as the fh get ready in case the default ask to set sync
[2342]966     if ( !g_streams[id]->ready && !(g_config->streams[ROAR_STREAM(g_streams[id])->dir].flags & ROAR_FLAG_SYNC) ) {
[2341]967      if ( streams_set_sync(id, 1) == -1 )
968       flag -= ROAR_FLAG_SYNC;
969     }
[1908]970  }
[1116]971 }
972
[1585]973 if ( flag & ROAR_FLAG_HWMIXER ) { // currently not supported -> ignored
[1590]974  g_streams[id]->flags |= flag;
975  if ( streams_set_mixer(id) == -1 ) {
976   g_streams[id]->flags -= flag;
977   return -1;
978  }
[1585]979 }
980
[2417]981 if ( flag & ROAR_FLAG_RECSOURCE ) {
982  if ( streams_recsource_id != -1 ) {
983   if ( streams_reset_flag(streams_recsource_id, ROAR_FLAG_RECSOURCE) == -1 )
984    return -1;
985  }
986
[4815]987  if ( g_streams[id]->ready ) {
988   tmp = 1;
989   if ( stream_vio_ctl(id, ROAR_VIO_CTL_SET_RECORD, &tmp) == -1 )
990    return -1;
991  }
992
[2417]993  streams_recsource_id = id;
994 }
995
[1029]996 g_streams[id]->flags |= flag;
997
[1498]998#ifdef ROAR_SUPPORT_META
[1043]999 if ( flag & ROAR_FLAG_META )
1000  stream_meta_finalize(id);
[1498]1001#endif
[1043]1002
[1029]1003 return 0;
1004}
1005
[4550]1006int streams_set_rawflag  (int id, uint32_t flag) {
[2734]1007 _CHECK_SID(id);
[2625]1008
1009 g_streams[id]->flags |= flag;
1010
1011 return 0;
1012}
1013
[4550]1014int streams_reset_flag   (int id, uint32_t flag) {
[4815]1015 int tmp;
1016
[2734]1017 _CHECK_SID(id);
[1029]1018
[4552]1019 // check if flags we are going to change are protected:
1020 if ( g_streams[id]->flags_protection & flag )
1021  return -1;
1022
[2952]1023 if ( g_streams[id]->flags & ROAR_FLAG_IMMUTABLE ) {
1024  flag |= ROAR_FLAG_PRIMARY;
1025  flag -= ROAR_FLAG_PRIMARY;
1026 }
1027
[4815]1028 if ( (flag & ROAR_FLAG_RECSOURCE) && streams_recsource_id == id ) {
1029  if ( g_streams[id]->ready ) {
1030   tmp = 0;
1031   if ( stream_vio_ctl(id, ROAR_VIO_CTL_SET_RECORD, &tmp) == -1 )
1032    return -1;
1033  }
1034
1035  streams_recsource_id = -1;
1036 }
1037
[2417]1038
[4540]1039 if ( flag & ROAR_FLAG_MMAP ) {
1040  if ( streams_set_mmap(id, 1) == -1 ) {
[1928]1041   flag -= ROAR_FLAG_MMAP;
[4540]1042   return -1;
1043  }
1044 }
[1928]1045
[1043]1046 if ( flag & ROAR_FLAG_PRIMARY ) {
1047  streams_set_primary(id, 0);
1048  flag -= ROAR_FLAG_PRIMARY;
1049 }
1050
[4537]1051 if ( flag & ROAR_FLAG_SINGLESINK ) {
[4540]1052  if ( streams_set_single_sink(id, 1) == -1 ) {
1053   return -1;
1054  }
[4545]1055  flag -= ROAR_FLAG_SINGLESINK;
[4537]1056 }
1057
[1116]1058 if ( flag & ROAR_FLAG_SYNC ) {
[2264]1059  // we refuse to reset the flag on FILTER streams
1060  if ( streams_get_dir(id) == ROAR_DIR_FILTER ) {
1061//   flags -= ROAR_FLAG_SYNC;
1062   return -1;
1063  } else {
1064   streams_set_sync(id, 0);
1065  }
[1116]1066 }
1067
[1029]1068 g_streams[id]->flags |= flag;
1069 g_streams[id]->flags -= flag;
1070
1071 return 0;
1072}
1073
[4550]1074int streams_get_flag     (int id, uint32_t flag) {
[2734]1075 _CHECK_SID(id);
[1042]1076
1077 return g_streams[id]->flags & flag ? 1 : 0;
1078}
1079
[4552]1080int streams_protect_flag (int id, uint32_t flag) {
1081 _CHECK_SID(id);
1082
1083 g_streams[id]->flags_protection |= flag;
1084
1085 return 0;
1086}
1087
[1842]1088int streams_set_name     (int id, char * name) {
1089 char * str;
1090
[2734]1091 _CHECK_SID(id);
[1842]1092
1093 if ( (str = strdup(name)) == NULL )
1094  return -1;
1095
1096 if ( g_streams[id]->name != NULL )
1097  free(g_streams[id]->name);
1098
1099 g_streams[id]->name = str;
[1845]1100
1101 return 0;
[1842]1102}
1103
1104char * streams_get_name  (int id) {
[2734]1105 _CHECK_SID_RET(id, NULL);
[1842]1106
1107 return g_streams[id]->name;
1108}
1109
1110
[1223]1111int streams_calc_delay    (int id) {
[1142]1112 struct roar_stream_server * ss;
[1151]1113 struct roar_stream        * s;
[1142]1114 register uint_least32_t d = 0;
1115 uint_least32_t t[1];
[1151]1116 uint64_t       tmp;
[1142]1117
[2734]1118 _CHECK_SID(id);
1119
[1151]1120 if ( (s = ROAR_STREAM(ss = g_streams[id])) == NULL )
[1142]1121  return -1;
1122
[3212]1123 // mixer store there value in ss->delay directly
1124 if ( s->dir == ROAR_DIR_MIXING )
1125  return 0;
1126
[4157]1127#if 0
1128 // this only confuses the user...
[3216]1129 if ( ss->mixer_stream != id ) {
1130  if ( streams_calc_delay(ss->mixer_stream) != -1 ) {
1131   d += g_streams[ss->mixer_stream]->delay; // in case we can calc the delay
1132                                            // the stream must exist, so no check here
1133  }
1134 }
[4157]1135#endif
[3216]1136
[1142]1137 if ( ss->codecfilter != -1 ) {
1138  if ( codecfilter_delay(ss->codecfilter_inst, ss->codecfilter, t) != -1 )
1139   d += *t;
1140 }
1141
[1151]1142 if ( ss->vio.ctl != NULL ) {
1143  if ( roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_GET_DELAY, t) != -1 ) { // *t is in byte
[1223]1144   ROAR_DBG("streams_calc_delay(id=%i): VIO delay in byte: %i", id, *t);
[1151]1145   tmp = *t;
1146   tmp *= 1000000; // musec per sec
1147   tmp /= s->info.rate * s->info.channels * (s->info.bits/8);
[2387]1148   ROAR_DBG("streams_calc_delay(id=%i): VIO delay in musec: %llu", id, tmp);
[1151]1149
1150   d += tmp;
1151  }
1152 }
1153
[1223]1154 ROAR_DBG("streams_calc_delay(id=%i): delay in musec: %i", id, d);
[1151]1155
[1142]1156 ss->delay = d;
1157
1158 return 0;
1159}
1160
[1590]1161int streams_set_mixer    (int id) {
1162 struct roar_stream_server * ss;
[2416]1163 struct roar_stream_server * pmss;
1164 int i;
1165 int subsys;
[4383]1166 int tsubsys;
[1590]1167
[2734]1168 _CHECK_SID(id);
1169
[1590]1170 if ( (ss = g_streams[id]) == NULL )
1171  return -1;
1172
[2416]1173 if ( streams_get_flag(id, ROAR_FLAG_PASSMIXER) == 1 ) {
1174  if ( (subsys = streams_get_subsys(id)) == -1 )
1175   return -1;
1176
1177  for (i = 0; i < ROAR_STREAMS_MAX; i++) {
1178   if ( (pmss = g_streams[i]) != NULL ) {
1179    if ( streams_get_flag(i, ROAR_FLAG_PASSMIXER) == 1 ) {
[4383]1180     tsubsys = streams_get_subsys(i);
1181     if ( tsubsys == subsys || tsubsys == ROAR_SUBSYS_NONE ) {
[4119]1182      if ( &(pmss->mixer) != &(ss->mixer) ) {
[4386]1183       roar_conv_volume(&(pmss->mixer), &(ss->mixer), ROAR_STREAM(pmss)->info.channels, ROAR_STREAM(ss)->info.channels);
[4119]1184      }
[2416]1185
1186      // update hwmixers and the like but do not set mixer value recrusivly.
1187      streams_reset_flag(i, ROAR_FLAG_PASSMIXER);
1188      streams_set_mixer(i);
1189      streams_set_flag(i, ROAR_FLAG_PASSMIXER);
1190     }
1191    }
1192   }
1193  }
1194 }
1195
[4417]1196 roar_notify_core_emit_snoargs(ROAR_OE_STREAM_CHANGE_VOLUME, -1, id, ROAR_OT_STREAM);
1197
[1590]1198 if ( !streams_get_flag(id, ROAR_FLAG_HWMIXER) )
1199  return 0;
1200
[4365]1201 if ( ss->driver_id != -1 ) {
1202  return driver_set_volume(id, &(ss->mixer));
[4753]1203#ifndef ROAR_WITHOUT_DCOMP_MIXER
[4365]1204 } else if ( ss->mixerstream != NULL ) {
1205  return hwmixer_set_volume(id, ss, ss->mixerstream, &(ss->mixer));
[4753]1206#endif
[4365]1207 } else {
[1590]1208  return 0;
[4365]1209 }
[1590]1210}
1211
[3542]1212int streams_set_map      (int id, char * map, size_t len) {
1213 struct roar_stream_server * ss;
1214 int ssdir;
1215
1216 _CHECK_SID(id);
1217
1218 if ( (ss = g_streams[id]) == NULL )
1219  return -1;
1220
1221 if ( map != NULL ) {
1222  if ( ROAR_STREAM(ss)->info.channels != len )
1223   return -1;
1224 }
1225
[3557]1226 ssdir = streams_get_ssdir(id);
1227
[3542]1228 switch (ssdir) {
1229  case STREAM_DIR_IN:
[3557]1230  case STREAM_DIR_NONE:
[3671]1231    memset(ss->chanmap.in, 0, sizeof(ss->chanmap.in));
1232
[3556]1233    if ( map != NULL )
1234     memcpy(ss->chanmap.in, map, len);
1235
[3542]1236    roardsp_chanmap_calc(&(ss->chanmap), ROARDSP_CHANMAP_MAP, 0);
1237   break;
1238  case STREAM_DIR_OUT:
[3671]1239    memset(ss->chanmap.out, 0, sizeof(ss->chanmap.out));
1240
[3556]1241    if ( map != NULL )
1242     memcpy(ss->chanmap.out, map, len);
1243
1244    roardsp_chanmap_calc(&(ss->chanmap), ROARDSP_CHANMAP_MAP, 0);
[3542]1245   break;
[3557]1246  default:
1247    return -1;
[3542]1248 }
1249
1250 return 0;
1251}
1252
[4272]1253int streams_ltm_ctl      (int id, int mt, int window, int cmd) {
1254 struct roar_stream_server * ss;
1255 struct roar_stream_ltm *    ltm;
1256 int i;
1257
1258 _CHECK_SID(id);
1259
1260 // currently we only support the WORKBLOCK window
1261 if ( window != ROAR_LTM_WIN_WORKBLOCK )
1262  return -1;
1263
1264 // currently we only support ROAR_LTM_MT_RMS
1265 if ( (mt | ROAR_LTM_MT_RMS) - ROAR_LTM_MT_RMS )
1266  return -1;
1267
1268 if ( (ss = g_streams[id]) == NULL )
1269  return -1;
1270
1271 switch (cmd) {
1272  case ROAR_LTM_SST_NOOP:
1273    return 0;
1274   break;
1275  case ROAR_LTM_SST_REGISTER:
1276    // test if the window is already registered:
1277    for (i = 0; i < MAX_LTM_WINDOWS_PER_STREAM; i++) {
1278     ltm = &(ss->ltm[i]);
1279     if ( ltm->refc && ltm->window == window ) {
1280      ltm->refc++;
1281      ltm->mt |= mt;
1282      return 0;
1283     }
1284    }
1285
1286    // register
1287    for (i = 0; i < MAX_LTM_WINDOWS_PER_STREAM; i++) {
1288     ltm = &(ss->ltm[i]);
1289     if ( ltm->refc == 0 ) {
1290      memset(ltm, 0, sizeof(struct roar_stream_ltm));
1291      ltm->refc = 1;
1292      ltm->window = window;
1293      ltm->parent_window = -1;
1294      ltm->mt = mt;
1295      ltm->channels = ROAR_STREAM(ss)->info.channels;
1296      if ( (ltm->cur = roar_mm_malloc(ltm->channels*sizeof(struct roar_ltm_vals))) == NULL ) {
1297       ltm->refc = 0; // reset
1298       return -1;
1299      }
1300      memset(ltm->cur, 0, ltm->channels*sizeof(struct roar_ltm_vals));
1301      return 0;
1302     }
1303    }
1304    return -1;
1305   break;
1306  case ROAR_LTM_SST_UNREGISTER:
1307    for (i = 0; i < MAX_LTM_WINDOWS_PER_STREAM; i++) {
1308     ltm = &(ss->ltm[i]);
1309     if ( ltm->refc && ltm->window == window ) {
1310      ltm->refc--;
1311      if ( ! ltm->refc ) {
1312       roar_mm_free(ltm->cur);
1313       return 0;
1314      }
1315     }
1316    }
1317    return -1;
1318   break;
1319  default:
1320    return -1;
1321   break;
1322 }
1323}
1324
1325int streams_ltm_calc     (int id, struct roar_audio_info * info, void * data, size_t len) {
1326 struct roar_stream_server * ss;
1327 struct roar_stream_ltm *    ltm = NULL;
1328 int64_t rmsbuf_real[8];
1329 int64_t * rmsbuf = rmsbuf_real;
1330 size_t samples = 0;
1331 int i;
1332
1333 _CHECK_SID(id);
1334
1335 if ( data == NULL || info == NULL )
1336  return -1;
1337
1338 if ( info->codec != ROAR_CODEC_DEFAULT )
1339  return -1;
1340
1341 if ( (ss = g_streams[id]) == NULL )
1342  return -1;
1343
1344 for (i = 0; i < MAX_LTM_WINDOWS_PER_STREAM; i++) {
1345  if ( ss->ltm[i].refc && ss->ltm[i].window == ROAR_LTM_WIN_WORKBLOCK ) {
1346   ltm = &(ss->ltm[i]);
1347   break;
1348  }
1349 }
1350
1351 if ( ltm == NULL )
1352  return -1;
1353
1354 // TODO: support change of number of channels
1355 if ( ltm->channels != info->channels )
1356  return -1;
1357
1358 if ( len == 0 ) {
1359  memset(ltm->cur, 0, ltm->channels * sizeof(struct roar_ltm_vals));
1360  return 0;
1361 }
1362
1363 // TODO: support more channels then rmsbuf_real has space for
1364 if ( ltm->channels > (sizeof(rmsbuf_real)/sizeof(*rmsbuf_real)) ) {
1365  return -1;
1366 }
1367
1368 samples = len / info->bits;
1369
1370 if ( ltm->mt & ROAR_LTM_MT_RMS ) {
1371  if ( roar_rms2_1_b_n(data, samples, rmsbuf, ltm->channels, info->bits) == -1 )
1372   return -1;
1373
1374  for (i = 0; i < ltm->channels; i++) {
[4286]1375   ltm->cur[i].rms = rmsbuf[i] << (64 - info->bits*2);
[4272]1376  }
1377
1378  ROAR_DBG("streams_ltm_calc(id=%i,...): rmsbuf[0]=%lli", id, (long long int)rmsbuf[0]);
1379 }
1380
1381 return 0;
1382}
1383
[4289]1384struct roar_stream_ltm * streams_ltm_get(int id, int mt, int window) {
[4278]1385 struct roar_stream_server * ss;
1386 struct roar_stream_ltm *    ltm = NULL;
1387 int i;
1388
[4290]1389 _CHECK_SID_RET(id, NULL);
[4278]1390
1391 if ( (ss = g_streams[id]) == NULL )
[4290]1392  return NULL;
[4278]1393
1394 for (i = 0; i < MAX_LTM_WINDOWS_PER_STREAM; i++) {
1395  if ( ss->ltm[i].refc && ss->ltm[i].window == window ) {
1396   ltm = &(ss->ltm[i]);
1397   break;
1398  }
1399 }
1400
1401 if ( ltm == NULL )
1402  return NULL;
1403
1404 if ( (ltm->mt & mt) != mt )
1405  return NULL;
1406
1407 return ltm;
1408}
[4272]1409
[4753]1410#ifndef ROAR_WITHOUT_DCOMP_MIXER
[4361]1411struct hwmixer_stream * streams_get_mixerstream(int id) {
1412 _CHECK_SID_RET(id, NULL);
1413
1414 return g_streams[id]->mixerstream;
1415}
1416
1417int streams_set_mixerstream(int id, struct hwmixer_stream * mstream) {
1418 _CHECK_SID(id);
1419
1420 g_streams[id]->mixerstream = mstream;
1421
1422 return 0;
1423}
1424
[4379]1425int streams_read_mixervalues(int id) {
1426 struct roar_stream_server * ss;
1427
1428 _CHECK_SID(id);
1429
1430 if ( (ss = g_streams[id]) == NULL )
1431  return -1;
1432
1433 if ( ss->mixerstream == NULL )
1434  return -1;
1435
1436 return hwmixer_get_volume(id, ss, ss->mixerstream, &(ss->mixer));
1437}
[4753]1438#endif
[4272]1439
[1224]1440int streams_ctl          (int id, int_least32_t cmd, void * data) {
1441 struct roar_stream_server * ss;
1442 int_least32_t comp;
1443
[2734]1444 _CHECK_SID(id);
1445
[1224]1446 if ( (ss = g_streams[id]) == NULL )
1447  return -1;
1448
1449 comp = cmd & ROAR_STREAM_CTL_COMPMASK;
1450
1451 cmd &= ~comp;
1452
[1239]1453 ROAR_DBG("streams_ctl(id=%i, cmd=?, data=%p): comp=0x%.8x, cmd=0x%.4x", id, data, comp, cmd);
[1238]1454
[1224]1455 switch (comp) {
1456  case ROAR_STREAM_CTL_COMP_BASE:
1457   break;
1458  case ROAR_STREAM_CTL_COMP_CF:
1459    return codecfilter_ctl(ss->codecfilter_inst, ss->codecfilter, cmd, data);
1460   break;
1461  case ROAR_STREAM_CTL_COMP_DRV:
1462   break;
1463  default:
1464   return -1;
1465 }
1466
1467 return -1;
1468}
1469
[0]1470int streams_get_outputbuffer  (int id, void ** buffer, size_t size) {
[2734]1471 _CHECK_SID(id);
[0]1472
1473 // output buffer size does never change.
1474 if ( g_streams[id]->output != NULL ) {
1475  *buffer = g_streams[id]->output;
1476  return 0;
1477 }
1478
1479 if ( (g_streams[id]->output = malloc(size)) == NULL ) {
1480  ROAR_ERR("streams_get_outputbuffer(*): Can not alloc: %s", strerror(errno));
1481  return -1;
1482 }
1483
1484 *buffer = g_streams[id]->output;
1485
1486 return 0;
1487}
1488
[2061]1489int streams_fill_mixbuffer2 (int id, struct roar_audio_info * info) {
1490 size_t   outlen = ROAR_OUTPUT_CALC_OUTBUFSIZE(info);
1491 void   * outdata;
1492 size_t   inlen;
1493 size_t   inlen_got;
1494 void   * indata = NULL;
[2091]1495 size_t   buflen;
1496 void   * bufdata = NULL;
1497 struct roar_buffer * bufbuf = NULL;
[2061]1498 int      is_the_same = 0;
1499 struct roar_audio_info    * stream_info;
1500 struct roar_stream        * s;
1501 struct roar_stream_server * ss;
1502
[2734]1503 _CHECK_SID(id);
1504
[2061]1505 if ( (s = ROAR_STREAM(ss = g_streams[id])) == NULL )
1506  return -1;
1507
1508 // set up stream_info
1509 stream_info = &(s->info);
1510
1511 // calc todo_in
1512 inlen = ROAR_OUTPUT_CALC_OUTBUFSIZE(stream_info);
1513
[2091]1514 buflen = ROAR_OUTPUT_CALC_OUTBUFSIZE_MAX(info, stream_info);
1515
[2747]1516 ROAR_DBG("streams_fill_mixbuffer2(id=%i, info=%p{...}): inlen=%lu, buflen=%lu", id, info, (unsigned long)inlen, (unsigned long)buflen);
1517
[2061]1518 if ( inlen == 0 ) {
1519  ROAR_WARN("streams_fill_mixbuffer2(id=%i, info=%p{...}): inlen == 0, this should not happen!", id, info);
1520  return -1;
1521 }
1522
1523 if ( streams_get_outputbuffer(id, &outdata, outlen) == -1 ) {
1524  return -1;
1525 }
1526
1527 if ( outdata == NULL ) {
1528  return -1;
1529 }
1530
1531 ROAR_DBG("streams_fill_mixbuffer2(*): outdata=%p, len=%i->%i (in->out)", outdata, inlen, outlen);
1532
1533 is_the_same = stream_info->rate     == info->rate     && stream_info->bits  == info->bits &&
1534               stream_info->channels == info->channels && stream_info->codec == info->codec;
1535
1536 ROAR_DBG("streams_fill_mixbuffer2(*): is_the_same=%i", is_the_same);
1537
[2091]1538 if ( !is_the_same && buflen > outlen ) {
1539/*
[2061]1540  // this is not supported at the moment
1541  memset(outdata, 0, outlen);
1542  return -1;
[2091]1543*/
1544
1545  if ( roar_buffer_new(&bufbuf, buflen) == -1 )
1546   return -1;
1547
1548  if ( roar_buffer_get_data(bufbuf, &bufdata) == -1 )
1549   return -1;
[2102]1550  indata  = bufdata;
[2061]1551 } else {
[2091]1552  indata  = outdata;
1553  bufdata = outdata;
[2061]1554 }
1555
1556 inlen_got = inlen;
1557
[2102]1558 ROAR_DBG("streams_fill_mixbuffer2(id=%i, info=...): inlen_got=%u", id, inlen_got);
1559
[2061]1560 if ( stream_shift_out_buffer(id, indata, &inlen_got) == -1 ) {
1561  if ( ss->is_new ) {
1562   ss->pre_underruns++;
[4417]1563   roar_notify_core_emit_simple(ROAR_OE_STREAM_XRUN, -1, id, ROAR_OT_STREAM, ROAR_XRUN_UNDER_PRE, ss->pre_underruns, NULL, 0);
[2061]1564  } else {
[2088]1565   ROAR_WARN("streams_fill_mixbuffer2(id=%i, info=...): underrun in stream", id);
[2061]1566   ss->post_underruns++;
[4417]1567   roar_notify_core_emit_simple(ROAR_OE_STREAM_XRUN, -1, id, ROAR_OT_STREAM, ROAR_XRUN_UNDER_POST, ss->post_underruns, NULL, 0);
[2061]1568  }
1569  memset(outdata, 0, outlen);
1570  return 0;
1571 }
1572
[2387]1573 ROAR_DBG("streams_fill_mixbuffer2(id=%i, info=...): inlen_got=%u", id, inlen_got);
1574
[2061]1575 if ( ss->is_new ) {
[4336]1576  //ROAR_INFO("streams_fill_mixbuffer2(id=%i, info=...): stream state: new->old", ROAR_DBG_INFO_VERBOSE, id);
1577  _streams_change_state(ss, ROAR_STREAMSTATE_OLD, "streams_fill_mixbuffer2");
[2061]1578 }
1579
1580 ss->is_new = 0;
1581
[3549]1582 // check channel map:
[3555]1583#if 0
[3554]1584 if ( roardsp_chanmap_mappcm(indata, indata, inlen, stream_info->channels, &(ss->chanmap), stream_info->bits) == -1 ) {
[3549]1585  if ( bufbuf != NULL )
1586   roar_buffer_free(bufbuf);
1587  return -1;
1588 }
[3555]1589#endif
[3549]1590
[4118]1591 // TODO: this only works in case a we have a amp for the given stream parameters.
1592 if ( !streams_get_flag(id, ROAR_FLAG_HWMIXER) && !streams_get_flag(id, ROAR_FLAG_PASSMIXER) ) {
1593  ROAR_DBG("streams_fill_mixbuffer2(*): CALL roar_amp_pcm(*)...");
[4120]1594  if ( roar_amp_pcm(indata, stream_info->bits, indata, 8*inlen / stream_info->bits, stream_info->channels, &(ss->mixer)) == -1 )
[4118]1595   return -1;
1596 }
1597
[3549]1598 // check codec, bits, channels, rate...
[2061]1599 if ( is_the_same ) {
1600  if ( indata != outdata )
1601   memcpy(outdata, indata, inlen);
1602
1603  if ( inlen < outlen )
1604   memset(outdata+inlen, 0, outlen-inlen);
1605 } else {
[2095]1606//  if ( roar_conv(outdata, indata, (8*inlen_got*info->rate)/(stream_info->rate * stream_info->bits), stream_info, info) == -1 ) {
[2387]1607  ROAR_DBG("streams_fill_mixbuffer2(*): CALL roar_conv2(*)...");
[4111]1608  if ( roar_conv2(bufdata, indata, inlen, stream_info, info, outlen) == -1 ) {
[2091]1609   if ( bufbuf != NULL )
1610    roar_buffer_free(bufbuf);
[2062]1611   return -1;
1612  }
1613
1614//  memset(outdata, 0, outlen);
[2061]1615 }
1616
[2091]1617 if ( bufbuf != NULL ) {
1618  memcpy(outdata, bufdata, outlen);
1619  roar_buffer_free(bufbuf);
1620 }
1621
[4272]1622 streams_ltm_calc(id, stream_info, outdata, outlen);
1623
[2153]1624 if ( streams_get_flag(id, ROAR_FLAG_ANTIECHO) ) {
[2747]1625  ROAR_DBG("streams_fill_mixbuffer2(*): Calcing antiecho...");
[2153]1626  // we can ignore errors here:
[2389]1627  if ( stream_outputbuffer_request(id, &bufbuf, buflen) == 0 ) {
[2153]1628   if ( roar_buffer_get_data(bufbuf, &bufdata) != -1 )
1629    memcpy(bufdata, outdata, outlen);
1630  }
1631 }
1632
[3932]1633 ROAR_DBG("streams_fill_mixbuffer2(*): inlen_got=%llu, stream_info={.bits=%i, .rate=%i,...}", (long long unsigned int)inlen_got, stream_info->bits, stream_info->rate);
1634 s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, (inlen_got*8)/stream_info->bits);
[2153]1635
[2747]1636 ROAR_DBG("streams_fill_mixbuffer2(*) = 0");
[2062]1637 return 0;
[2061]1638}
1639
[491]1640
[0]1641int streams_get_mixbuffers (void *** bufferlist, struct roar_audio_info * info, unsigned int pos) {
[84]1642 static void * bufs[ROAR_STREAMS_MAX+1];
[0]1643 int i;
1644 int have = 0;
[2458]1645 int dir;
[0]1646
1647 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
1648  if ( g_streams[i] != NULL ) {
[2458]1649   dir = streams_get_dir(i);
1650
1651   switch (dir) {
1652    case ROAR_DIR_PLAY:
1653    case ROAR_DIR_BIDIR:
1654     break;
[2459]1655    case ROAR_DIR_BRIDGE:
1656      if ( g_streams[i]->buffer == NULL )
1657       continue;
1658     break;
[2458]1659    default:
1660      continue;
1661   }
[0]1662
[2730]1663   if ( streams_get_flag(i, ROAR_FLAG_PAUSE) )
1664    continue;
1665
[0]1666   if ( streams_get_outputbuffer(i, &bufs[have], ROAR_OUTPUT_CALC_OUTBUFSIZE(info)) == -1 ) {
1667    ROAR_ERR("streams_get_mixbuffer(*): Can not alloc output buffer for stream %i, BAD!", i);
1668    ROAR_ERR("streams_get_mixbuffer(*): Ignoring stream for this round.");
1669    continue;
1670   }
[2061]1671   if ( streams_fill_mixbuffer2(i, info) == -1 ) {
[0]1672    ROAR_ERR("streams_get_mixbuffer(*): Can not fill output buffer for stream %i, this should not happen", i);
1673    continue;
1674   }
1675
[139]1676//   printf("D: bufs[have=%i] = %p\n", have, bufs[have]);
1677
[0]1678   ROAR_DBG("streams_get_mixbuffers(*):  bufs[have] = %p", bufs[have]);
1679   ROAR_DBG("streams_get_mixbuffers(*): *bufs[have] = 0x%08x...", *(uint32_t*)bufs[have]);
1680
[1887]1681   if ( !streams_get_flag(i, ROAR_FLAG_MUTE) )
1682    have++; // we have a new stream!
[0]1683  }
1684 }
1685
1686 bufs[have] = NULL;
[139]1687 //printf("D: bufs[have=%i] = %p\n", have, bufs[have]);
[0]1688
1689 ROAR_DBG("streams_get_mixbuffers(*): have = %i", have);
1690
1691 *bufferlist = bufs;
[547]1692 return have;
[0]1693}
1694
1695
1696int stream_add_buffer  (int id, struct roar_buffer * buf) {
1697 ROAR_DBG("stream_add_buffer(id=%i, buf=%p) = ?", id, buf);
1698
[2734]1699 _CHECK_SID(id);
[0]1700
1701 if ( g_streams[id]->buffer == NULL ) {
1702  g_streams[id]->buffer = buf;
1703  ROAR_DBG("stream_add_buffer(id=%i, buf=%p) = 0", id, buf);
1704  return 0;
1705 }
1706
1707 ROAR_DBG("stream_add_buffer(id=%i, buf=%p) = ?", id, buf);
1708 return roar_buffer_add(g_streams[id]->buffer, buf);
1709}
1710
[2061]1711int stream_shift_out_buffer   (int id, void * data, size_t * len) {
[2734]1712 _CHECK_SID(id);
[2061]1713
1714 if ( g_streams[id]->buffer == NULL )
1715  return -1;
1716
1717 return roar_buffer_shift_out(&(g_streams[id]->buffer), data, len);
1718}
1719
[0]1720int stream_shift_buffer   (int id, struct roar_buffer ** buf) {
1721 struct roar_buffer * next;
1722
[2734]1723 _CHECK_SID(id);
[0]1724
1725 if ( g_streams[id]->buffer == NULL ) {
1726  *buf = NULL;
1727  return 0;
1728 }
1729
1730 roar_buffer_get_next(g_streams[id]->buffer, &next);
1731
1732 *buf                  = g_streams[id]->buffer;
1733 g_streams[id]->buffer = next;
1734
1735 return 0;
1736}
1737int stream_unshift_buffer (int id, struct roar_buffer *  buf) {
[2734]1738 _CHECK_SID(id);
[0]1739
1740 if ( g_streams[id]->buffer == NULL ) {
1741  g_streams[id]->buffer = buf;
1742  return 0;
1743 }
1744
[4516]1745 roar_buffer_clear_next(buf);
[271]1746
[0]1747 roar_buffer_add(buf, g_streams[id]->buffer);
1748
1749 g_streams[id]->buffer = buf;
1750
1751 return 0;
1752}
1753
[2151]1754int stream_outputbuffer_request(int id, struct roar_buffer ** buf, size_t len) {
1755 register struct roar_stream_server *  ss;
1756 size_t buflen;
[2159]1757 void * bufdata;
[2151]1758 int ret;
1759
[2734]1760 _CHECK_SID(id);
1761
[2151]1762 if ( (ss = g_streams[id]) == NULL )
1763  return -1;
1764
1765 if ( buf != NULL ) /* just be be sure */
1766  *buf = NULL;
1767
1768 if ( ss->outputbuffer != NULL ) {
1769  if ( roar_buffer_get_len(ss->outputbuffer, &buflen) == 0 ) {
1770   if ( buflen == len ) {
1771    if ( buf != NULL )
1772     *buf = ss->outputbuffer;
1773    return 0;
1774   } else if ( buflen > len ) {
1775    if ( roar_buffer_set_len(ss->outputbuffer, len) == 0 ) {
1776     if ( buf != NULL )
1777      *buf = ss->outputbuffer;
1778     return 0;
1779    }
1780   }
1781  }
1782
1783  // if the buffer is not suitable:
1784
1785  ret = roar_buffer_free(ss->outputbuffer);
1786  ss->outputbuffer = NULL;
1787  if ( ret == -1 )
1788   return ret;
1789 }
1790
1791 if ( roar_buffer_new(&(ss->outputbuffer), len) == -1 )
1792  return -1;
1793
[2159]1794 if ( roar_buffer_get_data(ss->outputbuffer, &bufdata) == -1 ) {
1795  roar_buffer_free(ss->outputbuffer);
1796  ss->outputbuffer = NULL;
1797  return -1;
1798 }
1799
1800 memset(bufdata, 0, len);
1801
[2151]1802 if ( buf != NULL )
1803  *buf = ss->outputbuffer;
1804
1805 return 0;
1806}
1807
1808int stream_outputbuffer_destroy(int id) {
1809 int ret;
1810 register struct roar_stream_server *  ss;
1811
[2734]1812 _CHECK_SID(id);
1813
[2151]1814 if ( (ss = g_streams[id]) == NULL )
1815  return -1;
1816
1817 if ( ss->outputbuffer != NULL ) {
1818  ret = roar_buffer_free(ss->outputbuffer);
1819  ss->outputbuffer = NULL;
1820  return ret;
1821 }
1822
1823 return 0;
1824}
1825
[2816]1826int stream_prethru_add(int id, struct roar_buffer * buf) {
1827 register struct roar_stream_server *  ss;
1828
1829 _CHECK_SID(id);
1830
1831 if ( (ss = g_streams[id]) == NULL )
1832  return -1;
1833
1834 if ( ss->prethru == NULL ) {
1835  ss->prethru = buf;
1836  return 0;
1837 }
1838
1839 if ( roar_buffer_add(ss->prethru, buf) == -1 ) {
1840  return -1;
1841 }
1842
1843 return 0;
1844}
1845
1846int stream_prethru_add_data(int id, void ** buf, size_t len) {
1847 struct roar_buffer * buffer;
1848
1849 _CHECK_SID(id);
1850
1851 if ( roar_buffer_new(&buffer, len) == -1 )
1852  return -1;
1853
1854 if ( roar_buffer_get_data(buffer, buf) == -1 ) {
1855  roar_buffer_free(buffer);
1856  return -1;
1857 }
1858
1859 if ( stream_prethru_add(id, buffer) == -1 ) {
1860  roar_buffer_free(buffer);
1861  return -1;
1862 }
1863
1864 return 0;
1865}
1866
1867int stream_prethru_destroy(int id) {
1868 int ret;
1869 register struct roar_stream_server *  ss;
1870
1871 _CHECK_SID(id);
1872
1873 if ( (ss = g_streams[id]) == NULL )
1874  return -1;
1875
1876 if ( ss->prethru != NULL ) {
1877  ret = roar_buffer_free(ss->prethru);
1878  ss->prethru = NULL;
1879  return ret;
1880 }
1881
1882 return 0;
1883}
1884
1885int stream_prethru_send(int dst, int src) {
1886 struct roar_stream_server *  dst_ss, * src_ss;
1887 struct roar_buffer * bufbuf;
1888 void * bufdata;
1889 size_t buflen;
1890
1891 ROAR_DBG("stream_prethru_send(dst=%i, src=%i) = ?", dst, src);
1892
1893 _CHECK_SID(dst);
1894 _CHECK_SID(src);
1895
1896 if ( (dst_ss = g_streams[dst]) == NULL )
1897  return -1;
1898
1899 if ( (src_ss = g_streams[src]) == NULL )
1900  return -1;
1901
1902 bufbuf = src_ss->prethru;
1903
1904 ROAR_DBG("stream_prethru_send(dst=%i, src=%i): prethru buffer at %p", dst, src, bufbuf);
1905
1906 while (bufbuf != NULL) {
1907  ROAR_DBG("stream_prethru_send(dst=%i, src=%i): looping with buffer at %p", dst, src, bufbuf);
1908
1909  if ( roar_buffer_get_data(bufbuf, &bufdata) == -1 )
1910   return -1;
1911
1912  if ( roar_buffer_get_len(bufbuf, &buflen) == -1 )
1913   return -1;
1914
1915  if ( stream_vio_s_write(dst_ss, bufdata, buflen) != buflen )
1916   return -1;
1917
1918  if ( roar_buffer_get_next(bufbuf, &bufbuf) == -1 )
1919   return -1;
1920 }
1921
1922 ROAR_DBG("stream_prethru_send(dst=%i, src=%i) = 0", dst, src);
1923 return 0;
1924}
1925
[0]1926int streams_check  (int id) {
1927 int fh;
[508]1928 ssize_t req, realreq, done;
[0]1929 struct roar_stream        *   s;
1930 struct roar_stream_server *  ss;
1931 struct roar_buffer        *   b;
[4542]1932 void                      * buf;
[2248]1933// char                        tmp;
[0]1934
[2734]1935 _CHECK_SID(id);
[0]1936
1937 ROAR_DBG("streams_check(id=%i) = ?", id);
1938
[609]1939 s = ROAR_STREAM(ss = g_streams[id]);
[0]1940
1941 if ( (fh = s->fh) == -1 )
1942  return 0;
1943
[1821]1944 if ( streams_get_flag(id, ROAR_FLAG_PAUSE) )
[0]1945  return 0;
1946
[1821]1947 switch (s->dir) {
1948  case ROAR_DIR_LIGHT_IN:
[2493]1949#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1821]1950    return light_check_stream(id);
[2493]1951#else
1952    streams_delete(id);
1953    return -1;
1954#endif
[1821]1955   break;
[1845]1956  case ROAR_DIR_MIDI_IN:
[2493]1957#ifndef ROAR_WITHOUT_DCOMP_MIDI
[1845]1958    return midi_check_stream(id);
[2493]1959#else
1960    streams_delete(id);
1961    return -1;
1962#endif
[1845]1963   break;
[2237]1964  case ROAR_DIR_RAW_IN:
[2493]1965#ifndef ROAR_WITHOUT_DCOMP_RAW
[2237]1966    return raw_check_stream(id);
[2493]1967#else
1968    streams_delete(id);
1969    return -1;
1970#endif
[2237]1971   break;
[2721]1972  case ROAR_DIR_RDTCS_IN:
1973#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1974    return rdtcs_check_stream(id);
1975#else
1976    streams_delete(id);
1977    return -1;
1978#endif
1979   break;
[1821]1980  case ROAR_DIR_PLAY:
1981  case ROAR_DIR_BIDIR:
1982   break;
[4815]1983  case ROAR_DIR_OUTPUT:
1984    if ( !streams_get_flag(id, ROAR_FLAG_RECSOURCE) )
1985     return 0;
1986   break;
[1821]1987  default:
[2248]1988/*
1989    ROAR_WARN("streams_check(id=%i): Read event on non input stream of type/dir %s", id, roar_dir2str(s->dir));
1990    errno = 0;
1991    req = stream_vio_s_read(ss, &tmp, 1);
1992    ROAR_DBG("streams_check(id=%i): stream_vio_s_read(ss, &tmp, 1) = %li // errno=%s(%i)", id, req, strerror(errno), errno);
1993    if ( req == 1 ) {
1994     ROAR_ERR("streams_check(id=%i): Client violates protocol, got one byte of data on output stream, kicking stream");
1995     streams_delete(id);
1996     return -1;
1997    }
1998*/
[1821]1999    return 0;
2000   break;
2001 }
[1585]2002
[0]2003 ROAR_DBG("streams_check(id=%i): fh = %i", id, fh);
2004
[2387]2005/*
2006 ROAR_DBG("streams_check(id=%i): ROAR_OUTPUT_BUFFER_SAMPLES=%i, s->info.channels=%i, s->info.bits=%i, s->info.rat=%i, g_sa->rate=%i", id, ROAR_OUTPUT_BUFFER_SAMPLES, s->info.channels, s->info.bits, s->info.rate, g_sa->rate);
2007*/
2008
2009 req  = ROAR_OUTPUT_CALC_OUTBUFSIZE(&(s->info)); // optimal size
2010// req  = ROAR_OUTPUT_BUFFER_SAMPLES * s->info.channels * (s->info.bits / 8) * ((float)s->info.rate/g_sa->rate);
[0]2011 req += ss->need_extra; // bytes left we sould get....
2012
[2387]2013 ROAR_DBG("streams_check(id=%i): asking for %i bytes", id, req);
2014
[0]2015 if ( roar_buffer_new(&b, req) == -1 ) {
2016  ROAR_ERR("streams_check(*): Can not alloc buffer space!");
2017  ROAR_DBG("streams_check(*) = -1");
2018  return -1;
2019 }
2020
[4542]2021 roar_buffer_get_data(b, &buf);
[0]2022
2023 ROAR_DBG("streams_check(id=%i): buffer is up and ready ;)", id);
[2387]2024 ROAR_DBG("streams_check(id=%i): asking for %i bytes", id, req);
[0]2025
[270]2026 if ( ss->codecfilter == -1 ) {
[508]2027  realreq = req;
2028/*
[270]2029  req = read(fh, buf, req);
[508]2030  if ( req < realreq ) { // we can do this as the stream is in nonblocking mode!
2031   if ( (realreq = read(fh, buf+req, realreq-req)) > 0 )
2032    req += realreq;
2033  }
2034*/
2035  done = 0;
2036  while (req > 0 && done != realreq) {
[881]2037   if ( (req = stream_vio_s_read(ss, buf+done, realreq-done)) > 0 )
[508]2038    done += req;
2039  }
2040  req = done;
[1837]2041
[4542]2042  roar_buffer_get_data(b, &buf);
[270]2043 } else {
2044  req = codecfilter_read(ss->codecfilter_inst, ss->codecfilter, buf, req);
2045 }
2046
2047 if ( req > 0 ) {
[0]2048  ROAR_DBG("streams_check(id=%i): got %i bytes", id, req);
2049
2050  roar_buffer_set_len(b, req);
2051
2052  if ( stream_add_buffer(id, b) != -1 )
2053   return 0;
2054
2055  ROAR_ERR("streams_check(id=%i): something is wrong, could not add buffer to stream!", id);
2056  roar_buffer_free(b);
2057 } else {
[272]2058  ROAR_DBG("streams_check(id=%i): read() = %i // errno: %s", id, req, strerror(errno));
2059#ifdef ROAR_HAVE_LIBVORBISFILE
2060  if ( errno != EAGAIN && errno != ESPIPE ) { // libvorbis file trys to seek a bit ofen :)
2061#else
2062  if ( errno != EAGAIN ) {
2063#endif
2064   ROAR_DBG("streams_check(id=%i): EOF!", id);
2065   streams_delete(id);
2066   ROAR_DBG("streams_check(id=%i) = 0", id);
2067  }
[334]2068  roar_buffer_free(b);
[0]2069  return 0;
2070 }
2071
2072
2073 ROAR_DBG("streams_check(id=%i) = -1", id);
2074 return -1;
2075}
2076
2077
[2152]2078#define _return(x) return (x)
[0]2079int streams_send_mon   (int id) {
[936]2080// int fh;
[0]2081 struct roar_stream        *   s;
2082 struct roar_stream_server *  ss;
[2146]2083 struct roar_buffer        *  bufbuf = NULL;
[2155]2084 struct roar_remove_state     removalstate;
[4815]2085 void  * ip              = g_output_buffer;
[1157]2086 void  * obuf;
2087 int     olen;
[2150]2088 int     is_the_same     = 1;
2089 int     is_vol_eq       = 1;
[2155]2090 int     antiecho        = 0;
[1157]2091 ssize_t ret;
[0]2092
[2734]2093 _CHECK_SID(id);
[0]2094
2095 ROAR_DBG("streams_send_mon(id=%i) = ?", id);
2096
[585]2097 s = ROAR_STREAM((ss = g_streams[id]));
[0]2098
[934]2099/*
[0]2100 if ( (fh = s->fh) == -1 )
2101  return 0;
[934]2102*/
[0]2103
[1914]2104 if ( !ss->ready )
2105  return 0;
[930]2106
[3042]2107 if ( g_config->jumbo_mtu )
2108  roar_vio_sync(ss->viop);
2109
[1585]2110 if ( streams_get_flag(id, ROAR_FLAG_PAUSE) )
2111  return 0;
2112
[1821]2113 switch (s->dir) {
2114  case ROAR_DIR_LIGHT_OUT:
[2493]2115#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1821]2116    return light_send_stream(id);
[2493]2117#else
2118    streams_delete(id);
2119    return -1;
2120#endif
[1821]2121   break;
[1845]2122  case ROAR_DIR_MIDI_OUT:
[2493]2123#ifndef ROAR_WITHOUT_DCOMP_MIDI
[1845]2124    return midi_send_stream(id);
[2493]2125#else
2126    streams_delete(id);
2127    return -1;
2128#endif
[1845]2129   break;
[2721]2130  case ROAR_DIR_RDTCS_OUT:
2131#ifndef ROAR_WITHOUT_DCOMP_RDTCS
2132    return rdtcs_send_stream(id);
2133#else
2134    streams_delete(id);
2135    return -1;
2136#endif
2137   break;
[2694]2138
2139  case ROAR_DIR_COMPLEX_OUT:
2140    // send a tick:
2141    if ( ss->codecfilter != -1 ) {
2142     if ( codecfilter_write(ss->codecfilter_inst, ss->codecfilter, NULL, 0) == 0 )
[4237]2143      if ( ss->state != ROAR_STREAMSTATE_OLD ) {
[4336]2144       //ROAR_INFO("streams_send_mon(id=%i): stream state: %s->old", ROAR_DBG_INFO_VERBOSE, id, roar_streamstate2str(ss->state));
2145       _streams_change_state(ss, ROAR_STREAMSTATE_OLD, "streams_send_mon");
[4237]2146      }
[2694]2147    }
2148    return 0;
2149   break;
2150
[1821]2151  case ROAR_DIR_OUTPUT:
2152    if ( g_standby )
2153     return 0;
2154  case ROAR_DIR_MONITOR:
2155  case ROAR_DIR_BIDIR:
2156   break;
2157
[4815]2158  case ROAR_DIR_RECORD:
2159    ip = g_input_buffer;
2160   break;
[1821]2161  default:
2162    return 0;
2163   break;
2164 }
2165
2166
[1042]2167 ROAR_DBG("streams_send_mon(id=%i): fh = %i", id, s->fh);
[0]2168
[625]2169 if ( s->info.channels != g_sa->channels || s->info.bits  != g_sa->bits ||
[2147]2170      s->info.rate     != g_sa->rate     || s->info.codec != g_sa->codec  )
2171  is_the_same = 0;
2172
[2150]2173 if ( !streams_get_flag(id, ROAR_FLAG_HWMIXER) ) {
2174  is_vol_eq = need_vol_change(g_sa->channels, &(ss->mixer)) ? 0 : 1;
2175 }
2176
[2155]2177 if ( streams_get_flag(id, ROAR_FLAG_ANTIECHO) )
2178  antiecho = 1;
2179
2180 if ( !is_the_same || !is_vol_eq || antiecho ) {
[625]2181  olen = ROAR_OUTPUT_CALC_OUTBUFSIZE(&(s->info)); // we hope g_output_buffer_len
2182                                                  // is ROAR_OUTPUT_CALC_OUTBUFSIZE(g_sa) here
[2390]2183  if ( stream_outputbuffer_request(id, &bufbuf, ROAR_OUTPUT_CALC_OUTBUFSIZE_MAX(&(s->info), g_sa)) == -1 )
[625]2184   return -1;
2185
[2146]2186  if ( roar_buffer_get_data(bufbuf, &obuf) == -1 ) {
2187   _return(-1);
2188  }
2189
[625]2190  ROAR_DBG("streams_send_mon(id=%i): obuf=%p, olen=%i", id, obuf, olen);
[2147]2191 } else {
[4815]2192  obuf = ip;
[2147]2193  olen = g_output_buffer_len;
2194 }
[625]2195
[2155]2196 if ( antiecho ) {
[2397]2197  ROAR_DBG("streams_send_mon(id=%i): antiecho=%i", id, antiecho);
[2158]2198  if ( roar_remove_init(&removalstate) == -1 ) {
[2155]2199   _return(-1);
[2158]2200  }
2201
[2397]2202  ROAR_DBG("streams_send_mon(id=%i): antiecho=%i", id, antiecho);
[2158]2203  if ( roar_remove_so(obuf, ip, ROAR_OUTPUT_BUFFER_SAMPLES*g_sa->channels, g_sa->bits, &removalstate) == -1 ) {
[2397]2204   ROAR_DBG("streams_send_mon(id=%i): anti echo failed", id);
[2158]2205   _return(-1);
2206  }
[2397]2207  ROAR_DBG("streams_send_mon(id=%i): antiecho=%i", id, antiecho);
[2155]2208 }
2209
[2150]2210 if ( !is_vol_eq ) {
[2938]2211  if ( roar_amp_pcm(obuf, g_sa->bits, ip, ROAR_OUTPUT_BUFFER_SAMPLES*g_sa->channels, g_sa->channels, &(ss->mixer)) == -1 ) {
[2150]2212   _return(-1);
2213  }
2214
2215  ip = obuf;
2216 }
2217
[4288]2218 streams_ltm_calc(id, &(s->info), ip, (ROAR_OUTPUT_BUFFER_SAMPLES*g_sa->channels*g_sa->bits)/8);
2219
[2147]2220 if ( !is_the_same ) {
[2148]2221  if ( roar_conv(obuf, ip, ROAR_OUTPUT_BUFFER_SAMPLES*g_sa->channels, g_sa, &(s->info)) == -1 ) {
[2146]2222   _return(-1);
[625]2223  }
2224 }
2225
[585]2226 errno = 0;
2227
2228 if ( ss->codecfilter == -1 ) {
[1042]2229  ROAR_DBG("streams_send_mon(id=%i): not a CF stream", id);
[2146]2230  if ( s->fh == -1 && roar_vio_get_fh(&(ss->vio)) == -1 ) {
[2705]2231   ROAR_DBG("streams_send_mon(id=%i) = 0", id);
[2146]2232   _return(0);
2233  }
[1014]2234
[2705]2235  ROAR_DBG("streams_send_mon(id=%i) = ?", id);
2236
[1157]2237  if ( (ret = stream_vio_s_write(ss, obuf, olen)) == olen ) {
[981]2238   s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, ROAR_OUTPUT_CALC_OUTBUFSAMP(&(s->info), olen)*s->info.channels);
[4237]2239   if ( ss->state != ROAR_STREAMSTATE_OLD ) {
[4336]2240    //ROAR_INFO("streams_send_mon(id=%i): stream state: %s->old", ROAR_DBG_INFO_VERBOSE, id, roar_streamstate2str(ss->state));
2241    _streams_change_state(ss, ROAR_STREAMSTATE_OLD, "streams_send_mon");
[4237]2242   }
[2705]2243   ROAR_DBG("streams_send_mon(id=%i) = 0", id);
[2146]2244   _return(0);
[625]2245  }
[1157]2246
[2705]2247  ROAR_DBG("streams_send_mon(id=%i) = ?", id);
2248
[1157]2249  if ( ret > 0 && errno == 0 ) {
[1231]2250   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);
[4417]2251   roar_notify_core_emit_simple(ROAR_OE_STREAM_XRUN, -1, id, ROAR_OT_STREAM, ROAR_XRUN_OVER_POST, -1, NULL, 0);
[1157]2252   s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, ROAR_OUTPUT_CALC_OUTBUFSAMP(&(s->info), ret)*s->info.channels);
[4237]2253   if ( ss->state != ROAR_STREAMSTATE_OLD ) {
[4336]2254    //ROAR_INFO("streams_send_mon(id=%i): stream state: %s->old", ROAR_DBG_INFO_VERBOSE, id, roar_streamstate2str(ss->state));
2255    _streams_change_state(ss, ROAR_STREAMSTATE_OLD, "streams_send_mon");
[4237]2256   }
[2146]2257   _return(0);
[1157]2258  }
[585]2259 } else {
[1012]2260  errno = 0;
[625]2261  if ( codecfilter_write(ss->codecfilter_inst, ss->codecfilter, obuf, olen)
2262            == olen ) {
[981]2263   s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, ROAR_OUTPUT_CALC_OUTBUFSAMP(&(s->info), olen)*s->info.channels);
[4237]2264   if ( ss->state != ROAR_STREAMSTATE_OLD ) {
[4336]2265    //ROAR_INFO("streams_send_mon(id=%i): stream state: %s->old", ROAR_DBG_INFO_VERBOSE, id, roar_streamstate2str(ss->state));
2266    _streams_change_state(ss, ROAR_STREAMSTATE_OLD, "streams_send_mon");
[4237]2267   }
[2146]2268   _return(0);
[585]2269  } else { // we cann't retry on codec filetered streams
[1012]2270   if ( errno != EAGAIN ) {
2271    streams_delete(id);
[2146]2272    _return(-1);
[1012]2273   }
[585]2274  }
2275 }
[0]2276
[129]2277 if ( errno == EAGAIN ) {
2278  // ok, the client blocks for a moment, we try to sleep a bit an retry in the hope not to
2279  // make any gapes in any output because of this
2280
[1750]2281#ifdef ROAR_HAVE_USLEEP
[129]2282  usleep(100); // 0.1ms
[1750]2283#endif
[129]2284
[881]2285  if ( stream_vio_s_write(ss, obuf, olen) == olen ) {
[981]2286   s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, ROAR_OUTPUT_CALC_OUTBUFSAMP(&(s->info), olen)*s->info.channels);
[4237]2287   if ( ss->state != ROAR_STREAMSTATE_OLD ) {
[4336]2288    //ROAR_INFO("streams_send_mon(id=%i): stream state: %s->old", ROAR_DBG_INFO_VERBOSE, id, roar_streamstate2str(ss->state));
2289    _streams_change_state(ss, ROAR_STREAMSTATE_OLD, "streams_send_mon");
[4237]2290   }
[2146]2291   _return(0);
[1015]2292  } else if ( errno == EAGAIN ) {
2293   ROAR_WARN("streams_send_mon(id=%i): Can not send data to client: %s", id, strerror(errno));
[2146]2294   _return(0);
[625]2295  }
[129]2296 }
2297
[0]2298 // ug... error... delete stream!
2299
2300 streams_delete(id);
2301
[2146]2302 _return(-1);
[0]2303}
[2146]2304#undef _return
[0]2305
2306int streams_send_filter(int id) {
2307 int fh;
[127]2308 int have = 0;
2309 int len;
[0]2310 struct roar_stream        *   s;
2311 struct roar_stream_server *  ss;
2312
[2734]2313 _CHECK_SID(id);
[0]2314
2315 ROAR_DBG("streams_send_filter(id=%i) = ?", id);
2316
[609]2317 s = ROAR_STREAM(ss = g_streams[id]);
[0]2318
2319 if ( (fh = s->fh) == -1 )
2320  return 0;
2321
2322 if ( s->dir != ROAR_DIR_FILTER )
2323  return 0;
2324
[1585]2325 if ( streams_get_flag(id, ROAR_FLAG_PAUSE) )
2326  return 0;
2327
2328
[0]2329 ROAR_DBG("streams_send_filter(id=%i): fh = %i", id, fh);
2330
[881]2331 if ( stream_vio_s_write(ss, g_output_buffer, g_output_buffer_len) == g_output_buffer_len ) {
[127]2332  while ( have < g_output_buffer_len ) {
[881]2333   if ( (len = stream_vio_s_read(ss, g_output_buffer+have, g_output_buffer_len-have)) < 1 ) {
[127]2334    streams_delete(id);
2335    return -1;
2336   }
2337   have += len;
[0]2338  }
[127]2339  return 0;
[0]2340 }
2341
2342 // ug... error... delete stream!
2343
2344 streams_delete(id);
2345
2346 return -1;
2347}
2348
[596]2349
2350// VIO:
2351
2352ssize_t stream_vio_read (int stream, void *buf, size_t count) {
[2734]2353 _CHECK_SID(stream);
[596]2354
[2734]2355 return stream_vio_s_read(g_streams[stream], buf, count);
[596]2356}
2357
2358ssize_t stream_vio_write(int stream, void *buf, size_t count) {
[2734]2359 _CHECK_SID(stream);
[596]2360
[2734]2361 return stream_vio_s_write(g_streams[stream], buf, count);
[596]2362}
2363
[4815]2364int     stream_vio_ctl  (int stream, int cmd,   void * data) {
2365 _CHECK_SID(stream);
2366
2367 return stream_vio_s_ctl(g_streams[stream], cmd, data);
2368}
[596]2369
2370ssize_t stream_vio_s_read (struct roar_stream_server * stream, void *buf, size_t count) {
[2253]2371 void    * orig_buf = buf;
2372  size_t   len      =  0;
2373 ssize_t   r        = -1;
2374 int       i;
[739]2375
[596]2376 errno = 0;
2377
2378 if ( !stream )
2379  return -1;
2380
[1613]2381 //roar_vio_set_fh(&(stream->vio), ROAR_STREAM(stream)->fh);
[881]2382
[596]2383 if ( ! stream->vio.read )
2384  return -1;
2385
[881]2386 while ( (r = roar_vio_read(&(stream->vio), buf, count)) > 0 ) {
[739]2387  len   += r;
2388  buf   += r;
2389  count -= r;
2390  if ( count == 0 )
2391   break;
2392 }
2393
[740]2394 if ( len == 0 && r == -1 )
2395  return -1;
2396
[2816]2397 if ( streams_thru_num ) {
2398  for (i = 0; i < ROAR_STREAMS_MAX; i++) {
2399   if ( g_streams[i] != NULL && ROAR_STREAM(g_streams[i])->pos_rel_id == ROAR_STREAM(stream)->id ) {
2400    if ( ROAR_STREAM(g_streams[i])->dir == ROAR_DIR_THRU ) {
2401     if ( g_streams[i]->ready ) {
[2258]2402      if ( stream_vio_write(i, orig_buf, len) != len )
2403       streams_delete(i);
[2252]2404
[4237]2405      if ( g_streams[i] != NULL ) {
2406       if ( g_streams[i]->state != ROAR_STREAMSTATE_OLD ) {
[4336]2407        //ROAR_INFO("stream_vio_s_read(*): (stream: %i) stream state: %s->old", ROAR_DBG_INFO_VERBOSE, i, roar_streamstate2str(g_streams[i]->state));
2408        _streams_change_state(g_streams[i], ROAR_STREAMSTATE_OLD, "stream_vio_s_read");
[4237]2409       }
2410      }
[2816]2411     }
2412    }
2413   }
2414  }
2415 }
2416
[739]2417 return len;
[596]2418}
2419
2420ssize_t stream_vio_s_write(struct roar_stream_server * stream, void *buf, size_t count) {
[2259]2421 int i;
2422
[596]2423 errno = 0;
2424
2425 if ( !stream )
2426  return -1;
2427
[1613]2428/*
[934]2429 if ( roar_vio_get_fh(&(stream->vio)) == -1 && ROAR_STREAM(stream)->fh != -1 )
2430  roar_vio_set_fh(&(stream->vio), ROAR_STREAM(stream)->fh);
[1613]2431*/
[934]2432
2433// ROAR_WARN("stream_vio_s_write(*): writing...");
[596]2434
[2816]2435 if ( streams_thru_num ) {
2436  for (i = 0; i < ROAR_STREAMS_MAX; i++) {
2437   if ( g_streams[i] != NULL && ROAR_STREAM(g_streams[i])->pos_rel_id == ROAR_STREAM(stream)->id ) {
2438    if ( ROAR_STREAM(g_streams[i])->dir == ROAR_DIR_THRU ) {
2439     if ( g_streams[i]->ready ) {
2440      if ( g_streams[i]->state == ROAR_STREAMSTATE_NEW ) {
2441       if ( streams_get_flag(i, ROAR_FLAG_PRETHRU) == 1 ) {
[3042]2442        if ( stream_prethru_send(i, ROAR_STREAM(stream)->id) == -1 ) {
[2816]2443         streams_delete(i);
2444        }
2445       }
2446      }
2447
2448      if ( stream_vio_write(i, buf, count) != count ) {
[2259]2449       streams_delete(i);
[2816]2450      }
2451
[4237]2452      if ( g_streams[i] != NULL ) {
2453       if ( g_streams[i]->state != ROAR_STREAMSTATE_OLD ) {
[4336]2454        //ROAR_INFO("stream_vio_s_write(*): (stream: %i) stream state: %s->old", ROAR_DBG_INFO_VERBOSE, i, roar_streamstate2str(g_streams[i]->state));
2455        _streams_change_state(g_streams[i], ROAR_STREAMSTATE_OLD, "stream_vio_s_write");
[4237]2456       }
2457      }
[2816]2458     }
2459    }
2460   }
2461  }
2462 }
[2259]2463
[3042]2464 if ( g_config->jumbo_mtu ) {
2465  if ( stream->viop != &(stream->jumbo) ) {
2466   if ( roar_vio_open_jumbo(&(stream->jumbo), &(stream->vio), g_config->jumbo_mtu) != -1 ) {
2467    // if that works we continue using the jumbo vio,
2468    // in case it didn't we dont, just use normal VIO.
2469    stream->viop = &(stream->jumbo);
2470   }
2471  }
2472 }
2473
2474 return roar_vio_write(stream->viop, buf, count);
[596]2475}
2476
[4815]2477int     stream_vio_s_ctl  (struct roar_stream_server * stream, int cmd,   void * data) {
2478 if ( stream == NULL )
2479  return -1;
2480
2481 return roar_vio_ctl(stream->viop, cmd, data);
2482}
2483
[0]2484//ll
Note: See TracBrowser for help on using the repository browser.