changeset 4561:9df99116840a

[gaim-migrate @ 4842] This is the new sound subsystem Lots of stuff got renamed, and everything sound-wise is documented. Gaim now uses libaudiofile and libao to play sounds. Lots of ugly hacks were removed, and now we support playing audio through anything that libao will support. If you need to (you shouldn't) you can force libao to use a specific output driver, by putting a line into ~/.libao like: default_driver=esd You shouldn't need to do this, libao is pretty good at figuring out what driver to use. committer: Tailor Script <tailor@pidgin.im>
author Nathan Walp <nwalp@pidgin.im>
date Sun, 09 Feb 2003 01:55:35 +0000
parents eb32b3acef97
children 2c8372d4fb2a
files acinclude.m4 configure.ac configure.in plugins/docklet/docklet.c src/Makefile.am src/buddy.c src/gaim.h src/gaimrc.c src/gtkconv.c src/main.c src/perl.c src/prefs.c src/sound.c src/sound.h src/ui.h
diffstat 15 files changed, 587 insertions(+), 548 deletions(-) [+]
line wrap: on
line diff
--- a/acinclude.m4	Sun Feb 09 00:47:57 2003 +0000
+++ b/acinclude.m4	Sun Feb 09 01:55:35 2003 +0000
@@ -798,3 +798,119 @@
   AC_SUBST(GTK_LIBS)
   rm -f conf.gtktest
 ])
+
+dnl This is XIPH_PATH_AO renamed to GAIM_PATH_AO to prevent conflicts.
+dnl It's a long story.  --elb
+
+# ao.m4
+# Configure paths for libao
+# Jack Moffitt <jack@icecast.org> 10-21-2000
+# Shamelessly stolen from Owen Taylor and Manish Singh
+
+dnl GAIM_PATH_AO([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libao, and define AO_CFLAGS and AO_LIBS
+dnl
+AC_DEFUN(GAIM_PATH_AO,
+[dnl 
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(ao,[  --with-ao=PFX   Prefix where libao is installed (optional)], ao_prefix="$withval", ao_prefix="")
+AC_ARG_WITH(ao-libraries,[  --with-ao-libraries=DIR   Directory where libao library is installed (optional)], ao_libraries="$withval", ao_libraries="")
+AC_ARG_WITH(ao-includes,[  --with-ao-includes=DIR   Directory where libao header files are installed (optional)], ao_includes="$withval", ao_includes="")
+AC_ARG_ENABLE(aotest, [  --disable-aotest       Do not try to compile and run a test ao program],, enable_aotest=yes)
+
+
+  if test "x$ao_libraries" != "x" ; then
+    AO_LIBS="-L$ao_libraries"
+  elif test "x$ao_prefix" != "x"; then
+    AO_LIBS="-L$ao_prefix/lib"
+  elif test "x$prefix" != "xNONE"; then
+    AO_LIBS="-L$prefix/lib"
+  fi
+
+  if test "x$ao_includes" != "x" ; then
+    AO_CFLAGS="-I$ao_includes"
+  elif test "x$ao_prefix" != "x"; then
+    AO_CFLAGS="-I$ao_prefix/include"
+  elif test "x$prefix" != "xNONE"; then
+    AO_CFLAGS="-I$prefix/include"
+  fi
+
+  # see where dl* and friends live
+  AC_CHECK_FUNCS(dlopen, [AO_DL_LIBS=""], [
+    AC_CHECK_LIB(dl, dlopen, [AO_DL_LIBS="-ldl"], [
+      AC_MSG_WARN([could not find dlopen() needed by libao sound drivers
+      your system may not be supported.])
+    ])
+  ])
+
+  AO_LIBS="$AO_LIBS -lao $AO_DL_LIBS"
+
+  AC_MSG_CHECKING(for ao)
+  no_ao=""
+
+
+  if test "x$enable_aotest" = "xyes" ; then
+    ac_save_CFLAGS="$CFLAGS"
+    ac_save_LIBS="$LIBS"
+    CFLAGS="$CFLAGS $AO_CFLAGS"
+    LIBS="$LIBS $AO_LIBS"
+dnl
+dnl Now check if the installed ao is sufficiently new.
+dnl
+      rm -f conf.aotest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ao/ao.h>
+
+int main ()
+{
+  system("touch conf.aotest");
+  return 0;
+}
+
+],, no_ao=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+  fi
+
+  if test "x$no_ao" = "x" ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$1], , :, [$1])     
+  else
+     AC_MSG_RESULT(no)
+     if test -f conf.aotest ; then
+       :
+     else
+       echo "*** Could not run ao test program, checking why..."
+       CFLAGS="$CFLAGS $AO_CFLAGS"
+       LIBS="$LIBS $AO_LIBS"
+       AC_TRY_LINK([
+#include <stdio.h>
+#include <ao/ao.h>
+],     [ return 0; ],
+       [ echo "*** The test program compiled, but did not run. This usually means"
+       echo "*** that the run-time linker is not finding ao or finding the wrong"
+       echo "*** version of ao. If it is not finding ao, you'll need to set your"
+       echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+       echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+       echo "*** is required on your system"
+       echo "***"
+       echo "*** If you have an old version installed, it is best to remove it, although"
+       echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+       [ echo "*** The test program failed to compile or link. See the file config.log for the"
+       echo "*** exact error that occured. This usually means ao was incorrectly installed"
+       echo "*** or that you have moved ao since it was installed." ])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+     AO_CFLAGS=""
+     AO_LIBS=""
+     ifelse([$2], , :, [$2])
+  fi
+  AC_SUBST(AO_CFLAGS)
+  AC_SUBST(AO_LIBS)
+  rm -f conf.aotest
+])
--- a/configure.ac	Sun Feb 09 00:47:57 2003 +0000
+++ b/configure.ac	Sun Feb 09 01:55:35 2003 +0000
@@ -122,10 +122,7 @@
 AC_DEFINE_UNQUOTED(STATIC_PROTO_INIT, $extern_init void static_proto_init() { $load_proto },
 	[Loads static protocol plugin module initialization functions.])
 
-AC_ARG_ENABLE(esd,     [  --disable-esd           Turn off ESD (default=auto)],,enable_esd=yes)
-AC_ARG_ENABLE(nas,     [  --enable-nas            Enable NAS (Network Audio System) support],,enable_nas=no)
-AC_ARG_ENABLE(artsc,   [  --disable-artsc         Turn off ArtsC (default=auto)],,enable_artsc=yes)
-
+AC_ARG_ENABLE(audio,   [  --disable-audio         compile without libao/libaudiofile for sound playing],,enable_audio=yes)
 AC_ARG_ENABLE(plugins, [  --disable-plugins       compile without plugin support],,enable_plugins=yes)
 AC_ARG_ENABLE(perl,    [  --disable-perl          compile without perl scripting],,enable_perl=yes)
 AC_ARG_ENABLE(gtkspell, [  --disable-gtkspell      compile without GtkSpell automatic spell checking],,enable_gtkspell=yes)
@@ -274,45 +271,22 @@
 	fi
 fi
 
