diff src/gtksound.c @ 13718:988186eb1688

[gaim-migrate @ 16127] Use Gstreamer for IM sounds, kill ao/audiofile committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Tue, 02 May 2006 22:24:46 +0000
parents 47c12348cfd1
children 164932c4d050
line wrap: on
line diff
--- a/src/gtksound.c	Tue May 02 20:07:55 2006 +0000
+++ b/src/gtksound.c	Tue May 02 22:24:46 2006 +0000
@@ -31,10 +31,9 @@
 #include <mmsystem.h>
 #endif
 
-#ifdef USE_AO
-# include <ao/ao.h>
-# include <audiofile.h>
-#endif /* USE_AO */
+#ifdef USE_GSTREAMER
+# include <gst/gst.h>
+#endif /* USE_GSTREAMER */
 
 #include "debug.h"
 #include "notify.h"
@@ -55,7 +54,6 @@
 
 static guint mute_login_sounds_timeout = 0;
 static gboolean mute_login_sounds = FALSE;
-static gboolean sound_initialized = FALSE;
 
 static struct gaim_sound_event sounds[GAIM_NUM_SOUNDS] = {
 	{N_("Buddy logs in"), "login", "login.wav"},
@@ -72,10 +70,6 @@
 	{N_("Someone says your screen name in chat"), "nick_said", "alert.wav"}
 };
 
-#ifdef USE_AO
-static int ao_driver = -1;
-#endif /* USE_AO */
-
 static gboolean
 unmute_login_sounds_cb(gpointer data)
 {
@@ -235,35 +229,6 @@
 	mute_login_sounds_timeout = gaim_timeout_add(10000, unmute_login_sounds_cb, NULL);
 }
 
