Index: ChangeLog
===================================================================
--- ChangeLog	(revision 4737)
+++ ChangeLog	(revision 4740)
@@ -1,2 +1,5 @@
+v. 0.4beta4 - ?
+	* Added support for UNMAPPED volume control (Closes: #55)
+
 v. 0.4beta3 - Wed Jan 26 2011 23:26 CET
 	Prereleases: 0: Thu Jan 20 2011 19:36 CET
Index: include/libroar/ctl.h
===================================================================
--- include/libroar/ctl.h	(revision 4708)
+++ include/libroar/ctl.h	(revision 4740)
@@ -66,4 +66,5 @@
 
 int roar_set_vol      (struct roar_connection * con, int id, struct roar_mixer_settings * mixer, int   channels);
+int roar_set_vol2     (struct roar_connection * con, int id, struct roar_mixer_settings * mixer, int   channels, int mode);
 int roar_get_vol      (struct roar_connection * con, int id, struct roar_mixer_settings * mixer, int * channels);
 
Index: libroar/ctl.c
===================================================================
--- libroar/ctl.c	(revision 4708)
+++ libroar/ctl.c	(revision 4740)
@@ -228,4 +228,8 @@
 
 int roar_set_vol      (struct roar_connection * con, int id, struct roar_mixer_settings * mixer, int channels) {
+ return roar_set_vol2(con, id, mixer, channels, ROAR_SET_VOL_ALL);
+}
+
+int roar_set_vol2     (struct roar_connection * con, int id, struct roar_mixer_settings * mixer, int   channels, int mode) {
  struct roar_message m;
  uint16_t * info = (uint16_t *) m.data;
@@ -239,5 +243,5 @@
  info[0] = ROAR_HOST2NET16(1);
  info[1] = ROAR_HOST2NET16(mixer->scale);
- info[2] = ROAR_HOST2NET16(ROAR_SET_VOL_ALL);
+ info[2] = ROAR_HOST2NET16(mode);
 
  for (i = 0; i < channels; i++)
Index: libroar/vs.c
===================================================================
--- libroar/vs.c	(revision 4719)
+++ libroar/vs.c	(revision 4740)
@@ -829,4 +829,5 @@
  int oldchannels;
  int handled;
+ int mode = ROAR_SET_VOL_ALL;
 
  _ckvss(-1);
@@ -864,41 +865,24 @@
  mixer.scale = 65535;
 
- if ( channels != oldchannels ) {
-  handled = 0;
-  switch (oldchannels) {
-   case 1:
-     if ( channels == 2 ) {
-      mixer.mixer[0] = (mixer.mixer[0] + mixer.mixer[1]) / 2;
-      handled = 1;
-     }
-    break;
-   case 2:
-     if ( channels == 1 ) {
-      mixer.mixer[1] = mixer.mixer[0];
-      handled = 1;
-     }
-    break;
-   case 4:
-     if ( channels == 1 ) {
-      mixer.mixer[1] = mixer.mixer[0];
-      mixer.mixer[2] = mixer.mixer[0];
-      mixer.mixer[3] = mixer.mixer[0];
-      handled = 1;
-     } else if ( channels == 2 ) {
-      mixer.mixer[2] = mixer.mixer[0];
-      mixer.mixer[3] = mixer.mixer[1];
-      handled = 1;
-     }
-    break;
-  }
-  if ( handled ) {
-   channels = oldchannels;
-  } else {
-   _seterr(ROAR_ERROR_INVAL);
-   return -1;
-  }
- }
-
- if ( roar_set_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels) == -1 ) {
+ if ( channels != oldchannels )
+  mode = ROAR_SET_VOL_UNMAPPED;
+
+ if ( roar_set_vol2(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels, mode) == 0 )
+  return 0;
+
+ if ( mode == ROAR_SET_VOL_ALL ) {
+  _seterrre();
+  return -1;
+ }
+
+ if ( roar_conv_volume(&mixer, &mixer, oldchannels, channels) == -1 ) {
+  _seterrre();
+  return -1;
+ }
+
+ channels = oldchannels;
+ mode     = ROAR_SET_VOL_ALL;
+
+ if ( roar_set_vol2(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels, mode) == -1 ) {
   _seterrre();
   return -1;
Index: roarclients/roarctl.c
===================================================================
--- roarclients/roarctl.c	(revision 4708)
+++ roarclients/roarctl.c	(revision 4740)
@@ -644,8 +644,8 @@
  int len;
  int old_chans;
- int vol_l, vol_r, vol_mono;
  char * k;
  struct roar_mixer_settings mixer;
  struct roar_mixer_settings old_mixer;
+ int mode = ROAR_SET_VOL_ALL;
 
  if (*cur + 2 > max)
@@ -655,9 +655,4 @@
 
  k = arg[++(*cur)];
-
- if ( roar_get_vol(con, id, &old_mixer, &old_chans) == -1 ) {
-  fprintf(stderr, "Error: can not get stream mixer info for stream %i\n", id);
-  return -1;
- }
 
  if ( !strcmp(arg[*cur + 1], "scale") ) {
@@ -667,97 +662,52 @@
  }
 
-// TODO: clean up code here as the % vs. abs code is very duplicate...
-
- if ( strcmp(k, "mono") == 0 && old_chans != 1 ) {
+ mixer.scale = scale;
+
+ if ( roar_get_vol(con, id, &old_mixer, &old_chans) == -1 ) {
+  fprintf(stderr, "Error: can not get stream mixer info for stream %i\n", id);
+  return -1;
+ }
+
+ if ( strcmp(k, "mono") == 0 ) {
   chans = 1;
-
-  if ( *cur + 1 > max )
-   return -1;
-
+  mode  = ROAR_SET_VOL_UNMAPPED;
+ } else if ( strcmp(k, "stereo") == 0 ) {
+  chans = 2;
+  mode  = ROAR_SET_VOL_UNMAPPED;
+ } else {
+  chans = atoi(k);
+ }
+
+ // ensure most simple mode:
+ if ( old_chans == chans && mode == ROAR_SET_VOL_UNMAPPED )
+  mode = ROAR_SET_VOL_ALL;
+
+ if ( *cur + chans > max )
+  return -1;
+
+ for (i = 0; i < chans; i++) {
   k   = arg[++(*cur)];
   len = strlen(k);
 
-  vol_mono = set_mixer_parse_volume(k, len, scale);
-
-  for (i = 0; i < old_chans; i++)
-   mixer.mixer[i] = vol_mono;
-
-  chans = old_chans;
-
- } else if ( strcmp(k, "stereo") == 0 && old_chans != 2 ) {
-  chans = old_chans;
-
-  if ( *cur + 2 > max )
-   return -1;
-
-  k   = arg[++(*cur)];
-  len = strlen(k);
-
-  vol_l = set_mixer_parse_volume(k, len, scale);
-
-  k   = arg[++(*cur)];
-  len = strlen(k);
-
-  vol_r = set_mixer_parse_volume(k, len, scale);
-
-  vol_mono = (vol_l + vol_r) / 2;
-
-  mixer.mixer[0] = vol_l;
-  mixer.mixer[1] = vol_r;
-
-  switch (chans) {
-   case 1:
-     mixer.mixer[0] = vol_mono;
-    break;
-//   case 2: classic stereo...
-   case 3:
-     mixer.mixer[2] = vol_mono;
-    break;
-   case 4:
-     mixer.mixer[2] = vol_l;
-     mixer.mixer[3] = vol_r;
-    break;
-   case 5:
-     mixer.mixer[2] = vol_mono;
-     mixer.mixer[3] = vol_l;
-     mixer.mixer[4] = vol_r;
-    break;
-   case 6:
-     mixer.mixer[2] = vol_mono;
-     mixer.mixer[3] = vol_mono;
-     mixer.mixer[4] = vol_l;
-     mixer.mixer[5] = vol_r;
-    break;
-   default:
-     ROAR_ERR("mode stereo not supported on stream with %i channels", chans);
-     return -1;
-    break;
-  }
-
- } else {
-  if ( strcmp(k, "mono") == 0 ) {
-   chans = 1;
-  } else if ( strcmp(k, "stereo") == 0 ) {
-   chans = 2;
-  } else {
-   chans = atoi(k);
-  }
-
-//  printf("mode: int; chans=%i, old_chans=%i\n", chans, old_chans);
-
-  if ( *cur + chans > max )
-   return -1;
-
-  for (i = 0; i < chans; i++) {
-   k   = arg[++(*cur)];
-   len = strlen(k);
-
-   mixer.mixer[i] = set_mixer_parse_volume(k, len, scale);
-  }
- }
-
- mixer.scale = scale;
-
- return roar_set_vol(con, id, &mixer, chans);
+  mixer.mixer[i] = set_mixer_parse_volume(k, len, scale);
+ }
+
+ if ( roar_set_vol2(con, id, &mixer, chans, mode) == 0 )
+  return 0;
+
+ // no fallback if already using ROAR_SET_VOL_ALL:
+ if ( mode == ROAR_SET_VOL_ALL )
+  return -1;
+
+ if ( roar_conv_volume(&mixer, &mixer, old_chans, chans) == -1 )
+  return -1;
+
+ chans = old_chans;
+ mode  = ROAR_SET_VOL_ALL;
+
+ if ( roar_set_vol2(con, id, &mixer, chans, mode) == 0 )
+  return 0;
+
+ return -1;
 }
 
Index: roarclients/roarradio.c
===================================================================
--- roarclients/roarradio.c	(revision 4708)
+++ roarclients/roarradio.c	(revision 4740)
@@ -43,4 +43,9 @@
        );
 
+}
+
+static void die(const char * msg) {
+ fprintf(stderr, "Fatal error: %s\n", msg);
+ abort();
 }
 
