[xiph-commits] r16850 - trunk/ao/src/plugins/arts

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Fri Jan 29 04:09:58 PST 2010


Author: xiphmont
Date: 2010-01-29 04:09:58 -0800 (Fri, 29 Jan 2010)
New Revision: 16850

Modified:
   trunk/ao/src/plugins/arts/ao_arts.c
Log:
Add locking to the aRts C API global init()/free() state, track/lock 
server connection across multiple device opens.  This addesses a raft of 
concurrency concerns in aRts support.



Modified: trunk/ao/src/plugins/arts/ao_arts.c
===================================================================
--- trunk/ao/src/plugins/arts/ao_arts.c	2010-01-29 11:13:12 UTC (rev 16849)
+++ trunk/ao/src/plugins/arts/ao_arts.c	2010-01-29 12:09:58 UTC (rev 16850)
@@ -29,11 +29,16 @@
 
 #include <stdio.h>
 #include <errno.h>
+#include <pthread.h>
 
 #include <artsc.h>
 #include <ao/ao.h>
 #include <ao/plugin.h>
 
+/* we must serialize server setup/teardown communication as its state
+   is process-global */
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static int server_open_count = 0;
 
 static char *ao_arts_options[] = {"matrix","verbose","quiet","debug"};
 static ao_info ao_arts_info =
@@ -53,7 +58,6 @@
         4
 };
 
