source: roaraudio/roard/streams.c @ 4815:df2ef6edb97f

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

added support to roard for record streams.

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
[643]762int streams_set_primary (int id, int prim) {
[2734]763 _CHECK_SID(id);
[643]764
765 g_streams[id]->primary = prim;
766
767 return 0;
768}
769
770int streams_mark_primary (int id) {
771 return streams_set_primary(id, 1);
772}
[1029]773
[1116]774int streams_set_sync     (int id, int sync) {
[1117]775 int fh = streams_get_fh(id);
[1116]776
[2734]777 _CHECK_SID(id);
778
[1117]779 if ( fh != -1 ) {
780  if ( roar_socket_nonblock(fh, sync ? ROAR_SOCKET_BLOCK : ROAR_SOCKET_NONBLOCK) == -1 )
781   return -1;
[1116]782
[1498]783#ifdef ROAR_FDATASYNC
[1171]784  ROAR_FDATASYNC(fh);
[1498]785#endif
[1125]786
787  return 0;
[1117]788 } else {
789  return roar_vio_nonblock(&(g_streams[id]->vio), sync);
790 }
[1116]791}
792
[1928]793int streams_set_mmap (int id, int reset) {
794 int use = !reset;
795
[2734]796 _CHECK_SID(id);
[1928]797
798 return roar_vio_ctl(&(g_streams[id]->vio), ROAR_VIO_CTL_SET_UMMAP, &use);
799}
800
[4537]801int streams_set_single_sink(int id, int reset) {
[4543]802 struct roar_stream_server * self_ss, * ss;
803 struct roar_stream                   *  s;
804 int mixer;
805 size_t count = 0;
806 int i;
807 int ssdir;
808
809 /* FIXME: This code only uses one refc for the mixer shared with the inputs.
810  *        If the flag is unset on the mixer but got set by the sources the counter
811  *        may/will become corrupted.
812  */
813
[4537]814 _CHECK_SID(id);
815
[4543]816 self_ss = g_streams[id];
817
818 mixer = self_ss->mixer_stream;
819
[4547]820 ROAR_DBG("streams_set_single_sink(id=%i, reset=%i): mixer=%i", id, reset, mixer);
[4545]821
[4546]822 if ( !reset && id != mixer )
823  if ( self_ss->flags & ROAR_FLAG_SINGLESINK )
824   return 0;
825
[4543]826 if ( id == mixer ) {
827  if ( reset ) {
[4545]828   if ( self_ss->single_sink_self_c ) {
[4547]829    ROAR_DBG("streams_set_single_sink(id=%i, reset=%i): mixer=%i", id, reset, mixer);
[4545]830    self_ss->single_sink_self_c--;
[4543]831    self_ss->single_sink_c--;
[4545]832    if ( self_ss->single_sink_c == 0 ) {
[4547]833     ROAR_DBG("streams_set_single_sink(id=%i, reset=%i): mixer=%i", id, reset, mixer);
[4545]834     self_ss->flags |= ROAR_FLAG_SINGLESINK;
835     self_ss->flags -= ROAR_FLAG_SINGLESINK;
836    }
[4543]837    return 0;
[4545]838   } else {
839    return -1;
[4543]840   }
841  } else {
842   if ( self_ss->single_sink_c ) {
[4545]843    self_ss->single_sink_self_c++;
[4543]844    self_ss->single_sink_c++;
845    return 0;
846   }
847  }
848 } else if ( reset ) {
[4547]849  ROAR_DBG("streams_set_single_sink(id=%i, reset=%i): mixer=%i", id, reset, mixer);
[4545]850
[4689]851  if ( (ss = g_streams[mixer]) == NULL )
852   return -1;
853
854  if ( ss->single_sink_c == 0 )
[4543]855   return -1;
856  ss->single_sink_c--;
857
858  if ( ss->single_sink_c == 0 ) {
859    self_ss->flags |= ROAR_FLAG_SINGLESINK;
860    self_ss->flags -= ROAR_FLAG_SINGLESINK;
861         ss->flags |= ROAR_FLAG_SINGLESINK;
862         ss->flags -= ROAR_FLAG_SINGLESINK;
863  }
864
865  return 0;
866 }
867
868
869
870 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
871  if ( (s = ROAR_STREAM((ss = g_streams[i]))) != NULL ) {
872   if ( s->dir == ROAR_DIR_THRU )
[4544]873    if ( s->pos_rel_id == id || s->pos_rel_id == mixer || g_streams[s->pos_rel_id]->mixer_stream == mixer )
[4543]874     return -1;
875
876   if ( ss->mixer_stream != mixer )
877    continue;
878
879   ssdir = streams_get_ssdir(i);
880
[4544]881   if ( ssdir & STREAM_DIR_OUT )
[4543]882    count++;
883  }
884 }
885
886 if ( count > 1 )
887  return -1;
888
889 ss = g_streams[mixer];
890
[4545]891 if ( id == mixer )
892  ss->single_sink_self_c++;
893
[4543]894 ss->single_sink_c++;
895
896 self_ss->flags |= ROAR_FLAG_SINGLESINK;
897      ss->flags |= ROAR_FLAG_SINGLESINK;
898
899 return 0;
[4537]900}
901
[4550]902int streams_set_flag     (int id, uint32_t flag) {
[2626]903 int parent;
[4815]904 int tmp;
[2626]905
[2734]906 _CHECK_SID(id);
[1029]907
[2952]908 if ( flag & ROAR_FLAG_IMMUTABLE )
909  flag |= ROAR_FLAG_PRIMARY;
910
[4552]911
912 // check if flags we are going to change are protected:
913 if ( g_streams[id]->flags_protection & flag )
914  return -1;
915
916
[4540]917 if ( flag & ROAR_FLAG_MMAP ) {
918  if ( streams_set_mmap(id, 0) == -1 ) {
[1928]919   flag -= ROAR_FLAG_MMAP;
[4540]920   return -1;
921  }
922 }
[1926]923
[1043]924 if ( flag & ROAR_FLAG_PRIMARY ) {
925  streams_set_primary(id, 1);
926  flag -= ROAR_FLAG_PRIMARY;
927 }
928
[4537]929 if ( flag & ROAR_FLAG_SINGLESINK ) {
[4540]930  if ( streams_set_single_sink(id, 0) == -1 ) {
931   return -1;
932  }
[4545]933  flag -= ROAR_FLAG_SINGLESINK;
[4537]934 }
935
[2626]936 if ( flag & ROAR_FLAG_VIRTUAL ) {
937  if ( (parent = ROAR_STREAM(g_streams[id])->pos_rel_id) == -1 )
938   return -1;
939
940  if ( streams_ctl(parent, ROAR_CODECFILTER_CTL_VIRTUAL_NEW|ROAR_STREAM_CTL_TYPE_INT, &id) == -1 ) {
941//   flag -= ROAR_FLAG_VIRTUAL;
942   return -1;
943  }
[2705]944
945  if ( client_stream_move(streams_get_client(parent), id) == -1 ) {
946   return -1;
947  }
[2626]948 }
949
[1116]950 if ( flag & ROAR_FLAG_SYNC ) {
[1908]951  switch (ROAR_STREAM(g_streams[id])->dir) {
952   // for this stream types the flag is used in the subsystem:
953   case ROAR_DIR_BRIDGE:
954   case ROAR_DIR_MIDI_OUT:
955    break;
956
957   // normal behavor (vio blocking):
958   default:
[2341]959     // the fh is updated as soon as the fh get ready in case the default ask to set sync
[2342]960     if ( !g_streams[id]->ready && !(g_config->streams[ROAR_STREAM(g_streams[id])->dir].flags & ROAR_FLAG_SYNC) ) {
[2341]961      if ( streams_set_sync(id, 1) == -1 )
962       flag -= ROAR_FLAG_SYNC;
963     }
[1908]964  }
[1116]965 }
966
[1585]967 if ( flag & ROAR_FLAG_HWMIXER ) { // currently not supported -> ignored
[1590]968  g_streams[id]->flags |= flag;
969  if ( streams_set_mixer(id) == -1 ) {
970   g_streams[id]->flags -= flag;
971   return -1;
972  }
[1585]973 }
974
[2417]975 if ( flag & ROAR_FLAG_RECSOURCE ) {
976  if ( streams_recsource_id != -1 ) {
977   if ( streams_reset_flag(streams_recsource_id, ROAR_FLAG_RECSOURCE) == -1 )
978    return -1;
979  }
980
[4815]981  if ( g_streams[id]->ready ) {
982   tmp = 1;
983   if ( stream_vio_ctl(id, ROAR_VIO_CTL_SET_RECORD, &tmp) == -1 )
984    return -1;
985  }
986
[2417]987  streams_recsource_id = id;
988 }
989
[1029]990 g_streams[id]->flags |= flag;
991
[1498]992#ifdef ROAR_SUPPORT_META
[1043]993 if ( flag & ROAR_FLAG_META )
994  stream_meta_finalize(id);
[1498]995#endif
[1043]996
[1029]997 return 0;
998}
999
[4550]1000int streams_set_rawflag  (int id, uint32_t flag) {
[2734]1001 _CHECK_SID(id);
[2625]1002
1003 g_streams[id]->flags |= flag;
1004
1005 return 0;
1006}
1007
[4550]1008int streams_reset_flag   (int id, uint32_t flag) {
[4815]1009 int tmp;
1010
[2734]1011 _CHECK_SID(id);
[1029]1012
[4552]1013 // check if flags we are going to change are protected:
1014 if ( g_streams[id]->flags_protection & flag )
1015  return -1;
1016
[2952]1017 if ( g_streams[id]->flags & ROAR_FLAG_IMMUTABLE ) {
1018  flag |= ROAR_FLAG_PRIMARY;
1019  flag -= ROAR_FLAG_PRIMARY;
1020 }
1021
[4815]1022 if ( (flag & ROAR_FLAG_RECSOURCE) && streams_recsource_id == id ) {
1023  if ( g_streams[id]->ready ) {
1024   tmp = 0;
1025   if ( stream_vio_ctl(id, ROAR_VIO_CTL_SET_RECORD, &tmp) == -1 )
1026    return -1;
1027  }
1028
1029  streams_recsource_id = -1;
1030 }
1031
[2417]1032
[4540]1033 if ( flag & ROAR_FLAG_MMAP ) {
1034  if ( streams_set_mmap(id, 1) == -1 ) {
[1928]1035   flag -= ROAR_FLAG_MMAP;
[4540]1036   return -1;
1037  }
1038 }
[1928]1039
[1043]1040 if ( flag & ROAR_FLAG_PRIMARY ) {
1041  streams_set_primary(id, 0);
1042  flag -= ROAR_FLAG_PRIMARY;
1043 }
1044
[4537]1045 if ( flag & ROAR_FLAG_SINGLESINK ) {
[4540]1046  if ( streams_set_single_sink(id, 1) == -1 ) {
1047   return -1;
1048  }
[4545]1049  flag -= ROAR_FLAG_SINGLESINK;
[4537]1050 }
1051
[1116]1052 if ( flag & ROAR_FLAG_SYNC ) {
[2264]1053  // we refuse to reset the flag on FILTER streams
1054  if ( streams_get_dir(id) == ROAR_DIR_FILTER ) {
1055//   flags -= ROAR_FLAG_SYNC;
1056   return -1;
1057  } else {
1058   streams_set_sync(id, 0);
1059  }
[1116]1060 }
1061
[1029]1062 g_streams[id]->flags |= flag;
1063 g_streams[id]->flags -= flag;
1064
1065 return 0;
1066}
1067
[4550]1068int streams_get_flag     (int id, uint32_t flag) {
[2734]1069 _CHECK_SID(id);
[1042]1070
1071 return g_streams[id]->flags & flag ? 1 : 0;
1072}
1073
[4552]1074int streams_protect_flag (int id, uint32_t flag) {
1075 _CHECK_SID(id);
1076
1077 g_streams[id]->flags_protection |= flag;
1078
1079 return 0;
1080}
1081
[1842]1082int streams_set_name     (int id, char * name) {
1083 char * str;
1084
[2734]1085 _CHECK_SID(id);
[1842]1086
1087 if ( (str = strdup(name)) == NULL )
1088  return -1;
1089
1090 if ( g_streams[id]->name != NULL )
1091  free(g_streams[id]->name);
1092
1093 g_streams[id]->name = str;
[1845]1094
1095 return 0;
[1842]1096}
1097
1098char * streams_get_name  (int id) {
[2734]1099 _CHECK_SID_RET(id, NULL);
[1842]1100
1101 return g_streams[id]->name;
1102}
1103
1104
[1223]1105int streams_calc_delay    (int id) {
[1142]1106 struct roar_stream_server * ss;
[1151]1107 struct roar_stream        * s;
[1142]1108 register uint_least32_t d = 0;
1109 uint_least32_t t[1];
[1151]1110 uint64_t       tmp;
[1142]1111
[2734]1112 _CHECK_SID(id);
1113
[1151]1114 if ( (s = ROAR_STREAM(ss = g_streams[id])) == NULL )
[1142]1115  return -1;
1116
[3212]1117 // mixer store there value in ss->delay directly
1118 if ( s->dir == ROAR_DIR_MIXING )
1119  return 0;
1120
[4157]1121#if 0
1122 // this only confuses the user...
[3216]1123 if ( ss->mixer_stream != id ) {
1124  if ( streams_calc_delay(ss->mixer_stream) != -1 ) {
1125   d += g_streams[ss->mixer_stream]->delay; // in case we can calc the delay
1126                                            // the stream must exist, so no check here
1127  }
1128 }
[4157]1129#endif
[3216]1130
[1142]1131 if ( ss->codecfilter != -1 ) {
1132  if ( codecfilter_delay(ss->codecfilter_inst, ss->codecfilter, t) != -1 )
1133   d += *t;
1134 }
1135
[1151]1136 if ( ss->vio.ctl != NULL ) {
1137  if ( roar_vio_ctl(&(ss->vio), ROAR_VIO_CTL_GET_DELAY, t) != -1 ) { // *t is in byte
[1223]1138   ROAR_DBG("streams_calc_delay(id=%i): VIO delay in byte: %i", id, *t);
[1151]1139   tmp = *t;
1140   tmp *= 1000000; // musec per sec
1141   tmp /= s->info.rate * s->info.channels * (s->info.bits/8);
[2387]1142   ROAR_DBG("streams_calc_delay(id=%i): VIO delay in musec: %llu", id, tmp);
[1151]1143
1144   d += tmp;
1145  }
1146 }
1147
[1223]1148 ROAR_DBG("streams_calc_delay(id=%i): delay in musec: %i", id, d);
[1151]1149
[1142]1150 ss->delay = d;
1151
1152 return 0;
1153}
1154
[1590]1155int streams_set_mixer    (int id) {
1156 struct roar_stream_server * ss;
[2416]1157 struct roar_stream_server * pmss;
1158 int i;
1159 int subsys;
[4383]1160 int tsubsys;
[1590]1161
[2734]1162 _CHECK_SID(id);
1163
[1590]1164 if ( (ss = g_streams[id]) == NULL )
1165  return -1;
1166
[2416]1167 if ( streams_get_flag(id, ROAR_FLAG_PASSMIXER) == 1 ) {
1168  if ( (subsys = streams_get_subsys(id)) == -1 )
1169   return -1;
1170
1171  for (i = 0; i < ROAR_STREAMS_MAX; i++) {
1172   if ( (pmss = g_streams[i]) != NULL ) {
1173    if ( streams_get_flag(i, ROAR_FLAG_PASSMIXER) == 1 ) {
[4383]1174     tsubsys = streams_get_subsys(i);
1175     if ( tsubsys == subsys || tsubsys == ROAR_SUBSYS_NONE ) {
[4119]1176      if ( &(pmss->mixer) != &(ss->mixer) ) {
[4386]1177       roar_conv_volume(&(pmss->mixer), &(ss->mixer), ROAR_STREAM(pmss)->info.channels, ROAR_STREAM(ss)->info.channels);
[4119]1178      }
[2416]1179
1180      // update hwmixers and the like but do not set mixer value recrusivly.
1181      streams_reset_flag(i, ROAR_FLAG_PASSMIXER);
1182      streams_set_mixer(i);
1183      streams_set_flag(i, ROAR_FLAG_PASSMIXER);
1184     }
1185    }
1186   }
1187  }
1188 }
1189
[4417]1190 roar_notify_core_emit_snoargs(ROAR_OE_STREAM_CHANGE_VOLUME, -1, id, ROAR_OT_STREAM);
1191
[1590]1192 if ( !streams_get_flag(id, ROAR_FLAG_HWMIXER) )
1193  return 0;
1194
[4365]1195 if ( ss->driver_id != -1 ) {
1196  return driver_set_volume(id, &(ss->mixer));
[4753]1197#ifndef ROAR_WITHOUT_DCOMP_MIXER
[4365]1198 } else if ( ss->mixerstream != NULL ) {
1199  return hwmixer_set_volume(id, ss, ss->mixerstream, &(ss->mixer));
[4753]1200#endif
[4365]1201 } else {
[1590]1202  return 0;
[4365]1203 }
[1590]1204}
1205
[3542]1206int streams_set_map      (int id, char * map, size_t len) {
1207 struct roar_stream_server * ss;
1208 int ssdir;
1209
1210 _CHECK_SID(id);
1211
1212 if ( (ss = g_streams[id]) == NULL )
1213  return -1;
1214
1215 if ( map != NULL ) {
1216  if ( ROAR_STREAM(ss)->info.channels != len )
1217   return -1;
1218 }
1219
[3557]1220 ssdir = streams_get_ssdir(id);
1221
[3542]1222 switch (ssdir) {
1223  case STREAM_DIR_IN:
[3557]1224  case STREAM_DIR_NONE:
[3671]1225    memset(ss->chanmap.in, 0, sizeof(ss->chanmap.in));
1226
[3556]1227    if ( map != NULL )
1228     memcpy(ss->chanmap.in, map, len);
1229
[3542]1230    roardsp_chanmap_calc(&(ss->chanmap), ROARDSP_CHANMAP_MAP, 0);
1231   break;
1232  case STREAM_DIR_OUT:
[3671]1233    memset(ss->chanmap.out, 0, sizeof(ss->chanmap.out));
1234
[3556]1235    if ( map != NULL )
1236     memcpy(ss->chanmap.out, map, len);
1237
1238    roardsp_chanmap_calc(&(ss->chanmap), ROARDSP_CHANMAP_MAP, 0);
[3542]1239   break;
[3557]1240  default:
1241    return -1;
[3542]1242 }
1243
1244 return 0;
1245}
1246
[4272]1247int streams_ltm_ctl      (int id, int mt, int window, int cmd) {
1248 struct roar_stream_server * ss;
1249 struct roar_stream_ltm *    ltm;
1250 int i;
1251
1252 _CHECK_SID(id);
1253
1254 // currently we only support the WORKBLOCK window
1255 if ( window != ROAR_LTM_WIN_WORKBLOCK )
1256  return -1;
1257
1258 // currently we only support ROAR_LTM_MT_RMS
1259 if ( (mt | ROAR_LTM_MT_RMS) - ROAR_LTM_MT_RMS )
1260  return -1;
1261
1262 if ( (ss = g_streams[id]) == NULL )
1263  return -1;
1264
1265 switch (cmd) {
1266  case ROAR_LTM_SST_NOOP:
1267    return 0;
1268   break;
1269  case ROAR_LTM_SST_REGISTER:
1270    // test if the window is already registered:
1271    for (i = 0; i < MAX_LTM_WINDOWS_PER_STREAM; i++) {
1272     ltm = &(ss->ltm[i]);
1273     if ( ltm->refc && ltm->window == window ) {
1274      ltm->refc++;
1275      ltm->mt |= mt;
1276      return 0;
1277     }
1278    }
1279
1280    // register
1281    for (i = 0; i < MAX_LTM_WINDOWS_PER_STREAM; i++) {
1282     ltm = &(ss->ltm[i]);
1283     if ( ltm->refc == 0 ) {
1284      memset(ltm, 0, sizeof(struct roar_stream_ltm));
1285      ltm->refc = 1;
1286      ltm->window = window;
1287      ltm->parent_window = -1;
1288      ltm->mt = mt;
1289      ltm->channels = ROAR_STREAM(ss)->info.channels;
1290      if ( (ltm->cur = roar_mm_malloc(ltm->channels*sizeof(struct roar_ltm_vals))) == NULL ) {
1291       ltm->refc = 0; // reset
1292       return -1;
1293      }
1294      memset(ltm->cur, 0, ltm->channels*sizeof(struct roar_ltm_vals));
1295      return 0;
1296     }
1297    }
1298    return -1;
1299   break;
1300  case ROAR_LTM_SST_UNREGISTER:
1301    for (i = 0; i < MAX_LTM_WINDOWS_PER_STREAM; i++) {
1302     ltm = &(ss->ltm[i]);
1303     if ( ltm->refc && ltm->window == window ) {
1304      ltm->refc--;
1305      if ( ! ltm->refc ) {
1306       roar_mm_free(ltm->cur);
1307       return 0;
1308      }
1309     }
1310    }
1311    return -1;
1312   break;
1313  default:
1314    return -1;
1315   break;
1316 }
1317}
1318
1319int streams_ltm_calc     (int id, struct roar_audio_info * info, void * data, size_t len) {
1320 struct roar_stream_server * ss;
1321 struct roar_stream_ltm *    ltm = NULL;
1322 int64_t rmsbuf_real[8];
1323 int64_t * rmsbuf = rmsbuf_real;
1324 size_t samples = 0;
1325 int i;
1326
1327 _CHECK_SID(id);
1328
1329 if ( data == NULL || info == NULL )
1330  return -1;
1331
1332 if ( info->codec != ROAR_CODEC_DEFAULT )
1333  return -1;
1334
1335 if ( (ss = g_streams[id]) == NULL )
1336  return -1;
1337
1338 for (i = 0; i < MAX_LTM_WINDOWS_PER_STREAM; i++) {
1339  if ( ss->ltm[i].refc && ss->ltm[i].window == ROAR_LTM_WIN_WORKBLOCK ) {
1340   ltm = &(ss->ltm[i]);
1341   break;
1342  }
1343 }
1344
1345 if ( ltm == NULL )
1346  return -1;
1347
1348 // TODO: support change of number of channels
1349 if ( ltm->channels != info->channels )
1350  return -1;
1351
1352 if ( len == 0 ) {
1353  memset(ltm->cur, 0, ltm->channels * sizeof(struct roar_ltm_vals));
1354  return 0;
1355 }
1356
1357 // TODO: support more channels then rmsbuf_real has space for
1358 if ( ltm->channels > (sizeof(rmsbuf_real)/sizeof(*rmsbuf_real)) ) {
1359  return -1;
1360 }
1361
1362 samples = len / info->bits;
1363
1364 if ( ltm->mt & ROAR_LTM_MT_RMS ) {
1365  if ( roar_rms2_1_b_n(data, samples, rmsbuf, ltm->channels, info->bits) == -1 )
1366   return -1;
1367
1368  for (i = 0; i < ltm->channels; i++) {
[4286]1369   ltm->cur[i].rms = rmsbuf[i] << (64 - info->bits*2);
[4272]1370  }
1371
1372  ROAR_DBG("streams_ltm_calc(id=%i,...): rmsbuf[0]=%lli", id, (long long int)rmsbuf[0]);
1373 }
1374
1375 return 0;
1376}
1377
[4289]1378struct roar_stream_ltm * streams_ltm_get(int id, int mt, int window) {
[4278]1379 struct roar_stream_server * ss;
1380 struct roar_stream_ltm *    ltm = NULL;
1381 int i;
1382
[4290]1383 _CHECK_SID_RET(id, NULL);
[4278]1384
1385 if ( (ss = g_streams[id]) == NULL )
[4290]1386  return NULL;
[4278]1387
1388 for (i = 0; i < MAX_LTM_WINDOWS_PER_STREAM; i++) {
1389  if ( ss->ltm[i].refc && ss->ltm[i].window == window ) {
1390   ltm = &(ss->ltm[i]);
1391   break;
1392  }
1393 }
1394
1395 if ( ltm == NULL )
1396  return NULL;
1397
1398 if ( (ltm->mt & mt) != mt )
1399  return NULL;
1400
1401 return ltm;
1402}
[4272]1403
[4753]1404#ifndef ROAR_WITHOUT_DCOMP_MIXER
[4361]1405struct hwmixer_stream * streams_get_mixerstream(int id) {
1406 _CHECK_SID_RET(id, NULL);
1407
1408 return g_streams[id]->mixerstream;
1409}
1410
1411int streams_set_mixerstream(int id, struct hwmixer_stream * mstream) {
1412 _CHECK_SID(id);
1413
1414 g_streams[id]->mixerstream = mstream;
1415
1416 return 0;
1417}
1418
[4379]1419int streams_read_mixervalues(int id) {
1420 struct roar_stream_server * ss;
1421
1422 _CHECK_SID(id);
1423
1424 if ( (ss = g_streams[id]) == NULL )
1425  return -1;
1426
1427 if ( ss->mixerstream == NULL )
1428  return -1;
1429
1430 return hwmixer_get_volume(id, ss, ss->mixerstream, &(ss->mixer));
1431}
[4753]1432#endif
[4272]1433
[1224]1434int streams_ctl          (int id, int_least32_t cmd, void * data) {
1435 struct roar_stream_server * ss;
1436 int_least32_t comp;
1437
[2734]1438 _CHECK_SID(id);
1439
[1224]1440 if ( (ss = g_streams[id]) == NULL )
1441  return -1;
1442
1443 comp = cmd & ROAR_STREAM_CTL_COMPMASK;
1444
1445 cmd &= ~comp;
1446
[1239]1447 ROAR_DBG("streams_ctl(id=%i, cmd=?, data=%p): comp=0x%.8x, cmd=0x%.4x", id, data, comp, cmd);
[1238]1448
[1224]1449 switch (comp) {
1450  case ROAR_STREAM_CTL_COMP_BASE:
1451   break;
1452  case ROAR_STREAM_CTL_COMP_CF:
1453    return codecfilter_ctl(ss->codecfilter_inst, ss->codecfilter, cmd, data);
1454   break;
1455  case ROAR_STREAM_CTL_COMP_DRV:
1456   break;
1457  default:
1458   return -1;
1459 }
1460
1461 return -1;
1462}
1463
[0]1464int streams_get_outputbuffer  (int id, void ** buffer, size_t size) {
[2734]1465 _CHECK_SID(id);
[0]1466
1467 // output buffer size does never change.
1468 if ( g_streams[id]->output != NULL ) {
1469  *buffer = g_streams[id]->output;
1470  return 0;
1471 }
1472
1473 if ( (g_streams[id]->output = malloc(size)) == NULL ) {
1474  ROAR_ERR("streams_get_outputbuffer(*): Can not alloc: %s", strerror(errno));
1475  return -1;
1476 }
1477
1478 *buffer = g_streams[id]->output;
1479
1480 return 0;
1481}
1482
[2061]1483int streams_fill_mixbuffer2 (int id, struct roar_audio_info * info) {
1484 size_t   outlen = ROAR_OUTPUT_CALC_OUTBUFSIZE(info);
1485 void   * outdata;
1486 size_t   inlen;
1487 size_t   inlen_got;
1488 void   * indata = NULL;
[2091]1489 size_t   buflen;
1490 void   * bufdata = NULL;
1491 struct roar_buffer * bufbuf = NULL;
[2061]1492 int      is_the_same = 0;
1493 struct roar_audio_info    * stream_info;
1494 struct roar_stream        * s;
1495 struct roar_stream_server * ss;
1496
[2734]1497 _CHECK_SID(id);
1498
[2061]1499 if ( (s = ROAR_STREAM(ss = g_streams[id])) == NULL )
1500  return -1;
1501
1502 // set up stream_info
1503 stream_info = &(s->info);
1504
1505 // calc todo_in
1506 inlen = ROAR_OUTPUT_CALC_OUTBUFSIZE(stream_info);
1507
[2091]1508 buflen = ROAR_OUTPUT_CALC_OUTBUFSIZE_MAX(info, stream_info);
1509
[2747]1510 ROAR_DBG("streams_fill_mixbuffer2(id=%i, info=%p{...}): inlen=%lu, buflen=%lu", id, info, (unsigned long)inlen, (unsigned long)buflen);
1511
[2061]1512 if ( inlen == 0 ) {
1513  ROAR_WARN("streams_fill_mixbuffer2(id=%i, info=%p{...}): inlen == 0, this should not happen!", id, info);
1514  return -1;
1515 }
1516
1517 if ( streams_get_outputbuffer(id, &outdata, outlen) == -1 ) {
1518  return -1;
1519 }
1520
1521 if ( outdata == NULL ) {
1522  return -1;
1523 }
1524
1525 ROAR_DBG("streams_fill_mixbuffer2(*): outdata=%p, len=%i->%i (in->out)", outdata, inlen, outlen);
1526
1527 is_the_same = stream_info->rate     == info->rate     && stream_info->bits  == info->bits &&
1528               stream_info->channels == info->channels && stream_info->codec == info->codec;
1529
1530 ROAR_DBG("streams_fill_mixbuffer2(*): is_the_same=%i", is_the_same);
1531
[2091]1532 if ( !is_the_same && buflen > outlen ) {
1533/*
[2061]1534  // this is not supported at the moment
1535  memset(outdata, 0, outlen);
1536  return -1;
[2091]1537*/
1538
1539  if ( roar_buffer_new(&bufbuf, buflen) == -1 )
1540   return -1;
1541
1542  if ( roar_buffer_get_data(bufbuf, &bufdata) == -1 )
1543   return -1;
[2102]1544  indata  = bufdata;
[2061]1545 } else {
[2091]1546  indata  = outdata;
1547  bufdata = outdata;
[2061]1548 }
1549
1550 inlen_got = inlen;
1551
[2102]1552 ROAR_DBG("streams_fill_mixbuffer2(id=%i, info=...): inlen_got=%u", id, inlen_got);
1553
[2061]1554 if ( stream_shift_out_buffer(id, indata, &inlen_got) == -1 ) {
1555  if ( ss->is_new ) {
1556   ss->pre_underruns++;
[4417]1557   roar_notify_core_emit_simple(ROAR_OE_STREAM_XRUN, -1, id, ROAR_OT_STREAM, ROAR_XRUN_UNDER_PRE, ss->pre_underruns, NULL, 0);
[2061]1558  } else {
[2088]1559   ROAR_WARN("streams_fill_mixbuffer2(id=%i, info=...): underrun in stream", id);
[2061]1560   ss->post_underruns++;
[4417]1561   roar_notify_core_emit_simple(ROAR_OE_STREAM_XRUN, -1, id, ROAR_OT_STREAM, ROAR_XRUN_UNDER_POST, ss->post_underruns, NULL, 0);
[2061]1562  }
1563  memset(outdata, 0, outlen);
1564  return 0;
1565 }
1566
[2387]1567 ROAR_DBG("streams_fill_mixbuffer2(id=%i, info=...): inlen_got=%u", id, inlen_got);
1568
[2061]1569 if ( ss->is_new ) {
[4336]1570  //ROAR_INFO("streams_fill_mixbuffer2(id=%i, info=...): stream state: new->old", ROAR_DBG_INFO_VERBOSE, id);
1571  _streams_change_state(ss, ROAR_STREAMSTATE_OLD, "streams_fill_mixbuffer2");
[2061]1572 }
1573
1574 ss->is_new = 0;
1575
[3549]1576 // check channel map:
[3555]1577#if 0
[3554]1578 if ( roardsp_chanmap_mappcm(indata, indata, inlen, stream_info->channels, &(ss->chanmap), stream_info->bits) == -1 ) {
[3549]1579  if ( bufbuf != NULL )
1580   roar_buffer_free(bufbuf);
1581  return -1;
1582 }
[3555]1583#endif
[3549]1584
[4118]1585 // TODO: this only works in case a we have a amp for the given stream parameters.
1586 if ( !streams_get_flag(id, ROAR_FLAG_HWMIXER) && !streams_get_flag(id, ROAR_FLAG_PASSMIXER) ) {
1587  ROAR_DBG("streams_fill_mixbuffer2(*): CALL roar_amp_pcm(*)...");
[4120]1588  if ( roar_amp_pcm(indata, stream_info->bits, indata, 8*inlen / stream_info->bits, stream_info->channels, &(ss->mixer)) == -1 )
[4118]1589   return -1;
1590 }
1591
[3549]1592 // check codec, bits, channels, rate...
[2061]1593 if ( is_the_same ) {
1594  if ( indata != outdata )
1595   memcpy(outdata, indata, inlen);
1596
1597  if ( inlen < outlen )
1598   memset(outdata+inlen, 0, outlen-inlen);
1599 } else {
[2095]1600//  if ( roar_conv(outdata, indata, (8*inlen_got*info->rate)/(stream_info->rate * stream_info->bits), stream_info, info) == -1 ) {
[2387]1601  ROAR_DBG("streams_fill_mixbuffer2(*): CALL roar_conv2(*)...");
[4111]1602  if ( roar_conv2(bufdata, indata, inlen, stream_info, info, outlen) == -1 ) {
[2091]1603   if ( bufbuf != NULL )
1604    roar_buffer_free(bufbuf);
[2062]1605   return -1;
1606  }
1607
1608//  memset(outdata, 0, outlen);
[2061]1609 }
1610
[2091]1611 if ( bufbuf != NULL ) {
1612  memcpy(outdata, bufdata, outlen);
1613  roar_buffer_free(bufbuf);
1614 }
1615
[4272]1616 streams_ltm_calc(id, stream_info, outdata, outlen);
1617
[2153]1618 if ( streams_get_flag(id, ROAR_FLAG_ANTIECHO) ) {
[2747]1619  ROAR_DBG("streams_fill_mixbuffer2(*): Calcing antiecho...");
[2153]1620  // we can ignore errors here:
[2389]1621  if ( stream_outputbuffer_request(id, &bufbuf, buflen) == 0 ) {
[2153]1622   if ( roar_buffer_get_data(bufbuf, &bufdata) != -1 )
1623    memcpy(bufdata, outdata, outlen);
1624  }
1625 }
1626
[3932]1627 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);
1628 s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, (inlen_got*8)/stream_info->bits);
[2153]1629
[2747]1630 ROAR_DBG("streams_fill_mixbuffer2(*) = 0");
[2062]1631 return 0;
[2061]1632}
1633
[491]1634
[0]1635int streams_get_mixbuffers (void *** bufferlist, struct roar_audio_info * info, unsigned int pos) {
[84]1636 static void * bufs[ROAR_STREAMS_MAX+1];
[0]1637 int i;
1638 int have = 0;
[2458]1639 int dir;
[0]1640
1641 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
1642  if ( g_streams[i] != NULL ) {
[2458]1643   dir = streams_get_dir(i);
1644
1645   switch (dir) {
1646    case ROAR_DIR_PLAY:
1647    case ROAR_DIR_BIDIR:
1648     break;
[2459]1649    case ROAR_DIR_BRIDGE:
1650      if ( g_streams[i]->buffer == NULL )
1651       continue;
1652     break;
[2458]1653    default:
1654      continue;
1655   }
[0]1656
[2730]1657   if ( streams_get_flag(i, ROAR_FLAG_PAUSE) )
1658    continue;
1659
[0]1660   if ( streams_get_outputbuffer(i, &bufs[have], ROAR_OUTPUT_CALC_OUTBUFSIZE(info)) == -1 ) {
1661    ROAR_ERR("streams_get_mixbuffer(*): Can not alloc output buffer for stream %i, BAD!", i);
1662    ROAR_ERR("streams_get_mixbuffer(*): Ignoring stream for this round.");
1663    continue;
1664   }
[2061]1665   if ( streams_fill_mixbuffer2(i, info) == -1 ) {
[0]1666    ROAR_ERR("streams_get_mixbuffer(*): Can not fill output buffer for stream %i, this should not happen", i);
1667    continue;
1668   }
1669
[139]1670//   printf("D: bufs[have=%i] = %p\n", have, bufs[have]);
1671
[0]1672   ROAR_DBG("streams_get_mixbuffers(*):  bufs[have] = %p", bufs[have]);
1673   ROAR_DBG("streams_get_mixbuffers(*): *bufs[have] = 0x%08x...", *(uint32_t*)bufs[have]);
1674
[1887]1675   if ( !streams_get_flag(i, ROAR_FLAG_MUTE) )
1676    have++; // we have a new stream!
[0]1677  }
1678 }
1679
1680 bufs[have] = NULL;
[139]1681 //printf("D: bufs[have=%i] = %p\n", have, bufs[have]);
[0]1682
1683 ROAR_DBG("streams_get_mixbuffers(*): have = %i", have);
1684
1685 *bufferlist = bufs;
[547]1686 return have;
[0]1687}
1688
1689
1690int stream_add_buffer  (int id, struct roar_buffer * buf) {
1691 ROAR_DBG("stream_add_buffer(id=%i, buf=%p) = ?", id, buf);
1692
[2734]1693 _CHECK_SID(id);
[0]1694
1695 if ( g_streams[id]->buffer == NULL ) {
1696  g_streams[id]->buffer = buf;
1697  ROAR_DBG("stream_add_buffer(id=%i, buf=%p) = 0", id, buf);
1698  return 0;
1699 }
1700
1701 ROAR_DBG("stream_add_buffer(id=%i, buf=%p) = ?", id, buf);
1702 return roar_buffer_add(g_streams[id]->buffer, buf);
1703}
1704
[2061]1705int stream_shift_out_buffer   (int id, void * data, size_t * len) {
[2734]1706 _CHECK_SID(id);
[2061]1707
1708 if ( g_streams[id]->buffer == NULL )
1709  return -1;
1710
1711 return roar_buffer_shift_out(&(g_streams[id]->buffer), data, len);
1712}
1713
[0]1714int stream_shift_buffer   (int id, struct roar_buffer ** buf) {
1715 struct roar_buffer * next;
1716
[2734]1717 _CHECK_SID(id);
[0]1718
1719 if ( g_streams[id]->buffer == NULL ) {
1720  *buf = NULL;
1721  return 0;
1722 }
1723
1724 roar_buffer_get_next(g_streams[id]->buffer, &next);
1725
1726 *buf                  = g_streams[id]->buffer;
1727 g_streams[id]->buffer = next;
1728
1729 return 0;
1730}
1731int stream_unshift_buffer (int id, struct roar_buffer *  buf) {
[2734]1732 _CHECK_SID(id);
[0]1733
1734 if ( g_streams[id]->buffer == NULL ) {
1735  g_streams[id]->buffer = buf;
1736  return 0;
1737 }
1738
[4516]1739 roar_buffer_clear_next(buf);
[271]1740
[0]1741 roar_buffer_add(buf, g_streams[id]->buffer);
1742
1743 g_streams[id]->buffer = buf;
1744
1745 return 0;
1746}
1747
[2151]1748int stream_outputbuffer_request(int id, struct roar_buffer ** buf, size_t len) {
1749 register struct roar_stream_server *  ss;
1750 size_t buflen;
[2159]1751 void * bufdata;
[2151]1752 int ret;
1753
[2734]1754 _CHECK_SID(id);
1755
[2151]1756 if ( (ss = g_streams[id]) == NULL )
1757  return -1;
1758
1759 if ( buf != NULL ) /* just be be sure */
1760  *buf = NULL;
1761
1762 if ( ss->outputbuffer != NULL ) {
1763  if ( roar_buffer_get_len(ss->outputbuffer, &buflen) == 0 ) {
1764   if ( buflen == len ) {
1765    if ( buf != NULL )
1766     *buf = ss->outputbuffer;
1767    return 0;
1768   } else if ( buflen > len ) {
1769    if ( roar_buffer_set_len(ss->outputbuffer, len) == 0 ) {
1770     if ( buf != NULL )
1771      *buf = ss->outputbuffer;
1772     return 0;
1773    }
1774   }
1775  }
1776
1777  // if the buffer is not suitable:
1778
1779  ret = roar_buffer_free(ss->outputbuffer);
1780  ss->outputbuffer = NULL;
1781  if ( ret == -1 )
1782   return ret;
1783 }
1784
1785 if ( roar_buffer_new(&(ss->outputbuffer), len) == -1 )
1786  return -1;
1787
[2159]1788 if ( roar_buffer_get_data(ss->outputbuffer, &bufdata) == -1 ) {
1789  roar_buffer_free(ss->outputbuffer);
1790  ss->outputbuffer = NULL;
1791  return -1;
1792 }
1793
1794 memset(bufdata, 0, len);
1795
[2151]1796 if ( buf != NULL )
1797  *buf = ss->outputbuffer;
1798
1799 return 0;
1800}
1801
1802int stream_outputbuffer_destroy(int id) {
1803 int ret;
1804 register struct roar_stream_server *  ss;
1805
[2734]1806 _CHECK_SID(id);
1807
[2151]1808 if ( (ss = g_streams[id]) == NULL )
1809  return -1;
1810
1811 if ( ss->outputbuffer != NULL ) {
1812  ret = roar_buffer_free(ss->outputbuffer);
1813  ss->outputbuffer = NULL;
1814  return ret;
1815 }
1816
1817 return 0;
1818}
1819
[2816]1820int stream_prethru_add(int id, struct roar_buffer * buf) {
1821 register struct roar_stream_server *  ss;
1822
1823 _CHECK_SID(id);
1824
1825 if ( (ss = g_streams[id]) == NULL )
1826  return -1;
1827
1828 if ( ss->prethru == NULL ) {
1829  ss->prethru = buf;
1830  return 0;
1831 }
1832
1833 if ( roar_buffer_add(ss->prethru, buf) == -1 ) {
1834  return -1;
1835 }
1836
1837 return 0;
1838}
1839
1840int stream_prethru_add_data(int id, void ** buf, size_t len) {
1841 struct roar_buffer * buffer;
1842
1843 _CHECK_SID(id);
1844
1845 if ( roar_buffer_new(&buffer, len) == -1 )
1846  return -1;
1847
1848 if ( roar_buffer_get_data(buffer, buf) == -1 ) {
1849  roar_buffer_free(buffer);
1850  return -1;
1851 }
1852
1853 if ( stream_prethru_add(id, buffer) == -1 ) {
1854  roar_buffer_free(buffer);
1855  return -1;
1856 }
1857
1858 return 0;
1859}
1860
1861int stream_prethru_destroy(int id) {
1862 int ret;
1863 register struct roar_stream_server *  ss;
1864
1865 _CHECK_SID(id);
1866
1867 if ( (ss = g_streams[id]) == NULL )
1868  return -1;
1869
1870 if ( ss->prethru != NULL ) {
1871  ret = roar_buffer_free(ss->prethru);
1872  ss->prethru = NULL;
1873  return ret;
1874 }
1875
1876 return 0;
1877}
1878
1879int stream_prethru_send(int dst, int src) {
1880 struct roar_stream_server *  dst_ss, * src_ss;
1881 struct roar_buffer * bufbuf;
1882 void * bufdata;
1883 size_t buflen;
1884
1885 ROAR_DBG("stream_prethru_send(dst=%i, src=%i) = ?", dst, src);
1886
1887 _CHECK_SID(dst);
1888 _CHECK_SID(src);
1889
1890 if ( (dst_ss = g_streams[dst]) == NULL )
1891  return -1;
1892
1893 if ( (src_ss = g_streams[src]) == NULL )
1894  return -1;
1895
1896 bufbuf = src_ss->prethru;
1897
1898 ROAR_DBG("stream_prethru_send(dst=%i, src=%i): prethru buffer at %p", dst, src, bufbuf);
1899
1900 while (bufbuf != NULL) {
1901  ROAR_DBG("stream_prethru_send(dst=%i, src=%i): looping with buffer at %p", dst, src, bufbuf);
1902
1903  if ( roar_buffer_get_data(bufbuf, &bufdata) == -1 )
1904   return -1;
1905
1906  if ( roar_buffer_get_len(bufbuf, &buflen) == -1 )
1907   return -1;
1908
1909  if ( stream_vio_s_write(dst_ss, bufdata, buflen) != buflen )
1910   return -1;
1911
1912  if ( roar_buffer_get_next(bufbuf, &bufbuf) == -1 )
1913   return -1;
1914 }
1915
1916 ROAR_DBG("stream_prethru_send(dst=%i, src=%i) = 0", dst, src);
1917 return 0;
1918}
1919
[0]1920int streams_check  (int id) {
1921 int fh;
[508]1922 ssize_t req, realreq, done;
[0]1923 struct roar_stream        *   s;
1924 struct roar_stream_server *  ss;
1925 struct roar_buffer        *   b;
[4542]1926 void                      * buf;
[2248]1927// char                        tmp;
[0]1928
[2734]1929 _CHECK_SID(id);
[0]1930
1931 ROAR_DBG("streams_check(id=%i) = ?", id);
1932
[609]1933 s = ROAR_STREAM(ss = g_streams[id]);
[0]1934
1935 if ( (fh = s->fh) == -1 )
1936  return 0;
1937
[1821]1938 if ( streams_get_flag(id, ROAR_FLAG_PAUSE) )
[0]1939  return 0;
1940
[1821]1941 switch (s->dir) {
1942  case ROAR_DIR_LIGHT_IN:
[2493]1943#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1821]1944    return light_check_stream(id);
[2493]1945#else
1946    streams_delete(id);
1947    return -1;
1948#endif
[1821]1949   break;
[1845]1950  case ROAR_DIR_MIDI_IN:
[2493]1951#ifndef ROAR_WITHOUT_DCOMP_MIDI
[1845]1952    return midi_check_stream(id);
[2493]1953#else
1954    streams_delete(id);
1955    return -1;
1956#endif
[1845]1957   break;
[2237]1958  case ROAR_DIR_RAW_IN:
[2493]1959#ifndef ROAR_WITHOUT_DCOMP_RAW
[2237]1960    return raw_check_stream(id);
[2493]1961#else
1962    streams_delete(id);
1963    return -1;
1964#endif
[2237]1965   break;
[2721]1966  case ROAR_DIR_RDTCS_IN:
1967#ifndef ROAR_WITHOUT_DCOMP_RDTCS
1968    return rdtcs_check_stream(id);
1969#else
1970    streams_delete(id);
1971    return -1;
1972#endif
1973   break;
[1821]1974  case ROAR_DIR_PLAY:
1975  case ROAR_DIR_BIDIR:
1976   break;
[4815]1977  case ROAR_DIR_OUTPUT:
1978    if ( !streams_get_flag(id, ROAR_FLAG_RECSOURCE) )
1979     return 0;
1980   break;
[1821]1981  default:
[2248]1982/*
1983    ROAR_WARN("streams_check(id=%i): Read event on non input stream of type/dir %s", id, roar_dir2str(s->dir));
1984    errno = 0;
1985    req = stream_vio_s_read(ss, &tmp, 1);
1986    ROAR_DBG("streams_check(id=%i): stream_vio_s_read(ss, &tmp, 1) = %li // errno=%s(%i)", id, req, strerror(errno), errno);
1987    if ( req == 1 ) {
1988     ROAR_ERR("streams_check(id=%i): Client violates protocol, got one byte of data on output stream, kicking stream");
1989     streams_delete(id);
1990     return -1;
1991    }
1992*/
[1821]1993    return 0;
1994   break;
1995 }
[1585]1996
[0]1997 ROAR_DBG("streams_check(id=%i): fh = %i", id, fh);
1998
[2387]1999/*
2000 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);
2001*/
2002
2003 req  = ROAR_OUTPUT_CALC_OUTBUFSIZE(&(s->info)); // optimal size
2004// req  = ROAR_OUTPUT_BUFFER_SAMPLES * s->info.channels * (s->info.bits / 8) * ((float)s->info.rate/g_sa->rate);
[0]2005 req += ss->need_extra; // bytes left we sould get....
2006
[2387]2007 ROAR_DBG("streams_check(id=%i): asking for %i bytes", id, req);
2008
[0]2009 if ( roar_buffer_new(&b, req) == -1 ) {
2010  ROAR_ERR("streams_check(*): Can not alloc buffer space!");
2011  ROAR_DBG("streams_check(*) = -1");
2012  return -1;
2013 }
2014
[4542]2015 roar_buffer_get_data(b, &buf);
[0]2016
2017 ROAR_DBG("streams_check(id=%i): buffer is up and ready ;)", id);
[2387]2018 ROAR_DBG("streams_check(id=%i): asking for %i bytes", id, req);
[0]2019
[270]2020 if ( ss->codecfilter == -1 ) {
[508]2021  realreq = req;
2022/*
[270]2023  req = read(fh, buf, req);
[508]2024  if ( req < realreq ) { // we can do this as the stream is in nonblocking mode!
2025   if ( (realreq = read(fh, buf+req, realreq-req)) > 0 )
2026    req += realreq;
2027  }
2028*/
2029  done = 0;
2030  while (req > 0 && done != realreq) {
[881]2031   if ( (req = stream_vio_s_read(ss, buf+done, realreq-done)) > 0 )
[508]2032    done += req;
2033  }
2034  req = done;
[1837]2035
[4542]2036  roar_buffer_get_data(b, &buf);
[270]2037 } else {
2038  req = codecfilter_read(ss->codecfilter_inst, ss->codecfilter, buf, req);
2039 }
2040
2041 if ( req > 0 ) {
[0]2042  ROAR_DBG("streams_check(id=%i): got %i bytes", id, req);
2043
2044  roar_buffer_set_len(b, req);
2045
2046  if ( stream_add_buffer(id, b) != -1 )
2047   return 0;
2048
2049  ROAR_ERR("streams_check(id=%i): something is wrong, could not add buffer to stream!", id);
2050  roar_buffer_free(b);
2051 } else {
[272]2052  ROAR_DBG("streams_check(id=%i): read() = %i // errno: %s", id, req, strerror(errno));
2053#ifdef ROAR_HAVE_LIBVORBISFILE
2054  if ( errno != EAGAIN && errno != ESPIPE ) { // libvorbis file trys to seek a bit ofen :)
2055#else
2056  if ( errno != EAGAIN ) {
2057#endif
2058   ROAR_DBG("streams_check(id=%i): EOF!", id);
2059   streams_delete(id);
2060   ROAR_DBG("streams_check(id=%i) = 0", id);
2061  }
[334]2062  roar_buffer_free(b);
[0]2063  return 0;
2064 }
2065
2066
2067 ROAR_DBG("streams_check(id=%i) = -1", id);
2068 return -1;
2069}
2070
2071
[2152]2072#define _return(x) return (x)
[0]2073int streams_send_mon   (int id) {
[936]2074// int fh;
[0]2075 struct roar_stream        *   s;
2076 struct roar_stream_server *  ss;
[2146]2077 struct roar_buffer        *  bufbuf = NULL;
[2155]2078 struct roar_remove_state     removalstate;
[4815]2079 void  * ip              = g_output_buffer;
[1157]2080 void  * obuf;
2081 int     olen;
[2150]2082 int     is_the_same     = 1;
2083 int     is_vol_eq       = 1;
[2155]2084 int     antiecho        = 0;
[1157]2085 ssize_t ret;
[0]2086
[2734]2087 _CHECK_SID(id);
[0]2088
2089 ROAR_DBG("streams_send_mon(id=%i) = ?", id);
2090
[585]2091 s = ROAR_STREAM((ss = g_streams[id]));
[0]2092
[934]2093/*
[0]2094 if ( (fh = s->fh) == -1 )
2095  return 0;
[934]2096*/
[0]2097
[1914]2098 if ( !ss->ready )
2099  return 0;
[930]2100
[3042]2101 if ( g_config->jumbo_mtu )
2102  roar_vio_sync(ss->viop);
2103
[1585]2104 if ( streams_get_flag(id, ROAR_FLAG_PAUSE) )
2105  return 0;
2106
[1821]2107 switch (s->dir) {
2108  case ROAR_DIR_LIGHT_OUT:
[2493]2109#ifndef ROAR_WITHOUT_DCOMP_LIGHT
[1821]2110    return light_send_stream(id);
[2493]2111#else
2112    streams_delete(id);
2113    return -1;
2114#endif
[1821]2115   break;
[1845]2116  case ROAR_DIR_MIDI_OUT:
[2493]2117#ifndef ROAR_WITHOUT_DCOMP_MIDI
[1845]2118    return midi_send_stream(id);
[2493]2119#else
2120    streams_delete(id);
2121    return -1;
2122#endif
[1845]2123   break;
[2721]2124  case ROAR_DIR_RDTCS_OUT:
2125#ifndef ROAR_WITHOUT_DCOMP_RDTCS
2126    return rdtcs_send_stream(id);
2127#else
2128    streams_delete(id);
2129    return -1;
2130#endif
2131   break;
[2694]2132
2133  case ROAR_DIR_COMPLEX_OUT:
2134    // send a tick:
2135    if ( ss->codecfilter != -1 ) {
2136     if ( codecfilter_write(ss->codecfilter_inst, ss->codecfilter, NULL, 0) == 0 )
[4237]2137      if ( ss->state != ROAR_STREAMSTATE_OLD ) {
[4336]2138       //ROAR_INFO("streams_send_mon(id=%i): stream state: %s->old", ROAR_DBG_INFO_VERBOSE, id, roar_streamstate2str(ss->state));
2139       _streams_change_state(ss, ROAR_STREAMSTATE_OLD, "streams_send_mon");
[4237]2140      }
[2694]2141    }
2142    return 0;
2143   break;
2144
[1821]2145  case ROAR_DIR_OUTPUT:
2146    if ( g_standby )
2147     return 0;
2148  case ROAR_DIR_MONITOR:
2149  case ROAR_DIR_BIDIR:
2150   break;
2151
[4815]2152  case ROAR_DIR_RECORD:
2153    ip = g_input_buffer;
2154   break;
[1821]2155  default:
2156    return 0;
2157   break;
2158 }
2159
2160
[1042]2161 ROAR_DBG("streams_send_mon(id=%i): fh = %i", id, s->fh);
[0]2162
[625]2163 if ( s->info.channels != g_sa->channels || s->info.bits  != g_sa->bits ||
[2147]2164      s->info.rate     != g_sa->rate     || s->info.codec != g_sa->codec  )
2165  is_the_same = 0;
2166
[2150]2167 if ( !streams_get_flag(id, ROAR_FLAG_HWMIXER) ) {
2168  is_vol_eq = need_vol_change(g_sa->channels, &(ss->mixer)) ? 0 : 1;
2169 }
2170
[2155]2171 if ( streams_get_flag(id, ROAR_FLAG_ANTIECHO) )
2172  antiecho = 1;
2173
2174 if ( !is_the_same || !is_vol_eq || antiecho ) {
[625]2175  olen = ROAR_OUTPUT_CALC_OUTBUFSIZE(&(s->info)); // we hope g_output_buffer_len
2176                                                  // is ROAR_OUTPUT_CALC_OUTBUFSIZE(g_sa) here
[2390]2177  if ( stream_outputbuffer_request(id, &bufbuf, ROAR_OUTPUT_CALC_OUTBUFSIZE_MAX(&(s->info), g_sa)) == -1 )
[625]2178   return -1;
2179
[2146]2180  if ( roar_buffer_get_data(bufbuf, &obuf) == -1 ) {
2181   _return(-1);
2182  }
2183
[625]2184  ROAR_DBG("streams_send_mon(id=%i): obuf=%p, olen=%i", id, obuf, olen);
[2147]2185 } else {
[4815]2186  obuf = ip;
[2147]2187  olen = g_output_buffer_len;
2188 }
[625]2189
[2155]2190 if ( antiecho ) {
[2397]2191  ROAR_DBG("streams_send_mon(id=%i): antiecho=%i", id, antiecho);
[2158]2192  if ( roar_remove_init(&removalstate) == -1 ) {
[2155]2193   _return(-1);
[2158]2194  }
2195
[2397]2196  ROAR_DBG("streams_send_mon(id=%i): antiecho=%i", id, antiecho);
[2158]2197  if ( roar_remove_so(obuf, ip, ROAR_OUTPUT_BUFFER_SAMPLES*g_sa->channels, g_sa->bits, &removalstate) == -1 ) {
[2397]2198   ROAR_DBG("streams_send_mon(id=%i): anti echo failed", id);
[2158]2199   _return(-1);
2200  }
[2397]2201  ROAR_DBG("streams_send_mon(id=%i): antiecho=%i", id, antiecho);
[2155]2202 }
2203
[2150]2204 if ( !is_vol_eq ) {
[2938]2205  if ( roar_amp_pcm(obuf, g_sa->bits, ip, ROAR_OUTPUT_BUFFER_SAMPLES*g_sa->channels, g_sa->channels, &(ss->mixer)) == -1 ) {
[2150]2206   _return(-1);
2207  }
2208
2209  ip = obuf;
2210 }
2211
[4288]2212 streams_ltm_calc(id, &(s->info), ip, (ROAR_OUTPUT_BUFFER_SAMPLES*g_sa->channels*g_sa->bits)/8);
2213
[2147]2214 if ( !is_the_same ) {
[2148]2215  if ( roar_conv(obuf, ip, ROAR_OUTPUT_BUFFER_SAMPLES*g_sa->channels, g_sa, &(s->info)) == -1 ) {
[2146]2216   _return(-1);
[625]2217  }
2218 }
2219
[585]2220 errno = 0;
2221
2222 if ( ss->codecfilter == -1 ) {
[1042]2223  ROAR_DBG("streams_send_mon(id=%i): not a CF stream", id);
[2146]2224  if ( s->fh == -1 && roar_vio_get_fh(&(ss->vio)) == -1 ) {
[2705]2225   ROAR_DBG("streams_send_mon(id=%i) = 0", id);
[2146]2226   _return(0);
2227  }
[1014]2228
[2705]2229  ROAR_DBG("streams_send_mon(id=%i) = ?", id);
2230
[1157]2231  if ( (ret = stream_vio_s_write(ss, obuf, olen)) == olen ) {
[981]2232   s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, ROAR_OUTPUT_CALC_OUTBUFSAMP(&(s->info), olen)*s->info.channels);
[4237]2233   if ( ss->state != ROAR_STREAMSTATE_OLD ) {
[4336]2234    //ROAR_INFO("streams_send_mon(id=%i): stream state: %s->old", ROAR_DBG_INFO_VERBOSE, id, roar_streamstate2str(ss->state));
2235    _streams_change_state(ss, ROAR_STREAMSTATE_OLD, "streams_send_mon");
[4237]2236   }
[2705]2237   ROAR_DBG("streams_send_mon(id=%i) = 0", id);
[2146]2238   _return(0);
[625]2239  }
[1157]2240
[2705]2241  ROAR_DBG("streams_send_mon(id=%i) = ?", id);
2242
[1157]2243  if ( ret > 0 && errno == 0 ) {
[1231]2244   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]2245   roar_notify_core_emit_simple(ROAR_OE_STREAM_XRUN, -1, id, ROAR_OT_STREAM, ROAR_XRUN_OVER_POST, -1, NULL, 0);
[1157]2246   s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, ROAR_OUTPUT_CALC_OUTBUFSAMP(&(s->info), ret)*s->info.channels);
[4237]2247   if ( ss->state != ROAR_STREAMSTATE_OLD ) {
[4336]2248    //ROAR_INFO("streams_send_mon(id=%i): stream state: %s->old", ROAR_DBG_INFO_VERBOSE, id, roar_streamstate2str(ss->state));
2249    _streams_change_state(ss, ROAR_STREAMSTATE_OLD, "streams_send_mon");
[4237]2250   }
[2146]2251   _return(0);
[1157]2252  }
[585]2253 } else {
[1012]2254  errno = 0;
[625]2255  if ( codecfilter_write(ss->codecfilter_inst, ss->codecfilter, obuf, olen)
2256            == olen ) {
[981]2257   s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, ROAR_OUTPUT_CALC_OUTBUFSAMP(&(s->info), olen)*s->info.channels);
[4237]2258   if ( ss->state != ROAR_STREAMSTATE_OLD ) {
[4336]2259    //ROAR_INFO("streams_send_mon(id=%i): stream state: %s->old", ROAR_DBG_INFO_VERBOSE, id, roar_streamstate2str(ss->state));
2260    _streams_change_state(ss, ROAR_STREAMSTATE_OLD, "streams_send_mon");
[4237]2261   }
[2146]2262   _return(0);
[585]2263  } else { // we cann't retry on codec filetered streams
[1012]2264   if ( errno != EAGAIN ) {
2265    streams_delete(id);
[2146]2266    _return(-1);
[1012]2267   }
[585]2268  }
2269 }
[0]2270
[129]2271 if ( errno == EAGAIN ) {
2272  // ok, the client blocks for a moment, we try to sleep a bit an retry in the hope not to
2273  // make any gapes in any output because of this
2274
[1750]2275#ifdef ROAR_HAVE_USLEEP
[129]2276  usleep(100); // 0.1ms
[1750]2277#endif
[129]2278
[881]2279  if ( stream_vio_s_write(ss, obuf, olen) == olen ) {
[981]2280   s->pos = ROAR_MATH_OVERFLOW_ADD(s->pos, ROAR_OUTPUT_CALC_OUTBUFSAMP(&(s->info), olen)*s->info.channels);
[4237]2281   if ( ss->state != ROAR_STREAMSTATE_OLD ) {
[4336]2282    //ROAR_INFO("streams_send_mon(id=%i): stream state: %s->old", ROAR_DBG_INFO_VERBOSE, id, roar_streamstate2str(ss->state));
2283    _streams_change_state(ss, ROAR_STREAMSTATE_OLD, "streams_send_mon");
[4237]2284   }
[2146]2285   _return(0);
[1015]2286  } else if ( errno == EAGAIN ) {
2287   ROAR_WARN("streams_send_mon(id=%i): Can not send data to client: %s", id, strerror(errno));
[2146]2288   _return(0);
[625]2289  }
[129]2290 }
2291
[0]2292 // ug... error... delete stream!
2293
2294 streams_delete(id);
2295
[2146]2296 _return(-1);
[0]2297}
[2146]2298#undef _return
[0]2299
2300int streams_send_filter(int id) {
2301 int fh;
[127]2302 int have = 0;
2303 int len;
[0]2304 struct roar_stream        *   s;
2305 struct roar_stream_server *  ss;
2306
[2734]2307 _CHECK_SID(id);
[0]2308
2309 ROAR_DBG("streams_send_filter(id=%i) = ?", id);
2310
[609]2311 s = ROAR_STREAM(ss = g_streams[id]);
[0]2312
2313 if ( (fh = s->fh) == -1 )
2314  return 0;
2315
2316 if ( s->dir != ROAR_DIR_FILTER )
2317  return 0;
2318
[1585]2319 if ( streams_get_flag(id, ROAR_FLAG_PAUSE) )
2320  return 0;
2321
2322
[0]2323 ROAR_DBG("streams_send_filter(id=%i): fh = %i", id, fh);
2324
[881]2325 if ( stream_vio_s_write(ss, g_output_buffer, g_output_buffer_len) == g_output_buffer_len ) {
[127]2326  while ( have < g_output_buffer_len ) {
[881]2327   if ( (len = stream_vio_s_read(ss, g_output_buffer+have, g_output_buffer_len-have)) < 1 ) {
[127]2328    streams_delete(id);
2329    return -1;
2330   }
2331   have += len;
[0]2332  }
[127]2333  return 0;
[0]2334 }
2335
2336 // ug... error... delete stream!
2337
2338 streams_delete(id);
2339
2340 return -1;
2341}
2342
[596]2343
2344// VIO:
2345
2346ssize_t stream_vio_read (int stream, void *buf, size_t count) {
[2734]2347 _CHECK_SID(stream);
[596]2348
[2734]2349 return stream_vio_s_read(g_streams[stream], buf, count);
[596]2350}
2351
2352ssize_t stream_vio_write(int stream, void *buf, size_t count) {
[2734]2353 _CHECK_SID(stream);
[596]2354
[2734]2355 return stream_vio_s_write(g_streams[stream], buf, count);
[596]2356}
2357
[4815]2358int     stream_vio_ctl  (int stream, int cmd,   void * data) {
2359 _CHECK_SID(stream);
2360
2361 return stream_vio_s_ctl(g_streams[stream], cmd, data);
2362}
[596]2363
2364ssize_t stream_vio_s_read (struct roar_stream_server * stream, void *buf, size_t count) {
[2253]2365 void    * orig_buf = buf;
2366  size_t   len      =  0;
2367 ssize_t   r        = -1;
2368 int       i;
[739]2369
[596]2370 errno = 0;
2371
2372 if ( !stream )
2373  return -1;
2374
[1613]2375 //roar_vio_set_fh(&(stream->vio), ROAR_STREAM(stream)->fh);
[881]2376
[596]2377 if ( ! stream->vio.read )
2378  return -1;
2379
[881]2380 while ( (r = roar_vio_read(&(stream->vio), buf, count)) > 0 ) {
[739]2381  len   += r;
2382  buf   += r;
2383  count -= r;
2384  if ( count == 0 )
2385   break;
2386 }
2387
[740]2388 if ( len == 0 && r == -1 )
2389  return -1;
2390
[2816]2391 if ( streams_thru_num ) {
2392  for (i = 0; i < ROAR_STREAMS_MAX; i++) {
2393   if ( g_streams[i] != NULL && ROAR_STREAM(g_streams[i])->pos_rel_id == ROAR_STREAM(stream)->id ) {
2394    if ( ROAR_STREAM(g_streams[i])->dir == ROAR_DIR_THRU ) {
2395     if ( g_streams[i]->ready ) {
[2258]2396      if ( stream_vio_write(i, orig_buf, len) != len )
2397       streams_delete(i);
[2252]2398
[4237]2399      if ( g_streams[i] != NULL ) {
2400       if ( g_streams[i]->state != ROAR_STREAMSTATE_OLD ) {
[4336]2401        //ROAR_INFO("stream_vio_s_read(*): (stream: %i) stream state: %s->old", ROAR_DBG_INFO_VERBOSE, i, roar_streamstate2str(g_streams[i]->state));
2402        _streams_change_state(g_streams[i], ROAR_STREAMSTATE_OLD, "stream_vio_s_read");
[4237]2403       }
2404      }
[2816]2405     }
2406    }
2407   }
2408  }
2409 }
2410
[739]2411 return len;
[596]2412}
2413
2414ssize_t stream_vio_s_write(struct roar_stream_server * stream, void *buf, size_t count) {
[2259]2415 int i;
2416
[596]2417 errno = 0;
2418
2419 if ( !stream )
2420  return -1;
2421
[1613]2422/*
[934]2423 if ( roar_vio_get_fh(&(stream->vio)) == -1 && ROAR_STREAM(stream)->fh != -1 )
2424  roar_vio_set_fh(&(stream->vio), ROAR_STREAM(stream)->fh);
[1613]2425*/
[934]2426
2427// ROAR_WARN("stream_vio_s_write(*): writing...");
[596]2428
[2816]2429 if ( streams_thru_num ) {
2430  for (i = 0; i < ROAR_STREAMS_MAX; i++) {
2431   if ( g_streams[i] != NULL && ROAR_STREAM(g_streams[i])->pos_rel_id == ROAR_STREAM(stream)->id ) {
2432    if ( ROAR_STREAM(g_streams[i])->dir == ROAR_DIR_THRU ) {
2433     if ( g_streams[i]->ready ) {
2434      if ( g_streams[i]->state == ROAR_STREAMSTATE_NEW ) {
2435       if ( streams_get_flag(i, ROAR_FLAG_PRETHRU) == 1 ) {
[3042]2436        if ( stream_prethru_send(i, ROAR_STREAM(stream)->id) == -1 ) {
[2816]2437         streams_delete(i);
2438        }
2439       }
2440      }
2441
2442      if ( stream_vio_write(i, buf, count) != count ) {
[2259]2443       streams_delete(i);
[2816]2444      }
2445
[4237]2446      if ( g_streams[i] != NULL ) {
2447       if ( g_streams[i]->state != ROAR_STREAMSTATE_OLD ) {
[4336]2448        //ROAR_INFO("stream_vio_s_write(*): (stream: %i) stream state: %s->old", ROAR_DBG_INFO_VERBOSE, i, roar_streamstate2str(g_streams[i]->state));
2449        _streams_change_state(g_streams[i], ROAR_STREAMSTATE_OLD, "stream_vio_s_write");
[4237]2450       }
2451      }
[2816]2452     }
2453    }
2454   }
2455  }
2456 }
[2259]2457
[3042]2458 if ( g_config->jumbo_mtu ) {
2459  if ( stream->viop != &(stream->jumbo) ) {
2460   if ( roar_vio_open_jumbo(&(stream->jumbo), &(stream->vio), g_config->jumbo_mtu) != -1 ) {
2461    // if that works we continue using the jumbo vio,
2462    // in case it didn't we dont, just use normal VIO.
2463    stream->viop = &(stream->jumbo);
2464   }
2465  }
2466 }
2467
2468 return roar_vio_write(stream->viop, buf, count);
[596]2469}
2470
[4815]2471int     stream_vio_s_ctl  (struct roar_stream_server * stream, int cmd,   void * data) {
2472 if ( stream == NULL )
2473  return -1;
2474
2475 return roar_vio_ctl(stream->viop, cmd, data);
2476}
2477
[0]2478//ll
Note: See TracBrowser for help on using the repository browser.