@@ -62,4 +67,5 @@
  char buf0[80], buf1[80];
  int proto = P_UNKNOWN;
+ ssize_t slen;
 
  for (i = 1; i < argc; i++) {
@@ -160,5 +166,6 @@
 
       while (*buf0 != '\r' && *buf0 != '\n') {
-       fgets(buf0, 80, http);
+       if ( fgets(buf0, 80, http) == NULL )
+        die("Can not read header lion");
       }
 
@@ -173,6 +180,9 @@
       }
       // TODO: do some error checks here
-      write(in, file, strlen(file));
-      write(in, "\r\n", 2);
+      slen = strlen(file);
+      if ( write(in, file, slen) != slen )
+       die("Can not write selector");
+      if ( write(in, "\r\n", 2) != 2 )
+       die("Can not write selector terminator");
       ROAR_SHUTDOWN(in, SHUT_WR);
      break;
Index: roard/req.c
===================================================================
--- roard/req.c	(revision 4738)
+++ roard/req.c	(revision 4740)
@@ -1371,4 +1371,5 @@
 
 int req_on_set_vol (int client, struct roar_message * mes, char ** data, uint32_t flags[2]) {
+ struct roar_mixer_settings tmpmixer;
  struct roar_stream_server * s;
  uint16_t * info = (uint16_t *) mes->data;
@@ -1450,4 +1451,23 @@
     s->mixer.scale = scale;
    break;
+  case ROAR_SET_VOL_UNMAPPED:
+    chans = (mes->datalen/2) - 3;
+
+    if ( chans >= ROAR_MAX_CHANNELS )
+     return -1;
+
+    memcpy(&tmpmixer, &(s->mixer), sizeof(tmpmixer));
+
+    for (i = 0; i < chans; i++) {
+     tmpmixer.mixer[i] = ROAR_NET2HOST16(info[i+3]);
+    }
+
+    tmpmixer.scale = scale;
+
+    if ( roar_conv_volume(&(s->mixer), &tmpmixer, ROAR_STREAM(s)->info.channels, chans) == -1 )
+     return -1;
+
+   break;
+  case ROAR_SET_VOL_MS:
   default:
     return -1;
