Index: roard/include/streams.h
===================================================================
--- roard/include/streams.h	(revision 3517)
+++ roard/include/streams.h	(revision 3542)
@@ -52,4 +52,9 @@
 #define ROAR_STREAM_CTL_TYPE_FLOAT  0x00020000
 #define ROAR_STREAM_CTL_TYPE_FPI100 0x00030000 /* fix point integter int/100 */
+
+#define STREAM_DIR_NONE             0x00
+#define STREAM_DIR_IN               0x01
+#define STREAM_DIR_OUT              0x02
+#define STREAM_DIR_BIDIR            (STREAM_DIR_IN|STREAM_DIR_OUT)
 
 struct roar_stream_server {
@@ -107,4 +112,5 @@
 
 int streams_get_subsys (int id);
+int streams_get_ssdir  (int id);
 
 int streams_new_virtual (int parent, struct roar_stream_server ** stream);
@@ -132,4 +138,6 @@
 int streams_calc_delay   (int id);
 int streams_set_mixer    (int id);
+
+int streams_set_map      (int id, char * map, size_t len);
 
 int streams_ctl          (int id, int_least32_t cmd, void * data);
Index: roard/req.c
===================================================================
--- roard/req.c	(revision 3539)
+++ roard/req.c	(revision 3542)
@@ -664,28 +664,46 @@
  int i;
 
- if ( mes->datalen != 8 )
-  return -1;
-
- for (i = 0; i < mes->datalen/2; i++) {
+ if ( mes->datalen < 2*2 )
+  return -1;
+
+ for (i = 0; i < 2; i++) {
   d[i] = ROAR_NET2HOST16(d[i]);
  }
 
- if ( d[0] != 0 || d[1] != ROAR_STREAM_PARA_FLAGS ) {
-  ROAR_WARN("req_on_set_stream_para(*): unsupported command version: %i, %i", d[0], d[1]);
-  return -1;
- }
-
- mes->cmd     = ROAR_CMD_OK;
- mes->datalen = 0;
-
- ROAR_DBG("req_on_set_stream_para(*): request seems to be valid");
-
- if ( d[2] == ROAR_RESET_FLAG ) {
-  return streams_reset_flag(mes->stream, d[3]);
- } else {
-  return streams_set_flag(mes->stream, d[3]);
- }
-
- return -1;
+ if ( d[0] != 0 )
+  return -1;
+
+ switch (d[1]) {
+  case ROAR_STREAM_PARA_FLAGS:
+    if ( mes->datalen != 2*4 )
+     return -1;
+
+    d[2] = ROAR_NET2HOST16(d[2]);
+    d[3] = ROAR_NET2HOST16(d[3]);
+
+    ROAR_DBG("req_on_set_stream_para(*): request seems to be valid");
+
+    if ( d[2] == ROAR_RESET_FLAG ) {
+     if ( streams_reset_flag(mes->stream, d[3]) == -1 )
+      return -1;
+    } else {
+     if ( streams_set_flag(mes->stream, d[3]) == -1 )
+      return -1;
+    }
+   break;
+  case ROAR_STREAM_PARA_CHANMAP:
+    if ( streams_set_map(mes->stream, &(mes->data[4]), mes->datalen - 4) == -1 )
+     return -1;
+   break;
+  default:
+    ROAR_WARN("req_on_set_stream_para(*): unsupported command version: %i, %i", d[0], d[1]);
+    return -1;
+   break;
+ }
+
+ mes->cmd     = ROAR_CMD_OK;
+ mes->datalen = 0;
+
+ return 0;
 }
 
Index: roard/streams.c
===================================================================
--- roard/streams.c	(revision 3539)
+++ roard/streams.c	(revision 3542)
@@ -318,5 +318,5 @@
      roardsp_chanlist_init(ss->chanmap.in,  ROAR_STREAM(ss)->info.channels, ROARDSP_CHANLIST_MAP_ROARAUDIO);
      roardsp_chanlist_init(ss->chanmap.out, ROAR_STREAM(ss)->info.channels, ROARDSP_CHANLIST_MAP_ROARAUDIO);
-     roardsp_chanmap_calc(&(ss->chanmap), ROARDSP_CHANMAP_MAP, 0);
+     roardsp_chanmap_calc(&(ss->chanmap), ROARDSP_CHANMAP_MAP, 0); // MAP and INVMAP are the same when in==out
     break;
 #ifndef ROAR_WITHOUT_DCOMP_MIDI
@@ -415,4 +415,44 @@
 }
 
+int streams_get_ssdir  (int id) {
+ struct roar_stream_server * ss;
+
+ _CHECK_SID(id);
+
+ if ( (ss = g_streams[id]) == NULL )
+  return -1;
+
+ switch (ROAR_STREAM(ss)->dir) {
+  case ROAR_DIR_PLAY:
+  case ROAR_DIR_MIDI_IN:
+  case ROAR_DIR_LIGHT_IN:
+  case ROAR_DIR_RAW_IN:
+  case ROAR_DIR_COMPLEX_IN:
+    return STREAM_DIR_IN;
+   break;
+  case ROAR_DIR_RECORD:
+  case ROAR_DIR_MONITOR:
+  case ROAR_DIR_OUTPUT:
+  case ROAR_DIR_MIDI_OUT:
+  case ROAR_DIR_LIGHT_OUT:
+  case ROAR_DIR_RAW_OUT:
+  case ROAR_DIR_COMPLEX_OUT:
+    return STREAM_DIR_OUT;
+   break;
+  case ROAR_DIR_MIXING:
+    return STREAM_DIR_NONE;
+   break;
+  case ROAR_DIR_FILTER:
+  case ROAR_DIR_BIDIR:
+    return STREAM_DIR_BIDIR;
+   break;
+  case ROAR_DIR_THRU:
+    return streams_get_ssdir(ROAR_STREAM(ss)->pos_rel_id);
+   break;
+ }
+
+ return -1;
+}
+
 #define _err() streams_delete(id); return -1;
 int streams_new_virtual (int parent, struct roar_stream_server ** stream) {
@@ -895,4 +935,36 @@
 
  return driver_set_volume(id, &(ss->mixer));
+}
+
+int streams_set_map      (int id, char * map, size_t len) {
+ struct roar_stream_server * ss;
+ int ssdir;
+
+ _CHECK_SID(id);
+
+ if ( (ss = g_streams[id]) == NULL )
+  return -1;
+
+ ssdir = streams_get_ssdir(id);
+ if ( ssdir != STREAM_DIR_IN && ssdir != STREAM_DIR_OUT )
+  return -1;
+
+ if ( map != NULL ) {
+  if ( ROAR_STREAM(ss)->info.channels != len )
+   return -1;
+
+  memcpy(ss->chanmap.in, map, len);
+ }
+
+ switch (ssdir) {
+  case STREAM_DIR_IN:
+    roardsp_chanmap_calc(&(ss->chanmap), ROARDSP_CHANMAP_MAP, 0);
+   break;
+  case STREAM_DIR_OUT:
+    roardsp_chanmap_calc(&(ss->chanmap), ROARDSP_CHANMAP_INVMAP, 0);
+   break;
+ }
+
+ return 0;
 }
 