-if test "$enable_nas" = yes ; then
-	AC_DEFINE(NAS_SOUND, 1, [Define if we have NAS sound support.])
-        SOUND_LIBS="-laudio -lXt"
-fi
-if test "$enable_esd" = yes ; then
-	AM_PATH_GESD
-        if test "$no_esd" != yes ; then
-		old_CFLAGS="$CFLAGS"
-        	CFLAGS="$CFLAGS $ESD_CFLAGS"
-		AC_TRY_COMPILE(,[#include <esd.h>],
-			[
-				AC_DEFINE(ESD_SOUND, 1, [Define if we have ESD sound support.])
-				SOUND_LIBS="$SOUND_LIBS $ESD_LIBS"
-			],[
-				enable_esd=no
-				CFLAGS="$old_CFLAGS"
-			])
+if test "$enable_audio" = yes ; then
+	GAIM_PATH_AO(found_ao_lib=true)
+
+	AM_PATH_AUDIOFILE([0.2.0], found_af_lib=true)
+
+	if test "$found_ao_lib" = "true" -a "$found_af_lib" = "true"; then
+		SOUND_LIBS="$AO_LIBS $AUDIOFILE_LIBS"
+		AC_SUBST(SOUND_LIBS)
+		AC_DEFINE(USE_AO, 1, [Define if we're using libao and libaudiofile for sound playing])
+		enable_audio=yes
 	else
-		enable_esd=no
-        fi
+		enable_audio=no
+	fi
+else
+	enable_audio=no
 fi
-if test "x$enable_artsc" = "xyes"; then
-	AM_PATH_ARTSC
-	if test "x$no_artsc" != "xyes" ; then
-		old_CFLAGS="$CFLAGS"
-		CFLAGS="$CFLAGS $ARTSC_CFLAGS"
-		AC_TRY_COMPILE(,[#include <artsc.h>],
-			[
-				AC_DEFINE(ARTSC_SOUND, 1, [Define if we have artsc sound support.])
-				SOUND_LIBS="$SOUND_LIBS $ARTSC_LIBS"
-			],[
-				enable_artsc=no
-				CFLAGS="$old_CFLAGS"
-			])
-	else
-		enable_artsc=no
-	fi
-fi
-AC_SUBST(SOUND_LIBS)
 
 if test "$ac_cv_cygwin" = yes ; then
 	LDADD="$LDADD -static"
@@ -443,20 +417,16 @@
 echo Build Protocol Plugins........ : $enable_prpls
 echo Protocols to link statically.. : $STATIC_PRPLS
 echo
-echo UI Library.................... : GTK 2.0
+echo UI Library.................... : GTK 2.x
 echo
 echo Build with Plugin support..... : $enable_plugins
 echo Build with Perl support....... : $enable_perl
-echo
-echo Build with GtkSpell............: $enable_gtkspell
+echo Build with Audio support...... : $enable_audio
+echo Build with GtkSpell support... : $enable_gtkspell
 echo
 echo Use XScreenSaver Extension.... : $enable_xss
 echo Use X Session Management...... : $enable_sm
 echo
-echo Build with ESD................ : $enable_esd
-echo Build with NAS................ : $enable_nas
-echo Build with ArtsC.............. : $enable_artsc
-echo
 echo Print debugging messages...... : $enable_debug
 echo
 eval eval echo Gaim will be installed in $bindir.
--- a/configure.in	Sun Feb 09 00:47:57 2003 +0000
+++ b/configure.in	Sun Feb 09 01:55:35 2003 +0000
@@ -112,16 +112,13 @@
 AC_DEFINE_UNQUOTED(STATIC_PROTO_INIT, $extern_init void static_proto_init() { $load_proto },
 	[Loads static protocol plugin module initialization functions.])
 
-AC_ARG_ENABLE(esd,     [  --disable-esd           Turn off ESD (default=auto)],,enable_esd=yes)
-AC_ARG_ENABLE(nas,     [  --enable-nas            Enable NAS (Network Audio System) support],,enable_nas=no)
-AC_ARG_ENABLE(artsc,   [  --disable-artsc         Turn off ArtsC (default=auto)],,enable_artsc=yes)
-
+AC_ARG_ENABLE(audio,   [  --disable-audio         compile without libao/libaudiofile for sound playing],,enable_audio=yes)
 AC_ARG_ENABLE(plugins, [  --disable-plugins       compile without plugin support],,enable_plugins=yes)
 AC_ARG_ENABLE(perl,    [  --disable-perl          compile without perl scripting],,enable_perl=yes)
 AC_ARG_ENABLE(gtkspell, [  --disable-gtkspell      compile without GtkSpell automatic spell checking],,enable_gtkspell=yes)
-
 AC_ARG_ENABLE(debug,   [  --enable-debug          compile with debugging support],,enable_debug=no)
 AC_ARG_ENABLE(screensaver,   [  --disable-screensaver   compile without X screensaver extension],,enable_xss=yes)
+AC_ARG_ENABLE(sm,      [  --disable-sm            compile without X session management support],,enable_sm=yes)
 AC_ARG_WITH(krb4,      [  --with-krb4=PREFIX      Compile Zephyr plugin with Kerberos 4 support],kerberos="$withval",kerberos="no")
 
 if test "$enable_debug" = yes ; then
@@ -248,45 +245,22 @@
 	fi
 fi
 
-if test "$enable_nas" = yes ; then
-	AC_DEFINE(NAS_SOUND, 1, [Define if we have NAS sound support.])
-        SOUND_LIBS="-laudio -lXt"
-fi
-if test "$enable_esd" = yes ; then
-	AM_PATH_GESD
-        if test "$no_esd" != yes ; then
-		old_CFLAGS="$CFLAGS"
-        	CFLAGS="$CFLAGS $ESD_CFLAGS"
-		AC_TRY_COMPILE(,[#include <esd.h>],
-			[
-				AC_DEFINE(ESD_SOUND, 1, [Define if we have ESD sound support.])
-				SOUND_LIBS="$SOUND_LIBS $ESD_LIBS"
-			],[
-				enable_esd=no
-				CFLAGS="$old_CFLAGS"
-			])
+if test "$enable_audio" = yes ; then
+	GAIM_PATH_AO(found_ao_lib=true)
+
+	AM_PATH_AUDIOFILE([0.2.0], found_af_lib=true)
+
+	if test "$found_ao_lib" = "true" -a "$found_af_lib" = "true"; then
+		SOUND_LIBS="$AO_LIBS $AUDIOFILE_LIBS"
+		AC_SUBST(SOUND_LIBS)
+		AC_DEFINE(USE_AO, 1, [Define if we're using libao and libaudiofile for sound playing])
+		enable_audio=yes
 	else
-		enable_esd=no
-        fi
+		enable_audio=no
+	fi
+else
+	enable_audio=no
 fi
-if test "x$enable_artsc" = "xyes"; then
-	AM_PATH_ARTSC
-	if test "x$no_artsc" != "xyes" ; then
-		old_CFLAGS="$CFLAGS"
-		CFLAGS="$CFLAGS $ARTSC_CFLAGS"
-		AC_TRY_COMPILE(,[#include <artsc.h>],
-			[
-				AC_DEFINE(ARTSC_SOUND, 1, [Define if we have artsc sound support.])
-				SOUND_LIBS="$SOUND_LIBS $ARTSC_LIBS"
-			],[
-				enable_artsc=no
-				CFLAGS="$old_CFLAGS"
-			])
-	else
-		enable_artsc=no
-	fi
-fi
-AC_SUBST(SOUND_LIBS)
 
 if test "$ac_cv_cygwin" = yes ; then
 	LDADD="$LDADD -static"
@@ -419,18 +393,15 @@
 echo Build Protocol Plugins........ : $enable_prpls
 echo Protocols to link statically.. : $STATIC_PRPLS
 echo
-echo UI Library.................... : GTK 2.0
+echo UI Library.................... : GTK 2.x
 echo
 echo Build with Plugin support..... : $enable_plugins
 echo Build with Perl support....... : $enable_perl
-echo
-echo Build with GtkSpell............: $enable_gtkspell
+echo Build with Audio support...... : $enable_audio
+echo Build with GtkSpell support... : $enable_gtkspell
 echo
 echo Use XScreenSaver Extension.... : $enable_xss
-echo
-echo Build with ESD................ : $enable_esd
-echo Build with NAS................ : $enable_nas
-echo Build with ArtsC.............. : $enable_artsc
+echo Use X Session Management...... : $enable_sm
 echo
 echo Print debugging messages...... : $enable_debug
 echo
--- a/plugins/docklet/docklet.c	Sun Feb 09 00:47:57 2003 +0000
+++ b/plugins/docklet/docklet.c	Sun Feb 09 01:55:35 2003 +0000
@@ -30,6 +30,7 @@
 /* includes */
 #include <gtk/gtk.h>
 #include "gaim.h"
+#include "sound.h"
 #include "eggtrayicon.h"
 
 #ifndef GAIM_PLUGINS
@@ -60,7 +61,7 @@
 static enum docklet_status icon;
 
 static void docklet_toggle_mute(GtkWidget *toggle, void *data) {
-	mute_sounds = GTK_CHECK_MENU_ITEM(toggle)->active;
+	gaim_sound_set_mute(GTK_CHECK_MENU_ITEM(toggle)->active);
 }
 
 static void docklet_toggle_queue(GtkWidget *widget, void *data) {
@@ -149,7 +150,7 @@
 	gaim_separator(menu);
 
 	entry = gtk_check_menu_item_new_with_label(_("Mute Sounds"));
-	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(entry), mute_sounds);
+	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(entry), gaim_sound_get_mute());
 	g_signal_connect(G_OBJECT(entry), "toggled", G_CALLBACK(docklet_toggle_mute), NULL);
 	gtk_menu_append(GTK_MENU(menu), entry);
 
--- a/src/Makefile.am	Sun Feb 09 00:47:57 2003 +0000
+++ b/src/Makefile.am	Sun Feb 09 01:55:35 2003 +0000
@@ -55,6 +55,7 @@
 		session.c \
 		socket.c \
 		sound.c \
+		sound.h \
 		stock.c \
 		stock.h \
 		themes.c \
--- a/src/buddy.c	Sun Feb 09 00:47:57 2003 +0000
+++ b/src/buddy.c	Sun Feb 09 01:55:35 2003 +0000
@@ -45,6 +45,7 @@
 #include <gdk/gdkkeysyms.h>
 #include <gtk/gtk.h>
 #include "prpl.h"
+#include "sound.h"
 #include "gaim.h"
 
 #ifdef _WIN32
@@ -1459,9 +1460,9 @@
 			}
 			if (b->options & OPT_POUNCE_SOUND) {
 				if (strlen(b->sound))
-					play_file(b->sound);
+					gaim_sound_play_file(b->sound);
 				else
-					play_sound(SND_POUNCE_DEFAULT);
+					gaim_sound_play_event(GAIM_SOUND_POUNCE_DEFAULT);
 			}
 
 			if (!(b->options & OPT_POUNCE_SAVE))
@@ -2214,7 +2215,7 @@
 		}
 		if (b->present == 1) {
 			if (bs->sound != 2)
-				play_sound(SND_BUDDY_ARRIVE);
+				gaim_sound_play_event(GAIM_SOUND_BUDDY_ARRIVE);
 			if (blist_options & OPT_BLIST_POPUP)
 				gdk_window_show(blist->window);
 			pm = gdk_pixmap_create_from_xpm_d(blist->window, &bm,
@@ -2276,7 +2277,7 @@
 				   buddies that have already signed
 				   off */
 		if (bs->sound != 1)
-			play_sound(SND_BUDDY_LEAVE);
+			gaim_sound_play_event(GAIM_SOUND_BUDDY_LEAVE);
 		if (blist_options & OPT_BLIST_POPUP)
 			gdk_window_show(blist->window);
 		bs->connlist = g_slist_remove(bs->connlist, gc);
--- a/src/gaim.h	Sun Feb 09 00:47:57 2003 +0000
+++ b/src/gaim.h	Sun Feb 09 01:55:35 2003 +0000
@@ -312,30 +312,6 @@
 #define OPT_SOUND_ESD			0x00010000
 #define OPT_SOUND_CMD			0x00020000
 #define OPT_SOUND_CHAT_NICK             0x00040000
-/* remember to also change the struct in sound.c */
-
-#define SND_BUDDY_ARRIVE 0
-#define SND_BUDDY_LEAVE 1
-#define SND_RECEIVE 2
-#define SND_FIRST_RECEIVE 3
-#define SND_SEND 4
-#define SND_CHAT_JOIN 5
-#define SND_CHAT_LEAVE 6
-#define SND_CHAT_YOU_SAY 7
-#define SND_CHAT_SAY 8
-#define SND_POUNCE_DEFAULT 9
-#define SND_CHAT_NICK 10
-#define NUM_SOUNDS 11
-
-extern char *sound_file[NUM_SOUNDS];
-
-/* global sound struct */
-struct sound_struct {
-	char *label;
-	guint opt;
-	char *def;
-};
-extern struct sound_struct sounds[];
 
 extern guint away_options;
 #define OPT_AWAY_DISCARD		0x00000001
@@ -355,7 +331,6 @@
 extern GSList *message_queue;
 extern GSList *unread_message_queue;
 extern GSList *away_time_queue;
-extern char sound_cmd[2048];
 extern char web_command[2048];
 extern struct save_pos blist_pos;
 extern struct window_size conv_size, buddy_chat_size;
--- a/src/gaimrc.c	Sun Feb 09 00:47:57 2003 +0000
+++ b/src/gaimrc.c	Sun Feb 09 01:55:35 2003 +0000
@@ -38,6 +38,7 @@
 #include "gaim.h"
 #include "prpl.h"
 #include "proxy.h"
+#include "sound.h"
 
 #ifdef _WIN32
 #include "win32dep.h"
@@ -72,10 +73,6 @@
 struct save_pos blist_pos;
 struct window_size conv_size, buddy_chat_size;
 char web_command[2048] = "";
-char *sound_file[NUM_SOUNDS];
-#ifndef _WIN32
-char sound_cmd[2048];
-#endif
 
 struct parse {
 	char option[256];
@@ -802,8 +799,8 @@
 	}
 
 	/* this is where we do bugs and compatibility stuff */
-	if (!(sound_options & (OPT_SOUND_BEEP | OPT_SOUND_ESD | OPT_SOUND_NORMAL | OPT_SOUND_NAS | OPT_SOUND_ARTSC | OPT_SOUND_CMD)))
-		sound_options |= OPT_SOUND_ESD | OPT_SOUND_NORMAL | OPT_SOUND_NAS | OPT_SOUND_ARTSC;
+	if (!(sound_options & (OPT_SOUND_BEEP | OPT_SOUND_NORMAL | OPT_SOUND_CMD)))
+		sound_options |= OPT_SOUND_NORMAL;
 
 	if (conv_size.width == 0 &&
 	    conv_size.height == 0 &&
@@ -904,11 +901,9 @@
 
 	buf[0] = 0;
 
-	for (i = 0; i < NUM_SOUNDS; i++)
-		sound_file[i] = NULL;
-#ifndef _WIN32
-	sound_cmd[0] = 0;
-#endif
+	for(i=0; i<GAIM_NUM_SOUNDS; i++)
+		gaim_sound_set_event_file(i, NULL);
+
 	while (buf[0] != '}') {
 		if (buf[0] == '#')
 			continue;
@@ -919,14 +914,14 @@
 		p = parse_line(buf, &parse_buffer);
 #ifndef _WIN32
 		if (!strcmp(p->option, "sound_cmd")) {
-			g_snprintf(sound_cmd, sizeof(sound_cmd), "%s", p->value[0]);
-		} else 
+			gaim_sound_set_command(p->value[0]);
+		} else
 #endif
 		if (!strncmp(p->option, "sound", strlen("sound"))) {
 			i = p->option[strlen("sound")] - 'A';
 
 			if (p->value[0][0])
-				sound_file[i] = g_strdup(p->value[0]);
+				gaim_sound_set_event_file(i, p->value[0]);
 		}
 	}
 }
@@ -934,23 +929,30 @@
 static void gaimrc_write_sounds(FILE *f)
 {
 	int i;
+	char *cmd;
 	fprintf(f, "sound_files {\n");
-	for (i = 0; i < NUM_SOUNDS; i++)
-		if (sound_file[i]) {
+	for (i = 0; i < GAIM_NUM_SOUNDS; i++) {
+		char *file = gaim_sound_get_event_file(i);
+		if (file) {
 #ifndef _WIN32
-			fprintf(f, "\tsound%c { %s }\n", i + 'A', sound_file[i]);
+			fprintf(f, "\tsound%c { %s }\n", i + 'A', file);
 #else
 			/* Make sure windows dir speparators arn't swallowed up when
 			   path is read back in from resource file */
-			char* tmp=wgaim_escape_dirsep(sound_file[i]);
+			char* tmp=wgaim_escape_dirsep(file);
 			fprintf(f, "\tsound%c { %s }\n", i + 'A', tmp);
 			g_free(tmp);
 #endif
 		}
 		else
 			fprintf(f, "\tsound%c {  }\n", i + 'A');
+	}
 #ifndef _WIN32
-	fprintf(f, "\tsound_cmd { %s }\n", sound_cmd);
+	cmd = gaim_sound_get_command();
+	if(cmd)
+		fprintf(f, "\tsound_cmd { %s }\n", cmd);
+	else
+		fprintf(f, "\tsound_cmd {  }\n");
 #endif
 	fprintf(f, "}\n");
 }
@@ -1218,8 +1220,9 @@
 	away_options =
 		OPT_AWAY_BACK_ON_IM;
 
-	for (i = 0; i < NUM_SOUNDS; i++)
-		sound_file[i] = NULL;
+	for (i = 0; i < GAIM_NUM_SOUNDS; i++)
+		gaim_sound_set_event_file(i, NULL);
+
 	font_options = 0;
 	/* Enable all of the sound players that might be available.  The first
 	   available one will be used. */
@@ -1229,10 +1232,7 @@
 	    OPT_SOUND_RECV |
 	    OPT_SOUND_SEND |
 	    OPT_SOUND_SILENT_SIGNON |
-	    OPT_SOUND_NORMAL |
-	    OPT_SOUND_NAS |
-	    OPT_SOUND_ARTSC |
-	    OPT_SOUND_ESD;
+	    OPT_SOUND_NORMAL;
 
 #ifdef USE_SCREENSAVER
 	report_idle = IDLE_SCREENSAVER;
--- a/src/gtkconv.c	Sun Feb 09 00:47:57 2003 +0000
+++ b/src/gtkconv.c	Sun Feb 09 01:55:35 2003 +0000
@@ -43,6 +43,7 @@
 #include "prpl.h"
 #include "gtkimhtml.h"
 #include "dnd-hints.h"
+#include "sound.h"
 
 #ifdef _WIN32
 #include "win32dep.h"
@@ -3619,13 +3620,13 @@
 			if (gtkconv->u.im->a_virgin &&
 				(sound_options & OPT_SOUND_FIRST_RCV)) {
 
-				play_sound(SND_FIRST_RECEIVE);
+				gaim_sound_play_event(GAIM_SOUND_FIRST_RECEIVE);
 			}
 			else
-				play_sound(SND_RECEIVE);
+				gaim_sound_play_event(GAIM_SOUND_RECEIVE);
 		}
 		else {
-			play_sound(SND_SEND);
+			gaim_sound_play_event(GAIM_SOUND_SEND);
 		}
 	}
 
@@ -3645,12 +3646,12 @@
 	/* Play a sound, if specified in prefs. */
 	if (gtkconv->make_sound) {
 		if (!(flags & WFLAG_WHISPER) && (flags & WFLAG_SEND))
-			play_sound(SND_CHAT_YOU_SAY);
+			gaim_sound_play_event(GAIM_SOUND_CHAT_YOU_SAY);
 		else if (flags & WFLAG_RECV) {
 			if ((flags & WFLAG_NICK) && (sound_options & OPT_SOUND_CHAT_NICK))
-				play_sound(SND_CHAT_NICK);
+				gaim_sound_play_event(GAIM_SOUND_CHAT_NICK);
 			else
-				play_sound(SND_CHAT_SAY);
+				gaim_sound_play_event(GAIM_SOUND_CHAT_SAY);
 		}
 	}
 
@@ -3944,7 +3945,7 @@
 	gtk_label_set_text(GTK_LABEL(gtkchat->count), tmp);
 
 	if (gtkconv->make_sound)
-		play_sound(SND_CHAT_JOIN);
+		gaim_sound_play_event(GAIM_SOUND_CHAT_JOIN);
 
 	pos = g_list_index(gaim_chat_get_users(chat), user);
 
@@ -4063,7 +4064,7 @@
 	gtk_label_set_text(GTK_LABEL(gtkchat->count), tmp);
 
 	if (gtkconv->make_sound)
-		play_sound(SND_CHAT_LEAVE);
+		gaim_sound_play_event(GAIM_SOUND_CHAT_LEAVE);
 }
 
 static void
--- a/src/main.c	Sun Feb 09 00:47:57 2003 +0000
+++ b/src/main.c	Sun Feb 09 01:55:35 2003 +0000
@@ -47,6 +47,7 @@
 #include <stdlib.h>
 #include <ctype.h>
 #include "prpl.h"
+#include "sound.h"
 #include "gaim.h"
 #include "gaim-socket.h"
 #if HAVE_SIGNAL_H
@@ -71,6 +72,7 @@
 
 GtkWidget *mainwindow = NULL;
 
+
 int opt_away = 0;
 char *opt_away_arg = NULL;
 char *opt_rcfile_arg = NULL;
@@ -133,12 +135,11 @@
 	gtk_main_quit();
 }
 
-static int snd_tmout;
-int logins_not_muted = 1;
+static guint snd_tmout = 0;
 static gboolean sound_timeout(gpointer data)
 {
-	logins_not_muted = 1;
-	g_source_remove(snd_tmout);
+	gaim_sound_set_login_mute(FALSE);
+	snd_tmout = 0;
 	return FALSE;
 }
 
@@ -148,7 +149,10 @@
 void gaim_setup(struct gaim_connection *gc)
 {
 	if ((sound_options & OPT_SOUND_LOGIN) && (sound_options & OPT_SOUND_SILENT_SIGNON)) {
-		logins_not_muted = 0;
+		if(snd_tmout) {
+			g_source_remove(snd_tmout);
+		}
+		gaim_sound_set_login_mute(TRUE);
 		snd_tmout = g_timeout_add(10000, sound_timeout, NULL);
 	}
 }
@@ -526,6 +530,8 @@
 
 	setup_stock();
 
+	gaim_sound_init();
+
 #ifndef _WIN32
 	/* use the nice PNG icon for all the windows */
 	icon_path = g_build_filename(DATADIR, "pixmaps", "gaim.png", NULL);
@@ -899,7 +905,7 @@
 
 	gtk_main();
 	core_quit();
-	/* don't need ui_quit here because ui doesn't create anything */
+	gaim_sound_quit();
 #ifdef _WIN32
 	wgaim_cleanup();
 #endif
--- a/src/perl.c	Sun Feb 09 00:47:57 2003 +0000
+++ b/src/perl.c	Sun Feb 09 01:55:35 2003 +0000
@@ -81,6 +81,7 @@
 #endif
 #include "gaim.h"
 #include "prpl.h"
+#include "sound.h"
 
 struct perlscript {
 	char *name;
@@ -1183,7 +1184,7 @@
 
 	id = SvIV(ST(0));
 
-	play_sound(id);
+	gaim_sound_play_event(id);
 
 	XSRETURN_EMPTY;
 }
--- a/src/prefs.c	Sun Feb 09 00:47:57 2003 +0000
+++ b/src/prefs.c	Sun Feb 09 01:55:35 2003 +0000
@@ -38,6 +38,7 @@
 #include "gaim.h"
 #include "prpl.h"
 #include "proxy.h"
+#include "sound.h"
 
 #ifdef _WIN32
 #include "win32dep.h"
@@ -957,7 +958,7 @@
 #ifndef _WIN32
 static gint sound_cmd_yeah(GtkEntry *entry, gpointer d)
 {
-	g_snprintf(sound_cmd, sizeof(sound_cmd), "%s", gtk_entry_get_text(GTK_ENTRY(sndcmd)));
+	gaim_sound_set_command(gtk_entry_get_text(GTK_ENTRY(sndcmd)));
 	return TRUE;
 }
 #endif
@@ -970,6 +971,7 @@
 	GtkWidget *dd;
 	GtkWidget *hbox;
 	GtkWidget *label;
+	char *cmd;
 #endif
 
 	ret = gtk_vbox_new(FALSE, 18);
@@ -984,19 +986,12 @@
 #ifndef _WIN32
 	vbox = make_frame (ret, _("Sound Method"));
 	dd = gaim_dropdown(vbox, _("_Method"), &sound_options, OPT_SOUND_BEEP |
-		      OPT_SOUND_ESD | OPT_SOUND_ARTSC | OPT_SOUND_NAS | OPT_SOUND_NORMAL |
+		      OPT_SOUND_NORMAL |
 		      OPT_SOUND_CMD,
 		      _("Console beep"), OPT_SOUND_BEEP,
-#ifdef ESD_SOUND
-		      "ESD", OPT_SOUND_ESD,
+#ifdef USE_AO
+		      _("Automatic"), OPT_SOUND_NORMAL,
 #endif
-#ifdef ARTSC_SOUND
-		      "ArtsC", OPT_SOUND_ARTSC,
-#endif
-#ifdef NAS_SOUND
-		      "NAS", OPT_SOUND_NAS,
-#endif
-		      _("Internal"), OPT_SOUND_NORMAL,
 		      _("Command"), OPT_SOUND_CMD, NULL);
 	gtk_size_group_add_widget(sg, dd);
 	gtk_misc_set_alignment(GTK_MISC(dd), 0, 0);
@@ -1015,7 +1010,9 @@
 	gtk_label_set_mnemonic_widget(GTK_LABEL(label), sndcmd);
 
 	gtk_entry_set_editable(GTK_ENTRY(sndcmd), TRUE);
-	gtk_entry_set_text(GTK_ENTRY(sndcmd), sound_cmd);
+	cmd = gaim_sound_get_command();
+	if(cmd)
+		gtk_entry_set_text(GTK_ENTRY(sndcmd), cmd);
 	gtk_widget_set_size_request(sndcmd, 75, -1);
 
 	gtk_widget_set_sensitive(sndcmd, (sound_options & OPT_SOUND_CMD));
@@ -1343,8 +1340,8 @@
 	gtk_tree_model_get_iter (model, &iter, path);
 	gtk_tree_model_get (model, &iter, 2, &soundnum, -1);
 
-	sound_options ^= sounds[soundnum].opt;
-	gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, sound_options & sounds[soundnum].opt, -1);
+	sound_options ^= gaim_sound_get_event_option(soundnum);
+	gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, sound_options & gaim_sound_get_event_option(soundnum), -1);
 
 	gtk_tree_path_free(path);
 }
