Index: roarclients/roarctl.c
===================================================================
--- roarclients/roarctl.c	(revision 4740)
+++ roarclients/roarctl.c	(revision 4818)
@@ -48,4 +48,6 @@
 int g_verbose = 0;
 
+void display_client (struct roar_connection * con, int id);
+void display_stream (struct roar_connection * con, int id);
 int display_mixer (struct roar_connection * con, int stream);
 int show_meta_all (struct roar_connection * con, int id);
@@ -117,7 +119,11 @@
         "  serveroinfo             - Gets Information about server output\n"
         "  serveroinfo2 DIR        - Gets Information about server output for stream direction dir\n"
+        "\n"
         "  serverstandards         - Gets list of server supported standards\n"
+        "\n"
         "  listclients             - Gets Information about clients\n"
+        "  clientinfo ID           - Gets Information about client ID\n"
         "  liststreams             - Gets Information about streams\n"
+        "  streaminfo ID           - Gets Information about stream ID\n"
         "  allinfo                 - Get all infos\n"
        );
@@ -317,10 +323,23 @@
  int i;
  int num;
+ int id[ROAR_CLIENTS_MAX];
+
+ if ( (num = roar_list_clients(con, id, ROAR_CLIENTS_MAX)) == -1 ) {
+  fprintf(stderr, "Error: can not get client list\n");
+  return;
+ }
+
+ for (i = 0; i < num; i++) {
+  display_client(con, id[i]);
+ }
+}
+
+void display_client (struct roar_connection * con, int id) {
+ static int self_id = -1;
+ static struct roar_client   self_client_store;
+ static struct roar_client * self_client = NULL;
+ struct roar_client c;
+ char tmp[80];
  int h;
- int id[ROAR_CLIENTS_MAX];
- char tmp[80];
- int self_id;
- struct roar_client self_client;
- struct roar_client c;
 #ifdef _POSIX_USERS
  struct group  * grp = NULL;
@@ -328,84 +347,80 @@
 #endif
 
- if ( (self_id = roar_get_clientid(con)) != -1 ) {
-  if ( roar_get_client(con, &self_client, self_id) == -1 )
-   self_id = -1;
- }
-
- if ( (num = roar_list_clients(con, id, ROAR_CLIENTS_MAX)) == -1 ) {
-  fprintf(stderr, "Error: can not get client list\n");
+ if ( self_id == -1 ) {
+  if ( (self_id = roar_get_clientid(con)) != -1 ) {
+   if ( roar_get_client(con, &self_client_store, self_id) == -1 ) {
+    self_id = -1;
+   } else {
+    self_client = &self_client_store;
+   }
+  }
+ }
+
+ printf("client %i:\n", id);
+ if ( roar_get_client(con, &c, id) == -1 ) {
+  fprintf(stderr, "Error: can not get client info\n");
   return;
  }
 
- for (i = 0; i < num; i++) {
-  printf("client %i:\n", id[i]);
-  if ( roar_get_client(con, &c, id[i]) == -1 ) {
-   fprintf(stderr, "Error: can not get client info\n");
-   continue;
-  }
-
-  if ( c.name[0] != '\0' )
-   printf("Client name           : %s\n", c.name);
-
+ if ( c.name[0] != '\0' )
+  printf("Client name           : %s\n", c.name);
   if ( roar_nnode_get_socktype(&(c.nnode)) != ROAR_SOCKET_TYPE_UNKNOWN ) {
-   if ( roar_nnode_to_str(&(c.nnode), tmp, 80) == 0 ) {
-    printf("Client network node   : %s\n", tmp);
-   }
-  }
-
-  if ( c.pid != -1 ) {
-   if ( self_id != -1 && roar_nnode_cmp(&(self_client.nnode), &(c.nnode)) == 0 ) {
-    printf("Client PID            : %i(%s)\n", c.pid, proc_name(c.pid));
-   } else { 
-    printf("Client PID            : %i\n", c.pid);
-   }
-  }
-  if ( c.uid != -1 ) {
+  if ( roar_nnode_to_str(&(c.nnode), tmp, 80) == 0 ) {
+   printf("Client network node   : %s\n", tmp);
+  }
+ }
+
+ if ( c.pid != -1 ) {
+  if ( self_id != -1 && roar_nnode_cmp(&(self_client->nnode), &(c.nnode)) == 0 ) {
+   printf("Client PID            : %i(%s)\n", c.pid, proc_name(c.pid));
+  } else { 
+   printf("Client PID            : %i\n", c.pid);
+  }
+ }
+ if ( c.uid != -1 ) {
 #ifdef _POSIX_USERS
-   if ( self_id != -1 && roar_nnode_cmp(&(self_client.nnode), &(c.nnode)) == 0 ) {
-    pwd = getpwuid(c.uid);
-    grp = getgrgid(c.gid);
-    printf("Client UID/GID        : %i(%s)/%i(%s)\n", c.uid, pwd ? pwd->pw_name : "?", c.gid, grp ? grp->gr_name : "?");
-   } else {
+  if ( self_id != -1 && roar_nnode_cmp(&(self_client->nnode), &(c.nnode)) == 0 ) {
+   pwd = getpwuid(c.uid);
+   grp = getgrgid(c.gid);
+   printf("Client UID/GID        : %i(%s)/%i(%s)\n", c.uid, pwd ? pwd->pw_name : "?", c.gid, grp ? grp->gr_name : "?");
+  } else {
 #else
-   if ( 1 ) {
+  if ( 1 ) {
 #endif
-    printf("Client UID/GID        : %i/%i\n", c.uid, c.gid);
-   }
-  }
-
-  if ( g_verbose && c.proto != ROAR_PROTO_NONE ) {
-   printf("Client Protocol       : %s\n", roar_proto2str(c.proto));
-  }
-
-  if ( g_verbose && c.byteorder != ROAR_BYTEORDER_UNKNOWN ) {
-   if ( c.byteorder == ROAR_BYTEORDER_NETWORK ) {
-    strcpy(tmp, " (network byteorder");
-   } else {
-    *tmp = 0;
-   }
-
-   if ( c.byteorder == ROAR_BYTEORDER_NATIVE ) {
-    if ( *tmp ) {
-     strcat(tmp, ", native");
-    } else {
-     strcpy(tmp, " (native");
-    }
-   }
-
-   if ( *tmp )
-    strcat(tmp, ")");
-
-   printf("Client Byteorder      : %s%s\n", roar_byteorder2str(c.byteorder), tmp);
-  }
-
-  if ( c.execed != -1 )
-   printf("Execed stream         : %i\n", c.execed);
-
-  for (h = 0; h < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; h++)
-   if ( c.streams[h] != -1 )
-    printf("stream                : %i\n", c.streams[h]);
- }
-
+   printf("Client UID/GID        : %i/%i\n", c.uid, c.gid);
+  }
+ }
+
+ if ( g_verbose && c.proto != ROAR_PROTO_NONE ) {
+  printf("Client Protocol       : %s\n", roar_proto2str(c.proto));
+ }
+
+ if ( g_verbose && c.byteorder != ROAR_BYTEORDER_UNKNOWN ) {
+  if ( c.byteorder == ROAR_BYTEORDER_NETWORK ) {
+   strcpy(tmp, " (network byteorder");
+  } else {
+   *tmp = 0;
+  }
+
+  if ( c.byteorder == ROAR_BYTEORDER_NATIVE ) {
+   if ( *tmp ) {
+    strcat(tmp, ", native");
+   } else {
+    strcpy(tmp, " (native");
+   }
+  }
+
+  if ( *tmp )
+   strcat(tmp, ")");
+
+  printf("Client Byteorder      : %s%s\n", roar_byteorder2str(c.byteorder), tmp);
+ }
+
+ if ( c.execed != -1 )
+  printf("Execed stream         : %i\n", c.execed);
+
+ for (h = 0; h < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; h++)
+  if ( c.streams[h] != -1 )
+   printf("stream                : %i\n", c.streams[h]);
 }
 
@@ -414,4 +429,16 @@
  int num;
  int id[ROAR_STREAMS_MAX];
+
+ if ( (num = roar_list_streams(con, id, ROAR_STREAMS_MAX)) == -1 ) {
+  fprintf(stderr, "Error: can not get stream list\n");
+  return;
+ }
+
+ for (i = 0; i < num; i++) {
+  display_stream(con, id[i]);
+ }
+}
+
+void display_stream (struct roar_connection * con, int id) {
  char chanmap[ROAR_MAX_CHANNELS];
  struct roar_stream s;
@@ -424,152 +451,143 @@
  size_t len;
 
-
- if ( (num = roar_list_streams(con, id, ROAR_STREAMS_MAX)) == -1 ) {
-  fprintf(stderr, "Error: can not get stream list\n");
+ printf("stream %i:\n", id);
+ if ( roar_get_stream(con, &s, id) == -1 ) {
+  fprintf(stderr, "Error: can not get stream info\n");
   return;
  }
-
- for (i = 0; i < num; i++) {
-  printf("stream %i:\n", id[i]);
-  if ( roar_get_stream(con, &s, id[i]) == -1 ) {
-   fprintf(stderr, "Error: can not get stream info\n");
-   continue;
-  }
-  printf("Stream direction      : %s\n", roar_dir2str(s.dir));
-
-  if ( roar_stream_get_name(con, &s, name, 1024) == 0 )
-   printf("Stream name           : %s\n", name);
-
-  if ( (int)s.pos_rel_id == -1 ) {
-   printf("Relativ position id   : none (stream not synchronized)\n");
-  } else if ( (int)s.pos_rel_id == id[i] ) {
-   printf("Relativ position id   : %i (self synchronized)\n", s.pos_rel_id);
+ printf("Stream direction      : %s\n", roar_dir2str(s.dir));
+
+ if ( roar_stream_get_name(con, &s, name, 1024) == 0 )
+  printf("Stream name           : %s\n", name);
+
+ if ( (int)s.pos_rel_id == -1 ) {
+  printf("Relativ position id   : none (stream not synchronized)\n");
+ } else if ( (int)s.pos_rel_id == id ) {
+  printf("Relativ position id   : %i (self synchronized)\n", s.pos_rel_id);
+ } else {
+  printf("Relativ position id   : %i (synchronized)\n", s.pos_rel_id);
+ }
+ if ( g_verbose > 1 && s.pos != (uint32_t)-1 ) {
+  if ( s.info.rate && s.info.channels ) {
+   printf("Position              : %lu S (%.3fs)\n", (unsigned long int) s.pos,
+                                   (float)s.pos/(s.info.rate*s.info.channels));
   } else {
-   printf("Relativ position id   : %i (synchronized)\n", s.pos_rel_id);
-  }
-  if ( g_verbose > 1 && s.pos != (uint32_t)-1 ) {
-   if ( s.info.rate && s.info.channels ) {
-    printf("Position              : %lu S (%.3fs)\n", (unsigned long int) s.pos,
-                                    (float)s.pos/(s.info.rate*s.info.channels));
-   } else {
-    printf("Position              : %lu S\n", (unsigned long int) s.pos);
-   }
-  }
-
-  switch (s.dir) {
-   case ROAR_DIR_MIDI_IN:
-   case ROAR_DIR_MIDI_OUT:
-     infotext = " ticks/s";
-    break;
-   case ROAR_DIR_LIGHT_IN:
-   case ROAR_DIR_LIGHT_OUT:
-     infotext = " updates/s";
-    break;
-   default:
-     infotext = " Hz";
-  }
-  if ( s.info.rate )
-   printf("Stream sample rate    : %i%s\n", s.info.rate, infotext);
-  if ( s.info.bits )
-   printf("Stream bits           : %i\n", s.info.bits);
-  if ( s.info.channels )
+   printf("Position              : %lu S\n", (unsigned long int) s.pos);
+  }
+ }
+
+ switch (s.dir) {
+  case ROAR_DIR_MIDI_IN:
+  case ROAR_DIR_MIDI_OUT:
+    infotext = " ticks/s";
+   break;
+  case ROAR_DIR_LIGHT_IN:
+  case ROAR_DIR_LIGHT_OUT:
+    infotext = " updates/s";
+   break;
+  default:
+    infotext = " Hz";
+ }
+ if ( s.info.rate )
+  printf("Stream sample rate    : %i%s\n", s.info.rate, infotext);
+ if ( s.info.bits )
+  printf("Stream bits           : %i\n", s.info.bits);
+ if ( s.info.channels )
   printf("Stream channels       : %i\n", s.info.channels);
 
-  mime = roar_codec2mime(s.info.codec);
-  printf("Stream codec          : %2i (%s%s%s%s)\n", s.info.codec, roar_codec2str(s.info.codec),
-                                       s.info.codec == ROAR_CODEC_DEFAULT ? " native" : "",
-                                       mime == NULL ? "" : " mimetype:",
-                                       mime == NULL ? "" : mime
-                                      );
-  if ( roar_stream_get_info(con, &s, &info) != -1 ) {
-   if ( info.codec != s.info.codec ) {
-    mime = roar_codec2mime(info.codec);
-    printf("Streamed codec        : %2i (%s%s%s%s)\n", info.codec, roar_codec2str(info.codec),
-                                       info.codec == ROAR_CODEC_DEFAULT ? " native" : "",
-                                       mime == NULL ? "" : " mimetype:",
-                                       mime == NULL ? "" : mime
-                                      );
-   }
-
-   if ( g_verbose ) {
-    if ( info.block_size )
-     printf("Stream block size     : %i Byte\n", info.block_size);
-
-    printf("Underruns pre/post    : %i/%i\n",   info.pre_underruns, info.post_underruns);
-    if ( g_verbose > 1 )
-     printf("Stream delay          : %ims (%.2fm)\n",   (int)info.delay/1000, (info.delay*(float)_SPEED_OF_SOUND));
-
-    if ( g_verbose > 1 )
-     printf("Stream mixer          : %i\n",   info.mixer);
-
-    if ( g_verbose > 1 )
-     printf("Stream state          : %s\n",   roar_streamstate2str(info.state));
-
-    if ( g_verbose > 1 )
-     printf("Stream role           : %s\n",   roar_role2str(info.role));
-
-    *flags = 0;
-    if ( info.flags & ROAR_FLAG_PRIMARY )
-     strcat(flags, "primary ");
-    if ( info.flags & ROAR_FLAG_SYNC )
-     strcat(flags, "sync ");
-    if ( info.flags & ROAR_FLAG_OUTPUT )
-     strcat(flags, "output ");
-    if ( info.flags & ROAR_FLAG_SOURCE )
-     strcat(flags, "source ");
-    if ( info.flags & ROAR_FLAG_META )
-     strcat(flags, "meta ");
-    if ( info.flags & ROAR_FLAG_AUTOCONF )
-     strcat(flags, "autoconf ");
-    if ( info.flags & ROAR_FLAG_CLEANMETA )
-     strcat(flags, "cleanmeta ");
-    if ( info.flags & ROAR_FLAG_HWMIXER )
-     strcat(flags, "hwmixer ");
-    if ( info.flags & ROAR_FLAG_PAUSE )
-     strcat(flags, "pause ");
-    if ( info.flags & ROAR_FLAG_MUTE )
-     strcat(flags, "mute ");
-    if ( info.flags & ROAR_FLAG_MMAP )
-     strcat(flags, "mmap ");
-    if ( info.flags & ROAR_FLAG_ANTIECHO )
-     strcat(flags, "antiecho ");
-    if ( info.flags & ROAR_FLAG_VIRTUAL )
-     strcat(flags, "virtual ");
-    if ( info.flags & ROAR_FLAG_RECSOURCE )
-     strcat(flags, "recsource ");
-    if ( info.flags & ROAR_FLAG_PASSMIXER )
-     strcat(flags, "passmixer ");
-    if ( info.flags & ROAR_FLAG_PRETHRU )
-     strcat(flags, "prethru ");
-    if ( info.flags & ROAR_FLAG_IMMUTABLE )
-     strcat(flags, "immutable ");
-    if ( info.flags & ROAR_FLAG_ENHANCE )
-     strcat(flags, "enhance ");
-    if ( info.flags & ROAR_FLAG_SINGLESINK )
-     strcat(flags, "singlesink ");
-
-    printf("Flags                 : %s\n", flags);
-   }
+ mime = roar_codec2mime(s.info.codec);
+ printf("Stream codec          : %2i (%s%s%s%s)\n", s.info.codec, roar_codec2str(s.info.codec),
+                                      s.info.codec == ROAR_CODEC_DEFAULT ? " native" : "",
+                                      mime == NULL ? "" : " mimetype:",
+                                      mime == NULL ? "" : mime
+                                     );
+ if ( roar_stream_get_info(con, &s, &info) != -1 ) {
+  if ( info.codec != s.info.codec ) {
+   mime = roar_codec2mime(info.codec);
+   printf("Streamed codec        : %2i (%s%s%s%s)\n", info.codec, roar_codec2str(info.codec),
+                                      info.codec == ROAR_CODEC_DEFAULT ? " native" : "",
+                                      mime == NULL ? "" : " mimetype:",
+                                      mime == NULL ? "" : mime
+                                     );
   }
 
   if ( g_verbose ) {
-   len = ROAR_MAX_CHANNELS;
-   if ( roar_stream_get_chanmap(con, &s, chanmap, &len) == -1 ) {
-    fprintf(stderr, "Error: can not get stream channel map\n");
-   } else {
-    if ( roardsp_chanlist2str(chanmap, len, buffer, 1024) == -1 ) {
-     fprintf(stderr, "Error: can not convert channel map into string\n");
-    } else {
-     printf("Channel Map           : %s\n", buffer);
-    }
-   }
-  }
-
-  if ( s.dir != ROAR_DIR_THRU ) {
-   display_mixer(con, id[i]);
-   show_meta_all(con, id[i]);
-  }
- }
-
+   if ( info.block_size )
+    printf("Stream block size     : %i Byte\n", info.block_size);
+
+   printf("Underruns pre/post    : %i/%i\n",   info.pre_underruns, info.post_underruns);
+   if ( g_verbose > 1 )
+    printf("Stream delay          : %ims (%.2fm)\n",   (int)info.delay/1000, (info.delay*(float)_SPEED_OF_SOUND));
+
+   if ( g_verbose > 1 )
+    printf("Stream mixer          : %i\n",   info.mixer);
+
+   if ( g_verbose > 1 )
+    printf("Stream state          : %s\n",   roar_streamstate2str(info.state));
+
+   if ( g_verbose > 1 )
+    printf("Stream role           : %s\n",   roar_role2str(info.role));
+
+   *flags = 0;
+   if ( info.flags & ROAR_FLAG_PRIMARY )
+    strcat(flags, "primary ");
+   if ( info.flags & ROAR_FLAG_SYNC )
+    strcat(flags, "sync ");
+   if ( info.flags & ROAR_FLAG_OUTPUT )
+    strcat(flags, "output ");
+   if ( info.flags & ROAR_FLAG_SOURCE )
+    strcat(flags, "source ");
+   if ( info.flags & ROAR_FLAG_META )
+    strcat(flags, "meta ");
+   if ( info.flags & ROAR_FLAG_AUTOCONF )
+    strcat(flags, "autoconf ");
+   if ( info.flags & ROAR_FLAG_CLEANMETA )
+    strcat(flags, "cleanmeta ");
+   if ( info.flags & ROAR_FLAG_HWMIXER )
+    strcat(flags, "hwmixer ");
+   if ( info.flags & ROAR_FLAG_PAUSE )
+    strcat(flags, "pause ");
+   if ( info.flags & ROAR_FLAG_MUTE )
+    strcat(flags, "mute ");
+   if ( info.flags & ROAR_FLAG_MMAP )
+    strcat(flags, "mmap ");
+   if ( info.flags & ROAR_FLAG_ANTIECHO )
+    strcat(flags, "antiecho ");
+   if ( info.flags & ROAR_FLAG_VIRTUAL )
+    strcat(flags, "virtual ");
+   if ( info.flags & ROAR_FLAG_RECSOURCE )
+    strcat(flags, "recsource ");
+   if ( info.flags & ROAR_FLAG_PASSMIXER )
+    strcat(flags, "passmixer ");
+   if ( info.flags & ROAR_FLAG_PRETHRU )
+    strcat(flags, "prethru ");
+   if ( info.flags & ROAR_FLAG_IMMUTABLE )
+    strcat(flags, "immutable ");
+   if ( info.flags & ROAR_FLAG_ENHANCE )
+    strcat(flags, "enhance ");
+   if ( info.flags & ROAR_FLAG_SINGLESINK )
+    strcat(flags, "singlesink ");
+
+   printf("Flags                 : %s\n", flags);
+  }
+ }
+
+ if ( g_verbose ) {
+  len = ROAR_MAX_CHANNELS;
+  if ( roar_stream_get_chanmap(con, &s, chanmap, &len) == -1 ) {
+   fprintf(stderr, "Error: can not get stream channel map\n");
+  } else {
+   if ( roardsp_chanlist2str(chanmap, len, buffer, 1024) == -1 ) {
+    fprintf(stderr, "Error: can not convert channel map into string\n");
+   } else {
+    printf("Channel Map           : %s\n", buffer);
+   }
+  }
+ }
+
+ if ( s.dir != ROAR_DIR_THRU ) {
+  display_mixer(con, id);
+  show_meta_all(con, id);
+ }
 }
 
@@ -1108,6 +1126,10 @@
   } else if ( !strcmp(k, "listclients") ) {
    list_clients(&con);
+  } else if ( !strcmp(k, "clientinfo") ) {
+   display_client(&con, atoi(argv[++i]));
   } else if ( !strcmp(k, "liststreams") ) {
    list_streams(&con);
+  } else if ( !strcmp(k, "streaminfo") ) {
+   display_stream(&con, atoi(argv[++i]));
   } else if ( !strcmp(k, "allinfo") ) {
    server_oinfo(&con, -1);
