[xiph-commits] r17715 - in trunk/ao: doc src/plugins/roar

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Mon Dec 6 11:42:00 PST 2010


Author: xiphmont
Date: 2010-12-06 11:42:00 -0800 (Mon, 06 Dec 2010)
New Revision: 17715

Modified:
   trunk/ao/doc/drivers.html
   trunk/ao/src/plugins/roar/ao_roar.c
Log:
Commit RoarAudio backend driver update + documentation



Modified: trunk/ao/doc/drivers.html
===================================================================
--- trunk/ao/doc/drivers.html	2010-12-03 22:41:50 UTC (rev 17714)
+++ trunk/ao/doc/drivers.html	2010-12-06 19:42:00 UTC (rev 17715)
@@ -223,7 +223,13 @@
 <p>
 <b>Option keys:</b>
 <ul>
-<li>"host" - Specifies Roar server to use.
+<li>"server" - Specifies Roar server to use.
+<li>"host" - Specifies Roar server to use (legacy synonym for 'server').
+<li>"id" - Selects audio device to use for playback by number.  For a roar server, this is mapped to a given output mixer.
+<li>"dev" - Selects audio device to use for playback by name.  For a roar server, this is a number and thus synonymous with 'id' above.
+<li>"stream_name" - descriptive name for this playback stream (eg, the application name).
+<li>"role" - stream type as enumerated by Roar; see RoarAudio documentation.
+
 </ul>
 <p>
 

Modified: trunk/ao/src/plugins/roar/ao_roar.c
===================================================================
--- trunk/ao/src/plugins/roar/ao_roar.c	2010-12-03 22:41:50 UTC (rev 17714)
+++ trunk/ao/src/plugins/roar/ao_roar.c	2010-12-06 19:42:00 UTC (rev 17715)
@@ -33,21 +33,15 @@
 #include <ao/ao.h>
 #include <ao/plugin.h>
 
-static char *ao_roar_options[] = {"host","verbose","quiet","matrix","debug"};
+#define DEFAULT_CLIENT_NAME "libao client"
 
