[libgnome] Use libcanberra for sound



commit 0c5aeb7dbfefae1837e559b6dc46871b55a9b322
Author: Christian Persch <chpe gnome org>
Date:   Mon Nov 30 15:33:53 2009 +0100

    Use libcanberra for sound
    
    Bug #603198, bug #603349.

 NEWS                   |   11 +
 configure.in           |   23 ++-
 libgnome/gnome-sound.c |  570 +++++------------------------------------------
 3 files changed, 89 insertions(+), 515 deletions(-)
---
diff --git a/NEWS b/NEWS
index 2c993d7..02f8d0d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,14 @@
+libgnome 2.32.0
+
+gnome-sound APIs now use libcanberra internally. That means that
+gnome_sound_connection_get() and will always return error (-1), and
+gnome_sound_sample_load also always return -1 but still cache
+the sample using the libcanberra API.
+libgnome continues to link to libesound and libaudiofile for ABI
+compatibility; use --disable-esd to remove this dependency.
+(#603198, #603349)
+
+
 libgnome 2.30.0
 
 * Enable silent build using AM_SILENT_RULES (Christian Persch)
diff --git a/configure.in b/configure.in
index dbc0612..76ac84f 100644
--- a/configure.in
+++ b/configure.in
@@ -24,6 +24,7 @@ m4_define([gnome_vfs_required_version], [2.5.3])
 m4_define([libbonobo_required_version], [2.13.0])
 m4_define([gobject_required_version], [2.0.0])
 m4_define([gio_required_version],       [2.16.0])
+m4_define([canberra_required_version], [0])
 
 dnl libtool versioning from libgnome
 m4_define([libgnome_current], [m4_eval(100 * libgnome_minor_version + libgnome_micro_version - libgnome_interface_age)])
@@ -152,17 +153,27 @@ AC_ARG_ENABLE([esd],
     [enable_esd=yes])
 AC_MSG_RESULT([$enable_esd])
 
+ESD_DEPS=""
+SOUND_MODULES=""
 if test x$enable_esd = xyes; then
 	SOUND_MODULES="esound >= esound_required_version dnl
 		audiofile >= audiofile_required_version"
-	PKG_CHECK_MODULES(SOUND_TEST, [$SOUND_MODULES])
-	AC_DEFINE(HAVE_LIBAUDIOFILE,, [Compile with audiofile support])
-	AC_DEFINE(HAVE_ESD,, [Compile with esd support])
 	ESD_DEPS="esound"
-else
-	ESD_DEPS=""
-	SOUND_MODULES=""
 fi
+
+AC_MSG_CHECKING([whether to use libcanberra])
+AC_ARG_ENABLE([canberra],
+    AS_HELP_STRING([--enable-canberra],[Enable canberra (default=yes)]),
+    [],[enable_canberra=yes])
+AC_MSG_RESULT([$enable_canberra])
+
+if test "$enable_canberra" = "yes"; then
+  SOUND_MODULES="$SOUND_MODULES libcanberra >= canberra_required_version"
+  ESD_DEPS="$ESD_DEPS libcanberra >= canberra_required_version"
+
+  AC_DEFINE([HAVE_CANBERRA],[1],[Define if canberra is enabled])
+fi
+
 AC_SUBST(ESD_DEPS)
 
 PKG_CHECK_MODULES(LIBGNOME, dnl
diff --git a/libgnome/gnome-sound.c b/libgnome/gnome-sound.c
index e44cb32..1a10f60 100644
--- a/libgnome/gnome-sound.c
+++ b/libgnome/gnome-sound.c
@@ -37,524 +37,94 @@
 #include <time.h>
 #include <glib.h>
 
-#ifdef HAVE_ESD
-#include <esd.h>
+#ifdef HAVE_CANBERRA
+#include <canberra.h>
 #endif
 
-#ifdef HAVE_ESD
-static char *esound_hostname = NULL;
-static int gnome_sound_connection = -1;
-static gboolean gnome_sound_enabled = TRUE;
-#endif
-
-typedef struct _sample
-  {
-    int rate, format, samples, id, size;
-    short *data;
-  }
-GnomeSoundSample;
-
-#ifndef HAVE_LIBAUDIOFILE
-typedef struct _WAVFormatChunk
-  {
-    char chunkID[4];
-    int chunkSize;
+G_GNUC_INTERNAL void _gnome_sound_set_enabled (gboolean);
 
-    unsigned int dwSamplesPerSec;
-    unsigned int dwAvgBytesPerSec;
-    short wFormatTag;
-    unsigned short wChannels;
-    unsigned short wBlockAlign;
-    unsigned short wBitsPerSample;
-  }
-WAVFormatChunk;
+#ifdef HAVE_CANBERRA
 
-#ifdef WORDS_BIGENDIAN
-#define SWAP_SHORT( x ) x = ( ( x & 0x00ff ) << 8 ) | ( ( x >> 8 ) & 0x00ff )
-#define SWAP_LONG( x ) x = ( ( ( x & 0x000000ff ) << 24 ) |\
-( ( x & 0x0000ff00 ) << 8 ) |\
-( ( x & 0x00ff0000 ) >> 8 ) |\
-( ( x & 0xff000000 ) >> 24 ) )
-#endif
+static gboolean gnome_sound_enabled = TRUE;
+static ca_context *global_context = NULL;
 
-/**
- * gnome_sound_sample_load_wav:
- * @file: filename to try loading a WAV file from.
- *
- * Used to load a .wav file into esound.
- *
- * Returns a GnomeSoundSample or NULL if file did not exist.
- *
- */
-#ifdef HAVE_ESD
-static GnomeSoundSample *
-gnome_sound_sample_load_wav(const char *file)
+static ca_context *
+get_ca_context (const char *hostname)
 {
-  FILE *f;
-  GnomeSoundSample *s;
-  char buf[4];
-  WAVFormatChunk fmt;
-  int skipl = 0;
-  int skipr = 0;
-  char bytes = 0;
-  char stereo = 0;
-  int len;
+  int rv;
 
-  /* int                 count; */
+  if (global_context != NULL)
+    return global_context;
 
-  f = fopen (file, "r");
-  if (!f)
-    return NULL;
-  s = g_try_malloc (sizeof (GnomeSoundSample));
-  if (!s)
-    {
-      fclose (f);
-      return NULL;
-    }
-  s->rate = 44100;
-  s->format = ESD_STREAM | ESD_PLAY;
-  s->samples = 0;
-  s->data = NULL;
-  s->id = 0;
-  fread (buf, 1, 4, f);
-  if ((buf[0] != 'R') ||
-      (buf[1] != 'I') ||
-      (buf[2] != 'F') ||
-      (buf[3] != 'F'))
+  if ((rv = ca_context_create (&global_context)) != CA_SUCCESS)
     {
-      /* not a RIFF WAV file */
-      fclose (f);
-      g_free (s);
+      g_warning ("Failed to create canberra context: %s\n", ca_strerror (rv));
+      global_context = NULL;
       return NULL;
     }
-  fread (buf, 1, 4, f);
-  fread (buf, 1, 4, f);
-  fread (fmt.chunkID, 1, 4, f);
-  fread (&(fmt.chunkSize), 1, 4, f);
-
-#ifdef WORDS_BIGENDIAN
-  SWAP_LONG (fmt.chunkSize);
-#endif
 
-  if ((fmt.chunkID[0] == 'f') &&
-      (fmt.chunkID[1] == 'm') &&
-      (fmt.chunkID[2] == 't') &&
-      (fmt.chunkID[3] == ' ') &&
-      16 == fmt.chunkSize)
-    /* fmt chunk */
+  if (hostname != NULL)
     {
-      fread (&(fmt.wFormatTag), 1, 2, f);
-      fread (&(fmt.wChannels), 1, 2, f);
-      fread (&(fmt.dwSamplesPerSec), 1, 4, f);
-      fread (&(fmt.dwAvgBytesPerSec), 1, 4, f);
-      fread (&(fmt.wBlockAlign), 1, 2, f);
-      fread (&(fmt.wBitsPerSample), 1, 2, f);
-#ifdef WORDS_BIGENDIAN
-      SWAP_SHORT (fmt.wFormatTag);
-      SWAP_SHORT (fmt.wChannels);
-      SWAP_LONG (fmt.dwSamplesPerSec);
-      SWAP_LONG (fmt.dwAvgBytesPerSec);
-      SWAP_SHORT (fmt.wBlockAlign);
-      SWAP_SHORT (fmt.wBitsPerSample);
-#endif
-
-      if (fmt.wFormatTag != 1)
-	{
-	  /* unknown WAV encoding format - exit */
-	  fclose (f);
-	  g_free (s);
-	  return NULL;
-	}
-      skipl = 0;
-      skipr = 0;
-      bytes = 0;
-      stereo = 0;
-      if (fmt.wChannels == 1)
-	s->format |= ESD_MONO;
-      else if (fmt.wChannels == 2)
-	{
-	  stereo = 1;
-	  s->format |= ESD_STEREO;
-	}
-      else
-	{
-	  stereo = 1;
-	  s->format |= ESD_STEREO;
-	  if (fmt.wChannels == 3)
-	    {
-	      skipl = 0;
-	      skipr = 1;
-	    }
-	  else if (fmt.wChannels == 4)
-	    {
-	      skipl = 0;
-	      skipr = 2;
-	    }
-	  else if (fmt.wChannels == 4)
-	    {
-	      skipl = 0;
-	      skipr = 2;
-	    }
-	  else if (fmt.wChannels == 6)
-	    {
-	      skipl = 3;
-	      skipr = 1;
-	    }
-	  else
-	    {
-	      /* unknown channel encoding */
-	      fclose (f);
-	      g_free (s);
-	      return NULL;
-	    }
-	}
-      s->rate = fmt.dwSamplesPerSec;
-      if (fmt.wBitsPerSample <= 8)
-	{
-	  bytes = 1;
-	  s->format |= ESD_BITS8;
-	}
-      else if (fmt.wBitsPerSample <= 16)
-	s->format |= ESD_BITS16;
-      else
-	{
-	  /* unknown bits encoding encoding */
-	  fclose (f);
-	  g_free (s);
-	  return NULL;
-	}
+      ca_context_change_props (global_context,
+                               CA_PROP_APPLICATION_PROCESS_HOST, hostname,
+                               NULL);
     }
-  for (;;)
-    {
-      if (fread (buf, 1, 4, f) &&
-	  fread (&len, 4, 1, f))
-	{
-#ifdef WORDS_BIGENDIAN
-	  SWAP_LONG (len);
-#endif
-
-	  if ((buf[0] != 'd') ||
-	      (buf[1] != 'a') ||
-	      (buf[2] != 't') ||
-	      (buf[3] != 'a'))
-	    fseek (f, len, SEEK_CUR);
-	  else
-	    {
-	      s->data = g_try_malloc (len);
-	      if (!s->data)
-		{
-		  fclose (f);
-		  g_free (s);
-		  return NULL;
-		}
-	      if ((skipl == 0) && (skipr == 0))
-		{
-		  fread (s->data, len, 1, f);
-#ifdef WORDS_BIGENDIAN
-		  if (fmt.wBitsPerSample > 8 && fmt.wBitsPerSample <= 16)
-		    {
-		      char *tmp;
-		      char tmpval;
-		      int i;
 
-		      tmp = (char *) (s->data);
-
-		      for (i = 0; i < len; i++)
-			{
-			  tmpval = tmp[i];
-			  tmp[i] = tmp[i + 1];
-			  tmp[i + 1] = tmpval;
-			}
-		    }
-#endif
-		}
-	      else
-		{
-		}
-	      s->samples = len;
-	      if (stereo)
-		s->samples /= 2;
-	      if (!bytes)
-		s->samples /= 2;
-	      fclose (f);
-	      return s;
-	    }
-	}
-      else
-	{
-	  fclose (f);
-	  return NULL;
-	}
-    }
-  fclose (f);
-  g_free (s);
-  g_free (s->data);
-
-  return NULL;
-}
-#endif
-#endif
-
-#ifdef HAVE_ESD
-/*
- * This does delayed initialization of Esound
- */
-static gboolean
-use_sound (void)
-{
-  if (!gnome_sound_enabled)
-    return FALSE;
-
-  if (gnome_sound_connection == -1){
-      gnome_sound_connection = esd_open_sound (esound_hostname);
-  }
-
-  return gnome_sound_connection >= 0;
+  return global_context;
 }
 
-static void
-close_sound_connection (void)
-{
-  if(gnome_sound_connection >= 0){
-    esd_close(gnome_sound_connection);
-    gnome_sound_connection = -1;
-  }
-}
 #endif
 
-G_GNUC_INTERNAL void _gnome_sound_set_enabled (gboolean);
-
 void G_GNUC_INTERNAL
 _gnome_sound_set_enabled (gboolean enabled)
 {
-#ifdef HAVE_ESD
+#ifdef HAVE_CANBERRA
   gnome_sound_enabled = enabled;
-  if (!enabled) {
-    close_sound_connection();
-  }
-#endif
-}
-
-#if defined(HAVE_LIBAUDIOFILE) && defined(HAVE_ESD)
-#include <audiofile.h>
-
-static GnomeSoundSample *
-gnome_sound_sample_load_audiofile(const char *file)
-{
-  AFfilehandle in_file;
-  GnomeSoundSample *s = NULL;
-  int in_format = -1, in_width = -1, in_channels;
-  double in_rate;
-  int bytes_per_frame;
-  AFframecount frame_count, frames_read;
-
-  int out_bits, out_channels, out_rate;
-  int out_mode = ESD_STREAM, out_func = ESD_PLAY;
-  esd_format_t out_format;
-
-  in_file = afOpenFile(file, "r", NULL);
-  if(!in_file)
-    return NULL;
-
-  frame_count = afGetFrameCount(in_file, AF_DEFAULT_TRACK);
-  in_channels = afGetChannels(in_file, AF_DEFAULT_TRACK);
-  in_rate = afGetRate (in_file, AF_DEFAULT_TRACK);
-  afGetSampleFormat (in_file, AF_DEFAULT_TRACK, &in_format, &in_width);
-  if (in_width == 8)
-    out_bits = ESD_BITS8;
-  else if (in_width == 16)
-    out_bits = ESD_BITS16;
-  else {
-      g_warning ("only sample widths of 8 and 16 supported");
-      goto error_case;
-  }
-
-  if (frame_count == -1 ||
-      in_channels == -1 ||
-      in_rate == -1 ||
-      in_format == -1 ||
-      in_width == -1) {
-      g_warning ("Default track not found");
-      goto error_case;
-  }
-
-  bytes_per_frame = in_width / 8;
-
-  if (in_channels == 1)
-    out_channels = ESD_MONO;
-  else if (in_channels == 2)
-    out_channels = ESD_STEREO;
-  else {
-      g_warning ("only 1 or 2 channel samples supported");
-      goto error_case;
-  }
-
-  out_format = out_bits | out_channels | out_mode | out_func;
-
-  out_rate = (int) in_rate;
-
-  s = g_new0 (GnomeSoundSample, 1);
-
-  s->rate = out_rate;
-  s->format = out_format;
-  s->samples = frame_count;
-  s->data = g_try_malloc(frame_count * in_channels * bytes_per_frame);
-  s->id = 0;
-
-  if (!s->data) {
-    g_free (s);
-    s = NULL;
-    goto error_case;
-  }
-
-  frames_read = afReadFrames(in_file, AF_DEFAULT_TRACK, s->data,
-			     frame_count * in_channels);
-
- error_case:
-  afCloseFile(in_file);
-
-  return s;
-}
 #endif
-
-#ifdef HAVE_ESD
-static int
-send_all (int fd, const char *buf, size_t buflen)
-{
-	GPollFD pfd[1];
-	size_t nwritten = 0;
-	int flags, rv;
-	ssize_t n;
-	
-	if ((flags = fcntl (fd, F_GETFL)) == -1)
-		return -1;
-	
-	fcntl (fd, F_SETFL, flags | O_NONBLOCK);
-	
-	pfd[0].events = G_IO_OUT;
-	pfd[0].fd = fd;
-	
-	do {
-		do {
-			pfd[0].revents = 0;
-			rv = g_poll (pfd, 1, 100);
-		} while (rv == -1 && (errno == EINTR || errno == EAGAIN));
-		
-		if (rv == -1) {
-			if (errno != EBADF) {
-				rv = errno;
-				esd_close (fd);
-				errno = rv;
-			}
-			
-			fd = -1;
-			break;
-		} else if (rv < 1 || (pfd[0].revents & (G_IO_ERR | G_IO_HUP | G_IO_OUT)) != G_IO_OUT) {
-			/* we /just/ lost the esd connection */
-			esd_close (fd);
-			fd = -1;
-			break;
-		} else {
-			/* socket is ready for writing */
-			do {
-				n = write (fd, buf + nwritten, buflen - nwritten);
-			} while (n == -1 && errno == EINTR);
-			
-			if (n == -1) {
-				rv = errno;
-				esd_close (fd);
-				errno = rv;
-				fd = -1;
-				break;
-			}
-			
-			nwritten += n;
-		}
-	} while (nwritten < buflen);
-	
-	if (fd != -1 && flags != -1)
-		fcntl (fd, F_SETFL, flags);
-	
-	return fd;
 }
-#endif
 
 /**
  * gnome_sound_sample_load:
  * @sample_name: The name of the sample.
  * @filename: The filename where the audio is stored.
  *
- * Loads the audio from @filename and load it into the esd cache for later
+ * Loads the audio from @filename and load it into the canberra cache for later
  * playing. Programs will rarely want to call this function directly. Use
  * gnome_sound_play() instead for fire and forget sound playing.
  *
- * Returns: The esound sample_id or %-1 if the sample was unable to be cached
- * for esound.
+ * Returns: -1 or -2
  *
  * @Deprecated: 2.30: Use ca_context_cache() or ca_context_cache_full() instead
  */
 int
 gnome_sound_sample_load(const char *sample_name, const char *filename)
 {
-#ifdef HAVE_ESD
-  GnomeSoundSample *s = NULL;
-  int sample_id;
-  int size;
-  int confirm = 0;
+#ifdef HAVE_CANBERRA
+  ca_context *context;
+  int rv;
+
+  g_return_val_if_fail (sample_name != NULL, -2);
 
-  if (!use_sound ())
+  if (!gnome_sound_enabled)
     return -2;
 
   if(!filename || !*filename)
     return -2;
 
-#ifdef HAVE_LIBAUDIOFILE
-  s = gnome_sound_sample_load_audiofile(filename);
-#else
-  s = gnome_sound_sample_load_wav(filename);
-#endif
-  if(s)
-    goto playsamp;
-
-  /* XXX: Add handlers for more formats here */
-
- playsamp:
-  if (!s)
+  if ((context = get_ca_context (NULL)) == NULL)
     return -1;
 
-  size = s->samples;
-  if (s->format & ESD_STEREO)
-    size *= 2;
-  if (s->format & ESD_BITS16)
-    size *= 2;
-
-  if (gnome_sound_connection >= 0)
-    {
-      if (s->data)
-	{
-	  /* "name" of all samples is currently "E", should be name of sound
-	   * file, or event type, for later identification */
-	  s->id = esd_sample_cache (gnome_sound_connection, s->format, s->rate,
-				    size, (char *)sample_name);
-	  
-	  gnome_sound_connection = send_all (gnome_sound_connection, (const char *) s->data, size);
-	  if (gnome_sound_connection != -1)
-	    confirm = esd_confirm_sample_cache (gnome_sound_connection);
-	  
-	  if (s->id <= 0 || confirm != s->id)
-	    {
-	      g_warning ("error caching sample <%d>!\n", s->id);
-	      s->id = 0;
-	    }
-	}
-    }
-
-  sample_id = s->id;
+  rv = ca_context_cache (context,
+                         CA_PROP_MEDIA_NAME, sample_name,
+                         CA_PROP_MEDIA_FILENAME, filename,
+                         NULL);
+  
 
-  g_free(s->data);
-  g_free(s);
-
-  return sample_id;
+  if (rv != CA_SUCCESS)
+    g_warning ("Failed to cache sample '%s' from '%s': %s\n",
+               sample_name, filename, ca_strerror (rv));
+                    
+  return -1;
 #else
   return -1;
 #endif
@@ -572,32 +142,26 @@ gnome_sound_sample_load(const char *sample_name, const char *filename)
 void
 gnome_sound_play (const char * filename)
 {
-#ifdef HAVE_ESD
-  char buf[256];
-  int sample;
-  static guint cookie = 0;
+#ifdef HAVE_CANBERRA
+  ca_context *context;
+  int rv;
 
-  if(!use_sound ())
+  if (!gnome_sound_enabled)
     return;
 
-  if (cookie == 0)
-	  cookie = rand ();
-
-  g_snprintf(buf, sizeof(buf), "%d-%u-%d",
-	     getpid(), cookie++, rand ());
+  if(!filename || !*filename)
+    return;
 
-  /* overflow, make sure we don't reinit with rand again */
-  if (cookie == 0)
-	  cookie = 1;
+  if ((context = get_ca_context (NULL)) == NULL)
+    return;
 
-  sample = gnome_sound_sample_load (buf, filename);
+  rv = ca_context_play (context, 0,
+                        CA_PROP_MEDIA_FILENAME, filename,
+                        NULL);
 
-  if (gnome_sound_connection != -1 && sample > 0)
-    {
-      esd_sample_play(gnome_sound_connection, sample);
-      fsync (gnome_sound_connection);
-      esd_sample_free(gnome_sound_connection, sample);
-    }
+  if (rv != CA_SUCCESS)
+    g_warning ("Failed to play file '%s': %s\n",
+               filename, ca_strerror (rv));
 #endif
 }
 
@@ -612,10 +176,8 @@ gnome_sound_play (const char * filename)
 void
 gnome_sound_init(const char *hostname)
 {
-#ifdef HAVE_ESD
-	srand(time(NULL));
-	g_free (esound_hostname);
-	esound_hostname = g_strdup (hostname);
+#ifdef HAVE_CANBERRA
+  get_ca_context (hostname);
 #endif
 }
 
@@ -630,33 +192,23 @@ void
 gnome_sound_shutdown(void)
 {
 #ifdef HAVE_ESD
-	g_free (esound_hostname);
-	esound_hostname = NULL;
-
-        close_sound_connection ();
+  if (global_context != NULL)
+    {
+      ca_context_destroy (global_context);
+      global_context = NULL;
+    }
 #endif
 }
 
 /**
  * gnome_sound_connection_get:
  *
- * Rarely needed to by programs directly, this function may be useful if a
- * program has cached a sample with gnome_sound_sample_load() and now wishes to
- * call esd_sample_play() to play the sample.
- *
- * Returns: the file descriptor of our esound connection or %-1
- * on error.
+ * Returns: -1
  *
  * @Deprecated: 2.30
  **/
 int
 gnome_sound_connection_get (void)
 {
-#ifdef HAVE_ESD
-	if ( ! use_sound ())
-		return -1;
-	return gnome_sound_connection;
-#else
 	return -1;
-#endif
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]