-
 typedef struct ao_arts_internal
 {
 	arts_stream_t stream;
@@ -62,120 +66,142 @@
 
 int ao_plugin_test()
 {
-	if (arts_init() == 0) {
+  pthread_mutex_lock(&mutex);
+
+  if (server_open_count || arts_init() == 0) {
+    server_open_count++;
+
 #ifdef HAVE_ARTS_SUSPENDED
-		if (arts_suspended() == 1) {
-			arts_free();
-			return 0;
-		}
+    if (arts_suspended() == 1) {
+      server_open_count--;
+      if(!server_open_count)arts_free();
+      pthread_mutex_unlock(&mutex);
+      return 0;
+    }
 #endif
-		arts_free();
-		return 1;
-	} else
-		return 0;
+    server_open_count--;
+    if(!server_open_count)arts_free();
+    arts_free();
+    pthread_mutex_unlock(&mutex);
+    return 1;
+  }
+  pthread_mutex_unlock(&mutex);
+  return 0;
 }
 
 
 ao_info *ao_plugin_driver_info(void)
 {
-	return &ao_arts_info;
+  return &ao_arts_info;
 }
 
 
 int ao_plugin_device_init(ao_device *device)
 {
-	ao_arts_internal *internal;
+  ao_arts_internal *internal;
 
-	internal = (ao_arts_internal *) calloc(1,sizeof(ao_arts_internal));
+  internal = (ao_arts_internal *) calloc(1,sizeof(ao_arts_internal));
 
-	if (internal == NULL)
-		return 0; /* Could not initialize device memory */
+  if (internal == NULL)
+    return 0; /* Could not initialize device memory */
 
-	device->internal = internal;
+  device->internal = internal;
 
-	return 1; /* Memory alloc successful */
+  return 1; /* Memory alloc successful */
 }
 
 
 int ao_plugin_set_option(ao_device *device, const char *key, const char *value)
 {
-	return 1; /* No options */
+  return 1; /* No options */
 }
 
 int ao_plugin_open(ao_device *device, ao_sample_format *format)
 {
-	ao_arts_internal *internal = (ao_arts_internal *) device->internal;
-	int errorcode;
+  ao_arts_internal *internal = (ao_arts_internal *) device->internal;
+  int errorcode=0;
 
-        if(format->channels<1 || format->channels>2){
-          /* the docs aren't kidding here--- feed it more than 2
-             channels and the server simply stops answering; the
-             connection freezes. */
-          aerror("Cannot handle more than 2 channels\n");
-          return 0;
-        }
+  if(format->channels<1 || format->channels>2){
+    /* the docs aren't kidding here--- feed it more than 2
+       channels and the server simply stops answering; the
+       connection freezes. */
+    aerror("Cannot handle more than 2 channels\n");
+    return 0;
+  }
 
-	errorcode = arts_init();
+  pthread_mutex_lock(&mutex);
+  if(!server_open_count)
+    errorcode = arts_init();
 
-	if (0 != errorcode)
-	{
-          aerror("Could not connect to server => %s.\n",arts_error_text(errorcode));
-          return 0; /* Could not connect to server */
-	}
+  if (0 != errorcode){
+    pthread_mutex_unlock(&mutex);
+    aerror("Could not connect to server => %s.\n",arts_error_text(errorcode));
+    return 0; /* Could not connect to server */
+  }else
+    server_open_count++;
+  pthread_mutex_unlock(&mutex);
 
-	device->driver_byte_format = AO_FMT_NATIVE;
 
-	internal->stream = arts_play_stream(format->rate,
-					    format->bits,
-					    format->channels,
-					    "libao stream");
-        if(!internal->stream){
-          arts_free();
-          aerror("Could not open audio stream.\n");
-          return 0;
-        }
+  device->driver_byte_format = AO_FMT_NATIVE;
+  internal->stream = arts_play_stream(format->rate,
+                                      format->bits,
+                                      format->channels,
+                                      "libao stream");
+  if(!internal->stream){
+    pthread_mutex_lock(&mutex);
+    server_open_count--;
+    if(!server_open_count)arts_free();
+    pthread_mutex_unlock(&mutex);
 
-        if(!device->output_matrix){
-          /* set up out matrix such that users are warned about > stereo playback */
-          if(format->channels<=2)
-            device->output_matrix=strdup("L,R");
-          //else no matrix, which results in a warning
-        }
+    aerror("Could not open audio stream.\n");
+    return 0;
+  }
 
-	return 1;
+  if(!device->output_matrix){
+    /* set up out matrix such that users are warned about > stereo playback */
+    if(format->channels<=2)
+      device->output_matrix=strdup("L,R");
+    //else no matrix, which results in a warning
+  }
+
+  return 1;
 }
 
 
 int ao_plugin_play(ao_device *device, const char *output_samples,
 		uint_32 num_bytes)
 {
-	ao_arts_internal *internal = (ao_arts_internal *) device->internal;
+  ao_arts_internal *internal = (ao_arts_internal *) device->internal;
 
-	if (arts_write(internal->stream, output_samples,
-		       num_bytes) < num_bytes)
-		return 0;
-	else
-		return 1;
+  if (arts_write(internal->stream, output_samples,
+                 num_bytes) < num_bytes)
+    return 0;
+  else
+    return 1;
 }
 
 
 int ao_plugin_close(ao_device *device)
 {
-	ao_arts_internal *internal = (ao_arts_internal *) device->internal;
-        if(internal->stream)
-          arts_close_stream(internal->stream);
-        internal->stream = NULL;
-	arts_free();
+  ao_arts_internal *internal = (ao_arts_internal *) device->internal;
+  if(internal->stream)
+    arts_close_stream(internal->stream);
+  internal->stream = NULL;
 
-	return 1;
+  pthread_mutex_lock(&mutex);
+  server_open_count--;
+  if(!server_open_count)arts_free();
+  pthread_mutex_unlock(&mutex);
+
+  return 1;
 }
 
 
 void ao_plugin_device_clear(ao_device *device)
 {
-	ao_arts_internal *internal = (ao_arts_internal *) device->internal;
+  ao_arts_internal *internal = (ao_arts_internal *) device->internal;
 
-	if(internal)
-          free(internal);
-        device->internal=NULL;
+  if(internal)
+    free(internal);
+  device->internal=NULL;
 }



More information about the commits mailing list