-static void
-_pref_sound_method_changed(const char *name, GaimPrefType type,
-						   gconstpointer val, gpointer data)
-{
-	if(type != GAIM_PREF_STRING || strcmp(name, "/gaim/gtk/sound/method"))
-		return;
-
-	sound_initialized = TRUE;
-
-#ifdef USE_AO
-	ao_driver = -1;
-
-	if(!strcmp(val, "esd"))
-		ao_driver = ao_driver_id("esd");
-	else if(!strcmp(val, "arts"))
-		ao_driver = ao_driver_id("arts");
-	else if(!strcmp(val, "nas"))
-		ao_driver = ao_driver_id("nas");
-	else if(!strcmp(val, "automatic"))
-		ao_driver = ao_default_driver_id();
-
-	if(ao_driver != -1) {
-		ao_info *info = ao_driver_info(ao_driver);
-		gaim_debug_info("sound",
-						"Sound output driver loaded: %s\n", info->name);
-	}
-#endif /* USE_AO */
-}
-
 const char *
 gaim_gtk_sound_get_event_option(GaimSoundEventID event)
 {
@@ -332,13 +297,10 @@
 	gaim_prefs_add_string("/gaim/gtk/sound/method", "automatic");
 	gaim_prefs_add_int("/gaim/gtk/sound/volume", 50);
 
-#ifdef USE_AO
+#ifdef USE_GSTREAMER
 	gaim_debug_info("sound", "Initializing sound output drivers.\n");
-	ao_initialize();
-#endif /* USE_AO */
-
-	gaim_prefs_connect_callback(gaim_gtk_sound_get_handle(), "/gaim/gtk/sound/method",
-			_pref_sound_method_changed, NULL);
+	gst_init(NULL, NULL);
+#endif /* USE_GSTREAMER */
 
 	gaim_signal_connect(blist_handle, "buddy-signed-on",
 						gtk_sound_handle, GAIM_CALLBACK(buddy_state_cb),
@@ -369,15 +331,14 @@
 static void
 gaim_gtk_sound_uninit(void)
 {
-#ifdef USE_AO
-	ao_shutdown();
+#ifdef USE_GSTREAMER
+	gst_deinit();
 #endif
-	sound_initialized = FALSE;
 
 	gaim_signals_disconnect_by_handle(gaim_gtk_sound_get_handle());
 }
 
-#ifdef USE_AO
+#ifdef USE_GSTREAMER
 static gboolean
 expire_old_child(gpointer data)
 {
@@ -395,80 +356,47 @@
     return FALSE; /* do not run again */
 }
 
-/* Uncomment the following line to enable debugging of clipping in the scaling. */
-/* #define DEBUG_CLIPPING */
-
-static void
-scale_pcm_data(char *data, int nframes, int bits, int channels,
-			   double intercept, double minclip, double maxclip,
-			   float scale)
+static gboolean
+bus_call (GstBus     *bus,
+	  GstMessage *msg,
+  	  gpointer    data)
 {
-	int i;
-	float v;
-	gint16 *data16 = (gint16*)data;
-	gint32 *data32 = (gint32*)data;
-	gint64 *data64 = (gint64*)data;
+	GstElement *play = data;
+	GError *err;
 
-	switch(bits) {
-		case 16:
-			for(i = 0; i < nframes * channels; i++) {
-				v = ((data16[i] - intercept) * scale) + intercept;
-#ifdef DEBUG_CLIPPING
-				if (v > maxclip)
-					printf("Clipping detected!\n");
-				else if (v < minclip)
-					printf("Clipping detected!\n");
+	switch (GST_MESSAGE_TYPE (msg)) {
+	case GST_MESSAGE_EOS:
+		gst_element_set_state(play, GST_STATE_NULL);
+		gst_object_unref(GST_OBJECT(play));
+		break;
+	case GST_MESSAGE_ERROR:
+		gst_message_parse_error(msg, &err, NULL);
+		gaim_debug_error("gstreamer", err->message);
+		g_error_free(err);
+		break;
+	case GST_MESSAGE_WARNING:
+		gst_message_parse_warning(msg, &err, NULL);
+		gaim_debug_warning("gstreamer", err->message);
+		g_error_free(err);
+		break;
+	default:
+		break;
+	}
+	return TRUE;
+}
 #endif
-				v = CLAMP(v, minclip, maxclip);
-				data16[i]=(gint16)v;
-			}
-			break;
-		case 32:
-			for(i = 0; i < nframes * channels; i++) {
-				v = ((data32[i] - intercept) * scale) + intercept;
-#ifdef DEBUG_CLIPPING
-				if (v > maxclip)
-					printf("Clipping detected!\n");
-				else if (v < minclip)
-					printf("Clipping detected!\n");
-#endif
-				v = CLAMP(v, minclip, maxclip);
-				data32[i]=(gint32)v;
-			}
-			break;
-		case 64:
-			for(i = 0; i < nframes * channels; i++) {
-				v = ((data64[i] - intercept) * scale) + intercept;
-#ifdef DEBUG_CLIPPING
-				if (v > maxclip)
-					printf("Clipping detected!\n");
-				else if (v < minclip)
-					printf("Clipping detected!\n");
-#endif
-				v = CLAMP(v, minclip, maxclip);
-				data64[i]=(gint64)v;
-			}
-			break;
-		default:
-			gaim_debug_warning("gtksound", "Scaling of %d bit pcm data not supported.\n", bits);
-			break;
-	}
-}
-#endif /* USE_AO */
 
 static void
 gaim_gtk_sound_play_file(const char *filename)
 {
 	const char *method;
-#ifdef USE_AO
-	pid_t pid;
-	AFfilehandle file;
-	int volume = 50;
+#ifdef USE_GSTREAMER
+	float volume;
+	char *uri;
+	GstElement *sink = NULL;
+	GstElement *play = NULL;
 #endif
 
-	if (!sound_initialized)
-		gaim_prefs_trigger_callback("/gaim/gtk/sound/method");
-
 	if (gaim_prefs_get_bool("/gaim/gtk/sound/mute"))
 		return;
 
@@ -519,91 +447,37 @@
 		g_free(command);
 		return;
 	}
-#ifdef USE_AO
-	volume = gaim_prefs_get_int("/gaim/gtk/sound/volume");
-	volume = CLAMP(volume, 0, 100);
-
-	pid = fork();
-	if (pid < 0)
-		return;
-	else if (pid == 0) {
-		/* Child process */
-
-		/* calculating the scaling factor:
-		 *   scale(x)   = (x+30)^2 / 6400
-		 *   scale(0)   = 0.1406   (quiet)
-		 *   scale(50)  = 1.0      (no scaling, normal volume)
-		 *   scale(100) = 2.6406   (roughly maximized without clipping)
-		 */
-		float scale = ( ((float)volume + 30) * ((float)volume + 30) ) / 6400;
-		file = afOpenFile(filename, "rb", NULL);
-		if(file) {
-			ao_device *device;
-			ao_sample_format format;
-			int in_fmt;
-			int bytes_per_frame;
-			double slope, intercept, minclip, maxclip;
-
-			format.rate = afGetRate(file, AF_DEFAULT_TRACK);
-			format.channels = afGetChannels(file, AF_DEFAULT_TRACK);
-			afGetSampleFormat(file, AF_DEFAULT_TRACK, &in_fmt,
-					&format.bits);
-
-			afGetPCMMapping(file, AF_DEFAULT_TRACK, &slope,
-					&intercept, &minclip, &maxclip);
-
-			/* XXX: libao doesn't seem to like 8-bit sounds, so we'll
-			 * let libaudiofile make them a bit better for us */
-			if(format.bits == 8)
-				format.bits = 16;
-
-			afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK,
-					AF_SAMPFMT_TWOSCOMP, format.bits);
+#ifdef USE_GSTREAMER
+	volume = (float)(CLAMP(gaim_prefs_get_int("/gaim/gtk/sound/volume"),0,100)) / 50;
+	if (!strcmp(method, "automatic")) {
+		if (gaim_running_gnome()) {
+			sink = gst_element_factory_make("gconfaudiosink", "sink");
+		}
+	} else if (!strcmp(method, "esd")) {
+		sink = gst_element_factory_make("esdsink", "sink");
+	} else if (!strcmp(method, "arts")) {
+		sink = gst_element_factory_make("artssink", "sink");
+	} else if (!strcmp(method, "nas")) {
+		sink = gst_element_factory_make("nassink", "sink");
+	}
 
-#if G_BYTE_ORDER == G_BIG_ENDIAN
-			format.byte_format = AO_FMT_BIG;
-			afSetVirtualByteOrder(file, AF_DEFAULT_TRACK,
-					AF_BYTEORDER_BIGENDIAN);
-#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
-			format.byte_format = AO_FMT_LITTLE;
-			afSetVirtualByteOrder(file, AF_DEFAULT_TRACK,
-					AF_BYTEORDER_LITTLEENDIAN);
-#else
-#warning Unknown endianness
-#endif
-
-			bytes_per_frame = format.bits * format.channels / 8;
-
-			device = ao_open_live(ao_driver, &format, NULL);
-
-			if(device) {
-				int frames_read;
-				char buf[4096];
-				int buf_frames = sizeof(buf) / bytes_per_frame;
+	uri = g_strdup_printf("file://%s", filename);
+	play = gst_element_factory_make("playbin", "play");
+	
+	g_object_set(G_OBJECT(play), "uri", uri,
+		                     "volume", volume, 
+		                     "audio-sink", sink, NULL);
 
-				while((frames_read = afReadFrames(file, AF_DEFAULT_TRACK,
-								buf, buf_frames))) {
-					/* no need to scale at volume == 50 */
-					if(volume != 50)
-						scale_pcm_data(buf, frames_read, format.bits, format.channels,
-									   intercept, minclip, maxclip, scale);
-					if(!ao_play(device, buf, frames_read * bytes_per_frame))
-						break;
-				}
-				ao_close(device);
-			}
-			afCloseFile(file);
-		}
-		ao_shutdown();
-		_exit(0);
-	} else {
-		/* Parent process */
-		gaim_timeout_add(PLAY_SOUND_TIMEOUT, expire_old_child, GINT_TO_POINTER(pid));
-	}
-#else /* USE_AO */
+	gst_bus_add_watch(gst_pipeline_get_bus(GST_PIPELINE(play)),
+			  bus_call, play);
+	gst_element_set_state(play, GST_STATE_PLAYING);
+	
+	g_free(uri);
+	
+#else /* USE_GSTREAMER */
 	gdk_beep();
 	return;
-#endif /* USE_AO */
+#endif /* USE_GSTREAMER */
 #else /* _WIN32 */
 	gaim_debug_info("sound", "Playing %s\n", filename);