@@ -1354,9 +1351,9 @@
 	guint32 tmp_sound = sound_options;
 	if (!(sound_options & OPT_SOUND_WHEN_AWAY))
 		sound_options ^= OPT_SOUND_WHEN_AWAY;
-	if (!(sound_options & sounds[sound_row_sel].opt))
-		sound_options ^= sounds[sound_row_sel].opt;
-	play_sound(sound_row_sel);
+	if (!(sound_options & gaim_sound_get_event_option(sound_row_sel)))
+		sound_options ^= gaim_sound_get_event_option(sound_row_sel);
+	gaim_sound_play_event(sound_row_sel);
 
 	sound_options = tmp_sound;
 }
@@ -1364,10 +1361,7 @@
 static void reset_sound(GtkWidget *button, gpointer i_am_also_NULL)
 {
 	/* This just resets a sound file back to default */
-	if (sound_file[sound_row_sel]) {
-		g_free(sound_file[sound_row_sel]);
-		sound_file[sound_row_sel] = NULL;
-	}
+	gaim_sound_set_event_file(sound_row_sel, NULL);
 
 	gtk_entry_set_text(GTK_ENTRY(sound_entry), "(default)");
 }
@@ -1397,22 +1391,18 @@
 	if (file_is_dir(file, sounddialog))
 		return;
 