-/*
-typedef struct ao_info {
-        int  type; // live output or file output?
-        char *name; // full name of driver
-        char *short_name; // short name of driver
-        char *author; // driver author
-        char *comment; // driver comment
-        int  preferred_byte_format;
-        int  priority;
-        char **options;
-        int  option_count;
-} ao_info;
-*/
+static char *ao_roar_options[] = {
+  "host", "server",
+  "stream_name",
+  "id", "dev",
+  "role"
+  "verbose", "quiet", "matrix", "debug"
+};
 
 static ao_info ao_roar_info ={
   AO_TYPE_LIVE,
@@ -58,21 +52,25 @@
   AO_FMT_NATIVE,
   50,
   ao_roar_options,
-  5
+  sizeof(ao_roar_options)/sizeof(*ao_roar_options)
 };
 
 
 typedef struct ao_roar_internal {
-  struct roar_vio_calls svio;
-  int svio_p;
+  struct roar_connection con;
+  int con_opened;
+  roar_vs_t * vss;
   char * host;
+  char * mixer;
+  char * client_name;
+  int    role;
 } ao_roar_internal;
 
 
 int ao_plugin_test(void) {
   struct roar_connection con;
 
-  if ( roar_simple_connect(&con, NULL, "libao client") == -1 )
+  if ( roar_simple_connect(&con, NULL, DEFAULT_CLIENT_NAME) == -1 )
     return 0;
 
   if (roar_get_standby(&con)) {
@@ -89,7 +87,40 @@
   return &ao_roar_info;
 }
 
+enum errtype {
+ ERROR,
+ WARN,
+ INFO,
+ VERBOSE,
+ DEBUG
+};
 
+#define armsg(et,text) _ao_roar_err_real(device, __LINE__, (et), (text), error)
+static inline void _ao_roar_err_real(ao_device * device, long line, enum errtype errtype, const char * text, int error) {
+ const char * errmsg = roar_vs_strerr(error);
+#define _format "%s: %s"
+#define _format_dbg _format " at line %li"
+
+ switch (errtype) {
+  case ERROR:
+    aerror(_format "\n", text, errmsg, line);
+   break;
+  case WARN:
+    awarn(_format "\n", text, errmsg, line);
+   break;
+  case INFO:
+    ainfo(_format "\n", text, errmsg, line);
+   break;
+  case VERBOSE:
+    averbose(_format_dbg "\n", text, errmsg, line);
+   break;
+  case DEBUG:
+    adebug(_format_dbg "\n", text, errmsg, line);
+   break;
+ }
+}
+
+
 int ao_plugin_device_init(ao_device * device) {
   ao_roar_internal * internal;
 
@@ -98,8 +129,15 @@
   if (internal == NULL)
     return 0;
 
-  internal->host = NULL;
+  internal->con_opened  = 0;
 
+  internal->vss         = NULL;
+
+  internal->host        = NULL;
+  internal->mixer       = NULL;
+  internal->client_name = strdup(DEFAULT_CLIENT_NAME);
+  internal->role        = ROAR_ROLE_UNKNOWN;
+
   device->internal = internal;
   device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
 
@@ -109,22 +147,132 @@
 int ao_plugin_set_option(ao_device * device, const char * key, const char * value) {
   ao_roar_internal * internal = (ao_roar_internal *) device->internal;
 
-  if ( strcmp(key, "host") == 0 ) {
+  if ( !strcmp(key, "host") || !strcmp(key, "server") ) {
     if(internal->host) free(internal->host);
     internal->host = strdup(value);
+  } else if ( !strcmp(key, "id") || !strcmp(key, "dev") ) {
+    if(internal->mixer) free(internal->mixer);
+    internal->mixer = strdup(value);
+  } else if ( !strcmp(key, "stream_name") ) {
+    if(internal->client_name) free(internal->client_name);
+    internal->client_name = strdup(value);
+  } else if ( !strcmp(key, "role") ) {
+    internal->role = roar_str2role(value);
   }
 
   return 1;
 }
 
+static int ao_roar_con_open (ao_roar_internal * internal) {
+  if ( internal->con_opened )
+    return 1;
+
+  if ( roar_simple_connect(&(internal->con), internal->host, internal->client_name) == -1 )
+    return 0;
+
+  internal->con_opened = 1;
+
+  return 1;
+}
+
+#if defined(ROAR_FT_FUNC_LIST_FILTERED) && defined(ROAR_VS_CMD_SET_MIXER)
+static int ao_roar_find_mixer (ao_roar_internal * internal) {
+  struct roar_stream stream;
+  char name[80];
+  int id[ROAR_STREAMS_MAX];
+  int num;
+  int i;
+  int ret;
+
+  if ( internal->mixer == NULL )
+    return -1;
+
+  // test if mixer is numeric...
+  ret = atoi(internal->mixer);
+
+  if ( ret > 0 ) {
+    return ret;
+  } else if ( ret == 0 && internal->mixer[0] == '0' ) {
+    return 0;
+  }
+
+  if ( (num = roar_list_filtered(&(internal->con), id, ROAR_STREAMS_MAX, // normal parameters,
+                                 ROAR_CMD_LIST_STREAMS,      // normaly hidden by
+                                                             // roar_list_streams().
+                                 ROAR_CTL_FILTER_DIR,        // extra parameter: filter on /dir/
+                                 ROAR_CTL_CMP_EQ,            // extra parameter: ... that must be equal ...
+                                 ROAR_DIR_MIXING)) == -1 ) { // extra parameter: to this.
+    return -1;
+  }
+
+  for (i = 0; i < num; i++) {
+    if ( roar_stream_new_by_id(&stream, id[i]) == -1 )
+      continue;
+
+    if ( roar_stream_get_name(&(internal->con), &stream, name, sizeof(name)) != 0 )
+      continue;
+
+    if ( !strncasecmp(name, internal->mixer, sizeof(name)) )
+      return id[i];
+  }
+
+  return -1;
+}
+#endif
+
 int ao_plugin_open(ao_device * device, ao_sample_format * format) {
   ao_roar_internal * internal = (ao_roar_internal *) device->internal;
+  struct roar_audio_info info;
   char * map = NULL;
+  int codec = ROAR_CODEC_DEFAULT;
+  int mixer;
+  int error = -1;
 
-  if ( roar_vio_simple_stream(&(internal->svio), format->rate, format->channels, format->bits,
-                             ROAR_CODEC_DEFAULT, internal->host, ROAR_DIR_PLAY, "libao client") == -1 )
+  info.rate     = format->rate;
+  info.channels = format->channels;
+  info.codec    = codec;
+  info.bits     = format->bits;
+
+  if ( !ao_roar_con_open(internal) )
     return 0;
-  internal->svio_p=1;
+
+  internal->vss = roar_vs_new_from_con(&(internal->con), &error);
+
+  if ( internal->vss == NULL ) {
+    armsg(ERROR, "Can not create VS object");
+    return 0;
+  }
+
+#if defined(ROAR_FT_FUNC_LIST_FILTERED) && defined(ROAR_VS_CMD_SET_MIXER)
+  mixer = ao_roar_find_mixer(internal);
+
+  if ( mixer != -1 ) {
+    if ( roar_vs_ctl(internal->vss, ROAR_VS_CMD_SET_MIXER, &mixer, &error) == -1 ) {
+     roar_vs_close(internal->vss, ROAR_VS_FALSE, NULL);
+     internal->vss = NULL;
+     armsg(ERROR, "Can not set mixer");
+     return 0;
+    }
+    armsg(WARN, "Installed version of libroar does not support VS CTL, mixer setting is ignored.");
+  }
+#else
+  if ( internal->mixer != NULL ) {
+    error = ROAR_ERROR_NOTSUP;
+    armsg(WARN, "Installed version of libroar does not support VS CTL, mixer setting is ignored");
+  }
+#endif
+
+  if ( roar_vs_stream(internal->vss, &info, ROAR_DIR_PLAY, &error) == -1 ) {
+    roar_vs_close(internal->vss, ROAR_VS_FALSE, NULL);
+    internal->vss = NULL;
+    armsg(ERROR, "Can not start playback");
+    return 0;
+  }
+
+  if ( internal->role != ROAR_ROLE_UNKNOWN )
+    if ( roar_vs_role(internal->vss, internal->role, &error) == -1 )
+      armsg(WARN, "Can not set stream role");
+
   device->driver_byte_format = AO_FMT_NATIVE;
 
   if(!device->inter_matrix){ /* It would be set if an app or user force-sets the mapping; don't overwrite! */
@@ -147,8 +295,13 @@
 
 int ao_plugin_play(ao_device * device, const char * output_samples, uint_32 num_bytes) {
   ao_roar_internal * internal = (ao_roar_internal *) device->internal;
+  ssize_t ret;
 
-  if (roar_vio_write(&(internal->svio), (char*)output_samples, num_bytes) == -1) {
+  // TODO: handle short writes.
+
+  ret = roar_vs_write(internal->vss, output_samples, num_bytes, NULL);
+
+  if ( ret == -1 ) {
     return 0;
   } else {
     return 1;
@@ -159,10 +312,16 @@
 int ao_plugin_close(ao_device * device) {
   ao_roar_internal * internal = (ao_roar_internal *) device->internal;
 
-  if(internal->svio_p)
-    roar_vio_close(&(internal->svio));
-  internal->svio_p=0;
+  if(internal->vss != NULL)
+    roar_vs_close(internal->vss, ROAR_VS_FALSE, NULL);
 
+  internal->vss = NULL;
+
+  if (internal->con_opened)
+   roar_disconnect(&(internal->con));
+
+  internal->con_opened = 0;
+
   return 1;
 }
 
@@ -173,6 +332,12 @@
   if( internal->host != NULL )
     free(internal->host);
 
+  if( internal->mixer != NULL )
+    free(internal->mixer);
+
+  if( internal->client_name != NULL )
+    free(internal->client_name);
+
   free(internal);
   device->internal=NULL;
 }



More information about the commits mailing list