-	/* Let's just be safe */
-	if (sound_file[snd])
-		g_free(sound_file[snd]);
-
 	/* Set it -- and forget it */
-	sound_file[snd] = g_strdup(file);
+	gaim_sound_set_event_file(snd, file);
 
 	/* Set our text entry */
-	gtk_entry_set_text(GTK_ENTRY(sound_entry), sound_file[snd]);
+	gtk_entry_set_text(GTK_ENTRY(sound_entry), file);
 
 	/* Close the window! It's getting cold in here! */
 	close_sounddialog(NULL, sounddialog);
 
 	if (last_sound_dir)
 		g_free(last_sound_dir);
-	last_sound_dir = g_dirname(sound_file[snd]);
+	last_sound_dir = g_dirname(file);
 }
 
 static void sel_sound(GtkWidget *button, gpointer being_NULL_is_fun)
@@ -1447,13 +1437,15 @@
 static void prefs_sound_sel (GtkTreeSelection *sel, GtkTreeModel *model) {
 	GtkTreeIter  iter;
 	GValue val = { 0, };
+	char *file;
 
 	if (! gtk_tree_selection_get_selected (sel, &model, &iter))
 		return;
 	gtk_tree_model_get_value (model, &iter, 2, &val);
 	sound_row_sel = g_value_get_uint(&val);
+	file = gaim_sound_get_event_file(sound_row_sel);
 	if (sound_entry)
-		gtk_entry_set_text(GTK_ENTRY(sound_entry), sound_file[sound_row_sel] ? sound_file[sound_row_sel] : "(default)");
+		gtk_entry_set_text(GTK_ENTRY(sound_entry), file ? file : "(default)");
 	g_value_unset (&val);
 	if (sounddialog)
 		gtk_widget_destroy(sounddialog);
@@ -1472,6 +1464,7 @@
 	GtkTreeSelection *sel;
 	GtkTreePath *path;
 	int j;
+	char *file;
 
 	ret = gtk_vbox_new(FALSE, 18);
 	gtk_container_set_border_width (GTK_CONTAINER (ret), 12);
@@ -1483,14 +1476,15 @@
 	gtk_box_pack_start(GTK_BOX(ret), sw, TRUE, TRUE, 0);
 	event_store = gtk_list_store_new (3, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_UINT);
 
-	for (j=0; j < NUM_SOUNDS; j++) {
-		if (sounds[j].opt == 0)
+	for (j=0; j < GAIM_NUM_SOUNDS; j++) {
+		guint opt = gaim_sound_get_event_option(j);
+		if (opt == 0)
 			continue;
 
 		gtk_list_store_append (event_store, &iter);
 		gtk_list_store_set(event_store, &iter,
-				   0, sound_options & sounds[j].opt,
-				   1, gettext(sounds[j].label),
+				   0, sound_options & opt,
+				   1, gettext(gaim_sound_get_event_label(j)),
 				   2, j, -1);
 	}
 
@@ -1525,7 +1519,8 @@
 	hbox = gtk_hbox_new(FALSE, 6);
 	gtk_box_pack_start(GTK_BOX(ret), hbox, FALSE, FALSE, 0);
 	sound_entry = gtk_entry_new();
-	gtk_entry_set_text(GTK_ENTRY(sound_entry), sound_file[0] ? sound_file[0] : "(default)");
+	file = gaim_sound_get_event_file(0);
+	gtk_entry_set_text(GTK_ENTRY(sound_entry), file ? file : "(default)");
 	gtk_entry_set_editable(GTK_ENTRY(sound_entry), FALSE);
 	gtk_box_pack_start(GTK_BOX(hbox), sound_entry, FALSE, FALSE, 5);
 
--- a/src/sound.c	Sun Feb 09 00:47:57 2003 +0000
+++ b/src/sound.c	Sun Feb 09 01:55:35 2003 +0000
@@ -1,7 +1,7 @@
 /*
  * gaim
  *
- * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
+ * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -40,31 +40,38 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#ifdef ESD_SOUND
-#include <esd.h>
-#endif
-
-#ifdef ARTSC_SOUND
-#include <artsc.h>
-#endif
-
-#ifdef NAS_SOUND
-#include <audio/audiolib.h>
-#endif
+#ifdef USE_AO
+#include <ao/ao.h>
+#include <audiofile.h>
+#endif /* USE_AO */
 
 #include "gaim.h"
+#include "sound.h"
 
 #ifdef _WIN32
 #include "win32dep.h"
 #endif
 
-gboolean mute_sounds = 0;
+struct gaim_sound_event {
+	char *label;
+	guint opt;
+	char *def;
+};
+
+#ifdef USE_AO
+static int ao_driver;
+#endif /* USE_AO */
+
+
+static gboolean mute_login_sounds = FALSE;
+static gboolean mute_sounds = FALSE;
+static char *sound_cmd = NULL;
 
 /* description, option bit, default sound file             *
  * set the option bit to 0 to have it not display in prefs *
  * the order here has to match the defines in gaim.h.      *
  *                                               -Robot101 */
-struct sound_struct sounds[NUM_SOUNDS] = {
+static struct gaim_sound_event sounds[GAIM_NUM_SOUNDS] = {
 	{N_("Buddy logs in"), OPT_SOUND_LOGIN, "arrive.wav"},
 	{N_("Buddy logs out"), OPT_SOUND_LOGOUT, "leave.wav"},
 	{N_("Message received"), OPT_SOUND_RECV, "receive.wav"},
@@ -79,383 +86,235 @@
 	{N_("Someone says your name in chat"), OPT_SOUND_CHAT_NICK, "redalert.wav"}
 };
 
-#ifndef _WIN32
-static int check_dev(char *dev)
-{
-	struct stat stat_buf;
-	uid_t user = getuid();
-	gid_t group = getgid(), other_groups[32];
-	int i, numgroups;
-
-	if ((numgroups = getgroups(32, other_groups)) == -1)
-		return 0;
-	if (stat(dev, &stat_buf))
-		return 0;
-	if (user == stat_buf.st_uid && stat_buf.st_mode & S_IWUSR)
-		return 1;
-	if (stat_buf.st_mode & S_IWGRP) {
-		if (group == stat_buf.st_gid)
-			return 1;
-		for (i = 0; i < numgroups; i++)
-			if (other_groups[i] == stat_buf.st_gid)
-				return 1;
-	}
-	if (stat_buf.st_mode & S_IWOTH)
-		return 1;
-	return 0;
-}
+static char *sound_file[GAIM_NUM_SOUNDS];
 
-static void play_audio_file(char *file)
+void gaim_sound_init()
 {
-	/* here we can assume that we can write to /dev/audio */
-	char *buf;
-	struct stat info;
-	int fd = open(file, O_RDONLY);
-	if (fd <= 0) {
-		return;
-	}
-	fstat(fd, &info);
-	if (info.st_size < 24)
-		return;
-	buf = malloc(info.st_size + 1);
-	read(fd, buf, 24);
-	read(fd, buf, info.st_size - 24);
-	close(fd);
-
-	fd = open("/dev/audio", O_WRONLY | O_EXCL | O_NDELAY);
-	if (fd < 0) {
-		free(buf);
-		return;
-	}
-	write(fd, buf, info.st_size - 24);
-	free(buf);
-	close(fd);
-}
+#ifdef USE_AO
 
-static int can_play_audio()
-{
-	return check_dev("/dev/audio");
-}
-
-#ifdef ARTSC_SOUND
-
-/*
-** This routine converts from ulaw to 16 bit linear.
-**
-** Craig Reese: IDA/Supercomputing Research Center
-** 29 September 1989
-**
-** References:
-** 1) CCITT Recommendation G.711  (very difficult to follow)
-** 2) MIL-STD-188-113,"Interoperability and Performance Standards
-**     for Analog-to_Digital Conversion Techniques,"
-**     17 February 1987
-**
-** Input: 8 bit ulaw sample
-** Output: signed 16 bit linear sample
-** Z-note -- this is from libaudiofile.  Thanks guys!
-*/
+	ao_initialize();
+	ao_driver = ao_default_driver_id();
 
-static int _af_ulaw2linear(unsigned char ulawbyte)
-{
-	static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
-	int sign, exponent, mantissa, sample;
-
-	ulawbyte = ~ulawbyte;
-	sign = (ulawbyte & 0x80);
-	exponent = (ulawbyte >> 4) & 0x07;
-	mantissa = ulawbyte & 0x0F;
-	sample = exp_lut[exponent] + (mantissa << (exponent + 3));
-	if (sign != 0)
-		sample = -sample;
-
-	return (sample);
-}
-
-static int play_artsc(unsigned char *data, int size)
-{
-	arts_stream_t stream;
-	guint16 *lineardata;
-	int result = 1;
-	int error;
-	int i;
-
-	lineardata = g_malloc(size * 2);
-
-	for (i = 0; i < size; i++) {
-		lineardata[i] = _af_ulaw2linear(data[i]);
+	if(ao_driver == -1) {
+		do_error_dialog(_("Sound Driver Not Found"),
+				_("Gaim was unable to load a sound driver.  Sound files will "
+					"not be played."), GAIM_ERROR);
+	} else {
+		ao_info *info = ao_driver_info(ao_driver);
+		debug_printf("Sound output driver loaded: %s\n", info->name);
 	}
 
-	stream = arts_play_stream(8012, 16, 1, "gaim");
-
-	error = arts_write(stream, lineardata, size);
-	if (error < 0) {
-		result = 0;
-	}
-
-	arts_close_stream(stream);
-
-	g_free(lineardata);
-
-	arts_free();
-
-	return result;
-}
-
-static int can_play_artsc()
-{
-	int error;
-
-	error = arts_init();
-	if (error < 0)
-		return 0;
-
-	return 1;
+#endif
 }
 
-static int artsc_play_file(char *file)
+void gaim_sound_quit()
 {
-	struct stat stat_buf;
-	unsigned char *buf = NULL;
-	int result = 0;
-	int fd = -1;
-
-	if (!can_play_artsc())
-		return 0;
-
-	fd = open(file, O_RDONLY);
-	if (fd < 0)
-		return 0;
-
-	if (fstat(fd, &stat_buf)) {
-		close(fd);
-		return 0;
-	}
-
-	if (!stat_buf.st_size) {
-		close(fd);
-		return 0;
-	}
-
-	buf = g_malloc(stat_buf.st_size);
-	if (!buf) {
-		close(fd);
-		return 0;
-	}
+#ifdef USE_AO
 
-	if (read(fd, buf, stat_buf.st_size) < 0) {
-		g_free(buf);
-		close(fd);
-		return 0;
-	}
-
-	result = play_artsc(buf, stat_buf.st_size);
-
-	g_free(buf);
-	close(fd);
-	return result;
-}
-
-#endif /* ARTSC_SOUND */
-
-#ifdef NAS_SOUND
+	ao_shutdown();
 
-char nas_server[] = "localhost";
-AuServer *nas_serv = NULL;
-
-static AuBool NasEventHandler(AuServer * aud, AuEvent * ev, AuEventHandlerRec * handler)
-{
-	AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev;
-
-	if (ev->type == AuEventTypeElementNotify) {
-		switch (event->kind) {
-		case AuElementNotifyKindState:
-			switch (event->cur_state) {
-			case AuStateStop:
-				_exit(0);
-			}
-			break;
-		}
-	}
-	return AuTrue;
+#endif
 }
 
-
-static int play_nas(unsigned char *data, int size)
+void gaim_sound_play_file(char *filename)
 {
-	AuDeviceID device = AuNone;
-	AuFlowID flow;
-	AuElement elements[3];
-	int i, n, w;
-
-	/* look for an output device */
-	for (i = 0; i < AuServerNumDevices(nas_serv); i++) {
-		if ((AuDeviceKind(AuServerDevice(nas_serv, i)) ==
-		     AuComponentKindPhysicalOutput) &&
-		    AuDeviceNumTracks(AuServerDevice(nas_serv, i)) == 1) {
-			device = AuDeviceIdentifier(AuServerDevice(nas_serv, i));
-			break;
-		}
-	}
-
-	if (device == AuNone)
-		return 0;
-
-	if (!(flow = AuCreateFlow(nas_serv, NULL)))
-		return 0;
-
-
-	AuMakeElementImportClient(&elements[0], 8012, AuFormatULAW8, 1, AuTrue, size, size / 2, 0, NULL);
-	AuMakeElementExportDevice(&elements[1], 0, device, 8012, AuUnlimitedSamples, 0, NULL);
-	AuSetElements(nas_serv, flow, AuTrue, 2, elements, NULL);
-
-	AuStartFlow(nas_serv, flow, NULL);
-
-	AuWriteElement(nas_serv, flow, 0, size, data, AuTrue, NULL);
-
-	AuRegisterEventHandler(nas_serv, AuEventHandlerIDMask, 0, flow, NasEventHandler, NULL);
-
-	while (1) {
-		AuHandleEvents(nas_serv);
-	}
-
-	return 1;
-}
+#ifdef USE_AO
+	pid_t pid;
+#endif /* USE_AO */
 
-static int can_play_nas()
-{
-	if ((nas_serv = AuOpenServer(NULL, 0, NULL, 0, NULL, NULL)))
-		return 1;
-	return 0;
-}
-
-static int play_nas_file(char *file)
-{
-	struct stat stat_buf;
-	char *buf;
-	int ret;
-	int fd = open(file, O_RDONLY);
-	if (fd <= 0)
-		return 0;
-
-	if (!can_play_nas())
-		return 0;
+	if (mute_sounds)
+		return;
 
-	if (stat(file, &stat_buf))
-		return 0;
-
-	if (!stat_buf.st_size)
-		return 0;
-
-	buf = malloc(stat_buf.st_size);
-	read(fd, buf, stat_buf.st_size);
-	ret = play_nas(buf, stat_buf.st_size);
-	free(buf);
-	return ret;
-}
-
-#endif /* NAS_SOUND */
-
-#endif /* !_WIN32 */
-
-void play_file(char *filename)
-{
-#ifndef _WIN32
-	int pid;
-#endif
 	if (awaymessage && !(sound_options & OPT_SOUND_WHEN_AWAY))
 		return; /* check here in case a buddy pounce plays a file while away */
-	
+
 	if (sound_options & OPT_SOUND_BEEP) {
 		gdk_beep();
 		return;
 	}
 
-	else if (sound_options & OPT_SOUND_NORMAL) {
-		debug_printf("attempting to play audio file with internal method -- this is unlikely to work\n");
+	if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
+		char *tmp = g_strdup_printf(_("Unable to play sound because the chosen filename (%s) does not exist."), filename);
+		do_error_dialog(tmp, NULL, GAIM_ERROR);
+		g_free(tmp);
+		return;
 	}
+
 #ifndef _WIN32
+	if ((sound_options & OPT_SOUND_CMD)) {
+		char *command;
+		GError *error = NULL;
+
+		if(!sound_cmd) {
+			do_error_dialog(_("Unable to play sound because the 'Command' sound method has been chosen, but no command has been set."), NULL, GAIM_ERROR);
+			return;
+		}
+
+		command = g_strdup_printf(sound_cmd, filename);
+
+		if(!g_spawn_command_line_async(command, &error)) {
+			char *tmp = g_strdup_printf(_("Unable to play sound because the configured sound command could not be launched: %s"), error->message);
+			do_error_dialog(tmp, NULL, GAIM_ERROR);
+			g_free(tmp);
+			g_error_free(error);
+		}
+
+		g_free(command);
+		return;
+	}
+#ifdef USE_AO
+
+	if(ao_driver == -1) {
+		/* do _something_ audible ;-) */
+		gdk_beep();
+		return;
+	}
+
+
 	pid = fork();
 
 	if (pid < 0)
 		return;
 	else if (pid == 0) {
-		alarm(30);
-		
-		if ((sound_options & OPT_SOUND_CMD) && sound_cmd[0]) {
-			char *args[4];
-			char command[4096];
+		AFfilehandle file = afOpenFile(filename, "rb", NULL);
+		if(file) {
+			ao_device *device;
+			ao_sample_format format;
+			int in_fmt;
+			int bytes_per_frame;
 
-			g_snprintf(command, sizeof(command), sound_cmd, filename);
+			format.rate = afGetRate(file, AF_DEFAULT_TRACK);
+			format.channels = afGetChannels(file, AF_DEFAULT_TRACK);
+			afGetSampleFormat(file, AF_DEFAULT_TRACK, &in_fmt,
+					&format.bits);
+
+			afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK,
+					AF_SAMPFMT_TWOSCOMP, format.bits);
 
-			args[0] = "sh";
-			args[1] = "-c";
-			args[2] = command;
-			args[3] = NULL;
-			execvp(args[0], args);
-			_exit(0);
-		}
-#ifdef ESD_SOUND
-		else if (sound_options & OPT_SOUND_ESD) {
-			if (esd_play_file(NULL, filename, 1))
-				_exit(0);
+			if(afGetByteOrder(file, AF_DEFAULT_TRACK) == AF_BYTEORDER_BIGENDIAN)
+				format.byte_format = AO_FMT_BIG;
+			else
+				format.byte_format = AO_FMT_LITTLE;
+
+			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;
+
+				while((frames_read = afReadFrames(file, AF_DEFAULT_TRACK,
+								buf, buf_frames))) {
+					if(!ao_play(device, buf, frames_read * bytes_per_frame))
+						break;
+				}
+				ao_close(device);
+			}
+			afCloseFile(file);
 		}
-#endif
-
-#ifdef ARTSC_SOUND
-		else if (sound_options & OPT_SOUND_ARTSC) {
-			if (artsc_play_file(filename))
-				_exit(0);
-		}
-#endif
-
-#ifdef NAS_SOUND
-		else if (sound_options & OPT_SOUND_NAS) {
-			if (play_nas_file(filename))
-				_exit(0);
-		}
-#endif
-
-		else if ((sound_options & OPT_SOUND_NORMAL) &&
-			 can_play_audio()) {
-			play_audio_file(filename);
-			_exit(0);
-		}
-
 		_exit(0);
 	}
+#else /* USE_AO */
+	gdk_beep();
+	return;
+#endif /* USE_AO */
 #else /* _WIN32 */
 	debug_printf("Playing %s\n", filename);
 	if (!PlaySound(filename, 0, SND_ASYNC | SND_FILENAME))
 		debug_printf("Error playing sound.");
-#endif
+#endif /* _WIN32 */
 }
 
-extern int logins_not_muted;
-
-void play_sound(int sound)
+void gaim_sound_play_event(GaimSoundEventID event)
 {
-	if (mute_sounds)
-		return;
-	
-	if ((sound == SND_BUDDY_ARRIVE) && !logins_not_muted)
+	if ((event == GAIM_SOUND_BUDDY_ARRIVE) && mute_login_sounds)
 		return;
 
-	if (sound >= NUM_SOUNDS) {
-		debug_printf("got request for unknown sound: %d\n", sound);
+	if (event >= GAIM_NUM_SOUNDS) {
+		debug_printf("got request for unknown sound: %d\n", event);
 		return;
 	}
 
 	/* check NULL for sounds that don't have an option, ie buddy pounce */
-	if ((sound_options & sounds[sound].opt) || (sounds[sound].opt == 0)) {
-		if (sound_file[sound]) {
-			play_file(sound_file[sound]);
+	if ((sound_options & sounds[event].opt) || (sounds[event].opt == 0)) {
+		if (sound_file[event]) {
+			gaim_sound_play_file(sound_file[event]);
 		} else {
 			gchar *filename = NULL;
 
-			filename = g_build_filename(DATADIR, "sounds", "gaim", sounds[sound].def, NULL);
-			play_file(filename);
+			filename = g_build_filename(DATADIR, "sounds", "gaim", sounds[event].def, NULL);
+			gaim_sound_play_file(filename);
 			g_free(filename);
 		}
 	}
 }
+
+void gaim_sound_set_mute(gboolean mute)
+{
+	mute_sounds = mute;
+}
+
+gboolean gaim_sound_get_mute()
+{
+	return mute_sounds;
+}
+
+void gaim_sound_set_login_mute(gboolean mute)
+{
+	mute_login_sounds = mute;
+}
+
+void gaim_sound_set_event_file(GaimSoundEventID event, const char *filename)
+{
+	if(event >= GAIM_NUM_SOUNDS)
+		return;
+
+	if(sound_file[event])
+		g_free(sound_file[event]);
+
+	sound_file[event] = g_strdup(filename);
+}
+
+
+char *gaim_sound_get_event_file(GaimSoundEventID event)
+{
+	if(event >= GAIM_NUM_SOUNDS)
+		return NULL;
+
+	return sound_file[event];
+}
+
+guint gaim_sound_get_event_option(GaimSoundEventID event)
+{
+	if(event >= GAIM_NUM_SOUNDS)
+		return 0;
+
+	return sounds[event].opt;
+}
+
+char *gaim_sound_get_event_label(GaimSoundEventID event)
+{
+	if(event >= GAIM_NUM_SOUNDS)
+		return NULL;
+
+	return sounds[event].label;
+}
+
+
+void gaim_sound_set_command(const char *cmd)
+{
+	if(sound_cmd)
+		g_free(sound_cmd);
+	if(strlen(cmd) > 0)
+		sound_cmd = g_strdup(cmd);
+	else
+		sound_cmd = NULL;
+}
+
+char *gaim_sound_get_command()
+{
+	return sound_cmd;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sound.h	Sun Feb 09 01:55:35 2003 +0000
@@ -0,0 +1,149 @@
+/**
+ * @file sound.h Sound API
+ *
+ * gaim
+ *
+ * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _SOUND_H_
+#define _SOUND_H_
+
+/**************************************************************************/
+/** Data Structures                                                       */
+/**************************************************************************/
+
+
+/**
+ * A type of conversation.
+ */
+
+typedef enum _GaimSoundEventID
+{
+	GAIM_SOUND_BUDDY_ARRIVE = 0, /**< Buddy signs on.                       */
+	GAIM_SOUND_BUDDY_LEAVE,      /**< Buddy signs off.                      */
+	GAIM_SOUND_RECEIVE,          /**< Receive an IM.                        */
+	GAIM_SOUND_FIRST_RECEIVE,    /**< Receive an IM that starts a conv.     */
+	GAIM_SOUND_SEND,             /**< Send an IM.                           */
+	GAIM_SOUND_CHAT_JOIN,        /**< Someone joins a chat.                 */
+	GAIM_SOUND_CHAT_LEAVE,       /**< Someone leaves a chat.                */
+	GAIM_SOUND_CHAT_YOU_SAY,     /**< You say something in a chat.          */
+	GAIM_SOUND_CHAT_SAY,         /**< Someone else says somthing in a chat. */
+	GAIM_SOUND_POUNCE_DEFAULT,   /**< Default sound for a buddy pounce.     */
+	GAIM_SOUND_CHAT_NICK,        /**< Someone says your name in a chat.     */
+	GAIM_NUM_SOUNDS              /**< Total number of sounds.               */
+} GaimSoundEventID;
+
+/**************************************************************************/
+/** @name Sound API                                                       */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * Sets up the sound system.
+ */
+void gaim_sound_init();
+
+/**
+ * Properly shuts down the sound system.
+ */
+void gaim_sound_quit();
+
+/**
+ * Plays the specified sound file.
+ *
+ * @param filename The file to play.
+ */
+void gaim_sound_play_file(char *filename);
+
+/**
+ * Plays the sound associated with the specified event.
+ *
+ * @param event The event.
+ */
+void gaim_sound_play_event(GaimSoundEventID event);
+
+/**
+ * Mutes or un-mutes sounds.
+ *
+ * @param mute The mute state.
+ */
+void gaim_sound_set_mute(gboolean mute);
+
+/**
+ * Gets mute state for sounds.
+ *
+ * @return The mute state.
+ */
+gboolean gaim_sound_get_mute();
+
+/**
+ * Mutes or un-mutes login sounds.
+ *
+ * @param mute The mute state.
+ */
+void gaim_sound_set_login_mute(gboolean mute);
+
+/**
+ * Set sound file for an event.
+ *
+ * @param event The event.
+ * @param filename The sound file.
+ */
+void gaim_sound_set_event_file(GaimSoundEventID event, const char *filename);
+
+/** Get sound file for an event.
+ *
+ * @param event The event.
+ * @return The filename if set, otherwise @c NULL.
+ */
+char *gaim_sound_get_event_file(GaimSoundEventID event);
+
+/**
+ * Get the prefs option for an event.
+ *
+ * @param event The event.
+ * @return The option.
+ */
+guint gaim_sound_get_event_option(GaimSoundEventID event);
+
+/**
+ * Get the label for an event.
+ *
+ * @param event The event.
+ * @return The label.
+ */
+char *gaim_sound_get_event_label(GaimSoundEventID event);
+
+/**
+ * Set sound command for command mode.
+ *
+ * @param cmd The command.
+ */
+void gaim_sound_set_command(const char *cmd);
+
+/**
+ * Get sound command for command mode.
+ *
+ * @return The command if set, otherwise @c NULL.
+ */
+char *gaim_sound_get_command();
+
+/*@}*/
+
+#endif /* _CONVERSATION_H_ */
--- a/src/ui.h	Sun Feb 09 00:47:57 2003 +0000
+++ b/src/ui.h	Sun Feb 09 01:55:35 2003 +0000
@@ -306,9 +306,6 @@
 /* Globals in session.c */
 extern gboolean session_managed;
 
-/* Globals in sound.c */
-extern gboolean mute_sounds;
-
 /* Globals in themes.c */
 extern struct smiley_theme *current_smiley_theme;
 extern GSList *smiley_themes;
@@ -504,10 +501,6 @@
 extern void session_init(gchar *, gchar *);
 extern void session_end();
 
-/* Functions in sound.c */
-extern void play_sound(int);
-extern void play_file(char *);
-
 /* Functions in themes.c */
 extern void smiley_themeize(GtkWidget *);
 extern void smiley_theme_probe();