? gm
? gm.patch
? gnome-media-2.12.0.1
? grecord/src/out
? grecord/src/gst/Makefile
? grecord/src/gst/Makefile.in
? grecord/src/recent-files/Makefile
? grecord/src/recent-files/Makefile.in
? gst-mixer/gnome-volume-control.schemas
? gst-mixer/doc/uk/gnome-volume-control-uk.omf.out
Index: .cvsignore
===================================================================
RCS file: /cvs/gnome/gnome-media/.cvsignore,v
retrieving revision 1.9
diff -u -p -r1.9 .cvsignore
--- .cvsignore	16 Dec 2002 16:57:00 -0000	1.9
+++ .cvsignore	16 Jan 2006 22:27:58 -0000
@@ -32,3 +32,5 @@ intltool-update
 intltool-extract.in
 intltool-merge.in
 intltool-update.in
+compile
+depcomp
Index: Makefile.am
===================================================================
RCS file: /cvs/gnome/gnome-media/Makefile.am,v
retrieving revision 1.51
diff -u -p -r1.51 Makefile.am
--- Makefile.am	1 Jun 2004 10:08:56 -0000	1.51
+++ Makefile.am	16 Jan 2006 22:27:58 -0000
@@ -21,7 +21,8 @@ EXTRA_DIST =	config.rpath gnome-media.sp
 		gnome-media.spec \
 		sgmldocs.make xmldocs.make omf.make \
 		m4/as-compiler-flag.m4 m4/as-version.m4 \
-		$(INTLTOOL_BUILT:=.in)
+		$(INTLTOOL_BUILT:=.in) \
+		autogen.sh gstreamer-0.10.patch transmogrify-into-gstreamer-0.10
 
 DISTCLEANFILES = po/.intltool-merge-cache \
                  $(INTLTOOL_BUILT)
Index: README
===================================================================
RCS file: /cvs/gnome/gnome-media/README,v
retrieving revision 1.5
diff -u -p -r1.5 README
--- README	1 Jun 2004 10:49:42 -0000	1.5
+++ README	16 Jan 2006 22:27:58 -0000
@@ -1,4 +1,13 @@
-These are the GNOME media tools for GNOME 2.7 (and beyond).
+These are the GNOME media tools for GNOME 2.14 (and beyond).
+
+NOTE:
+-----
+This tarball by default builds against GStreamer 0.8
+If you want it to build against GStreamer 0.10, do this:
+
+./transmogrify-into-gstreamer-0.10
+./autogen.sh
+make
 
 gnome-cd/               - GNOME CD player, with CDDB support.
 cddb-slave2/            - Helper daemon for gnome-cd's CDDB support.
Index: configure.in
===================================================================
RCS file: /cvs/gnome/gnome-media/configure.in,v
retrieving revision 1.287
diff -u -p -r1.287 configure.in
--- configure.in	14 Jan 2006 01:40:46 -0000	1.287
+++ configure.in	16 Jan 2006 22:27:58 -0000
@@ -2,7 +2,7 @@ AC_PREREQ(2.53)
 AC_INIT(cddb-slave2)
 
 
-AS_VERSION(gnome-media, GNOME_MEDIA_VERSION, 2, 12, 0, 1,
+AS_VERSION(gnome-media, GNOME_MEDIA_VERSION, 2, 13, 0, 0,
   GM_RELEASE="yes", GM_RELEASE="no")
 
 AM_MAINTAINER_MODE
Index: gstreamer-0.10.patch
===================================================================
RCS file: gstreamer-0.10.patch
diff -N gstreamer-0.10.patch
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gstreamer-0.10.patch	16 Jan 2006 22:27:59 -0000
@@ -0,0 +1,6362 @@
+Index: Makefile.am
+===================================================================
+RCS file: /cvs/gnome/gnome-media/Makefile.am,v
+retrieving revision 1.51
+retrieving revision 1.51.8.1
+diff -u -p -r1.51 -r1.51.8.1
+--- Makefile.am	1 Jun 2004 10:08:56 -0000	1.51
++++ Makefile.am	13 Jan 2006 15:07:51 -0000	1.51.8.1
+@@ -2,8 +2,8 @@ always_built_SUBDIRS = cddb-slave2 profi
+ 
+ SUBDIRS = po $(always_built_SUBDIRS) \
+ 	  @PROGRAMS_VUMETER@ \
+-	  @PROGRAMS_GNOME_CD@ \
+ 	  @PROGRAMS_GSTMIXER@ \
++	  @PROGRAMS_GNOME_CD@ \
+ 	  @PROGRAMS_GRECORD@ \
+ 	  @PROGRAMS_GSTPROPS@
+ 
+Index: configure.in
+===================================================================
+RCS file: /cvs/gnome/gnome-media/configure.in,v
+retrieving revision 1.286
+retrieving revision 1.286.4.9
+diff -u -p -r1.286 -r1.286.4.9
+--- configure.in	28 Oct 2005 23:58:23 -0000	1.286
++++ configure.in	16 Jan 2006 21:16:31 -0000	1.286.4.9
+@@ -127,29 +127,84 @@ AC_SUBST(VUMETER_LIBS)
+ # Check for GStreamer stuff and GSR depds
+ HAVE_GST=no
+ 
+-GST_REQ=0.8.2
++GST_REQ=0.10.2
++GSTPB_REQ=0.10.2
++
+ PROGRAMS_GSTRECORD=""
+ 
+-dnl start with 0.8
+-GST_MAJORMINOR=0.8
++dnl start with 0.10
++GST_MAJORMINOR=0.10
++dnl make available to Makefile.am
++AC_SUBST(GST_MAJORMINOR)
++AC_DEFINE_UNQUOTED(GST_MAJORMINOR_QUOTED, "$GST_MAJORMINOR",
++  [major/minor of GStreamer as a string constant])
++
++dnl  gstreamer-libs-$GST_MAJORMINOR >= $GST_REQ 
++dnl  gstreamer-gconf-$GST_MAJORMINOR >= $GST_REQ
++
+ PKG_CHECK_MODULES(GSR, \
+   gstreamer-$GST_MAJORMINOR >= $GST_REQ \
+-  gstreamer-libs-$GST_MAJORMINOR >= $GST_REQ \
+-  gstreamer-gconf-$GST_MAJORMINOR >= $GST_REQ \
++  gstreamer-plugins-base-$GST_MAJORMINOR >= $GST_REQ \
+   gtk+-2.0 >= 2.6.0 libgnomeui-2.0 >= 1.102.0 gnome-vfs-2.0,
+   HAVE_GST=yes,HAVE_GST=no)
+ 
+-if test "x$HAVE_GST" = "xno"; then
+-  AC_MSG_WARN(you need GStreamer installed for the mixer and recorder to work)
+-else
++if test "x$HAVE_GST" = "xyes"; then
+   PROGRAMS_GRECORD="grecord"
++
++  gst010_toolsdir=`$PKG_CONFIG --variable=toolsdir gstreamer-0.10`
++  gst010_inspect="$gst010_toolsdir/gst-inspect-0.10"
++
++  dnl Check for elements from gst-plugins-base
++  for base_element in playbin audioconvert audioresample
++  do
++    AC_MSG_CHECKING([for GStreamer 0.10 $base_element plugin])
++    if $gst010_inspect $base_element >/dev/null 2>/dev/null; then
++      AC_MSG_RESULT([yes])
++    else
++      AC_MSG_RESULT([no])
++      AC_MSG_WARN([
++                    Cannot find required GStreamer-0.10 plugin '$base_element'.
++                    It should be part of gst-plugins-base. Please install it.
++                    You need it installed for the sound recorder to work.
++      ])
++      sleep 5 2>/dev/null
++      PROGRAMS_GRECORD=""
++    fi
++  done
++
++
++  dnl Check for elements from gst-plugins-good
++  for good_element in gconfaudiosink gconfaudiosrc
++  do
++    AC_MSG_CHECKING([for GStreamer 0.10 $good_element plugin])
++    if $gst010_inspect $good_element >/dev/null 2>/dev/null; then
++      AC_MSG_RESULT([yes])
++    else
++      AC_MSG_RESULT([no])
++      AC_MSG_WARN([
++                   Cannot find required GStreamer-0.10 plugin '$good_element'.
++                   It should be part of gst-plugins-good. Please install it.
++                   You need it installed for the sound recorder to work.
++      ])
++      sleep 5 2>/dev/null
++      PROGRAMS_GRECORD=""
++    fi
++  done
++else
++  AC_MSG_WARN([You need GStreamer installed for the mixer and recorder to work])
++  sleep 5 2>/dev/null
+ fi
++
+ AC_SUBST(PROGRAMS_GRECORD)
+ AM_CONDITIONAL(HAVE_GSTREAMER, test "x$HAVE_GST" = "xyes")
+ 
+ AC_SUBST(GSR_CFLAGS)
+ AC_SUBST(GSR_LIBS)
+ 
++dnl uninstalled gsr ui dir
++AC_DEFINE_UNQUOTED(GSR_UIDIR_UNINSTALLED, "`pwd`/grecord/src",
++    [path to uninstalled gnome-sound-recorder UI dir])
++
+ AC_PATH_PROG(GCONFTOOL, gconftool-2)
+ AM_GCONF_SOURCE_2
+ 
+@@ -223,7 +278,11 @@ AC_MSG_RESULT($MAIL_TRANSFER_AGENT)
+ 
+ # Everything OK for gnome-cd?
+ # Check for the gnome-cd
+-PKG_CHECK_MODULES(GNOMECD, libnautilus-burn >= 2.9.0)
++PKG_CHECK_MODULES(GNOMECD, \
++  gstreamer-$GST_MAJORMINOR >= $GST_REQ \
++  gstreamer-plugins-base-$GST_MAJORMINOR >= $GSTPB_REQ \
++  libnautilus-burn >= 2.9.0,
++  HAVE_GST=yes,HAVE_GST=no)
+ AC_SUBST(GNOMECD_CFLAGS)
+ AC_SUBST(GNOMECD_LIBS)
+ 
+@@ -310,6 +369,11 @@ AC_SUBST(default_cd_device)
+ AC_DEFINE_UNQUOTED(default_cd_device, "$default_cd_device",
+   [Default CD device to use])
+ 
++dnl uninstalled theme dir
++AC_DEFINE_UNQUOTED(THEME_DIR_UNINSTALLED, "`pwd`/gnome-cd/images",
++    [path to uninstalled gnome-cd themes dir])
++AC_SUBST(THEME_DIR_UNINSTALLED)
++
+ PKG_CHECK_MODULES(GAILUTIL, gail >= 0.0.3)
+ 
+ AC_SUBST(GAILUTIL_CFLAGS)
+@@ -319,7 +383,9 @@ AC_SUBST(GAILUTIL_LIBS)
+ PROGRAMS_GSTPROPS=""
+ if test "x$HAVE_GST" = "xyes";
+ then
+-  COMMON_MODULES="gconf-2.0 libgnomeui-2.0 libglade-2.0 >= 1.99.12 gstreamer-$GST_MAJORMINOR gstreamer-libs-$GST_MAJORMINOR gstreamer-gconf-$GST_MAJORMINOR"
++  dnl gstreamer-libs-$GST_MAJORMINOR
++  dnl gstreamer-gconf-$GST_MAJORMINOR
++  COMMON_MODULES="gconf-2.0 libgnomeui-2.0 libglade-2.0 >= 1.99.12 gstreamer-$GST_MAJORMINOR"
+   PKG_CHECK_MODULES(GSTPROPS, $COMMON_MODULES libxml-2.0 gnome-vfs-2.0,
+   		  PROGRAMS_GSTPROPS="gstreamer-properties")
+   GSTPROPS_LIBS="$GSTPROPS_LIBS"
+@@ -338,16 +404,26 @@ fi
+ if test "x$HAVE_GST" = "xyes";
+ then
+   PROGRAMS_GSTMIX=""
+-  COMMON_MODULES="libgnomeui-2.0 gstreamer-$GST_MAJORMINOR gstreamer-interfaces-$GST_MAJORMINOR"
+-  PKG_CHECK_MODULES(GSTMIXER, $COMMON_MODULES, [
++  dnl gstreamer-interfaces-$GST_MAJORMINOR
++  PKG_CHECK_MODULES(GSTMIXER,
++  [
++    libgnomeui-2.0
++    gstreamer-$GST_MAJORMINOR
++    gstreamer-plugins-base-$GST_MAJORMINOR
++  ],
++  [
+     OLD_CPPFLAGS=$CPPFLAGS
+     CPPFLAGS="$CPPFLAGS $GSTMIXER_CFLAGS"
+     PROGRAMS_GSTMIXER="gst-mixer"
+-    AC_CHECK_HEADER(gst/mixer/mixer.h, , PROGRAMS_GSTMIXER="")
+-    if test x$PROGRAMS_GSTMIXER != x; then
+-      AC_CHECK_HEADER(gst/propertyprobe/propertyprobe.h, , PROGRAMS_GSTMIXER="")
++    AC_CHECK_HEADER(gst/audio/mixerutils.h, , PROGRAMS_GSTMIXER="")
++    if test "x$PROGRAMS_GSTMIXER" != "x"; then
++      AC_CHECK_HEADER(gst/interfaces/mixer.h, , PROGRAMS_GSTMIXER="")
++    fi
++    if test "x$PROGRAMS_GSTMIXER" != "x"; then
++      AC_CHECK_HEADER(gst/interfaces/propertyprobe.h, , PROGRAMS_GSTMIXER="")
+     fi
+     CPPFLAGS=$OLD_CPPFLAGS
++    GSTMIXER_LIBS="$GSTMIXER_LIBS -lgstinterfaces-$GST_MAJORMINOR -lgstaudio-$GST_MAJORMINOR"
+   ],
+   [])
+ 
+@@ -357,7 +433,7 @@ then
+ fi
+ 
+ # profiles
+-PKG_CHECK_MODULES(GMP, gconf-2.0 libglade-2.0 libgnomeui-2.0,
++PKG_CHECK_MODULES(GMP, gconf-2.0 libglade-2.0 libgnomeui-2.0 gnome-vfs-module-2.0,
+                   USE_GMP=yes, USE_GMP=no)
+ AC_SUBST(GMP_CFLAGS)
+ AC_SUBST(GMP_LIBS)
+@@ -393,7 +469,6 @@ gnome-cd/doc/zh_TW/Makefile
+ grecord/Makefile
+ grecord/gnome-sound-recorder.schemas.in
+ grecord/src/Makefile
+-grecord/src/gst/Makefile
+ grecord/src/recent-files/Makefile
+ grecord/doc/Makefile
+ grecord/doc/C/Makefile
+Index: gnome-cd/Makefile.am
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gnome-cd/Makefile.am,v
+retrieving revision 1.32
+retrieving revision 1.32.4.2
+diff -u -p -r1.32 -r1.32.4.2
+--- gnome-cd/Makefile.am	27 Aug 2005 16:05:24 -0000	1.32
++++ gnome-cd/Makefile.am	13 Jan 2006 15:43:03 -0000	1.32.4.2
+@@ -14,7 +14,6 @@ INCLUDES =					\
+ 	$(MEDIA_CFLAGS)				\
+ 	$(GNOMECD_CFLAGS)			\
+ 	$(GAILUTIL_CFLAGS)			\
+-	$(GSR_CFLAGS)                           \
+ 	$(GST_CFLAGS)				\
+ 	-DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\"	\
+ 	-DDATADIR=\""$(datadir)"\"		\
+@@ -31,8 +30,8 @@ EXTRA_DIST = \
+ 	bsd-cdrom.h		\
+ 	linux-cdrom.c		\
+ 	linux-cdrom.h		\
+-	gst-cdparanoia-cdrom.c	\
+-	gst-cdparanoia-cdrom.h	\
++	gst-cdrom.c	  	\
++	gst-cdrom.h		\
+ 	gnome-cd.png gnome-cd.desktop.in gnome-cd.schemas.in
+ 
+ ### intermediate libtool library generated from IDL source
+@@ -52,7 +51,7 @@ noinst_LTLIBRARIES = libgnomemedia-cddbs
+ nodist_libgnomemedia_cddbslave2_la_SOURCES = $(IDL_GENERATED)
+ 
+ if HAVE_GSTREAMER
+-cd_sources = gst-cdparanoia-cdrom.c
++cd_sources = gst-cdrom.c
+ else
+ if CDROM_HOST_BSD
+ cd_sources = bsd-cdrom.c bsd-cdrom.h
+Index: gnome-cd/cdrom.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gnome-cd/cdrom.c,v
+retrieving revision 1.31
+retrieving revision 1.31.4.1
+diff -u -p -r1.31 -r1.31.4.1
+--- gnome-cd/cdrom.c	13 Jun 2005 09:38:43 -0000	1.31
++++ gnome-cd/cdrom.c	13 Jan 2006 15:07:51 -0000	1.31.4.1
+@@ -404,7 +404,7 @@ static void
+ cdrom_update_cd (GnomeCDRom *cdrom)
+ 
+ {
+-	g_error ("cdrom_update_cd not implmented");
++	g_error ("cdrom_update_cd not implemented");
+ }
+ 
+ static void
+Index: gnome-cd/display.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gnome-cd/display.c,v
+retrieving revision 1.32
+retrieving revision 1.32.4.1
+diff -u -p -r1.32 -r1.32.4.1
+--- gnome-cd/display.c	21 Dec 2005 14:30:10 -0000	1.32
++++ gnome-cd/display.c	13 Jan 2006 16:16:46 -0000	1.32.4.1
+@@ -804,14 +804,28 @@ cd_display_clear (CDDisplay *disp)
+ 	gtk_widget_queue_resize (GTK_WIDGET (disp));
+ }
+ 
++/* given a theme name and a file name, create the full path to the image file */
+ static inline char *
+ make_fullname (const char *theme_name,
+ 	       const char *name)
+ {
+ 	char *image;
++	char *tmp;
+ 
+-	image = g_build_filename (THEME_DIR, theme_name, name, NULL);
+-	
++        tmp = g_strdup_printf ("%s-theme", theme_name);
++
++	image = g_build_filename (THEME_DIR_UNINSTALLED, tmp, name, NULL);
++        if (g_file_test (image,
++                         G_FILE_TEST_IS_REGULAR |
++                         G_FILE_TEST_IS_SYMLINK) == TRUE) {
++                g_free (tmp);
++                return image;
++        }
++
++	g_free (image);
++	image = g_build_filename (THEME_DIR, tmp, name, NULL);
++
++	g_free (tmp);
+ 	return image;
+ }
+ 
+Index: gnome-cd/gnome-cd.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gnome-cd/gnome-cd.c,v
+retrieving revision 1.103
+retrieving revision 1.103.2.1
+diff -u -p -r1.103 -r1.103.2.1
+--- gnome-cd/gnome-cd.c	10 Jan 2006 12:10:42 -0000	1.103
++++ gnome-cd/gnome-cd.c	13 Jan 2006 15:07:51 -0000	1.103.2.1
+@@ -978,9 +978,6 @@ int 
+ main (int argc, char *argv[])
+ {
+ 	static struct poptOption cd_popt_options [] = {
+-#ifdef HAVE_GST
+-		{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, NULL, 0, "GStreamer", NULL },
+-#endif
+ 		{ "device", '\0', POPT_ARG_STRING, &cd_option_device, 0,
+ 		  N_("CD device to use"), NULL },
+ 		{ "unique", '\0', POPT_ARG_NONE, &cd_option_unique, 0,
+@@ -1006,29 +1003,16 @@ main (int argc, char *argv[])
+ 	textdomain (GETTEXT_PACKAGE);
+ 
+ #ifdef HAVE_GST
+-	cd_popt_options[0].arg = (void*) gst_init_get_popt_table();
++	/* FIXME when transition to GOption is being made */
++        /* g_option_context_add_group (context, gst_init_get_goption_group()); */
++
++	gst_init (&argc, &argv); /* gst will remove its own options */
+ #endif
++
+ 	gnome_program_init ("gnome-cd", VERSION, LIBGNOMEUI_MODULE, 
+ 			    argc, argv, 
+ 			    GNOME_PARAM_POPT_TABLE, cd_popt_options,
+ 			    GNOME_PARAM_APP_DATADIR, DATADIR, NULL);
+-
+-#ifdef HAVE_GST
+-	if (!gst_scheduler_factory_get_default_name ()) {
+-		GtkWidget *dialog;
+-
+-		dialog = gtk_message_dialog_new (NULL,
+-						 0,
+-						 GTK_MESSAGE_ERROR,
+-						 GTK_BUTTONS_CLOSE,
+-						 _("Registry is not present or it is corrupted, please update it by running gst-register"));
+-
+-		gtk_dialog_run (GTK_DIALOG (dialog));
+-		gtk_widget_destroy (dialog);
+-
+-		exit (1);
+-	}
+-#endif
+ 
+ 	register_stock_icons ();
+ 	client = gnome_master_client ();
+Index: gnome-cd/gst-cdrom.c
+===================================================================
+RCS file: gnome-cd/gst-cdrom.c
+diff -N gnome-cd/gst-cdrom.c
+--- /dev/null	1 Jan 1970 00:00:00 -0000
++++ gnome-cd/gst-cdrom.c	15 Jan 2006 20:12:56 -0000	1.1.2.2
+@@ -0,0 +1,1172 @@
++/*
++ * gst-cdrom.c: Gstreamer Audio CD controlling functions.
++ *
++ * Copyright (C) 2005 Tim-Philipp Müller <tim centricular net>
++ *
++ * Remaining issues:
++ *  - why doesn't it start playing when fired up automatically, even though
++ *    that's what is selected in the preferences?
++ *  - tray status checking (we should really have an interface for that
++ *    in GStreamer, incl. drive locking and eject and things like that)
++ */
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#define _ISOC99_SOURCE
++#include <math.h>
++#include <string.h>
++#include <glib/gi18n.h>
++#include <sys/types.h>
++#include <sys/ioctl.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <unistd.h>
++
++#include <gst/gst.h>
++#include <gst/cdda/gstcddabasesrc.h>
++
++#include "gst-cdrom.h"
++#include "cddb.h"
++
++#ifdef __linux__
++#include <linux/cdrom.h>
++#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
++#include <sys/cdio.h>
++#endif
++#if defined(__FreeBSD__)
++#include <sys/cdrio.h>
++#endif
++
++#if defined(__FreeBSD__)
++# define GST_CDROM_IOCTL_CDCAPABILITY_REQUEST  CDIOCCAPABILITY
++# define GST_CDROM_IOCTL_EJECT_REQUEST         CDIOCEJECT
++#elif defined(__NetBSD__) || defined(__OpenBSD__)
++# define GST_CDROM_IOCTL_CDCAPABILITY_REQUEST  CDIOCGETVOL
++# define GST_CDROM_IOCTL_EJECT_REQUEST         CDIOCEJECT
++#else
++# define GST_CDROM_IOCTL_CDCAPABILITY_REQUEST  CDROM_GET_CAPABILITY
++# define GST_CDROM_IOCTL_EJECT_REQUEST         CDROMEJECT
++#endif
++
++GST_DEBUG_CATEGORY_STATIC (gnomecd_debug);
++#define GST_CAT_DEFAULT gnomecd_debug
++
++struct _GstCDRomPrivate {
++  GstElement          *playbin;
++  GstElement          *source; /* e.g. cdparanoia or cddasrc element */
++
++  GnomeCDRomCDDBData  *cddb_data;
++  GstTagList          *tags;
++
++  gchar               *device;
++  GnomeCDRomStatus     status;
++};
++
++static void           gst_cdrom_notify_source_cb (GstCDRom           * cdrom,
++                                                  GParamSpec         * pspec,
++                                                  gpointer             foo);
++
++static void           gst_cdrom_update_cd        (GnomeCDRom         * cdrom);
++
++static gboolean       gst_cdrom_set_device       (GnomeCDRom         * cdrom,
++                                                  const char         * dev,
++                                                  GError            ** err);
++
++static gboolean       gst_cdrom_get_status       (GnomeCDRom         * cdrom,
++                                                  GnomeCDRomStatus  ** status,
++                                                  GError            ** error);
++
++static gboolean       gst_cdrom_eject            (GnomeCDRom         * cdrom,
++                                                  GError            ** error);
++
++static gboolean       gst_cdrom_play             (GnomeCDRom         * cdrom,
++                                                  int                  start_track,
++                                                  GnomeCDRomMSF      * start,
++                                                  int                  finish_track,
++                                                  GnomeCDRomMSF      * finish,
++                                                  GError            ** error);
++
++static gboolean        gst_cdrom_next            (GnomeCDRom         * cdrom,
++                                                  GError            ** error);
++
++static gboolean        gst_cdrom_back            (GnomeCDRom         * cdrom,
++                                                  GError            ** error);
++
++static gboolean        gst_cdrom_update_tray_status (GstCDRom * cdrom,
++                                                     GError  ** error);
++
++static gboolean        gst_cdrom_get_cddb_data   (GnomeCDRom          * cdrom,
++                                                  GnomeCDRomCDDBData ** data,
++                                                  GError             ** error);
++
++static gboolean        gst_cdrom_set_cddb_data_from_tags (GstCDRom  * cdrom,
++                                                          GstTagList * tags);
++
++
++G_DEFINE_TYPE (GstCDRom, gst_cdrom, GNOME_CDROM_TYPE);
++
++static GnomeCDRomMSF blank_msf = { 0, 0, 0 };
++
++static gboolean
++nanoseconds_to_msf (gint64 nanoseconds, GnomeCDRomMSF *msf)
++{
++  gint m = 0, s = 0, f = 0;
++
++  if (nanoseconds >= 0) {
++    m = nanoseconds / (GST_SECOND * 60);
++    nanoseconds -= m * 60 * GST_SECOND;
++    s = nanoseconds / GST_SECOND;
++    nanoseconds -= s * GST_SECOND;
++    f = nanoseconds / 75;
++  }
++
++  if (msf) {
++    msf->minute= m;
++    msf->second = s;
++    msf->frame = f;
++  }
++
++  return (nanoseconds >= 0);
++}
++
++/* Why do we need this? when a bin changes from READY => NULL state, its
++ * bus is set to flushing and we're unlikely to ever see any of its messages
++ * if the bin's state reaches NULL before we/the watch in the main thread
++ * collects them. That's why we set the state to READY first, process all
++ * messages 'manually', and then finally set it to NULL. This makes sure
++ * our state-changed handler actually gets to see all the state changes */
++
++static void
++gst_cdrom_set_playbin_state_to_null (GstCDRom * cdrom)
++{
++  GstMessage *msg;
++  GstState cur_state, pending;
++  GstBus *bus;
++
++  gst_element_get_state (cdrom->priv->playbin, &cur_state, &pending, 0);
++
++  if (cur_state == GST_STATE_NULL && pending == GST_STATE_VOID_PENDING)
++    return;
++
++  if (cur_state == GST_STATE_NULL && pending != GST_STATE_VOID_PENDING) {
++    gst_element_set_state (cdrom->priv->playbin, GST_STATE_NULL);
++    return;
++  }
++
++  gst_element_set_state (cdrom->priv->playbin, GST_STATE_READY);
++  gst_element_get_state (cdrom->priv->playbin, NULL, NULL, -1);
++
++  bus = gst_element_get_bus (cdrom->priv->playbin);
++  while ((msg = gst_bus_pop (bus))) {
++    gst_bus_async_signal_func (bus, msg, NULL);
++  }
++  gst_object_unref (bus);
++
++  gst_element_set_state (cdrom->priv->playbin, GST_STATE_NULL);
++  /* maybe we should be paranoid and do _get_state() and check for
++   * the return value here, but then errors in shutdown should be
++   * rather unlikely */
++}
++
++static gboolean
++gst_cdrom_is_cdrom_device (GnomeCDRom * cdrom, const char *device,
++    GError ** error)
++{
++  gboolean res = FALSE;
++
++  GST_DEBUG ("device = %s", GST_STR_NULL (device));
++
++  if (device != NULL && *device != '\0') {
++    int fd;
++
++    fd = open (device, O_RDONLY | O_NONBLOCK);
++    if (fd > 0) {
++      if (ioctl (fd, GST_CDROM_IOCTL_CDCAPABILITY_REQUEST, 0) >= 0)        
++        res = TRUE;
++
++      close (fd);
++    }
++  }
++
++  GST_DEBUG ("%s is%s a CD-ROM device", GST_STR_NULL (device),
++      (res) ? "" : " not");
++
++  return res;
++}
++
++static gboolean
++gst_cdrom_set_volume (GnomeCDRom * gnome_cdrom, int volume, GError ** error)
++{
++  GstCDRom *cdrom = GST_CDROM (gnome_cdrom);
++  gdouble vol;
++
++  vol = CLAMP (volume, 0, 255);
++  vol = (gdouble) volume / 255.0;
++  g_object_set (cdrom->priv->playbin, "volume", vol, NULL);
++  cdrom->priv->status.volume = volume;
++
++  return TRUE;
++}
++
++static gboolean
++gst_cdrom_pause (GnomeCDRom * gnome_cdrom, GError ** error)
++{
++  GstCDRom *cdrom = GST_CDROM (gnome_cdrom);
++  GstState state, pending_state;
++  gboolean res = FALSE;
++
++  gst_element_get_state (cdrom->priv->playbin, &state, &pending_state, 0);
++
++  if (pending_state != GST_STATE_VOID_PENDING)
++    state = pending_state;
++
++  GST_DEBUG ("cur_state=%d, pending_state=%d", state, pending_state);
++
++  switch (state) {
++    case GST_STATE_NULL:
++    case GST_STATE_READY:
++      break;
++    case GST_STATE_PAUSED:
++      /* we are already paused or pausing, nothing to do here */
++      res = TRUE;
++      break;
++    case GST_STATE_PLAYING:
++      gst_element_set_state (cdrom->priv->playbin, GST_STATE_PAUSED);
++      res = TRUE;
++      break;
++    default:
++      break;
++  }
++
++  return res;
++}
++
++static gboolean
++gst_cdrom_eject (GnomeCDRom * gnome_cdrom, GError ** error)
++{
++  GnomeCDRomStatus *status = NULL;
++  GstCDRom *cdrom;
++  gboolean res = FALSE;
++
++  cdrom = GST_CDROM (gnome_cdrom);
++
++  GST_DEBUG ("eject disc");
++
++  gst_cdrom_set_playbin_state_to_null (cdrom);
++  gst_element_get_state (cdrom->priv->playbin, NULL, NULL, -1);
++
++  if (!gnome_cdrom_open_dev (gnome_cdrom, error))
++    return FALSE;
++
++  if (!gst_cdrom_get_status (gnome_cdrom, &status, error))
++    goto done;
++
++  if (status->cd != GNOME_CDROM_STATUS_TRAY_OPEN) {
++    if (ioctl (gnome_cdrom->fd, GST_CDROM_IOCTL_EJECT_REQUEST, 0) < 0) {
++      GST_DEBUG ("ioctl() failed: %s", g_strerror (errno));
++      /* FIXME: try invoking command-line eject utility as fallback? */
++      if (error) {
++        *error = g_error_new (GNOME_CDROM_ERROR,
++                              GNOME_CDROM_ERROR_SYSTEM_ERROR,
++                              _("Failed to eject CD: %s"),
++                              g_strerror (errno));
++      }
++      res = FALSE;
++    } else {
++      res = TRUE;
++    }
++  } else {
++    GST_DEBUG ("tray seems to be open, closing tray ...");
++    /* Try to close the tray if it's open */
++    res = gnome_cdrom_close_tray (gnome_cdrom, error); ///// FIXME: use gst_cdrom_close_tray() directly once implemented /////
++  }
++
++  /* FIXME: update our status in cdrom->priv->status as well? */
++done:
++
++  /* force close here so it disconnects the check timeout */
++  gnome_cdrom_close_dev (gnome_cdrom, TRUE);
++  g_free (status);
++
++  return res;
++}
++
++static gboolean
++gst_cdrom_next (GnomeCDRom * gnome_cdrom, GError ** error)
++{
++  GnomeCDRomMSF start_msf, end_msf;
++  GstCDRom *cdrom;
++  gboolean ret;
++  guint cur_track;
++
++  cdrom = GST_CDROM (gnome_cdrom);
++
++  cur_track = cdrom->priv->status.track;
++
++  GST_DEBUG ("cur_track = %d/%d", cur_track, cdrom->priv->cddb_data->ntrks);
++
++  if (cur_track >= cdrom->priv->cddb_data->ntrks)
++    return FALSE;
++
++  if (cur_track < 0)
++    cur_track = 0;
++
++  start_msf.minute = 0;
++  start_msf.second = 0;
++  start_msf.frame = 0;
++
++  if (gnome_cdrom->playmode == GNOME_CDROM_WHOLE_CD) {
++    ret = gst_cdrom_play (gnome_cdrom, cur_track + 1, &start_msf,
++        -1, NULL, error);
++  } else {
++    /* for clarity ... */
++    end_msf.minute = 0;
++    end_msf.second = 0;
++    end_msf.frame = 0;
++
++    ret = gst_cdrom_play (gnome_cdrom, cur_track + 1, &start_msf,
++        cur_track + 2, &end_msf, error);
++  }
++
++  return ret;
++}
++
++static gboolean
++gst_cdrom_back (GnomeCDRom * gnome_cdrom, GError ** error)
++{
++  GnomeCDRomMSF start_msf, end_msf;
++  GstCDRom *cdrom;
++  gboolean ret;
++  gint cur_track, target_track;
++
++  cdrom = GST_CDROM (gnome_cdrom);
++
++  cur_track = cdrom->priv->status.track;
++
++  GST_DEBUG ("cur_track = %d/%d", cur_track, cdrom->priv->cddb_data->ntrks);
++
++  /* If we're > 0:01 on the track go back to the start 
++   * of it, otherwise go to the previous track */
++  if (cdrom->priv->status.relative.minute > 0 ||
++      (cdrom->priv->status.relative.minute == 0 &&
++          cdrom->priv->status.relative.second > 1)) {
++    target_track = cur_track;
++  } else {
++    target_track = cur_track - 1;
++  }
++
++  /* can't go before the first track */
++  if (target_track < 1)
++    target_track = 1;
++
++  nanoseconds_to_msf (0, &start_msf);
++
++  if (gnome_cdrom->playmode == GNOME_CDROM_WHOLE_CD) {
++    ret = gst_cdrom_play (gnome_cdrom, target_track, &start_msf,
++        -1, NULL, error);
++  } else {
++    nanoseconds_to_msf (0, &end_msf);
++
++    ret = gst_cdrom_play (gnome_cdrom, target_track, &start_msf,
++        CLAMP (target_track + 1, 1, cdrom->priv->cddb_data->ntrks),
++        &end_msf, error);
++  }
++
++  return ret;
++}
++
++static gboolean
++gst_cdrom_seek_to_time (GstCDRom * cdrom, guint64 nanoseconds)
++{
++  GST_DEBUG ("seeking to %" GST_TIME_FORMAT, GST_TIME_ARGS (nanoseconds));
++
++  if (!gst_element_seek (cdrom->priv->playbin, 1.0, GST_FORMAT_TIME,
++      GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, nanoseconds,
++      GST_SEEK_TYPE_NONE, -1)) {
++    GST_DEBUG ("seek failed");
++    return FALSE;
++  }
++
++  /* during the seek playbin will set itself to PAUSED temporarily, and
++   * then back to playing. When we were playing, wait for it go back to
++   * PLAYING again before doing anything else (but wait no longer than
++   * five seconds, just in case something goes wrong) */
++  if (cdrom->priv->status.audio != GNOME_CDROM_AUDIO_PAUSE) {
++    gst_element_get_state (cdrom->priv->playbin, NULL, NULL, 5 * GST_SECOND);
++  }
++
++  return TRUE;
++}
++
++static gboolean
++gst_cdrom_skip (GstCDRom * cdrom, gint64 diff, GError ** error)
++{
++  GstFormat fmt = GST_FORMAT_TIME;
++  gboolean ret;
++  gint64 maxpos, pos = -1;
++
++  if (!gst_element_query_position (cdrom->priv->playbin, &fmt, &pos) || pos < 0) {
++    GST_DEBUG ("failed to query position");
++    return FALSE;
++  }
++
++  if (diff >= 0) {
++    GST_DEBUG ("fast forward:  %" GST_TIME_FORMAT " + %" GST_TIME_FORMAT,
++       GST_TIME_ARGS (pos), GST_TIME_ARGS (diff));
++  } else {
++    GST_DEBUG ("fast backward: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
++       GST_TIME_ARGS (pos), GST_TIME_ARGS (-diff));
++  }
++
++  maxpos = GST_SECOND * (cdrom->priv->status.length.second +
++      (60 * cdrom->priv->status.length.minute));
++
++  pos = CLAMP (pos + diff, 0, maxpos);
++
++  if ((ret = gst_cdrom_seek_to_time (cdrom, pos))) {
++    nanoseconds_to_msf (pos, &cdrom->priv->status.relative);
++  }
++
++  return ret;
++}
++
++static gboolean
++gst_cdrom_ffwd (GnomeCDRom * gnome_cdrom, GError ** error)
++{
++  return gst_cdrom_skip (GST_CDROM (gnome_cdrom), GST_SECOND, error);
++}
++
++static gboolean
++gst_cdrom_rewind (GnomeCDRom * gnome_cdrom, GError ** error)
++{
++  return gst_cdrom_skip (GST_CDROM (gnome_cdrom), 0 - GST_SECOND, error);
++}
++
++static gboolean
++gst_cdrom_stop (GnomeCDRom * gnome_cdrom, GError ** error)
++{
++  GstCDRom *cdrom = GST_CDROM (gnome_cdrom);
++
++  GST_DEBUG ("stopping");
++
++  gst_cdrom_set_playbin_state_to_null (cdrom);
++
++  /* wait until it's finished */
++  gst_element_get_state (cdrom->priv->playbin, NULL, NULL, -1);
++  return TRUE;
++}
++
++static void
++gst_cdrom_finalize (GObject * obj)
++{
++  GstCDRom *cdrom = GST_CDROM (obj);
++
++  if (cdrom->priv->playbin) {
++	GstBus *bus;
++
++	bus = gst_element_get_bus (cdrom->priv->playbin);
++	gst_bus_set_flushing (bus, TRUE);
++	gst_object_unref (bus);
++
++    gst_element_set_state (cdrom->priv->playbin, GST_STATE_NULL);
++    gst_object_unref (cdrom->priv->playbin);
++  }
++
++  if (cdrom->priv->source) {
++    gst_element_set_state (cdrom->priv->source, GST_STATE_NULL);
++    gst_object_unref (cdrom->priv->source);
++  }
++
++  g_free (cdrom->priv);
++  cdrom->priv = NULL;
++
++  G_OBJECT_CLASS (gst_cdrom_parent_class)->finalize (obj);
++}
++
++static void
++gst_cdrom_init (GstCDRom * cdrom)
++{
++  cdrom->priv = g_new0 (GstCDRomPrivate, 1);
++
++  /* FIXME: initialize other fields too! */
++  cdrom->priv->status.volume = 255; /* equivalent to 1.0 in playbin */
++  cdrom->priv->status.length = blank_msf;
++  cdrom->priv->status.relative = blank_msf;
++  cdrom->priv->status.absolute = blank_msf;
++  /*
++  cdrom->priv->status.cd = 0;
++  cdrom->priv->status.audio = 0;
++  */
++}
++
++static void
++gst_cdrom_class_init (GstCDRomClass * klass)
++{
++  GnomeCDRomClass *gnomecdrom_class;
++  GObjectClass *gobject_class;
++
++  gobject_class = G_OBJECT_CLASS (klass);
++  gnomecdrom_class = GNOME_CDROM_CLASS (klass);
++
++  gobject_class->finalize = gst_cdrom_finalize;
++
++#if 0
++  gnomecdrom_class->close_tray = gst_cdrom_close_tray;
++#endif
++
++  gnomecdrom_class->play = gst_cdrom_play;
++  gnomecdrom_class->pause = gst_cdrom_pause;
++  gnomecdrom_class->stop = gst_cdrom_stop;
++  gnomecdrom_class->next = gst_cdrom_next;
++  gnomecdrom_class->back = gst_cdrom_back;
++  gnomecdrom_class->ffwd = gst_cdrom_ffwd;
++  gnomecdrom_class->rewind = gst_cdrom_rewind;
++  gnomecdrom_class->get_status = gst_cdrom_get_status;
++  gnomecdrom_class->set_device = gst_cdrom_set_device;
++  gnomecdrom_class->update_cd = gst_cdrom_update_cd;
++  gnomecdrom_class->set_volume = gst_cdrom_set_volume;
++  gnomecdrom_class->is_cdrom_device = gst_cdrom_is_cdrom_device;
++  gnomecdrom_class->eject = gst_cdrom_eject;
++
++  /* For CDDB */
++  gnomecdrom_class->get_cddb_data = gst_cdrom_get_cddb_data;
++
++  GST_DEBUG_CATEGORY_INIT (gnomecd_debug, "gnome-cd", 0, "gnome-cd");
++}
++
++static void
++gst_cdrom_error_msg (GstCDRom * cdrom, GstMessage * msg, GstBus * bus)
++{
++  GError *err = NULL;
++  gchar *dbg = NULL;
++
++  gst_message_parse_error (msg, &err, &dbg);
++  g_warning ("ERROR: %s", err->message);
++  g_error_free (err);
++  g_free (dbg);
++
++  cdrom->priv->status.audio = GNOME_CDROM_AUDIO_ERROR;
++}
++
++static void
++gst_cdrom_eos_msg (GstCDRom * cdrom, GstMessage * msg, GstBus * bus)
++{
++  gboolean was_last = FALSE;
++
++  if (cdrom->priv->cddb_data) {
++    was_last = (cdrom->priv->status.track >= cdrom->priv->cddb_data->ntrks);
++  }
++
++  GST_DEBUG ("received EOS %s", (was_last) ? "(last track)" : "");
++
++  if (was_last) {
++    gst_cdrom_set_playbin_state_to_null (cdrom);
++    cdrom->priv->status.audio = GNOME_CDROM_AUDIO_COMPLETE;
++  } else {
++    if (GNOME_CDROM (cdrom)->playmode == GNOME_CDROM_WHOLE_CD) {
++      gst_cdrom_next (GNOME_CDROM (cdrom), NULL);
++    } else {
++      cdrom->priv->status.audio = GNOME_CDROM_AUDIO_COMPLETE;
++    }
++  }
++
++}
++
++static void
++gst_cdrom_state_change_msg (GstCDRom * cdrom, GstMessage * msg, GstBus * bus)
++{
++  GstState old_state, new_state, pending_state;
++
++  if (msg->src != GST_OBJECT (cdrom->priv->playbin))
++    return;
++
++  gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
++
++  GST_DEBUG ("playbin state: %s", gst_element_state_get_name (new_state));
++
++  /* Note: we'll never get to see NULL here, as the bush is set to
++   * flushing in READY=>NULL */
++  switch (new_state) {
++    case GST_STATE_VOID_PENDING:
++    case GST_STATE_NULL:
++      g_return_if_reached ();
++    case GST_STATE_READY:
++      if (cdrom->priv->status.audio != GNOME_CDROM_AUDIO_STOP)
++        cdrom->priv->status.audio = GNOME_CDROM_AUDIO_COMPLETE;
++      cdrom->priv->status.track = 1;
++      nanoseconds_to_msf (0, &cdrom->priv->status.relative);
++      break;
++    case GST_STATE_PAUSED:
++      cdrom->priv->status.audio = GNOME_CDROM_AUDIO_PAUSE;
++      break;
++    case GST_STATE_PLAYING:
++      cdrom->priv->status.audio = GNOME_CDROM_AUDIO_PLAY;
++      break;
++  }
++}
++
++static void
++gst_cdrom_tag_msg (GstCDRom * cdrom, GstMessage * msg, GstBus * bus)
++{
++  GstTagList *tags = NULL;
++
++  gst_message_parse_tag (msg, &tags);
++
++  if (cdrom->priv->tags) {
++    gst_tag_list_free (cdrom->priv->tags);
++    cdrom->priv->tags = NULL;
++  }
++
++  if (tags) {
++    guint64 val = 0;
++    guint cur_track;
++
++    GST_DEBUG ("got tags: %" GST_PTR_FORMAT, tags);
++
++    gst_cdrom_set_cddb_data_from_tags (cdrom, tags);
++
++    if (gst_tag_list_get_uint (tags, GST_TAG_TRACK_NUMBER, &cur_track)) {
++      cdrom->priv->status.track = cur_track;
++    } else {
++      g_warning ("Could not retrieve track number from tags");
++      cdrom->priv->status.track = -1;
++    }      
++      
++    if (gst_tag_list_get_uint64 (tags, GST_TAG_DURATION, &val) && val > 0) {
++      nanoseconds_to_msf (val, &cdrom->priv->status.length);
++      GST_DEBUG ("Track duration: %02u:%02u",
++          cdrom->priv->status.length.minute,
++          cdrom->priv->status.length.second);
++    } else {
++      g_warning ("Could not retrieve track duration from tags");
++      cdrom->priv->status.length = blank_msf;
++    }      
++
++    cdrom->priv->tags = tags;
++  }
++}
++
++GnomeCDRom *
++gnome_cdrom_new (const char *cdrom_device,
++		 GnomeCDRomUpdate update, GError ** error)
++{
++  const gchar *cur_element;
++  GnomeCDRom *ret;
++  GstElement *playbin;
++  GstElement *audiosink;
++  GstCDRom *gstcdrom;
++  GstBus *bus;
++
++  cur_element = "gconfaudiosink";
++  if (!gst_default_registry_check_feature_version ("gconfaudiosink",
++      GST_VERSION_MAJOR, GST_VERSION_MINOR, 0)) {
++    goto element_create_error;
++  }
++
++  cur_element = "playbin";
++  if (!gst_default_registry_check_feature_version ("playbin",
++      GST_VERSION_MAJOR, GST_VERSION_MINOR, 0)) {
++    goto element_create_error;
++  }
++
++  playbin = gst_element_factory_make ("playbin", "playbin");
++  audiosink = gst_element_factory_make ("gconfaudiosink", "gconfaudiosink");
++
++  gstcdrom = g_object_new (GST_TYPE_CDROM, NULL);
++
++  gstcdrom->priv->playbin = playbin;
++
++  g_object_set (playbin, "audio-sink", audiosink, NULL);
++
++  g_signal_connect_swapped (playbin, "notify::source",
++                            G_CALLBACK (gst_cdrom_notify_source_cb),
++                            gstcdrom);
++
++  bus = gst_element_get_bus (playbin);
++
++  gst_bus_add_signal_watch (bus);
++
++  g_signal_connect_swapped (bus, "message::error",
++                            G_CALLBACK (gst_cdrom_error_msg),
++                            gstcdrom);
++
++  g_signal_connect_swapped (bus, "message::eos",
++                            G_CALLBACK (gst_cdrom_eos_msg),
++                            gstcdrom);
++
++  g_signal_connect_swapped (bus, "message::tag",
++                            G_CALLBACK (gst_cdrom_tag_msg),
++                            gstcdrom);
++
++  g_signal_connect_swapped (bus, "message::state-changed",
++                            G_CALLBACK (gst_cdrom_state_change_msg),
++                            gstcdrom);
++
++  gst_object_unref (bus);
++
++  ret = gnome_cdrom_construct (GNOME_CDROM (gstcdrom),
++                               cdrom_device, update,
++                               GNOME_CDROM_DEVICE_STATIC,
++                               error);
++
++  return ret;
++
++element_create_error:
++
++  if (error) {
++    *error = g_error_new (GNOME_CDROM_ERROR,
++                          GNOME_CDROM_ERROR_SYSTEM_ERROR,
++                          "Failed to create a GStreamer '%s' element. "
++                          "Please fix your GStreamer installation.",
++                          cur_element);
++  }
++
++  return NULL;
++}
++
++static gboolean
++object_has_property (gpointer object, const gchar *prop_name)
++{
++  gpointer klass = G_OBJECT_GET_CLASS (G_OBJECT (object));
++
++  if (g_object_class_find_property (G_OBJECT_CLASS (klass), prop_name))
++    return  TRUE;
++
++  return FALSE;
++}
++
++static void
++gst_cdrom_notify_source_cb (GstCDRom * cdrom, GParamSpec * pspec, gpointer foo)
++{
++  GstObject *src = NULL;
++
++  g_object_get (cdrom->priv->playbin, "source", &src, NULL);
++
++  gst_object_replace ((GstObject **) &cdrom->priv->source, src);
++
++  if (cdrom->priv->device && object_has_property (src, "device")) {
++    g_object_set (src, "device", cdrom->priv->device, NULL);
++  }
++
++  if (src) {
++    GST_DEBUG ("source changed to %s of type %s", GST_OBJECT_NAME (src),
++      g_type_name (G_OBJECT_TYPE (src)));
++
++    if (object_has_property (src, "read-speed")) {
++      g_object_set (src, "read-speed", 2, NULL);
++    }
++  } else {
++    GST_DEBUG ("source change to NULL");
++  }
++
++  gst_object_unref (src);
++}
++
++
++static gboolean
++gst_cdrom_is_open (GstCDRom * cdrom)
++{
++  GstState cur_state;
++
++  gst_element_get_state (cdrom->priv->playbin, &cur_state, NULL, 0);
++
++  return (cur_state >= GST_STATE_PAUSED);
++}
++
++static gboolean
++gst_cdrom_ensure_open (GstCDRom * cdrom)
++{
++  GstStateChangeReturn ret;
++
++  if (gst_cdrom_is_open (cdrom)) {
++    GST_DEBUG ("playbin is either paused or playing");
++    return TRUE;
++  }
++
++  GST_DEBUG ("starting up playbin with track 1");
++
++  g_object_set (cdrom->priv->playbin, "uri", "cdda://1", NULL);
++
++  /* FIXME: do we want PLAYING here? (that would start playing at startup
++   * regardless of the set preferences though, but then gnome-cd doesn't
++   * seem to call our play vfunc() on its own when that is selected either,
++   * so what to do?) */
++  gst_element_set_state (cdrom->priv->playbin, GST_STATE_PAUSED);
++
++  ret = gst_element_get_state (cdrom->priv->playbin, NULL, NULL, 10*GST_SECOND);
++  if (ret == GST_STATE_CHANGE_FAILURE)
++    return FALSE;
++
++  return TRUE;
++}
++
++static gboolean
++gst_cdrom_set_device (GnomeCDRom *gnome_cdrom, const char *dev, GError **err)
++{
++  GnomeCDRomClass *klass;
++  GstCDRom *cdrom = GST_CDROM (gnome_cdrom);
++
++  g_free (cdrom->priv->device);
++  cdrom->priv->device = g_strdup (dev);
++
++  GST_DEBUG ("setting device to '%s'", GST_STR_NULL (dev));
++
++  klass = GNOME_CDROM_CLASS (gst_cdrom_parent_class);
++  if (klass->set_device != NULL)
++    return klass->set_device (gnome_cdrom, dev, err);
++
++  return TRUE;
++}
++
++/********** FIXME: see if there's anything else we need to do here ******/
++
++static void
++gst_cdrom_update_cd (GnomeCDRom * gnome_cdrom)
++{
++  GstCDRom *cdrom = GST_CDROM (gnome_cdrom);
++
++  GST_DEBUG ("updating cd ...");
++
++  if (!gst_cdrom_ensure_open (cdrom)) {
++    g_warning ("Error opening CD"); /* FIXME? */
++    return;
++  }
++
++/*
++	GstCdparanoiaCDRom *lcd = GST_CDPARANOIA_CDROM (cdrom);
++	GstCdparanoiaCDRomPrivate *priv;
++#if defined(__FreeBSD__)
++	struct ioc_read_toc_single_entry tocentry;
++#elif defined(__NetBSD__) || defined(__OpenBSD__)
++	struct ioc_read_toc_entry tocentries;
++	struct cd_toc_entry tocentry;
++#else
++	struct cdrom_tocentry tocentry;
++#endif
++	int i, j;
++	GError *error;
++
++	priv = lcd->priv;
++
++	if (gst_cdparanoia_cdrom_open (lcd, &error) == FALSE) {
++		g_warning ("Error opening CD");
++		return;
++	}
++
++#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
++	if (ioctl (cdrom->fd, CDIOREADTOCHEADER, priv->tochdr) < 0) {
++#else
++	if (ioctl (cdrom->fd, CDROMREADTOCHDR, priv->tochdr) < 0) {
++#endif
++		g_warning ("Error reading CD header");
++		gst_cdparanoia_cdrom_close (lcd);
++
++		return;
++	}
++
++#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
++	priv->track0 = priv->tochdr->starting_track;
++	priv->track1 = priv->tochdr->ending_track;
++#else
++	priv->track0 = priv->tochdr->cdth_trk0;
++	priv->track1 = priv->tochdr->cdth_trk1;
++#endif
++	priv->number_tracks = priv->track1 - priv->track0 + 1;
++
++	gst_cdparanoia_cdrom_invalidate (lcd);
++	priv->track_info =
++	    g_malloc ((priv->number_tracks +
++		       1) * sizeof (GstCdparanoiaCDRomTrackInfo));
++#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
++#if defined(__FreeBSD__)
++	for (i = 0, j = priv->track0; i < priv->number_tracks; i++, j++) {
++		tocentry.track = j;
++		tocentry.address_format = CD_MSF_FORMAT;
++#else
++	tocentries.data_len = sizeof(tocentry);
++	tocentries.data = &tocentry;
++	for (i = 0, j = priv->track0; i < priv->number_tracks; i++, j++) {
++		tocentries.starting_track = j;
++		tocentries.address_format = CD_MSF_FORMAT;
++#endif
++
++#if defined(__FreeBSD__)
++		if (ioctl (cdrom->fd, CDIOREADTOCENTRY, &tocentry) < 0) {
++#else
++		if (ioctl (cdrom->fd, CDIOREADTOCENTRYS, &tocentries) < 0) {
++#endif
++			g_warning ("IOCtl failed");
++			continue;
++		}
++
++		priv->track_info[i].track = j;
++#if defined(__FreeBSD__)
++		priv->track_info[i].audio_track =
++		    tocentry.entry.control != CDROM_DATA_TRACK ? 1 : 0;
++		ASSIGN_MSF (priv->track_info[i].address,
++			    tocentry.entry.addr.msf);
++#else
++		priv->track_info[i].audio_track =
++		    tocentry.control != CDROM_DATA_TRACK ? 1 : 0;
++		ASSIGN_MSF (priv->track_info[i].address, tocentry.addr.msf);
++#endif
++#else
++	for (i = 0, j = priv->track0; i < priv->number_tracks; i++, j++) {
++		tocentry.cdte_track = j;
++		tocentry.cdte_format = CDROM_MSF;
++
++		if (ioctl (cdrom->fd, CDROMREADTOCENTRY, &tocentry) < 0) {
++			g_warning ("IOCtl failed");
++			continue;
++		}
++
++		priv->track_info[i].track = j;
++		priv->track_info[i].audio_track =
++		    tocentry.cdte_ctrl != CDROM_DATA_TRACK ? 1 : 0;
++		ASSIGN_MSF (priv->track_info[i].address,
++			    tocentry.cdte_addr.msf);
++#endif
++	}
++#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
++#if defined(__FreeBSD__)
++	tocentry.track = CDROM_LEADOUT;
++	tocentry.address_format = CD_MSF_FORMAT;
++	if (ioctl (cdrom->fd, CDIOREADTOCENTRY, &tocentry) < 0) {
++#else
++	tocentries.starting_track = 0xAA;
++	tocentries.address_format = CD_MSF_FORMAT;
++	if (ioctl (cdrom->fd, CDIOREADTOCENTRYS, &tocentries) < 0) {
++#endif
++		g_warning ("Error getting leadout");
++		gst_cdparanoia_cdrom_invalidate (lcd);
++		return;
++	}
++#if defined(__FreeBSD__)
++	ASSIGN_MSF (priv->track_info[priv->number_tracks].address,
++		    tocentry.entry.addr.msf);
++#else
++	ASSIGN_MSF (priv->track_info[priv->number_tracks].address,
++		    tocentry.addr.msf);
++#endif
++#else
++
++	tocentry.cdte_track = CDROM_LEADOUT;
++	tocentry.cdte_format = CDROM_MSF;
++	if (ioctl (cdrom->fd, CDROMREADTOCENTRY, &tocentry) < 0) {
++		g_warning ("Error getting leadout");
++		gst_cdparanoia_cdrom_invalidate (lcd);
++		return;
++	}
++	ASSIGN_MSF (priv->track_info[priv->number_tracks].address,
++		    tocentry.cdte_addr.msf);
++#endif
++	calculate_track_lengths (lcd);
++
++	gst_cdparanoia_cdrom_close (lcd);
++*/
++}
++
++static gboolean
++gst_cdrom_update_tray_status (GstCDRom * cdrom, GError ** error)
++{
++  return FALSE;
++}
++
++/********** FIXME: do tray status checking ******/
++
++static gboolean
++gst_cdrom_get_status (GnomeCDRom * gnome_cdrom, GnomeCDRomStatus ** status,
++    GError ** error)
++{
++  GstFormat fmt;
++  GstCDRom *cdrom;
++  gint64 pos = -1;
++
++  cdrom = GST_CDROM (gnome_cdrom);
++
++  /* only spin up the disc if we don't know the disc
++   * details already (e.g. when stopped on purpose) */
++  /* FIXME: make sure we reset cdrom->priv->cddb_data when the tray is open! */
++  if (cdrom->priv->cddb_data == NULL) {
++    GST_DEBUG ("need to get track details");
++    if (!gst_cdrom_ensure_open (cdrom)) {
++      *status = NULL;
++      GST_DEBUG ("ensure_open failed");
++      return FALSE;
++    }
++  }
++
++  *status = g_memdup (&cdrom->priv->status, sizeof (GnomeCDRomStatus));
++
++  if (!gst_cdrom_get_cddb_data (gnome_cdrom, NULL, NULL)) {
++    (*status)->cd = GNOME_CDROM_STATUS_NO_DISC;
++    (*status)->audio = GNOME_CDROM_AUDIO_NOTHING;
++    (*status)->track = -1;
++    GST_DEBUG ("get_cddb_data failed, returning NO_DISC, AUDIO_NOTHING");
++    return TRUE;
++  }
++
++  (*status)->cd = GNOME_CDROM_STATUS_OK;
++
++  fmt = GST_FORMAT_TIME;
++  if (gst_element_query_position (cdrom->priv->playbin, &fmt, &pos) && pos != -1) {
++    nanoseconds_to_msf (pos, &cdrom->priv->status.relative);
++    (*status)->relative = cdrom->priv->status.relative;
++    (*status)->absolute = blank_msf; /* dunno what the UI needs that for */
++  } else {
++    GST_DEBUG ("failed to query current position");
++    (*status)->relative = blank_msf;
++    (*status)->absolute = blank_msf;
++  }
++
++  GST_DEBUG ("[%02u] %02u:%02u / %02u:%02u  cd_status=%d, audio_status=%d "
++      "playmode=%d", (*status)->track, (*status)->relative.minute,
++      (*status)->relative.second, (*status)->length.minute,
++      (*status)->length.second, (*status)->cd, (*status)->audio,
++      gnome_cdrom->playmode);
++
++  return TRUE;
++}
++
++static gboolean
++gst_cdrom_play (GnomeCDRom * gnome_cdrom, int start_track,
++    GnomeCDRomMSF * start, int finish_track, GnomeCDRomMSF * finish,
++    GError ** error)
++{
++  GstStateChangeReturn ret;
++  GstFormat track_format;
++  GstCDRom *cdrom;
++  guint64 seek_pos;
++
++  cdrom = GST_CDROM (gnome_cdrom);
++
++  GST_DEBUG ("PLAY track %u at %02u:%02u", start_track, start->minute,
++      start->second);
++
++  if (!gst_cdrom_is_open (cdrom)) {
++    /* FIXME: maybe call ensure_open() here instead? */
++    gst_element_set_state (cdrom->priv->playbin, GST_STATE_PAUSED);
++    ret = gst_element_get_state (cdrom->priv->playbin, NULL, NULL, 10 * GST_SECOND);
++    if (ret != GST_STATE_CHANGE_SUCCESS) {
++      /* this would probably block if the open was still blocking, no? */
++      /* gst_element_set_state (cdrom->priv->playbin, GST_STATE_NULL); */
++      return FALSE;
++    }
++  }
++
++  track_format = gst_format_get_by_nick ("track");
++  if (!gst_element_seek (cdrom->priv->playbin, 1.0, track_format,
++      GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, start_track - 1,
++      GST_SEEK_TYPE_NONE, -1)) {
++    GST_DEBUG ("seek to track %d failed", start_track);
++    return FALSE;
++  }
++
++  seek_pos = (start->second + (60 * start->minute)) * GST_SECOND;
++  if (!gst_cdrom_seek_to_time (cdrom, seek_pos)) {
++    GST_DEBUG ("seek to time %" GST_TIME_FORMAT " failed",
++        GST_TIME_ARGS (seek_pos));
++    return FALSE;
++  }
++
++  gst_element_set_state (cdrom->priv->playbin, GST_STATE_PLAYING);
++  return TRUE;
++}
++
++static gboolean
++gst_cdrom_set_cddb_data_from_tags (GstCDRom * cdrom, GstTagList * tags)
++{
++  GnomeCDRomCDDBData data = { 0, };
++  gchar **arr = NULL;
++  gchar *id_str = NULL;
++  guint i;
++
++  if (cdrom->priv->cddb_data) {
++    g_free (cdrom->priv->cddb_data->offsets);
++    g_free (cdrom->priv->cddb_data);
++    cdrom->priv->cddb_data = NULL;
++  }
++
++  if (tags == NULL)
++    return FALSE;
++
++  if (!gst_tag_list_get_string (tags, GST_TAG_CDDA_CDDB_DISCID_FULL, &id_str))
++    return FALSE;
++
++  GST_DEBUG ("parsing CDDB ID string '%s'", GST_STR_NULL (id_str));
++
++  if (id_str == NULL)
++    return FALSE;
++
++  if (sscanf (id_str, "%" G_GINT32_MODIFIER "x ", &data.discid) != 1)
++    goto parse_error;
++
++  GST_DEBUG ("id = %08x", data.discid);
++
++  /* we know strchr() will succeed because of the trailing space above */
++  arr = g_strsplit (strchr (id_str, ' ') + 1, " ", -1);
++  if (arr == NULL || arr[0] == NULL)
++    goto parse_error;
++
++  data.ntrks = atoi (arr[0]);
++  if (data.ntrks <= 0 || data.ntrks > 100)
++    goto parse_error;
++
++  GST_DEBUG ("num_tracks = %u", data.ntrks);
++
++  if (g_strv_length (arr) != data.ntrks + 2)
++    goto parse_error;
++
++  data.nsecs = atoi (arr[data.ntrks + 1]);
++
++  data.offsets = g_new0 (gint, data.ntrks);
++  for (i = 1; i <= data.ntrks; ++i) {
++    data.offsets[i-1] = atoi (arr[i]);
++    GST_DEBUG ("offset[%02u] = %6u", i-1, data.offsets[i-1]);
++  }
++
++  cdrom->priv->cddb_data = g_memdup (&data, sizeof (GnomeCDRomCDDBData));
++
++  return TRUE;
++
++parse_error:
++  GST_DEBUG ("error parsing CDDB ID string");
++  g_free (id_str);
++  g_strfreev (arr);
++  return FALSE;
++}
++
++static gboolean
++gst_cdrom_get_cddb_data (GnomeCDRom          * gnome_cdrom,
++                         GnomeCDRomCDDBData ** p_cddb_data,
++                         GError             ** error)
++{
++  GnomeCDRomCDDBData data = { 0, };
++  GstCDRom *cdrom;
++  gint i;
++
++  cdrom = GST_CDROM (gnome_cdrom);
++
++  if (cdrom->priv == NULL || cdrom->priv->cddb_data == NULL)
++    return FALSE;
++
++  data.ntrks = cdrom->priv->cddb_data->ntrks;
++  data.nsecs = cdrom->priv->cddb_data->nsecs;
++  data.discid = cdrom->priv->cddb_data->discid;
++ 
++  data.offsets = g_new (gint, cdrom->priv->cddb_data->ntrks);
++
++  for (i = 0; i < data.ntrks; ++i) {
++    data.offsets[i] = cdrom->priv->cddb_data->offsets[i];
++  }
++
++  if (p_cddb_data) {
++    *p_cddb_data = g_memdup (&data, sizeof (GnomeCDRomCDDBData));
++  } else {
++    g_free (data.offsets);
++  }
++
++  return TRUE;
++}
+Index: gnome-cd/gst-cdrom.h
+===================================================================
+RCS file: gnome-cd/gst-cdrom.h
+diff -N gnome-cd/gst-cdrom.h
+--- /dev/null	1 Jan 1970 00:00:00 -0000
++++ gnome-cd/gst-cdrom.h	13 Jan 2006 15:07:51 -0000	1.1.2.1
+@@ -0,0 +1,43 @@
++/*
++ * gst-cdrom.c: Gstreamer Audio CD controlling functions.
++ *
++ * Copyright (C) 2005 Tim-Philipp Müller <tim centricular net>
++ *
++ */
++
++#ifndef __GST_CDROM_H__
++#define __GST_CDROM_H__
++
++#include <glib/gerror.h>
++#include <glib-object.h>
++
++#include "cdrom.h"
++
++G_BEGIN_DECLS
++
++#define GST_TYPE_CDROM            (gst_cdrom_get_type ())
++#define GST_CDROM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_CDROM, GstCDRom))
++#define GST_CDROM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_CDROM, GstCDRomClass))
++#define GST_IS_CDROM(obj)         (GTK_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_CDROM))
++#define GST_IS_CDROM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_CDROM))
++#define GST_CDROM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_CDROM, GstCDRomClass))
++
++typedef struct _GstCDRom GstCDRom;
++typedef struct _GstCDRomClass GstCDRomClass;
++typedef struct _GstCDRomPrivate GstCDRomPrivate;
++
++struct _GstCDRom {
++  GnomeCDRom cdrom;
++
++  GstCDRomPrivate *priv;
++};
++
++struct _GstCDRomClass {
++  GnomeCDRomClass klass;
++};
++
++GType   gst_cdrom_get_type  (void);
++
++G_END_DECLS
++
++#endif /* __GST_CDROM_H__ */
+Index: gnome-cd/theme.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gnome-cd/theme.c,v
+retrieving revision 1.12
+retrieving revision 1.12.4.3
+diff -u -p -r1.12 -r1.12.4.3
+--- gnome-cd/theme.c	23 Apr 2005 11:14:41 -0000	1.12
++++ gnome-cd/theme.c	13 Jan 2006 16:19:52 -0000	1.12.4.3
+@@ -2,7 +2,7 @@
+ /*
+  *  Authors: Iain Holmes <iain@ximian.com>
+  *
+- *  Copyright 2002 Iain Holmes 
++ *  Copyright 2002 Iain Holmes
+  *
+  *  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
+@@ -32,50 +32,78 @@
+ #include "gnome-cd.h"
+ #include "display.h"
+ 
+-GCDTheme *
+-theme_load (GnomeCD *gcd,
+-	    const char *theme_name)
++#define FALLBACK_THEME "lcd"
++
++/* check if under the given directory, a theme directory exists, and contains
++ * the proper .theme file
++ * return path to the .theme file
++ * caller-owns-return
++ */
++
++static gchar *
++theme_check (const char *theme_dir, const char *theme_name)
+ {
+-	char *theme_path, *xml_file, *tmp;
+-	GCDTheme *theme;
+-	xmlDocPtr xml;
+-	xmlNodePtr ptr;
+-	
+-	g_return_val_if_fail (gcd != NULL, NULL);
+-	g_return_val_if_fail (theme_name != NULL, NULL);
++	char *theme_path, *tmp, *xml_file;
+ 
+-	theme_path = g_build_filename (THEME_DIR, theme_name, NULL);
++	/* check if a dir named theme_name exists under theme_dir */
++	tmp = g_strconcat (theme_name, "-theme", NULL);
++	theme_path = g_build_filename (theme_dir, tmp, NULL);
++        g_free (tmp);
+ 	if (g_file_test (theme_path, G_FILE_TEST_IS_DIR) == FALSE) {
+-		/* Theme dir isn't a dir */
+-		
+-		g_print ("Not a dir %s\n", theme_path);
+ 		g_free (theme_path);
+-		theme_name = g_strdup ("lcd");
+-		theme_path = g_build_filename (THEME_DIR, theme_name, NULL);
++		return NULL;
+ 	}
+-	
++
++	/* check if a file named (theme_name).theme exists in that directory */
+ 	tmp = g_strconcat (theme_name, ".theme", NULL);
+ 	xml_file = g_build_filename (theme_path, tmp, NULL);
+ 	g_free (tmp);
++	g_free (theme_path);
+ 
+ 	if (g_file_test (xml_file,
+ 			 G_FILE_TEST_IS_REGULAR |
+ 			 G_FILE_TEST_IS_SYMLINK) == FALSE) {
+-		/* No .theme file */
+-
+-		g_print ("No .theme file: %s\n", xml_file);
+-		g_free (theme_path);
+ 		g_free (xml_file);
+ 		return NULL;
+ 	}
+ 
++        return xml_file;
++}
++
++GCDTheme *
++theme_load (GnomeCD *gcd,
++	    const char *theme_name)
++{
++	char *xml_file;
++	GCDTheme *theme;
++	xmlDocPtr xml;
++	xmlNodePtr ptr;
++
++	g_return_val_if_fail (gcd != NULL, NULL);
++	g_return_val_if_fail (theme_name != NULL, NULL);
++
++        /* prefer uninstalled theme over installed, and chosen over fallback */
++	xml_file = theme_check (THEME_DIR_UNINSTALLED, theme_name);
++	if (!xml_file)
++		xml_file = theme_check (THEME_DIR_UNINSTALLED, FALLBACK_THEME);
++	if (!xml_file)
++		xml_file = theme_check (THEME_DIR, theme_name);
++	if (!xml_file)
++		xml_file = theme_check (THEME_DIR, FALLBACK_THEME);
++
++	if (!xml_file) {
++		g_warning ("No .theme file found for %s or fallback them %s",
++			theme_name, FALLBACK_THEME);
++		return NULL;
++        }
++
++        /* we have a valid .theme file, parse it */
+ 	xml = xmlParseFile (xml_file);
+ 	g_free (xml_file);
+-	
++
+ 	if (xml == NULL) {
+ 
+ 		g_print ("No XML\n");
+-		g_free (theme_path);
+ 		return NULL;
+ 	}
+ 
+@@ -84,19 +112,15 @@ theme_load (GnomeCD *gcd,
+ 	if (ptr == NULL) {
+ 
+ 		g_print ("No root\n");
+-		g_free (theme_path);
+ 		xmlFreeDoc (xml);
+ 		return NULL;
+ 	}
+ 	if (xmlStrcmp (ptr->name, (guchar *)"gnome-cd")) {
+ 		g_print ("Not gnome-cd: %s\n", ptr->name);
+-		g_free (theme_path);
+ 		xmlFreeDoc (xml);
+ 		return NULL;
+ 	}
+ 
+-	g_free (theme_path);
+-	
+ 	theme = g_new0 (GCDTheme, 1);
+ 
+ 	theme->name = g_strdup (theme_name);
+@@ -115,10 +139,10 @@ theme_load (GnomeCD *gcd,
+ 		if (xmlStrcmp (ptr->name, (const xmlChar *) "display") == 0) {
+ 			cd_display_parse_theme ((CDDisplay*)gcd->display, theme, xml, ptr->xmlChildrenNode);
+ 		}
+-		
++
+ 		ptr = ptr->next;
+ 	}
+-	
++
+ 	return theme;
+ }
+ 
+@@ -126,9 +150,9 @@ void
+ theme_free (GCDTheme *theme)
+ {
+ 	g_return_if_fail (theme != NULL);
+-	
++
+ 	g_free (theme->name);
+-	
++
+ 	g_free (theme);
+ }
+ 
+Index: gnome-cd/images/None-theme/Makefile.am
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gnome-cd/images/None-theme/Makefile.am,v
+retrieving revision 1.1
+retrieving revision 1.1.12.1
+diff -u -p -r1.1 -r1.1.12.1
+--- gnome-cd/images/None-theme/Makefile.am	3 Jul 2003 07:25:05 -0000	1.1
++++ gnome-cd/images/None-theme/Makefile.am	13 Jan 2006 16:16:46 -0000	1.1.12.1
+@@ -1,4 +1,4 @@
+-pixmapdir = $(datadir)/pixmaps/gnome-cd/themes/None
++pixmapdir = $(datadir)/pixmaps/gnome-cd/themes/None-theme
+ 
+ BITMAPS = 			\
+ 	    top-left.png	\
+Index: gnome-cd/images/lcd-theme/Makefile.am
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gnome-cd/images/lcd-theme/Makefile.am,v
+retrieving revision 1.3
+retrieving revision 1.3.14.1
+diff -u -p -r1.3 -r1.3.14.1
+--- gnome-cd/images/lcd-theme/Makefile.am	7 Dec 2002 14:07:26 -0000	1.3
++++ gnome-cd/images/lcd-theme/Makefile.am	13 Jan 2006 16:16:47 -0000	1.3.14.1
+@@ -1,4 +1,4 @@
+-pixmapdir = $(datadir)/pixmaps/gnome-cd/themes/lcd
++pixmapdir = $(datadir)/pixmaps/gnome-cd/themes/lcd-theme
+ 
+ BITMAPS = 		\
+ 	    top-left.png	\
+Index: gnome-cd/images/media-theme/Makefile.am
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gnome-cd/images/media-theme/Makefile.am,v
+retrieving revision 1.2
+retrieving revision 1.2.14.1
+diff -u -p -r1.2 -r1.2.14.1
+--- gnome-cd/images/media-theme/Makefile.am	7 Dec 2002 14:07:26 -0000	1.2
++++ gnome-cd/images/media-theme/Makefile.am	13 Jan 2006 16:16:47 -0000	1.2.14.1
+@@ -1,4 +1,4 @@
+-pixmapdir = $(datadir)/pixmaps/gnome-cd/themes/media
++pixmapdir = $(datadir)/pixmaps/gnome-cd/themes/media-theme
+ 
+ BITMAPS = 		\
+ 	    top-left.png	\
+Index: gnome-cd/images/red-lcd-theme/Makefile.am
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gnome-cd/images/red-lcd-theme/Makefile.am,v
+retrieving revision 1.2
+retrieving revision 1.2.14.1
+diff -u -p -r1.2 -r1.2.14.1
+--- gnome-cd/images/red-lcd-theme/Makefile.am	7 Dec 2002 14:07:27 -0000	1.2
++++ gnome-cd/images/red-lcd-theme/Makefile.am	13 Jan 2006 16:16:47 -0000	1.2.14.1
+@@ -1,4 +1,4 @@
+-pixmapdir = $(datadir)/pixmaps/gnome-cd/themes/red-lcd
++pixmapdir = $(datadir)/pixmaps/gnome-cd/themes/red-lcd-theme
+ 
+ BITMAPS = 		\
+ 	    top-left.png	\
+Index: grecord/src/Makefile.am
+===================================================================
+RCS file: /cvs/gnome/gnome-media/grecord/src/Makefile.am,v
+retrieving revision 1.16
+retrieving revision 1.16.4.3
+diff -u -p -r1.16 -r1.16.4.3
+--- grecord/src/Makefile.am	8 Jun 2005 08:16:52 -0000	1.16
++++ grecord/src/Makefile.am	16 Jan 2006 17:13:26 -0000	1.16.4.3
+@@ -1,6 +1,6 @@
+ ## Process this file with automake to produce Makefile.in
+ 
+-SUBDIRS = gst recent-files
++SUBDIRS = recent-files
+ 
+ INCLUDES = \
+ 	-DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\"	\
+@@ -24,7 +24,6 @@ ui_DATA = ui.xml
+ EXTRA_DIST = $(ui_DATA)
+ 
+ gnome_sound_recorder_LDADD =					\
+-	$(GSR_LIBS)						\
++	$(GSR_LIBS) -lgstinterfaces-@GST_MAJORMINOR@		\
+ 	$(top_builddir)/profiles/libgnome-media-profiles.la	\
+-	recent-files/librecent.la				\
+-	gst/libgstrecelements.la
++	recent-files/librecent.la
+Index: grecord/src/gnome-recorder.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/grecord/src/gnome-recorder.c,v
+retrieving revision 1.20
+retrieving revision 1.20.4.2
+diff -u -p -r1.20 -r1.20.4.2
+--- grecord/src/gnome-recorder.c	9 Jun 2005 14:45:05 -0000	1.20
++++ grecord/src/gnome-recorder.c	15 Jan 2006 20:12:52 -0000	1.20.4.2
+@@ -33,7 +33,6 @@
+ #include <gst/gst.h>
+ 
+ #include "gsr-window.h"
+-#include "gst/manager.h"
+ #include "egg-recent-model.h"
+ 
+ extern void gnome_media_profiles_init (GConfClient *conf);
+@@ -126,7 +125,7 @@ gsr_add_recent (gchar *filename)
+ 	g_free (uri);
+ }
+ 
+-gint sample_count = 1;
++gint gsr_sample_count = 1;
+ 
+ GtkWidget *
+ gsr_open_window (const char *filename)
+@@ -139,13 +138,12 @@ gsr_open_window (const char *filename)
+ 		 * there is no active sound sample. Any newly
+ 		 * recorded samples will be saved to disk with this
+ 		 * name as default value. */
+-		if (sample_count == 1) {
++		if (gsr_sample_count == 1) {
+ 			name = g_strdup (_("Untitled"));
+ 		} else {
+-			name = g_strdup_printf (_("Untitled-%d"),
+-						sample_count);
++			name = g_strdup_printf (_("Untitled-%d"), gsr_sample_count);
+ 		}
+-		sample_count++;
++		++gsr_sample_count;
+ 	} else {
+ 		name = g_strdup (filename);
+ 	}
+@@ -170,82 +168,81 @@ main (int argc,
+       char **argv)
+ {
+ 	GnomeProgram *program;
+-	poptContext pctx;
+-	GValue value = {0, };
+-	char **args = NULL;
+-
+-	static struct poptOption gsr_options[] = {
+-		{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, NULL, 0, "GStreamer", NULL },
+-		{ NULL, 'p', POPT_ARG_NONE, NULL, 1, N_("Dummy option"), NULL },
+-		POPT_TABLEEND
+-	};
++	gchar **filenames = NULL;
+ 
+ 	/* Init gettext */
+ 	bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ 	textdomain (GETTEXT_PACKAGE);
+ 
+-	/* init gstreamer */
+-	gsr_options[0].arg = (void *) gst_init_get_popt_table ();
++/* FIXME: remove ifdef here and else branch when bumping requirements to 2.14 */
++#ifdef GNOME_PARAM_GOPTION_CONTEXT
++	if (1) {
++		GOptionContext *ctx;
++		/* this is necessary because someone apparently forgot to add a
++		 * convenient way to get the remaining arguments to the GnomeProgram
++		 * API when adding the GOption stuff to it ... */
++		GOptionEntry entries[] = {
++			{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames,
++			"Special option that collects any remaining arguments for us" },
++			{ NULL }
++		};
++
++		ctx = g_option_context_new ("gnome-sound-recorder");
++		g_option_context_add_group (ctx, gst_init_get_option_group ());
++		g_option_context_add_main_entries (ctx, entries, GETTEXT_PACKAGE);
++		program = gnome_program_init ("gnome-sound-recorder", VERSION,
++		                              LIBGNOMEUI_MODULE, argc, argv,
++		                              GNOME_PARAM_GOPTION_CONTEXT, ctx,
++		                              GNOME_PARAM_HUMAN_READABLE_NAME,
++		                              "GNOME Sound Recorder",
++		                              GNOME_PARAM_APP_DATADIR, DATADIR,
++		                              NULL);
++	}
++#else /* GNOME_PARAM_GOPTION_CONTEXT */
++	gst_init (&argc, &argv);
+ 
+-	/* Init GNOME */
+ 	program = gnome_program_init ("gnome-sound-recorder", VERSION,
+ 				      LIBGNOMEUI_MODULE,
+ 				      argc, argv,
+-				      GNOME_PARAM_POPT_TABLE, gsr_options,
+ 				      GNOME_PARAM_HUMAN_READABLE_NAME,
+ 				      "GNOME Sound Recorder",
+ 				      GNOME_PARAM_APP_DATADIR, DATADIR,
+ 				      NULL);
+ 
+-	init_recent ();
+-
+-	if (!gst_scheduler_factory_get_default_name ()) {
+-		GtkWidget *dialog;
+-
+-		dialog = gtk_message_dialog_new (NULL,
+-						 0,
+-						 GTK_MESSAGE_ERROR,
+-						 GTK_BUTTONS_CLOSE,
+-						 _("Registry is not present or it is corrupted, please update it by running gst-register"));
+-
+-		gtk_dialog_run (GTK_DIALOG (dialog));
+-		gtk_widget_destroy (dialog);
+-
+-		exit (1);
++	if (argc > 1) {
++		filenames = g_strdupv (&argv[1]);
++	} else {
++		filenames = NULL;
+ 	}
+-	gst_rec_elements_init ();
++#endif /* GNOME_PARAM_GOPTION_CONTEXT */
++
++	init_recent ();
+ 
+ 	gtk_window_set_default_icon_name ("gnome-grecord");
+ 
+ 	/* use it like a singleton */
+ 	gconf_client = gconf_client_get_default ();
+ 
+-        /* init gnome-media-profiles */
+-        gnome_media_profiles_init (gconf_client);
++	/* init gnome-media-profiles */
++	gnome_media_profiles_init (gconf_client);
+ 
+-	/* Get the args */
+-	g_value_init (&value, G_TYPE_POINTER);
+-	g_object_get_property (G_OBJECT (program),
+-			       GNOME_PARAM_POPT_CONTEXT, &value);
+-	pctx = g_value_get_pointer (&value);
+-	g_value_unset (&value);
+-
+-	args = (char **) poptGetArgs (pctx);
+-	if (args == NULL) {
+-		gsr_open_window (NULL);
+-	} else {
+-		int i;
++	if (filenames != NULL && filenames[0] != NULL) {
++		guint i, num;
+ 
+-		for (i = 0; args[i]; i++) {
+-			gsr_open_window (args[i]);
++		num = g_strv_length (filenames);
++		for (i = 0; i < num; ++i) {
++			gsr_open_window (filenames[i]);
+ 		}
++	} else {
++			gsr_open_window (NULL);
+ 	}
+ 
+-	poptFreeContext (pctx);
++	if (filenames) {
++		g_strfreev (filenames);
++	}
+ 
+ 	gtk_main ();
+ 
+ 	return 0;
+ }
+-
+Index: grecord/src/gsr-window.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/grecord/src/gsr-window.c,v
+retrieving revision 1.64
+retrieving revision 1.64.2.4
+diff -u -p -r1.64 -r1.64.2.4
+--- grecord/src/gsr-window.c	10 Jan 2006 12:38:14 -0000	1.64
++++ grecord/src/gsr-window.c	16 Jan 2006 18:43:48 -0000	1.64.2.4
+@@ -2,6 +2,7 @@
+ /*
+  *  Authors: Iain Holmes <iain@prettypeople.org>
+  *           Johan Dahlin <johan@gnome.org>
++ *           Tim-Philipp Müller <tim centricular net>
+  *
+  *  Copyright 2002 Iain Holmes
+  *
+@@ -21,7 +22,8 @@
+  * Boston, MA 02111-1307, USA.
+  *
+  * 4th Februrary 2005: Christian Schaller: changed license to LGPL with
+- * permission of Iain Holmes, Ronald Bultje, Leontine Binchy (SUN), Johan Dalhin * and Joe Marcus Clarke
++ * permission of Iain Holmes, Ronald Bultje, Leontine Binchy (SUN), Johan Dalhin
++ * and Joe Marcus Clarke
+  *
+  */
+ 
+@@ -40,7 +42,7 @@
+ #include <libgnomevfs/gnome-vfs.h>
+ #include <gconf/gconf-client.h>
+ #include <gst/gst.h>
+-#include <gst/gconf/gconf.h>
++#include <gst/interfaces/mixer.h>
+ 
+ #include <profiles/gnome-media-profiles.h>
+ 
+@@ -51,6 +53,9 @@
+ 
+ #include "gsr-window.h"
+ 
++GST_DEBUG_CATEGORY_STATIC (gsr_debug);
++#define GST_CAT_DEFAULT gsr_debug
++
+ extern GtkWidget * gsr_open_window (const char *filename);
+ extern void gsr_quit (void);
+ 
+@@ -67,9 +72,13 @@ extern void gsr_add_recent (gchar *filen
+ 
+ typedef struct _GSRWindowPipeline {
+ 	GstElement *pipeline;
++	GstState    state;     /* last seen (async) pipeline state */
++	GstBus     *bus;
++
++	GstElement *src;
++	GstElement *sink;
+ 
+-	GstElement *src, *sink;
+-	guint32 state_change_id;
++	guint       tick_id;
+ } GSRWindowPipeline;
+ 
+ enum {
+@@ -84,7 +93,7 @@ static GtkWindowClass *parent_class = NU
+ struct _GSRWindowPrivate {
+ 	GtkWidget *main_vbox;
+ 	GtkWidget *scale;
+-	GtkWidget *profile;
++	GtkWidget *profile, *input;
+ 	GtkWidget *rate, *time_sec, *format, *channels;
+ 	GtkWidget *name_label;
+ 	GtkWidget *length_label;
+@@ -100,9 +109,11 @@ struct _GSRWindowPrivate {
+ 	guint tip_message_cid;
+ 
+ 	/* Pipelines */
+-	GSRWindowPipeline *play, *record;
+-	char *filename, *record_filename;
+-        char *extension;
++	GSRWindowPipeline *play;
++	GSRWindowPipeline *record;
++	char *record_filename;
++	char *filename;
++	char *extension;
+ 	char *working_file; /* Working file: Operations only occur on the
+ 			       working file. The result of that operation then
+ 			       becomes the new working file. */
+@@ -112,44 +123,114 @@ struct _GSRWindowPrivate {
+ 	int len_secs; /* In seconds */
+ 	int get_length_attempts;
+ 
+-	int n_channels, bitrate, samplerate;
++	/* ATOMIC access */
++	struct {
++		gint n_channels;
++		gint bitrate;
++		gint samplerate;
++	} atomic;
++
+ 	gboolean has_file;
+ 	gboolean saved;
+ 	gboolean dirty;
+ 	gboolean seek_in_progress;
+ 
++	gboolean quit_after_save;
++
+ 	guint32 tick_id; /* tick_callback timeout ID */
+ 	guint32 record_id; /* record idle callback timeout ID */
+-	guint32 gstenc_id; /* encode idle callback iterator ID */
++
++	GstElement *ebusy_pipeline;  /* which pipeline we're trying to start */
++	guint       ebusy_timeout_id;
++
++	GstElement *source;
++	GstMixer *mixer;
+ };
+ 
++static gboolean            make_record_source      (GSRWindow         *window);
++static void                fill_record_input       (GSRWindow         *window);
+ static GSRWindowPipeline * make_record_pipeline    (GSRWindow         *window);
+ static GSRWindowPipeline * make_play_pipeline      (GSRWindow         *window);
+ 
+ static void
+-show_error_dialog (GtkWindow *window, gchar *error)
++show_error_dialog (GtkWindow   *window,
++                   const gchar *debug_message,
++                   const gchar *format, ...) G_GNUC_PRINTF (3,4);
++
++static void
++show_error_dialog (GtkWindow *win, const gchar *dbg, const gchar * format, ...)
+ {
+ 	GtkWidget *dialog;
++	va_list args;
++	gchar *s;
+ 
+-	dialog = gtk_message_dialog_new (window,
++	va_start (args, format);
++	s = g_strdup_vprintf (format, args);
++	va_end (args);
++
++	dialog = gtk_message_dialog_new (win,
+ 					 GTK_DIALOG_DESTROY_WITH_PARENT,
+ 					 GTK_MESSAGE_ERROR,
+ 					 GTK_BUTTONS_CLOSE,
+-					 error);
+-	
++					 s);
++
++	if (dbg != NULL) {
++		g_printerr ("ERROR: %s\nDEBUG MESSAGE: %s\n", s, dbg);
++	}
++
+ 	gtk_dialog_run (GTK_DIALOG (dialog));
+ 	gtk_widget_destroy (dialog);
++	g_free (s);
+ }
+ 
++/* Why do we need this? when a bin changes from READY => NULL state, its
++ * bus is set to flushing and we're unlikely to ever see any of its messages
++ * if the bin's state reaches NULL before we/the watch in the main thread
++ * collects them. That's why we set the state to READY first, process all
++ * messages 'manually', and then finally set it to NULL. This makes sure
++ * our state-changed handler actually gets to see all the state changes */
++
+ static void
+-shutdown_pipeline (GSRWindowPipeline *pipe)
++set_pipeline_state_to_null (GstElement *pipeline)
+ {
+-	if (pipe->state_change_id > 0) {
+-		g_signal_handler_disconnect (G_OBJECT (pipe->pipeline),
+-					     pipe->state_change_id);
++	GstMessage *msg;
++	GstState cur_state, pending;
++	GstBus *bus;
++
++	gst_element_get_state (pipeline, &cur_state, &pending, 0);
++
++	if (cur_state == GST_STATE_NULL && pending == GST_STATE_VOID_PENDING)
++		return;
++
++	if (cur_state == GST_STATE_NULL && pending != GST_STATE_VOID_PENDING) {
++		gst_element_set_state (pipeline, GST_STATE_NULL);
++		return;
+ 	}
++
++	gst_element_set_state (pipeline, GST_STATE_READY);
++	gst_element_get_state (pipeline, NULL, NULL, -1);
++
++	bus = gst_element_get_bus (pipeline);
++	while ((msg = gst_bus_pop (bus))) {
++		gst_bus_async_signal_func (bus, msg, NULL);
++	}
++	gst_object_unref (bus);
++
++	gst_element_set_state (pipeline, GST_STATE_NULL);
++	/* maybe we should be paranoid and do _get_state() and check for
++	 * the return value here, but then errors in shutdown should be
++	 * rather unlikely */
++}
++
++
++static void
++shutdown_pipeline (GSRWindowPipeline *pipe)
++{
++	gst_bus_set_flushing (pipe->bus, TRUE);
++	gst_bus_remove_signal_watch (pipe->bus);
+ 	gst_element_set_state (pipe->pipeline, GST_STATE_NULL);
+-	gst_object_unref (GST_OBJECT (pipe->pipeline));	
++	gst_object_unref (pipe->pipeline);	
++	gst_object_unref (pipe->bus);
+ }
+ 
+ static char *
+@@ -225,6 +306,7 @@ seconds_to_full_string (guint seconds)
+ 	return NULL;
+ }
+ 
++static void
+ set_action_sensitive (GSRWindow  *window,
+ 		      const char *name,
+ 		      gboolean    sensitive)
+@@ -242,44 +324,14 @@ file_new_cb (GtkAction *action,
+ }
+ 
+ static void
+-file_chooser_open_response_cb (GtkDialog *file_chooser,
+-			       int response_id,
+-			       GSRWindow *window)
+-{
+-	char *name;
+-	char *dirname;
+-
+-	if (response_id != GTK_RESPONSE_OK)
+-		goto out;
+-	
+-	name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser));
+-	if (name == NULL)
+-		goto out;
+-		
+-	dirname = g_path_get_dirname (name);
+-	gconf_client_set_string (gconf_client, KEY_OPEN_DIR, dirname, NULL);
+-	g_free (dirname);
+-
+-	if (window->priv->has_file == TRUE) {
+-		/* Just open a new window with the file */
+-		gsr_open_window (name);
+-	} else {
+-		/* Set the file in this window */
+-		g_object_set (G_OBJECT (window), "location", name, NULL);
+-	}
+-		
+-	g_free (name);
+-	
+- out:
+-	gtk_widget_destroy (GTK_WIDGET (file_chooser));
+-}
+-
+-static void
+ file_open_cb (GtkAction *action,
+ 	      GSRWindow *window)
+ {
+ 	GtkWidget *file_chooser;
+-	char *directory;
++	gchar *directory;
++	gint response;
++
++	g_return_if_fail (GSR_IS_WINDOW (window));
+ 
+ 	file_chooser = gtk_file_chooser_dialog_new (_("Open a File"),
+ 						    GTK_WINDOW (window),
+@@ -289,14 +341,39 @@ file_open_cb (GtkAction *action,
+ 						    NULL);
+ 
+ 	directory = gconf_client_get_string (gconf_client, KEY_OPEN_DIR, NULL);
++
+ 	if (directory != NULL && *directory != 0) {
+-		gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (file_chooser), directory);
++		gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (file_chooser),
++		                                     directory);
+ 	}
+-	g_free (directory);
+ 
+-	g_signal_connect (G_OBJECT (file_chooser), "response",
+-			  G_CALLBACK (file_chooser_open_response_cb), window);
+-	gtk_widget_show (file_chooser);
++	response = gtk_dialog_run (GTK_DIALOG (file_chooser));
++
++	if (response == GTK_RESPONSE_OK) {
++		gchar *name;
++
++		name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser));
++		if (name) {
++			gchar *dirname;
++
++			dirname = g_path_get_dirname (name);
++			gconf_client_set_string (gconf_client, KEY_OPEN_DIR, dirname, NULL);
++			g_free (dirname);
++
++			if (window->priv->has_file == TRUE) {
++				/* Just open a new window with the file */
++				gsr_open_window (name);
++			} else {
++				/* Set the file in this window */
++				g_object_set (G_OBJECT (window), "location", name, NULL);
++			}
++		
++			g_free (name);
++		}
++    }
++
++	gtk_widget_destroy (file_chooser);
++	g_free (directory);
+ }
+ 
+ static void
+@@ -351,62 +428,6 @@ file_open_recent_cb (EggRecentViewGtk *v
+ 	g_free (uri);
+ }
+ 
+-struct _eos_data {
+-	GSRWindow *window;
+-	char *location;
+-	GstElement *pipeline;
+-};
+-
+-static gboolean
+-eos_done (struct _eos_data *ed)
+-{
+-	GSRWindow *window = ed->window;
+-
+- 	gst_element_set_state (ed->pipeline, GST_STATE_NULL);
+-	if (window->priv->gstenc_id > 0) {
+-	    g_source_remove (window->priv->gstenc_id);
+-	    window->priv->gstenc_id = 0;
+-	}
+- 
+-	g_object_set (G_OBJECT (window),
+-		      "location", ed->location,
+-		      NULL);
+-
+-
+-	gdk_window_set_cursor (window->priv->main_vbox->window, NULL);
+-
+-	set_action_sensitive (window, "Stop", FALSE);
+-	set_action_sensitive (window, "Play", TRUE);
+-	set_action_sensitive (window, "Record", TRUE);
+-	set_action_sensitive (window, "FileSave", FALSE);
+-	set_action_sensitive (window, "FileSaveAs", TRUE);
+-	gtk_widget_set_sensitive (window->priv->scale, TRUE);
+-
+-	gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
+-			   window->priv->status_message_cid);
+-	gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar),
+-			    window->priv->status_message_cid,
+-			    _("Ready"));
+-
+-	g_free (ed);
+-
+-	return FALSE;
+-}
+-
+-static GstElement *
+-gst_element_get_child (GstElement* element, const gchar *name)
+-{
+-	const GList *kids = GST_BIN (element)->children;
+-	GstElement *sink;
+-
+-	while (kids && !(strcmp (gst_object_get_name (GST_OBJECT (kids->data)), name)))
+-		kids = kids->next;
+-	g_assert (kids);
+-	sink = kids->data;
+-
+-	return sink;
+-}
+-
+ #if 0
+ static gboolean
+ cb_iterate (GstBin  *bin,
+@@ -433,81 +454,104 @@ cb_iterate (GstBin  *bin,
+ #endif
+ 
+ static gboolean
+-is_set_ebusy_timeout (GSRWindow *window)
++handle_ebusy_error (GSRWindow *window)
+ {
+-	if (g_object_get_data (G_OBJECT (window), "ebusy_timeout"))
+-		return TRUE;
++	g_return_val_if_fail (window->priv->ebusy_pipeline != NULL, FALSE);
+ 
++	gst_element_set_state (window->priv->ebusy_pipeline, GST_STATE_NULL);
++	gst_element_get_state (window->priv->ebusy_pipeline, NULL, NULL, -1);
++	gst_element_set_state (window->priv->ebusy_pipeline, GST_STATE_PLAYING);
++
++	/* Try only once */
+ 	return FALSE;
+ }
+ 
+-static void
+-set_ebusy_timeout (GSRWindow *window, gpointer data)
++static GstElement *
++notgst_element_get_toplevel (GstElement * element)
+ {
+-	g_object_set_data (G_OBJECT (window), "ebusy_timeout", data);
+-}
++	g_return_val_if_fail (element != NULL, NULL);
++	g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
+ 
+-static gboolean
+-handle_ebusy_error (GSRWindow *window)
+-{
+-	GSRWindowPrivate *priv = window->priv;
++	do {
++		GstElement *parent;
+ 
+-	/* FIXME: which pipeline to reset state on? */
+-	if (priv->play) {
+-		gst_element_set_state (priv->play->pipeline, GST_STATE_NULL);
+-		gst_element_set_state (priv->play->pipeline, GST_STATE_PLAYING);
+-	} else if (priv->record) {
+-		gst_element_set_state (priv->record->pipeline, GST_STATE_NULL);
+-		gst_element_set_state (priv->record->pipeline, GST_STATE_PLAYING);
+-	} else {
+-		g_warning ("Don't know which pipeline to reset");
+-	}
++		parent = (GstElement *) gst_element_get_parent (element);
+ 
+-	/* Try only once */
+-	return FALSE;
++		if (parent == NULL)
++			break;
++
++		gst_object_unref (parent);
++		element = parent;
++	} while (1);
++
++	return element;
+ }
+ 
+ static void
+-pipeline_error_cb (GstElement *parent,
+-		   GstElement *cause,
+-		   GError     *error,
+-		   gchar      *debug,
+-		   gpointer    data)
++pipeline_error_cb (GstBus * bus, GstMessage * msg, GSRWindow * window)
+ {
+-	GSRWindow *window = data;
+-	struct _eos_data *ed;
+-	GstElement *sink;
++	GstElement *pipeline;
++	GError *error = NULL;
++	gchar *dbg = NULL;
+ 
+-	g_return_if_fail (GTK_IS_WINDOW (window));
+-	
+-	if (error->code == GST_RESOURCE_ERROR_BUSY) {
+-		if (! is_set_ebusy_timeout (window)) {
+-			g_timeout_add (EBUSY_TRY_AGAIN, (GSourceFunc) handle_ebusy_error, window);
+-			set_ebusy_timeout (window, GUINT_TO_POINTER (TRUE));
++	g_return_if_fail (GSR_IS_WINDOW (window));
++
++	gst_message_parse_error (msg, &error, &dbg);
++	g_return_if_fail (error != NULL);
+ 
++	pipeline = notgst_element_get_toplevel (GST_ELEMENT (msg->src));
++
++	if (error->code == GST_RESOURCE_ERROR_BUSY) {
++		if (window->priv->ebusy_timeout_id == 0) {
+ 			set_action_sensitive (window, "FileSave", FALSE);
+ 			set_action_sensitive (window, "FileSaveAs", FALSE);
+ 			set_action_sensitive (window, "Play", FALSE);
+ 			set_action_sensitive (window, "Record", FALSE);
++
++			window->priv->ebusy_pipeline = pipeline;
++
++			window->priv->ebusy_timeout_id = 
++				g_timeout_add (EBUSY_TRY_AGAIN,
++				               (GSourceFunc) handle_ebusy_error,
++				               window);
++
++			g_error_free (error);
++			g_free (dbg);
+ 			return;
+ 		}
+ 	}
+ 
+-	set_ebusy_timeout (window, NULL);
++	if (window->priv->ebusy_timeout_id) {
++		g_source_remove (window->priv->ebusy_timeout_id);
++		window->priv->ebusy_timeout_id = 0;
++		window->priv->ebusy_pipeline = NULL;
++	}
++
+ 
+-	show_error_dialog (GTK_WINDOW (window), error->message);
++	/* set pipeline to NULL before showing error dialog to make sure
++	 * the audio device is freed, in case any accessability software
++	 * wants to make use of it to read out the error message */
++	set_pipeline_state_to_null (pipeline);
+ 
+-	ed = g_new (struct _eos_data, 1);
+-	ed->window = window;
+-	ed->pipeline = parent;
++	show_error_dialog (GTK_WINDOW (window), dbg, "%s", error->message);
++
++	gdk_window_set_cursor (window->priv->main_vbox->window, NULL);
++
++	set_action_sensitive (window, "Stop", FALSE);
++	set_action_sensitive (window, "Play", TRUE);
++	set_action_sensitive (window, "Record", TRUE);
++	set_action_sensitive (window, "FileSave", FALSE);
++	set_action_sensitive (window, "FileSaveAs", TRUE);
++	gtk_widget_set_sensitive (window->priv->scale, TRUE);
+ 
+-	sink = gst_element_get_child (parent, "sink");
+-	g_object_get (G_OBJECT (sink),
+-		      "location", &ed->location,
+-		      NULL);
++	gtk_statusbar_pop (GTK_STATUSBAR (window->priv->statusbar),
++			   window->priv->status_message_cid);
++	gtk_statusbar_push (GTK_STATUSBAR (window->priv->statusbar),
++			    window->priv->status_message_cid,
++			    _("Ready"));
+ 
+-	/*g_idle_add ((GSourceFunc) eos_done, ed);*/
+-	eos_done (ed);
++	g_error_free (error);
++	g_free (dbg);
+ }
+ 
+ static GtkWidget *
+@@ -619,23 +663,19 @@ do_save_file (GSRWindow *window,
+ 			g_object_set (G_OBJECT (window), "location", name, NULL);
+ 			priv->dirty = FALSE;
+ 			window->priv->saved = TRUE;
+-			if ( GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window), "save_quit")))
++			if (window->priv->quit_after_save == TRUE) {
+ 				gsr_window_close (window);
++			}
+ 		} else {
+-			gchar *error_message;
+- 
+-			error_message = g_strdup_printf (_("Could not save the file \"%s\""), gnome_vfs_result_to_string (result));
+-			show_error_dialog (GTK_WINDOW (window), error_message);
+-			g_free (error_message);
++			show_error_dialog (GTK_WINDOW (window), NULL,
++			                   _("Could not save the file \"%s\""),
++			                   gnome_vfs_result_to_string (result));
+ 		}
+ 		gnome_vfs_uri_unref (src_uri);
+ 		gnome_vfs_uri_unref (dst_uri);
+ 	} else {
+-		gchar *error_message;
+-
+-		error_message = g_strdup_printf (_("Could not save the file \"%s\""), name);
+-		show_error_dialog (GTK_WINDOW (window), error_message);
+-		g_free (error_message);
++		show_error_dialog (GTK_WINDOW (window), NULL,
++			           _("Could not save the file \"%s\""), name);
+ 	}
+ 
+ 	g_free (name);
+@@ -643,38 +683,14 @@ do_save_file (GSRWindow *window,
+ }
+ 
+ static void
+-file_chooser_save_response_cb (GtkDialog *file_chooser,
+-			       int response_id,
+-			       GSRWindow *window)
+-{
+-	char *name;
+-	char *dirname;
+-
+-	if (response_id != GTK_RESPONSE_OK)
+-		goto out;
+-	
+-	name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser));
+-	if (name == NULL)
+-		goto out;
+-
+-	dirname = g_path_get_dirname (name);
+-	gconf_client_set_string (gconf_client, KEY_SAVE_DIR, dirname, NULL);
+-	g_free (dirname);
+-	
+-	do_save_file (window, name);
+-	g_free (name);
+-
+- out:	
+-	g_object_set_data (G_OBJECT (window), "save_quit", GPOINTER_TO_INT (NULL));
+-	gtk_widget_destroy (GTK_WIDGET (file_chooser));
+-}
+-
+-static void
+ file_save_as_cb (GtkAction *action,
+ 		 GSRWindow *window)
+ {
+ 	GtkWidget *file_chooser;
+-	char *directory;
++	gchar *directory;
++	gint response;
++
++	g_return_if_fail (GSR_IS_WINDOW (window));
+ 
+ 	file_chooser = gtk_file_chooser_dialog_new (_("Save file as"),
+ 						    GTK_WINDOW (window),
+@@ -716,11 +732,30 @@ file_save_as_cb (GtkAction *action,
+ 		g_free (basename);
+ 	}
+ 
+-	g_signal_connect (G_OBJECT (file_chooser), "response",
+-			  G_CALLBACK (file_chooser_save_response_cb), window);
+-	gtk_widget_show (file_chooser);
++	response = gtk_dialog_run (GTK_DIALOG (file_chooser));
++
++	if (response == GTK_RESPONSE_OK) {
++		gchar *name;
++
++		name = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (file_chooser));
++		if (name) {
++			gchar *dirname;
++
++			dirname = g_path_get_dirname (name);
++			gconf_client_set_string (gconf_client, KEY_SAVE_DIR, dirname, NULL);
++			g_free (dirname);
++	
++			do_save_file (window, name);
++			g_free (name);
++	    }
++	}
++
++	gtk_widget_destroy (file_chooser);
++
++	window->priv->quit_after_save = FALSE;
+ }
+ 
++
+ static void
+ file_save_cb (GtkAction *action,
+ 	      GSRWindow *window)
+@@ -750,21 +785,18 @@ run_mixer_cb (GtkAction *action,
+ 	/* Open the mixer */
+ 	mixer_path = g_find_program_in_path ("gnome-volume-control");
+ 	if (mixer_path == NULL) {
+-		char *tmp;
+-		tmp = g_strdup_printf(_("%s is not installed in the path."), "gnome-volume-control");
+-		show_error_dialog (GTK_WINDOW (window), tmp);
+-		g_free(tmp);
++		show_error_dialog (GTK_WINDOW (window), NULL,
++		                   _("%s is not installed in the path."),
++		                   "gnome-volume-control");
+ 		return;
+ 	}
+ 
+ 	argv[0] = mixer_path;
+ 	ret = g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, &error);
+ 	if (ret == FALSE) {
+-		char *tmp;
+-		tmp = g_strdup_printf (_("There was an error starting %s: %s"),
+-				       mixer_path, error->message);
+-		show_error_dialog (GTK_WINDOW (window), tmp);
+-		g_free(tmp);
++		show_error_dialog (GTK_WINDOW (window), NULL,
++		                   _("There was an error starting %s: %s"),
++		                   mixer_path, error->message);
+ 		g_error_free (error);
+ 	}
+ 
+@@ -777,34 +809,13 @@ gsr_window_is_saved (GSRWindow *window)
+ 	return window->priv->saved;
+ }
+ 
+-static void
+-handle_confirmation_response (GtkDialog *dialog, gint response_id, GSRWindow *window)
+-{
+-	switch (response_id) {
+-		case GTK_RESPONSE_YES:
+-			g_object_set_data (G_OBJECT (window), "save_quit", GINT_TO_POINTER (TRUE));
+-			file_save_as_cb (NULL, window);
+-				break;
+-
+-		case GTK_RESPONSE_NO:
+-			gsr_window_close (window);
+-			break;
+-
+-		case GTK_RESPONSE_CANCEL:
+-		default: 
+-			break;
+-	} 
+-
+-	gtk_widget_destroy (GTK_WIDGET (dialog));
+-	return;
+-}
+-
+ void 
+ close_confirmation_dialog (GSRWindow *window)
+ {
+-	GtkDialog *confirmation_dialog;
+-	char *msg;
++	GtkWidget *confirmation_dialog;
+ 	AtkObject *atk_obj;
++	gchar *msg;
++	gint response_id;
+ 
+ 	msg = g_strdup_printf (_("Save the changes to file \"%s\" before closing?"),
+ 			       window->priv->record_filename);
+@@ -816,20 +827,35 @@ close_confirmation_dialog (GSRWindow *wi
+ 								  "<span weight=\"bold\" size=\"larger\">%s</span>",
+ 								  msg);
+ 
+-	gtk_dialog_add_buttons (confirmation_dialog,
++	gtk_dialog_add_buttons (GTK_DIALOG (confirmation_dialog),
+ 			 	_("Close _without Saving"), GTK_RESPONSE_NO,
+ 				GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ 				GTK_STOCK_SAVE, GTK_RESPONSE_YES, NULL);
+ 
+ 	gtk_window_set_title (GTK_WINDOW (confirmation_dialog), "");
+ 
+-	g_signal_connect (G_OBJECT (confirmation_dialog), "response",
+-			  G_CALLBACK (handle_confirmation_response), window);
+-
+-	atk_obj = gtk_widget_get_accessible (GTK_WIDGET (confirmation_dialog));
++	atk_obj = gtk_widget_get_accessible (confirmation_dialog);
+ 	atk_object_set_name (atk_obj, _("Question"));
+ 
+-	gtk_widget_show_all (GTK_WIDGET (confirmation_dialog));
++	response_id = gtk_dialog_run (GTK_DIALOG (confirmation_dialog));
++
++	switch (response_id) {
++		case GTK_RESPONSE_YES:
++			window->priv->quit_after_save = TRUE;
++			file_save_as_cb (NULL, window);
++			break;
++
++		case GTK_RESPONSE_NO:
++			gsr_window_close (window);
++			break;
++
++		case GTK_RESPONSE_CANCEL:
++		default: 
++			break;
++	} 
++
++	gtk_widget_destroy (confirmation_dialog);
++
+ 	g_free (msg);
+ }
+ 
+@@ -888,9 +914,10 @@ static void
+ fill_in_information (GSRWindow *window,
+ 		     struct _file_props *fp)
+ {
+-	char *text;
+-	char *name;
+ 	struct stat buf;
++	guint64 file_size = 0;
++	gchar *text, *name;
++	gint n_channels, bitrate, samplerate;
+ 
+ 	/* dirname */
+ 	text = g_path_get_dirname (window->priv->filename);
+@@ -910,11 +937,13 @@ fill_in_information (GSRWindow *window,
+ 	
+ 	/* Size */
+ 	if (stat (window->priv->working_file, &buf) == 0) {
+-		char *human;
+-		human = gnome_vfs_format_file_size_for_display (buf.st_size);
++		gchar *human;
++
++		file_size = (guint64) buf.st_size;
++		human = gnome_vfs_format_file_size_for_display (file_size);
+ 
+ 		text = g_strdup_printf (ngettext ("%s (%llu byte)", "%s (%llu bytes)", 
+-						   buf.st_size), human, buf.st_size);
++		                        file_size), human, file_size);
+ 		g_free (human);
+ 	} else {
+ 		text = g_strdup (_("Unknown size"));
+@@ -923,7 +952,7 @@ fill_in_information (GSRWindow *window,
+ 	g_free (text);
+ 
+ 	/* FIXME: Set up and run our own pipeline 
+-	          till we can get the info */
++	 *        till we can get the info */
+ 	/* Length */
+ 	if (window->priv->len_secs == 0) {
+ 		text = g_strdup (_("Unknown"));
+@@ -934,25 +963,32 @@ fill_in_information (GSRWindow *window,
+ 	g_free (text);
+ 
+ 	/* sample rate */
+-	if (window->priv->samplerate == 0) {
++	samplerate = g_atomic_int_get (&window->priv->atomic.samplerate);
++	if (samplerate == 0) {
+ 		text = g_strdup (_("Unknown"));
+ 	} else {
+-		text = g_strdup_printf (_("%.1f kHz"), (float) window->priv->samplerate / 1000);
++		text = g_strdup_printf (_("%.1f kHz"), (float) samplerate / 1000);
+ 	}
+ 	gtk_label_set_text (GTK_LABEL (fp->samplerate), text);
+ 	g_free (text);
+ 
+ 	/* bit rate */
+-	if (window->priv->bitrate == 0) {
+-		text = g_strdup (_("Unknown"));
++	bitrate = g_atomic_int_get (&window->priv->atomic.bitrate);
++	if (bitrate > 0) {
++		text = g_strdup_printf (_("%.0f kb/s"), (float) bitrate / 1000);
++	} else if (window->priv->len_secs > 0 && file_size > 0) {
++		bitrate = (file_size * 8.0) / window->priv->len_secs;
++		text = g_strdup_printf (_("%.0f kb/s (Estimated)"),
++		                        (float) bitrate / 1000);
+ 	} else {
+-		text = g_strdup_printf (_("%.0f kb/s"), (float) window->priv->bitrate / 1000);
++		text = g_strdup (_("Unknown"));
+ 	}
+ 	gtk_label_set_text (GTK_LABEL (fp->bitrate), text);
+ 	g_free (text);
+ 
+ 	/* channels */
+-	switch (window->priv->n_channels) {
++	n_channels = g_atomic_int_get (&window->priv->atomic.n_channels);
++	switch (n_channels) {
+ 	case 0:
+ 		text = g_strdup (_("Unknown"));
+ 		break;
+@@ -963,7 +999,7 @@ fill_in_information (GSRWindow *window,
+ 		text = g_strdup (_("2 (stereo)"));
+ 		break;
+ 	default:
+-		text = g_strdup_printf ("%d", window->priv->n_channels);
++		text = g_strdup_printf ("%d", n_channels);
+ 		break;
+ 	}
+ 	gtk_label_set_text (GTK_LABEL (fp->channels), text);
+@@ -1137,6 +1173,7 @@ about_cb (GtkAction *action,
+ 	const char * const authors[] = {"Iain Holmes <iain@prettypeople.org>", 
+ 		"Ronald Bultje <rbultje@ronald.bitfreak.net>", 
+ 		"Johan Dahlin  <johan@gnome.org>", 
++		"Tim-Philipp M\303\274ller <tim centricular net>",
+ 		NULL};
+ 	const char * const documenters[] = {"Sun Microsystems", NULL};
+  
+@@ -1161,39 +1198,28 @@ play_cb (GtkAction *action,
+ 		return;
+ 
+ 	if (priv->play) {
+-		gst_element_set_state (priv->play->pipeline, GST_STATE_NULL);
+-		g_object_unref (priv->play->pipeline);
++		shutdown_pipeline (priv->play);
+ 	}
+-	priv->play = make_play_pipeline (window);
+-
+-	g_object_set (G_OBJECT (window->priv->play->src),
+-		      "location", priv->filename,
+-		      NULL);
+ 
+-	if (priv->record && gst_element_get_state (priv->record->pipeline) == GST_STATE_PLAYING) {
+-		gst_element_set_state (priv->record->pipeline, GST_STATE_READY);
+-	}
++	if ((priv->play = make_play_pipeline (window))) {
++		gchar *uri;
+ 
+-	if (priv->play)
+-		gst_element_set_state (priv->play->pipeline, GST_STATE_PLAYING);
+-}
+-
+-static void
+-cb_rec_eos (GstElement * element,
+-	    GSRWindow * window)
+-{
+-	GSRWindowPrivate *priv = window->priv;
+-
+-	gst_element_set_state (priv->record->pipeline, GST_STATE_READY);
+-
+-	g_free (priv->working_file);
+-	priv->working_file = g_strdup (priv->record_filename);
++		/* FIXME: do we need to complete relative paths
++		 * here or is it always an absolute path? */
++		if (!g_path_is_absolute (priv->filename)) {
++			g_warning ("Filename '%s' is not an absolute path (FIXME)",
++			           priv->filename);
++		}
++		uri = g_strdup_printf ("file://%s", priv->filename);
++		g_object_set (window->priv->play->pipeline, "uri", uri, NULL);
++		g_free (uri);
+ 
+-	g_free (priv->filename);
+-	priv->filename = g_strdup (priv->record_filename);
++		if (priv->record && priv->record->state == GST_STATE_PLAYING) {
++			set_pipeline_state_to_null (priv->record->pipeline);
++		}
+ 
+-	priv->dirty = TRUE;
+-	priv->has_file = TRUE;
++		gst_element_set_state (priv->play->pipeline, GST_STATE_PLAYING);
++	}
+ }
+ 
+ static void
+@@ -1202,27 +1228,22 @@ stop_cb (GtkAction *action,
+ {
+ 	GSRWindowPrivate *priv = window->priv;
+ 
+-	/* Work out whats playing */
+-	if (priv->play && gst_element_get_state (priv->play->pipeline) == GST_STATE_PLAYING) {
+-		gst_element_set_state (priv->play->pipeline, GST_STATE_READY);
+-	} else if (priv->record && gst_element_get_state (priv->record->pipeline) == GST_STATE_PLAYING) {
+-#if 0
+-		gst_element_set_state (priv->record->pipeline, GST_STATE_READY);
+-
+-		g_free (priv->working_file);
+-		priv->working_file = g_strdup (priv->record_filename);
+-
+-		g_free (priv->filename);
+-		priv->filename = g_strdup (priv->record_filename);
+-
+-		priv->dirty = TRUE;
+-		priv->has_file = TRUE;
+-#endif
+-		g_signal_connect (priv->record->pipeline, "eos",
+-				  G_CALLBACK (cb_rec_eos), window);
+-		gst_pad_send_event (gst_element_get_pad (priv->record->src,
+-							 "src"),
+-				    gst_event_new (GST_EVENT_EOS));
++	/* Work out what's playing */
++	if (priv->play && priv->play->state == GST_STATE_PLAYING) {
++		set_pipeline_state_to_null (priv->play->pipeline);
++	} else if (priv->record && priv->record->state == GST_STATE_PLAYING) {
++		GstPad *pad;
++
++		pad = gst_element_get_pad (priv->record->src, "src");
++		if (pad) {
++			/* FIXME: this is a bit evil, we should have a clean way of
++			 * doing this programmatically. Or maybe GstBaseSrc should just
++			 * send an EOS itself in PAUSED => READY? */
++			GST_PAD_STREAM_LOCK (pad);
++			gst_pad_push_event (pad, gst_event_new_eos ());
++			GST_PAD_STREAM_UNLOCK (pad);
++			gst_object_unref (pad);
++		}
+ 	}
+ }
+ 
+@@ -1233,53 +1254,21 @@ record_cb (GtkAction *action,
+ 	GSRWindowPrivate *priv = window->priv;
+ 
+ 	if (priv->record) {
+-		gst_element_set_state (priv->record->pipeline, GST_STATE_NULL);
+-		g_object_unref (priv->record->pipeline);
+-	}
+-	priv->record = make_record_pipeline (window);
+-	if (!priv->record)
+-		return;
+-
+-	g_object_set (G_OBJECT (priv->record->sink),
+-		      "location", priv->record_filename,
+-		      NULL);
+-	window->priv->len_secs = 0;
+-	window->priv->saved = FALSE;
+-	gst_element_set_state (priv->record->pipeline, GST_STATE_PLAYING);
+-}
+-
+-static gboolean
+-get_length (GSRWindow *window)
+-{
+-	gint64 value;
+-	GstFormat format = GST_FORMAT_TIME;
+-	gboolean query_worked = FALSE;
+-
+-	if (window->priv->play->sink != NULL) {
+-		query_worked = gst_element_query (window->priv->play->sink,
+-						  GST_QUERY_TOTAL, &format, &value);
++		shutdown_pipeline (priv->record);
++		if (!make_record_source (window)) exit (1);
++		fill_record_input (window);
+ 	}
+ 
+-	if (query_worked) {
+-		char *len_str;
++	if ((priv->record = make_record_pipeline (window))) {
++		window->priv->len_secs = 0;
++		window->priv->saved = FALSE;
+ 
+-		window->priv->len_secs = value / GST_SECOND;
++		g_object_set (G_OBJECT (priv->record->sink),
++			      "location", priv->record_filename,
++			      NULL);
+ 
+-		len_str = seconds_to_full_string (window->priv->len_secs);
+-		gtk_label_set (GTK_LABEL (window->priv->length_label), len_str);
+-		
+-		g_free (len_str);
+-
+-		return FALSE;
+-	} else {
+-		if (window->priv->get_length_attempts-- < 1) {
+-			/* Attempts to get length ran out. */
+-			gtk_label_set (GTK_LABEL (window->priv->length_label), _("Unknown"));
+-			return FALSE;
+-		}
++		gst_element_set_state (priv->record->pipeline, GST_STATE_PLAYING);
+ 	}
+-
+-	return (gst_element_get_state (window->priv->play->pipeline) == GST_STATE_PLAYING);
+ }
+ 
+ static gboolean
+@@ -1298,129 +1287,147 @@ seek_to (GtkRange *range,
+ 	 GdkEventButton *gdkevent,
+ 	 GSRWindow *window)
+ {
+-	double value = range->adjustment->value;
++	gdouble value;
+ 	gint64 time;
+-	GstEvent *event;
+-	GstElementState old_state;
+ 
+-	old_state = gst_element_get_state (window->priv->play->pipeline);
+-	if (old_state == GST_STATE_READY || old_state == GST_STATE_NULL) {
++	if (window->priv->play->state < GST_STATE_PLAYING)
+ 		return FALSE;
+-	}
+ 
+-	gst_element_set_state (window->priv->play->pipeline, GST_STATE_PAUSED);
+-	time = ((value / 100) * window->priv->len_secs) * GST_SECOND;
++	value = range->adjustment->value;
++	time = ((value / 100.0) * window->priv->len_secs) * GST_SECOND;
++
++	gst_element_seek (window->priv->play->pipeline, 1.0, GST_FORMAT_TIME,
++	                  GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, time,
++	                  GST_SEEK_TYPE_NONE, 0);
+ 
+-	event = gst_event_new_seek (GST_FORMAT_TIME | GST_SEEK_FLAG_FLUSH, time);
+-	gst_element_send_event (window->priv->play->sink, event);
+-	gst_element_set_state (window->priv->play->pipeline, old_state);
+ 	window->priv->seek_in_progress = FALSE;
+ 
+ 	return FALSE;
+ }
+ 
+ static gboolean
+-tick_callback (GSRWindow *window)
++play_tick_callback (GSRWindow *window)
+ {
+-	int secs;
+-	gint64 value;
+-	gboolean query_worked = FALSE;
++	GstElement *playbin;
+ 	GstFormat format = GST_FORMAT_TIME;
++	gint64 val = -1;
++
++	g_return_val_if_fail (window->priv->play != NULL, FALSE);
++	g_return_val_if_fail (window->priv->play->pipeline != NULL, FALSE);
+ 
+-	if (gst_element_get_state (window->priv->play->pipeline) != GST_STATE_PLAYING) {
+-		/* This check stops us from doing an unnecessary query */
++	playbin = window->priv->play->pipeline;
++
++	/* This check stops us from doing an unnecessary query */
++	if (window->priv->play->state != GST_STATE_PLAYING) {
++		GST_DEBUG ("pipeline in wrong state: %s",
++			gst_element_state_get_name (window->priv->play->state));
++		window->priv->play->tick_id = 0;
+ 		return FALSE;
+ 	}
+ 
+-#if 0
+-	if (window->priv->len_secs == 0) {
+-		/* Check if we've exhausted the length check yet */
+-		if (window->priv->get_length_attempts == 0) {
+-			return FALSE;
++	if (gst_element_query_duration (playbin, &format, &val) && val != -1) {
++		gchar *len_str;
++
++		window->priv->len_secs = val / GST_SECOND;
++
++		len_str = seconds_to_full_string (window->priv->len_secs);
++		gtk_label_set (GTK_LABEL (window->priv->length_label), len_str);
++		g_free (len_str);
++	} else {
++		if (window->priv->get_length_attempts <= 0) {
++			/* Attempts to get length ran out. */
++			gtk_label_set (GTK_LABEL (window->priv->length_label), _("Unknown"));
+ 		} else {
+-			return TRUE;
++			--window->priv->get_length_attempts;
+ 		}
+ 	}
+-#endif
+-	get_length (window);
+ 
+-	if (window->priv->seek_in_progress)
++	if (window->priv->seek_in_progress) {
++		GST_DEBUG ("seek in progress, try again later");
+ 		return TRUE;
++	}
+ 
+-	query_worked = gst_element_query (window->priv->play->sink,
+-					  GST_QUERY_POSITION, 
+-					  &format, &value);
+-	if (query_worked && window->priv->len_secs != 0) {
+-		double percentage;
+-		secs = value / GST_SECOND;
+-		
+-		percentage = ((double) secs / (double) window->priv->len_secs) * 100.0;
+-		gtk_adjustment_set_value (GTK_RANGE (window->priv->scale)->adjustment, percentage + 0.5);
++	if (window->priv->len_secs == 0) {
++		GST_DEBUG ("no duration, try again later");
++		return TRUE;
++	}
++
++	if (gst_element_query_position (playbin, &format, &val) && val != -1) {
++		gdouble pos, len, percentage;
+ 
++		pos = (gdouble) (val - (val % GST_SECOND));
++		len = (gdouble) window->priv->len_secs * GST_SECOND;
++		percentage = pos / len * 100.0;
++		
++		gtk_adjustment_set_value (GTK_RANGE (window->priv->scale)->adjustment,
++		                          CLAMP (percentage + 0.5, 0.0, 100.0));
++	} else {
++		GST_DEBUG ("failed to query position");
+ 	}
+ 
+-	return (gst_element_get_state (window->priv->play->pipeline) == GST_STATE_PLAYING);
++	return TRUE;
+ }
+ 
+ static gboolean
+ record_tick_callback (GSRWindow *window)
+ {
+-	int secs;
+-	gint64 value;
+-	gboolean query_worked = FALSE;
++	GstElement *pipeline;
+ 	GstFormat format = GST_FORMAT_TIME;
++	gint64 val = -1;
++	gint secs;
+ 
+-	if (gst_element_get_state (window->priv->record->pipeline) != GST_STATE_PLAYING) {
+-		/* This check stops us from doing an unnecessary query */
++	/* This check stops us from doing an unnecessary query */
++	if (window->priv->record->state != GST_STATE_PLAYING) {
++		GST_DEBUG ("pipeline in wrong state: %s",
++			gst_element_state_get_name (window->priv->record->state));
+ 		return FALSE;
+-	}
++    }
+ 
+ 	if (window->priv->seek_in_progress)
+ 		return TRUE;
+ 
+-	query_worked = gst_element_query (window->priv->record->sink,
+-					  GST_QUERY_POSITION, 
+-					  &format, &value);
+-	if (query_worked) {
++	pipeline = window->priv->record->pipeline;
++
++	if (gst_element_query_position (pipeline, &format, &val) && val != -1) {
+ 		gchar* len_str;
+-		secs = value / GST_SECOND;
++
++		secs = val / GST_SECOND;
+ 		
+ 		len_str = seconds_to_full_string (secs);
+ 		window->priv->len_secs = secs;
+ 		gtk_label_set (GTK_LABEL (window->priv->length_label), len_str);
+ 		g_free (len_str);
++	} else {
++		GST_DEBUG ("failed to query position");
+ 	}
+ 
+-	return (gst_element_get_state (window->priv->record->pipeline) == GST_STATE_PLAYING);
++	return TRUE;
+ }
+ 
+-static gboolean
+-play_iterate (GSRWindow *window)
++static void
++play_state_changed_cb (GstBus * bus, GstMessage * msg, GSRWindow * window)
+ {
+-	gboolean ret;
+-	ret =  gst_bin_iterate (GST_BIN (window->priv->play->pipeline));
++	GstState new_state;
+ 
+-	if (!ret)
+-		gst_element_set_state (window->priv->play->pipeline, GST_STATE_NULL);
+-	return ret;
+-}
++	gst_message_parse_state_changed (msg, NULL, &new_state, NULL);
+ 
+-static void
+-play_state_changed_cb (GstElement *element,
+-		       GstElementState old,
+-		       GstElementState state,
+-		       GSRWindow *window)
+-{
+-	switch (state) {
++	g_return_if_fail (GSR_IS_WINDOW (window));
++
++	/* we are only interested in state changes of the top-level pipeline */
++	if (msg->src != GST_OBJECT (window->priv->play->pipeline))
++		return;
++
++	window->priv->play->state = new_state;
++
++	GST_DEBUG ("playbin state: %s", gst_element_state_get_name (new_state));
++
++	switch (new_state) {
+ 	case GST_STATE_PLAYING:
+-		g_idle_add ((GSourceFunc) play_iterate, window);
+-		window->priv->tick_id = g_timeout_add (200, (GSourceFunc) tick_callback, window);
+-#if 0
+-		if (window->priv->len_secs == 0) {
+-			window->priv->get_length_attempts = 16;
+-			g_timeout_add (200, (GSourceFunc) get_length, window);
++		if (window->priv->play->tick_id == 0) {
++			window->priv->play->tick_id =
++				g_timeout_add (200, (GSourceFunc) play_tick_callback, window);
+ 		}
+-#endif		
++
+ 		set_action_sensitive (window, "Stop", TRUE);
+ 		set_action_sensitive (window, "Play", FALSE);
+ 		set_action_sensitive (window, "Record", FALSE);
+@@ -1434,12 +1441,21 @@ play_state_changed_cb (GstElement *eleme
+ 				    window->priv->status_message_cid,
+ 				    _("Playing..."));
+ 
+-		set_ebusy_timeout (window, NULL);
++		if (window->priv->ebusy_timeout_id) {
++			g_source_remove (window->priv->ebusy_timeout_id);
++			window->priv->ebusy_timeout_id = 0;
++			window->priv->ebusy_pipeline = NULL;
++		}
+ 		break;
+ 
+ 	case GST_STATE_READY:
++		if (window->priv->play->tick_id > 0) {
++			g_source_remove (window->priv->play->tick_id);
++			window->priv->play->tick_id = 0;
++		}
+ 		gtk_adjustment_set_value (GTK_RANGE (window->priv->scale)->adjustment, 0.0);
+ 		gtk_widget_set_sensitive (window->priv->scale, FALSE);
++		/* fallthrough */
+ 	case GST_STATE_PAUSED:
+ 		set_action_sensitive (window, "Stop", FALSE);
+ 		set_action_sensitive (window, "Play", TRUE);
+@@ -1459,25 +1475,60 @@ play_state_changed_cb (GstElement *eleme
+ }
+ 
+ static void
+-pipeline_deep_notify_cb (GstElement *element,
+-			 GstElement *orig,
+-			 GParamSpec *param,
+-			 GSRWindow *window)
++pipeline_deep_notify_caps_cb (GstObject  *pipeline,
++                              GstObject  *object,
++                              GParamSpec *pspec,
++                              GSRWindow  *window)
+ {
+ 	GSRWindowPrivate *priv;
+-	GObject *obj;
+-	const char *pname;
++	GstPadDirection direction;
++
++	if (!GST_IS_PAD (object))
++		return;
+ 
+-	obj = G_OBJECT (orig);
+ 	priv = window->priv;
+-	
+-	pname = g_param_spec_get_name (param);
+-	if (strstr (pname, "channels")) {
+-		g_object_get (obj, "channels", &priv->n_channels, NULL);
+-	} else if (strstr (pname, "samplerate")) {
+-		g_object_get (obj,"samplerate", &priv->samplerate, NULL);
+-	} else if (strstr (pname, "bitrate")) {
+-		g_object_get (obj, "bitrate", &priv->bitrate, NULL);
++	if (priv->play && pipeline == GST_OBJECT_CAST (priv->play->pipeline)) {
++		direction = GST_PAD_SRC;
++	} else if (priv->record && pipeline == GST_OBJECT_CAST (priv->record->pipeline)) {
++		direction = GST_PAD_SINK;
++	} else {
++		g_return_if_reached ();
++	}
++
++	if (GST_PAD_DIRECTION (object) == direction) {
++		GstObject *pad_parent;
++
++		pad_parent = gst_object_get_parent (object);
++		if (GST_IS_ELEMENT (pad_parent)) {
++			GstElementFactory *factory;
++			GstElement *element;
++			const gchar *klass;
++
++			element = GST_ELEMENT_CAST (pad_parent);
++			factory = gst_element_get_factory (element);
++			klass = gst_element_factory_get_klass (factory);
++			if (klass && strstr (klass, "Audio") &&
++			    (strstr (klass, "Decoder") || strstr (klass, "Encoder"))) {
++				GstCaps *caps;
++
++				caps = gst_pad_get_negotiated_caps (GST_PAD_CAST (object));
++				if (caps) {
++					GstStructure *s;
++					gint val;
++
++					s = gst_caps_get_structure (caps, 0);
++					if (gst_structure_get_int (s, "channels", &val)) {
++						gst_atomic_int_set (&priv->atomic.n_channels, val);
++					}
++					if (gst_structure_get_int (s, "rate", &val)) {
++						gst_atomic_int_set (&priv->atomic.samplerate, val);
++					}
++					gst_caps_unref (caps);
++				}
++			}
++		}
++		if (pad_parent)
++			gst_object_unref (pad_parent);
+ 	}
+ }
+ 
+@@ -1492,60 +1543,95 @@ profile_changed_cb (GObject *object, GSR
+ 	profile = gm_audio_profile_choose_get_active (GTK_WIDGET (object));
+   
+ 	id = g_strdup (gm_audio_profile_get_id (profile));
++	GST_DEBUG ("profile changed to %s", GST_STR_NULL (id));
+ 	gconf_client_set_string (gconf_client, KEY_LAST_PROFILE_ID, id, NULL);
+ 	g_free (id);
+ }
+ 
++static void
++play_eos_msg_cb (GstBus * bus, GstMessage * msg, GSRWindow * window)
++{
++	g_return_if_fail (GSR_IS_WINDOW (window));
++
++	GST_DEBUG ("EOS");
++
++	stop_cb (NULL, window);
++}
++
+ static GSRWindowPipeline *
+ make_play_pipeline (GSRWindow *window)
+ {
+ 	GSRWindowPipeline *obj;
+-	GstElement *pipeline;
+-	guint32 id;
+-	GstElement *spider, *conv, *scale;
++	GstElement *playbin;
++	GstElement *audiosink;
+ 
+-	pipeline = gst_pipeline_new ("play-pipeline");
+-	g_signal_connect (pipeline, "deep-notify",
+-			  G_CALLBACK (pipeline_deep_notify_cb), window);
+-	g_signal_connect (pipeline, "error",
+-			  G_CALLBACK (pipeline_error_cb), window);
+-	id = g_signal_connect (pipeline, "state-change",
+-			       G_CALLBACK (play_state_changed_cb), window);
+-
+-	obj = g_new (GSRWindowPipeline, 1);
+-	obj->pipeline = pipeline;
+-	obj->state_change_id = id;
+-	
+-	obj->src = gst_element_factory_make ("filesrc", "src");
+-	if (!obj->src)
+-	{
+-		g_error ("Could not find \"filesrc\" GStreamer element");
+-		return NULL;
+-	}
+-	
+- 	spider = gst_element_factory_make ("spider", "spider");
+-	if (!spider) {
+-		g_error ("Could not find \"spider\" GStreamer element");
++	audiosink = gst_element_factory_make ("gconfaudiosink", "sink");
++	if (audiosink == NULL) {
++		show_error_dialog (NULL, NULL, _("Could not find GStreamer element "
++		                   "\"%s\" - please install it"), "gconfaudiosink");
+ 		return NULL;
+ 	}
+ 
+-	conv = gst_element_factory_make ("audioconvert", "conf");
+-	scale = gst_element_factory_make ("audioscale", "scale");
+-	obj->sink = gst_gconf_get_default_audio_sink ();
+-	if (!obj->sink)
+-	{
+-		g_error ("Could not find default audio output element");
++	playbin = gst_element_factory_make ("playbin", "playbin");
++	if (playbin == NULL) {
++		gst_object_unref (audiosink);
++		show_error_dialog (NULL, NULL, _("Could not find GStreamer element "
++		                   "\"%s\" - please install it"), "playbin");
+ 		return NULL;
+ 	}
+ 
+-	gst_bin_add_many (GST_BIN (pipeline),
+-			  obj->src, spider, conv, scale, obj->sink, NULL);
+-	gst_element_link_many (obj->src, spider, conv, scale, obj->sink, NULL);
++	obj = g_new0 (GSRWindowPipeline, 1);
++	obj->pipeline = playbin;
++	obj->src = NULL; /* don't need that for playback */
++	obj->sink = NULL; /* don't need that for playback */
++
++	g_object_set (playbin, "audio-sink", audiosink, NULL);
++
++	/* we ultimately want to find out the caps on the decoder's source pad */
++	g_signal_connect (playbin, "deep-notify::caps",
++	                  G_CALLBACK (pipeline_deep_notify_caps_cb),
++	                  window);
++
++	obj->bus = gst_element_get_bus (playbin);
++
++	gst_bus_add_signal_watch_full (obj->bus, G_PRIORITY_HIGH);
++
++	g_signal_connect (obj->bus, "message::state-changed",
++	                  G_CALLBACK (play_state_changed_cb),
++	                  window);
+ 
++	g_signal_connect (obj->bus, "message::error",
++	                  G_CALLBACK (pipeline_error_cb),
++	                  window);
++
++	g_signal_connect (obj->bus, "message::eos",
++	                  G_CALLBACK (play_eos_msg_cb),
++	                  window);
++	
+ 	return obj;
+ }
+ 
+-extern int sample_count;
++static void
++record_eos_msg_cb (GstBus * bus, GstMessage * msg, GSRWindow * window)
++{
++	g_return_if_fail (GSR_IS_WINDOW (window));
++
++	GST_DEBUG ("EOS. Finished recording");
++
++	/* FIXME: this was READY before (why?) */
++	set_pipeline_state_to_null (window->priv->record->pipeline);
++
++	g_free (window->priv->working_file);
++	window->priv->working_file = g_strdup (window->priv->record_filename);
++
++	g_free (window->priv->filename);
++	window->priv->filename = g_strdup (window->priv->record_filename);
++
++	window->priv->dirty = TRUE;
++	window->priv->has_file = TRUE;
++}
++
++extern int gsr_sample_count;
+ 
+ static gboolean
+ record_start (gpointer user_data) 
+@@ -1575,13 +1661,12 @@ record_start (gpointer user_data) 
+ 	 * there is no active sound sample. Any newly
+ 	 * recorded samples will be saved to disk with this
+ 	 * name as default value. */
+-	if (sample_count == 1) {
++	if (gsr_sample_count == 1) {
+ 		name = g_strdup (_("Untitled"));
+ 	} else {
+-		name = g_strdup_printf (_("Untitled-%d"),
+-					sample_count);
++		name = g_strdup_printf (_("Untitled-%d"), gsr_sample_count);
+ 	}
+-	sample_count++;
++	++gsr_sample_count;
+ 	gtk_window_set_title (GTK_WINDOW(window), name);
+ 
+ 	g_free (name);
+@@ -1590,12 +1675,23 @@ record_start (gpointer user_data) 
+ }
+ 
+ static void
+-record_state_changed_cb (GstElement *element,
+-			 GstElementState old,
+-			 GstElementState state,
+-			 GSRWindow *window)
++record_state_changed_cb (GstBus *bus, GstMessage *msg, GSRWindow *window)
+ {
+-	switch (state) {
++	GstState  new_state;
++
++	gst_message_parse_state_changed (msg, NULL, &new_state, NULL);
++
++	g_return_if_fail (GSR_IS_WINDOW (window));
++
++	/* we are only interested in state changes of the top-level pipeline */
++	if (msg->src != GST_OBJECT (window->priv->record->pipeline))
++		return;
++
++	window->priv->record->state = new_state;
++
++	GST_DEBUG ("record pipeline state: %s", gst_element_state_get_name (new_state));
++
++	switch (new_state) {
+ 	case GST_STATE_PLAYING:
+ 		window->priv->record_id = g_idle_add (record_start, window);
+ 		gtk_widget_set_sensitive (window->priv->profile, FALSE);
+@@ -1624,75 +1720,264 @@ record_state_changed_cb (GstElement *ele
+ 	}
+ }
+ 
++/* go through a bin, finding the one pad that is unconnected in the given
++ * direction, and return that pad; nicked from the GStreamer gconf plugin */
++static GstPad *
++notgst_bin_find_unconnected_pad (GstBin * bin, GstPadDirection direction)
++{
++	GstPad *pad = NULL;
++	GList *elements = NULL;
++	const GList *pads = NULL;
++	GstElement *element = NULL;
++
++	GST_OBJECT_LOCK (bin);
++	elements = bin->children;
++	/* traverse all elements looking for unconnected pads */
++	while (elements && pad == NULL) {
++		element = GST_ELEMENT (elements->data);
++		GST_OBJECT_LOCK (element);
++		pads = element->pads;
++		while (pads) {
++			GstPad *testpad = GST_PAD (pads->data);
++
++			/* check if the direction matches */
++			if (GST_PAD_DIRECTION (testpad) == direction) {
++				GST_OBJECT_LOCK (testpad);
++				if (GST_PAD_PEER (testpad) == NULL) {
++					GST_OBJECT_UNLOCK (testpad);
++					/* found it ! */
++					pad = testpad;
++					break;
++				}
++				GST_OBJECT_UNLOCK (testpad);
++			}
++			pads = g_list_next (pads);
++		}
++		GST_OBJECT_UNLOCK (element);
++		elements = g_list_next (elements);
++	}
++	GST_OBJECT_UNLOCK (bin);
++
++	return pad;
++}
++
++/* nicked from the GStreamer gconf plugin */
++static GstElement *
++notgst_render_bin_from_description (const gchar * description, GError ** err)
++{
++	GstPad *pad = NULL;
++	GstBin *bin;
++ 	gchar *desc;
++
++	GST_DEBUG ("making bin from description '%s'", GST_STR_NULL (description));
++
++ 	/* parse the pipeline to a bin */
++ 	desc = g_strdup_printf ("bin.( %s )", description);
++	bin = (GstBin *) gst_parse_launch (desc, err);
++	g_free (desc);
++
++	if (bin == NULL || (err && *err != NULL)) {
++		if (bin)
++			gst_object_unref (bin);
++		return NULL;
++	}
++
++	/* find pads and ghost them if necessary */
++	if ((pad = notgst_bin_find_unconnected_pad (bin, GST_PAD_SRC))) {
++		gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", pad));
++	}
++	if ((pad = notgst_bin_find_unconnected_pad (bin, GST_PAD_SINK))) {
++		gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", pad));
++	}
++
++	return GST_ELEMENT (bin);
++}
++
++/* create the gconf-based source for recording.
++ * store the source and the mixer in it in our window-private data
++ */
++static gboolean
++make_record_source (GSRWindow *window)
++{
++	GstElement *source, *e;
++
++	source = gst_element_factory_make ("gconfaudiosrc", "gconfaudiosource");
++	if (source == NULL) {
++		show_error_dialog (NULL, NULL, _("Could not find GStreamer element "
++		                   "\"%s\" - please install it"), "gconfaudiosrc");
++		return FALSE;
++	}
++
++	/* instantiate the underlying element so we can query it */
++	/* FIXME: maybe we want to trap errors in this case ? */
++        if (!gst_element_set_state (source, GST_STATE_READY)) {
++		show_error_dialog (NULL, NULL,
++			_("Could not activate GStreamer element "
++		                   "\"%s\""), "gconfaudiosrc");
++		return FALSE;
++	}
++	window->priv->source = source;
++	e = gst_bin_get_by_interface (GST_BIN (source), GST_TYPE_MIXER);
++	window->priv->mixer = GST_MIXER (e);
++
++	return TRUE;
++}
++
++static void
++record_input_changed_cb (GtkComboBox *input, GSRWindow *window)
++{
++	const gchar *text;
++	const GList *l;
++	GstMixerTrack *t = NULL;
++	GstMixerTrack *selected = NULL;
++
++	text = gtk_combo_box_get_active_text (input);
++
++	GST_DEBUG ("record input changed to '%s'", GST_STR_NULL (text));
++
++	for (l = gst_mixer_list_tracks (window->priv->mixer); l != NULL; l = l->next) {
++		t = l->data;
++
++		if (!(t->flags & GST_MIXER_TRACK_INPUT)) continue;
++
++		if ((strcmp (t->label, text) == 0) && (t->flags & GST_MIXER_TRACK_INPUT))
++			selected = t;
++		else {
++			/* we make sure other channels are not recording */
++			if (t->flags & GST_MIXER_TRACK_RECORD) {
++				GST_DEBUG ("turning off record on %s\n", t->label);
++				gst_mixer_set_record (window->priv->mixer, t, FALSE);
++			}
++		}
++	}
++
++	if (!selected)
++		return;
++
++	gst_mixer_set_record (window->priv->mixer, selected, TRUE);
++	GST_DEBUG ("input changed to: %s\n", selected->label);
++}
++
++static void
++fill_record_input (GSRWindow *window)
++{
++	GstElement *e;
++	const GList *l;
++	int i = 0;
++
++	g_return_if_fail (GST_IS_MIXER (window->priv->mixer));
++
++	for (l = gst_mixer_list_tracks (window->priv->mixer); l != NULL; l = l->next) {
++		GstMixerTrack *t = l->data;
++		if (t->flags & GST_MIXER_TRACK_INPUT) {
++			gtk_combo_box_append_text (GTK_COMBO_BOX (window->priv->input), t->label);
++			++i;
++		}
++		if (t->flags & GST_MIXER_TRACK_RECORD) {
++			gtk_combo_box_set_active (GTK_COMBO_BOX (window->priv->input), i - 1);
++		}
++	}
++}
++
+ static GSRWindowPipeline *
+ make_record_pipeline (GSRWindow *window)
+ {
+ 	GSRWindowPipeline *pipeline;
+-	gint32 id;
+ 	GMAudioProfile *profile;
+-	gchar *pipeline_desc, *source;
+-	GstElement *esource = NULL, *encoder, *manager;
+-	
+-	pipeline = g_new (GSRWindowPipeline, 1);
+-	pipeline->pipeline = gst_thread_new ("record-pipeline");
+-	id = g_signal_connect (G_OBJECT (pipeline->pipeline),
+-			       "state-change",
+-			       G_CALLBACK (record_state_changed_cb),
+-			       window);
+-	pipeline->state_change_id = id;
+-	
+-	g_signal_connect (G_OBJECT (pipeline->pipeline), "error",
+-			  G_CALLBACK (pipeline_error_cb), window);
+-	
+-        profile = gm_audio_profile_choose_get_active (window->priv->profile);
+-	source = gst_gconf_get_string ("default/audiosrc");
+-	if (source) {
+-		esource = gst_gconf_render_bin_from_description (source);
+-	}
+-	if (!esource) {
+-		show_error_dialog (NULL, _("There is no default GStreamer "
+-				   "audio input element set - please install "
+-				   "the GStreamer-GConf schemas or set one "
+-				   "manually"));
++	const gchar *profile_pipeline_desc;
++	GstElement *encoder, *source, *filesink;
++	GError *err = NULL;
++	gchar *pipeline_desc;
++
++	source = window->priv->source;
++
++	/* Any reason we are not using gnomevfssink here? (tpm) */
++	filesink = gst_element_factory_make ("filesink", "sink");
++	if (filesink == NULL)
++	{
++		show_error_dialog (NULL, NULL, _("Could not find GStreamer element "
++		                   "\"%s\" - please install it"), "filesink");
++		gst_object_unref (source);
+ 		return NULL;
+ 	}
+-	pipeline->src = manager =
+-		gst_element_factory_make ("manager", "manager");
+-	gst_bin_add (GST_BIN (manager), esource);
+-	gst_bin_add (GST_BIN (pipeline->pipeline), manager);
+-
+-	pipeline_desc = g_strdup_printf ("audioconvert ! %s",
+-					 gm_audio_profile_get_pipeline (profile));
+-	g_free (source);
+-	
+-	encoder = gst_gconf_render_bin_from_description (pipeline_desc);
++
++	pipeline = g_new (GSRWindowPipeline, 1);
++
++	pipeline->pipeline = gst_pipeline_new ("record-pipeline");
++	pipeline->src = source;
++	pipeline->sink = filesink;
++
++	gst_bin_add (GST_BIN (pipeline->pipeline), source);
++
++	profile = gm_audio_profile_choose_get_active (window->priv->profile);
++	profile_pipeline_desc = gm_audio_profile_get_pipeline (profile);
++
++	GST_DEBUG ("encoder profile pipeline: '%s'",
++		GST_STR_NULL (profile_pipeline_desc));
++
++	pipeline_desc = g_strdup_printf ("audioconvert ! %s", profile_pipeline_desc);
++	encoder = notgst_render_bin_from_description (pipeline_desc, &err);
+ 	g_free (pipeline_desc);
+-	if (!encoder) {
+-		show_error_dialog (NULL, _("Failed to create GStreamer "
+-				   "encoder elements - check your encoding "
+-				   "setup"));
++	pipeline_desc = NULL;
++
++	if (err) {
++		show_error_dialog (NULL, err->message, _("Failed to create GStreamer "
++				   "encoder elements - check your encoding setup."));
++		g_printerr ("Failed to create GStreamer encoder elements [%s]: %s",
++		           profile_pipeline_desc, err->message);
++		g_error_free (err);
++		gst_object_unref (pipeline->pipeline);
++		gst_object_unref (filesink);
++		g_free (pipeline);
+ 		return NULL;
+ 	}
++
+ 	gst_bin_add (GST_BIN (pipeline->pipeline), encoder);
+-	
+-	pipeline->sink = gst_element_factory_make ("filesink", "sink");
+-	if (!pipeline->sink)
+-	{
+-		show_error_dialog (NULL, _("Could not find \"filesink\" GStreamer "
+-				   "element - broken GStreamer install"));
++	gst_bin_add (GST_BIN (pipeline->pipeline), filesink);
++
++	/* now link it all together */
++	if (!gst_element_link (source, encoder)) {
++		show_error_dialog (NULL, NULL, _("Failed to link input element "
++		                   "with encoder elements - you probably "
++		                   "selected an invalid encoder"));
++		g_error_free (err);
++		gst_object_unref (pipeline->pipeline);
++		g_free (pipeline);
+ 		return NULL;
+ 	}
+-	gst_bin_add (GST_BIN (pipeline->pipeline), pipeline->sink);
+-	
+-	if (!gst_element_link (manager, encoder) ||
+-	    !gst_element_link (encoder, pipeline->sink))
+-	{
+-		show_error_dialog (NULL, _("Failed to link encoder element "
+-				   "with file output element - you probably "
+-				   "selected an invalid encoder"));
++
++	if (!gst_element_link (encoder, filesink)) {
++		show_error_dialog (NULL, NULL, _("Failed to link encoder element "
++		                   "with file output element - you probably "
++		                   "selected an invalid encoder"));
++		g_error_free (err);
++		gst_object_unref (pipeline->pipeline);
++		g_free (pipeline);
+ 		return NULL;
+ 	}
+-	
++
++	/* we ultimately want to find out the caps on the encoder's source pad */
++	g_signal_connect (pipeline->pipeline, "deep-notify::caps",
++	                  G_CALLBACK (pipeline_deep_notify_caps_cb),
++	                  window);
++
++
++	pipeline->bus = gst_element_get_bus (pipeline->pipeline);
++
++	gst_bus_add_signal_watch (pipeline->bus);
++
++	g_signal_connect (pipeline->bus, "message::state-changed",
++	                  G_CALLBACK (record_state_changed_cb),
++	                  window);
++
++	g_signal_connect (pipeline->bus, "message::error",
++	                  G_CALLBACK (pipeline_error_cb),
++	                  window);
++
++	g_signal_connect (pipeline->bus, "message::eos",
++	                  G_CALLBACK (record_eos_msg_cb),
++	                  window);
++
+ 	return pipeline;
+ }
+ 
+@@ -1701,9 +1986,9 @@ calculate_format_value (GtkScale *scale,
+ 			double value,
+ 			GSRWindow *window)
+ {
+-	int seconds;
++	gint seconds;
+ 
+-	if (window->priv->record && gst_element_get_state (window->priv->record->pipeline) == GST_STATE_PLAYING) {
++	if (window->priv->record && window->priv->record->state == GST_STATE_PLAYING) {
+ 		seconds = value;
+ 		return seconds_to_string (seconds);
+ 	} else {
+@@ -1804,6 +2089,25 @@ disconnect_proxy_cb (GtkUIManager *manag
+ 	}
+ }
+ 
++/* find the given filename in the uninstalled or installed ui dir */
++static gchar *
++find_ui_file (const gchar * filename)
++{
++	gchar * path;
++
++	path = g_build_filename (GSR_UIDIR_UNINSTALLED, filename, NULL);
++	if (g_file_test (path, G_FILE_TEST_EXISTS))
++		return path;
++
++	g_free (path);
++	path = g_build_filename (GSR_UIDIR, filename, NULL);
++	if (g_file_test (path, G_FILE_TEST_EXISTS))
++		return path;
++
++	g_free (path);
++	return NULL;
++}
++
+ static void
+ gsr_window_init (GSRWindow *window)
+ {
+@@ -1820,8 +2124,11 @@ gsr_window_init (GSRWindow *window)
+ 	GtkWidget *label;
+ 	GtkWidget *table;
+ 	gchar *id;
++	gchar *path;
+ 	GtkAction *action;
+ 
++	GstElement *source;
++
+ 	window->priv = GSR_WINDOW_GET_PRIVATE (window);
+ 	priv = window->priv;
+ 
+@@ -1840,14 +2147,17 @@ gsr_window_init (GSRWindow *window)
+ 	gtk_window_add_accel_group (GTK_WINDOW (window),
+ 				    gtk_ui_manager_get_accel_group (priv->ui_manager));
+ 
+-	gtk_ui_manager_add_ui_from_file (priv->ui_manager, GSR_UIDIR "ui.xml", &error);
++	path = find_ui_file ("ui.xml");
++	gtk_ui_manager_add_ui_from_file (priv->ui_manager, path, &error);
++
+ 	if (error != NULL)
+ 	{
+-		show_error_dialog (GTK_WINDOW (window),
++		show_error_dialog (GTK_WINDOW (window), error->message,
+ 			_("Could not load ui.xml. The program may be not properly installed"));
+ 		g_error_free (error);
+ 		exit (1);
+ 	}
++	g_free (path);
+ 
+ 	/* show tooltips in the statusbar */
+ 	g_signal_connect (priv->ui_manager, "connect_proxy",
+@@ -1900,7 +2210,7 @@ gsr_window_init (GSRWindow *window)
+ 			  G_CALLBACK (file_open_recent_cb), window);
+ 
+ 	/* window content: hscale, labels, etc */
+-	content_vbox = gtk_vbox_new (FALSE, 6);
++	content_vbox = gtk_vbox_new (FALSE, 7);
+ 	gtk_container_set_border_width (GTK_CONTAINER (content_vbox), 6);
+ 	gtk_box_pack_start (GTK_BOX (main_vbox), content_vbox, TRUE, TRUE, 0);
+ 	gtk_widget_show (content_vbox);
+@@ -1909,9 +2219,9 @@ gsr_window_init (GSRWindow *window)
+ 	priv->seek_in_progress = FALSE;
+ 	g_signal_connect (priv->scale, "format-value",
+ 			  G_CALLBACK (calculate_format_value), window);
+-	g_signal_connect (priv->scale, "button_press_event",
++	g_signal_connect (priv->scale, "button-press-event",
+ 			  G_CALLBACK (seek_started), window);
+-	g_signal_connect (priv->scale, "button_release_event",
++	g_signal_connect (priv->scale, "button-release-event",
+ 			  G_CALLBACK (seek_to), window);
+ 
+ 	gtk_scale_set_value_pos (GTK_SCALE (window->priv->scale), GTK_POS_BOTTOM);
+@@ -1920,6 +2230,24 @@ gsr_window_init (GSRWindow *window)
+ 	gtk_box_pack_start (GTK_BOX (content_vbox), priv->scale, TRUE, TRUE, 6);
+ 	gtk_widget_show (window->priv->scale);
+ 
++        /* create source and choose mixer input */
++	hbox = gtk_hbox_new (FALSE, 12);
++	gtk_box_pack_start (GTK_BOX (content_vbox), hbox, FALSE, FALSE, 0);
++
++	label = gtk_label_new (_("Record from input:"));
++	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
++	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
++
++	priv->input = gtk_combo_box_new_text ();
++	gtk_box_pack_start (GTK_BOX (hbox), priv->input, TRUE, TRUE, 0);
++	gtk_widget_show (priv->input);
++
++	if (!make_record_source (window)) exit (1);
++	fill_record_input (window);
++	g_signal_connect (priv->input, "changed",
++			  G_CALLBACK (record_input_changed_cb), window);
++
++	/* choose profile */
+ 	hbox = gtk_hbox_new (FALSE, 12);
+ 	gtk_box_pack_start (GTK_BOX (content_vbox), hbox, FALSE, FALSE, 0);
+ 
+@@ -1977,7 +2305,7 @@ gsr_window_init (GSRWindow *window)
+ 			  GTK_FILL, 0, 0, 0);
+ 	
+ 	priv->length_label = gtk_label_new ("");
+-	gtk_label_set_selectable (GTK_LABEL (priv->length_label), TRUE);
++	gtk_label_set_selectable (GTK_LABEL (priv->length_label), FALSE);
+ 	gtk_misc_set_alignment (GTK_MISC (priv->length_label), 0, 0.5);
+ 	gtk_table_attach (GTK_TABLE (table), priv->length_label,
+ 			  1, 2, 1, 2,
+@@ -2006,7 +2334,6 @@ gsr_window_init (GSRWindow *window)
+ 	priv->len_secs = 0;
+ 	priv->get_length_attempts = 16;
+ 	priv->dirty = FALSE;
+-	priv->gstenc_id = 0;
+ }
+ 
+ static void
+@@ -2094,6 +2421,8 @@ gsr_window_finalize (GObject *object)
+ 	window = GSR_WINDOW (object);
+ 	priv = window->priv;
+ 
++	GST_DEBUG ("finalizing ...");
++
+ 	if (priv == NULL) {
+ 		return;
+ 	}
+@@ -2116,6 +2445,10 @@ gsr_window_finalize (GObject *object)
+ 		g_source_remove (priv->record_id);
+ 	}
+ 
++	if (priv->ebusy_timeout_id > 0) {
++		g_source_remove (window->priv->ebusy_timeout_id);
++	}
++
+ 	g_idle_remove_by_data (window);
+ 
+ 	if (priv->play != NULL) {
+@@ -2165,6 +2498,8 @@ gsr_window_class_init (GSRWindowClass *k
+ 							      G_PARAM_READWRITE));
+ 
+ 	g_type_class_add_private (object_class, sizeof (GSRWindowPrivate));
++
++	GST_DEBUG_CATEGORY_INIT (gsr_debug, "gsr", 0, "Gnome Sound Recorder");
+ }
+ 
+ GType
+@@ -2195,9 +2530,8 @@ gsr_window_new (const char *filename)
+ {
+ 	GSRWindow *window;
+ 	struct stat buf;
+-	char *short_name;
+ 
+-        /* filename has been changed to be without extension */
++	/* filename has been changed to be without extension */
+ 	window = g_object_new (GSR_TYPE_WINDOW, 
+ 			       "location", filename,
+ 			       NULL);
+Index: grecord/src/gsr-window.h
+===================================================================
+RCS file: /cvs/gnome/gnome-media/grecord/src/gsr-window.h,v
+retrieving revision 1.4
+retrieving revision 1.4.4.1
+diff -u -p -r1.4 -r1.4.4.1
+--- grecord/src/gsr-window.h	2 May 2005 10:19:31 -0000	1.4
++++ grecord/src/gsr-window.h	13 Jan 2006 15:07:52 -0000	1.4.4.1
+@@ -57,4 +57,8 @@ GtkWidget	*gsr_window_new		(const char *
+ 
+ void		 gsr_window_close	(GSRWindow *window);
+ 
++gboolean     gsr_window_is_saved (GSRWindow *window);
++
++void         close_confirmation_dialog (GSRWindow *window);
++
+ #endif
+Index: gst-mixer/src/element.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gst-mixer/src/element.c,v
+retrieving revision 1.6
+retrieving revision 1.6.4.1
+diff -u -p -r1.6 -r1.6.4.1
+--- gst-mixer/src/element.c	8 Apr 2005 08:13:58 -0000	1.6
++++ gst-mixer/src/element.c	13 Jan 2006 15:07:52 -0000	1.6.4.1
+@@ -25,7 +25,6 @@
+ 
+ #include <gnome.h>
+ #include <gtk/gtk.h>
+-#include <gst/mixer/mixer.h>
+ 
+ #include "element.h"
+ #include "keys.h"
+Index: gst-mixer/src/element.h
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gst-mixer/src/element.h,v
+retrieving revision 1.3
+retrieving revision 1.3.6.1
+diff -u -p -r1.3 -r1.3.6.1
+--- gst-mixer/src/element.h	10 Jan 2005 21:10:42 -0000	1.3
++++ gst-mixer/src/element.h	13 Jan 2006 15:07:52 -0000	1.3.6.1
+@@ -26,7 +26,7 @@
+ #include <gtk/gtknotebook.h>
+ #include <libgnomeui/gnome-appbar.h>
+ #include <gconf/gconf-client.h>
+-#include <gst/mixer/mixer.h>
++#include <gst/interfaces/mixer.h>
+ 
+ G_BEGIN_DECLS
+ 
+Index: gst-mixer/src/main.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gst-mixer/src/main.c,v
+retrieving revision 1.9
+retrieving revision 1.9.2.1
+diff -u -p -r1.9 -r1.9.2.1
+--- gst-mixer/src/main.c	10 Jan 2006 12:38:14 -0000	1.9
++++ gst-mixer/src/main.c	13 Jan 2006 15:07:52 -0000	1.9.2.1
+@@ -27,22 +27,12 @@
+ #include <glib.h>
+ #include <gnome.h>
+ #include <gst/gst.h>
+-#include <gst/mixer/mixer.h>
+-#include <gst/propertyprobe/propertyprobe.h>
++#include <gst/audio/mixerutils.h>
+ 
+ #include "keys.h"
+ #include "stock.h"
+ #include "window.h"
+ 
+-static gint
+-sort_by_rank (GstElement * a, GstElement * b)
+-{
+-#define gst_element_rank(x) \
+-  gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE ( \
+-      gst_element_get_factory (x)))
+-  return gst_element_rank (b) - gst_element_rank (a);
+-}
+-
+ /*
+  * Probe for mixer elements. Set up GList * with elements,
+  * where each element has a GObject data node set of the
+@@ -53,107 +43,64 @@ sort_by_rank (GstElement * a, GstElement
+  * GST_STATE_NULL.
+  */
+ 
+-static GList *
+-create_mixer_collection (void)
++static gboolean
++mixer_filter_func (GstMixer * mixer, gpointer user_data)
+ {
+-  const GList *elements;
+-  GList *collection = NULL;
+-  gint num = 0;
+-
+-  /* go through all elements of a certain class and check whether
+-   * they implement a mixer. If so, add it to the list. */
+-  elements = gst_registry_pool_feature_list (GST_TYPE_ELEMENT_FACTORY);
+-  for ( ; elements != NULL; elements = elements->next) {
+-    GstElementFactory *factory = GST_ELEMENT_FACTORY (elements->data);
+-    gchar *title = NULL, *name;
+-    const gchar *klass;
+-    GstElement *element = NULL;
+-    const GParamSpec *devspec;
+-    GstPropertyProbe *probe;
+-    GValueArray *array = NULL;
+-    gint n;
+-
+-    /* check category */
+-    klass = gst_element_factory_get_klass (factory);
+-    if (strcmp (klass, "Generic/Audio"))
+-      goto next;
+-
+-    /* FIXME:
+-     * - maybe we want to rename the element to its actual name
+-     *     if we've found that?
+-     */
+-#define _label N_("Unknown Volume Control %d")
+-
+-    /* create element */
+-    title = g_strdup_printf (gettext("Unknown Volume Control %d"), num);
+-    element = gst_element_factory_create (factory, title);
+-    if (!element)
+-      goto next;
+-
+-    if (!GST_IS_PROPERTY_PROBE (element))
+-      goto next;
+-
+-    probe = GST_PROPERTY_PROBE (element);
+-    if (!(devspec = gst_property_probe_get_property (probe, "device")))
+-      goto next;
+-    if (!(array = gst_property_probe_probe_and_get_values (probe, devspec)))
+-      goto next;
+-
+-    /* set all devices and test for mixer */
+-    for (n = 0; n < array->n_values; n++) {
+-      GValue *device = g_value_array_get_nth (array, n);
+-      gchar *devname = NULL;
+-
+-      /* set this device */
+-      g_object_set_property (G_OBJECT (element), "device", device);
+-      if (gst_element_set_state (element,
+-				 GST_STATE_READY) == GST_STATE_FAILURE)
+-        continue;
+-
+-      /* is this device a mixer? */
+-      if (!GST_IS_MIXER (element)) {
+-        gst_element_set_state (element, GST_STATE_NULL);
+-        continue;
+-      }
+-
+-      /* any tracks? */
+-      if (!gst_mixer_list_tracks (GST_MIXER (element))) {
+-        gst_element_set_state (element, GST_STATE_NULL);
+-        continue;
+-      }
+-
+-      /* fetch name */
+-      if (g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (element)),
+-					"device-name")) {
+-        g_object_get (element, "device-name", &devname, NULL);
+-      }
+-
+-      name = g_strdup_printf ("%s (%s)", devname ? devname : title,
+-			      gst_element_factory_get_longname (factory));
+-      g_free (devname);
+-      g_object_set_data (G_OBJECT (element), "gnome-volume-control-name",
+-			 name);
+-
+-      /* add to list */
+-      gst_element_set_state (element, GST_STATE_NULL);
+-      collection = g_list_append (collection, element);
+-      num++;
+-
+-      /* and recreate this object, since we give it to the mixer */
+-      g_free (title);
+-      title = g_strdup_printf (gettext("Unknown Volume Control %d"), num);
+-      element = gst_element_factory_create (factory, title);
+-    }
++  GstElementFactory *factory;
++  const gchar *long_name;
++  gchar *devname = NULL;
++  gchar *name;
++  gint *p_count = (gint *) user_data;
++
++  /* fetch name */
++  if (g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (mixer)),
++                                    "device-name")) {
++    g_object_get (mixer, "device-name", &devname, NULL);
++    GST_DEBUG ("device name: %s", GST_STR_NULL (devname));
++  } else {
++    devname = NULL;
++    GST_DEBUG ("device name unknown, no 'device-name' property");
++  }
++    
++  factory = gst_element_get_factory (GST_ELEMENT (mixer));
++  long_name = gst_element_factory_get_longname (factory);
++
++  if (devname) {
++    name = g_strdup_printf ("%s (%s)", devname, long_name);
++    g_free (devname);
++  } else {
++    gchar *title;
++
++    *p_count += 1;
+ 
+-next:
+-    if (element)
+-      gst_object_unref (GST_OBJECT (element));
+-    if (array)
+-      g_value_array_free (array);
++    title = g_strdup_printf (_("Unknown Volume Control %d"),  *p_count);
++    name = g_strdup_printf ("%s (%s)", title, long_name);
+     g_free (title);
+   }
+ 
+-  return g_list_sort (collection, (GCompareFunc) sort_by_rank);
++  g_object_set_data_full (G_OBJECT (mixer),
++                          "gnome-volume-control-name",
++                          name,
++                          (GDestroyNotify) g_free);
++
++  GST_DEBUG ("Adding '%s' to list of available mixers", name);
++
++  gst_element_set_state (GST_ELEMENT (mixer), GST_STATE_NULL);
++
++  return TRUE; /* add mixer to list */
++}
++
++static GList *
++create_mixer_collection (void)
++{
++  GList *mixer_list;
++  gint counter = 0;
++
++  mixer_list = gst_audio_default_registry_mixer_filter (mixer_filter_func,
++                                                        FALSE,
++                                                        &counter);
++
++  return mixer_list;
+ }
+ 
+ static void
+@@ -221,10 +168,6 @@ main (gint   argc,
+ {
+   gchar *appfile;
+   GtkWidget *win;
+-  struct poptOption options[] = {
+-    { NULL, '\0', POPT_ARG_INCLUDE_TABLE, NULL, 0, "GStreamer", NULL },
+-    POPT_TABLEEND
+-  };
+   GList *elements;
+ 
+   /* i18n */
+@@ -232,31 +175,29 @@ main (gint   argc,
+   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+   textdomain (GETTEXT_PACKAGE);
+ 
+-  /* init gstreamer */
+-  options[0].arg = (void *) gst_init_get_popt_table ();
+-
+-  /* init gtk/gnome */
++/* FIXME: remove when bumping requirements to 2.14 */
++#ifdef GNOME_PARAM_GOPTION_CONTEXT
++  if (1) {
++    GOptionContext *ctx;
++    GOptionGroup *group;
++
++    ctx = g_option_context_new ("gnome-volume-control");
++    g_option_context_add_group (ctx, gst_init_get_option_group ());
++
++    gnome_program_init ("gnome-volume-control", VERSION,
++                        LIBGNOMEUI_MODULE, argc, argv,
++                        GNOME_PARAM_GOPTION_CONTEXT, ctx,
++                        GNOME_PARAM_APP_DATADIR, DATA_DIR,
++                        NULL);
++  }
++#else /* GNOME_PARAM_GOPTION_CONTEXT */
++  gst_init (&argc, &argv);
+   gnome_program_init ("gnome-volume-control", VERSION,
+ 		      LIBGNOMEUI_MODULE, argc, argv,
+-		      GNOME_PARAM_POPT_TABLE, options,
+ 		      GNOME_PARAM_APP_DATADIR, DATA_DIR, NULL);
+ 
+-   if (!gst_scheduler_factory_get_default_name ()) {
+-		GtkWidget *dialog;
+-
+-		dialog = gtk_message_dialog_new (NULL,
+-						 0,
+-						 GTK_MESSAGE_ERROR,
+-						 GTK_BUTTONS_CLOSE,
+-						 _("Registry is not present or it is corrupted, please update it by running gst-register"));
+-
+-		gtk_dialog_run (GTK_DIALOG (dialog));
+-		gtk_widget_destroy (dialog);
+-
+-		exit (1);
+-	}
++#endif /* GNOME_PARAM_GOPTION_CONTEXT */
+ 
+-		
+ 
+   /* init ourselves */
+   register_stock_icons ();
+Index: gst-mixer/src/preferences.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gst-mixer/src/preferences.c,v
+retrieving revision 1.4
+retrieving revision 1.4.4.1
+diff -u -p -r1.4 -r1.4.4.1
+--- gst-mixer/src/preferences.c	3 Apr 2005 15:26:51 -0000	1.4
++++ gst-mixer/src/preferences.c	13 Jan 2006 15:07:52 -0000	1.4.4.1
+@@ -25,7 +25,6 @@
+ 
+ #include <gnome.h>
+ #include <gtk/gtk.h>
+-#include <gst/mixer/mixer.h>
+ 
+ #include "element.h"
+ #include "preferences.h"
+Index: gst-mixer/src/preferences.h
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gst-mixer/src/preferences.h,v
+retrieving revision 1.1
+retrieving revision 1.1.6.1
+diff -u -p -r1.1 -r1.1.6.1
+--- gst-mixer/src/preferences.h	16 Sep 2004 20:20:11 -0000	1.1
++++ gst-mixer/src/preferences.h	13 Jan 2006 15:07:52 -0000	1.1.6.1
+@@ -25,7 +25,7 @@
+ #include <glib.h>
+ #include <gtk/gtkdialog.h>
+ #include <gconf/gconf-client.h>
+-#include <gst/mixer/mixer.h>
++#include <gst/interfaces/mixer.h>
+ 
+ G_BEGIN_DECLS
+ 
+Index: gst-mixer/src/track.h
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gst-mixer/src/track.h,v
+retrieving revision 1.2
+retrieving revision 1.2.6.1
+diff -u -p -r1.2 -r1.2.6.1
+--- gst-mixer/src/track.h	11 Dec 2004 11:26:45 -0000	1.2
++++ gst-mixer/src/track.h	13 Jan 2006 15:07:52 -0000	1.2.6.1
+@@ -26,7 +26,7 @@
+ #include <gtk/gtk.h>
+ #include <gconf/gconf-client.h>
+ #include <gst/gst.h>
+-#include <gst/mixer/mixer.h>
++#include <gst/interfaces/mixer.h>
+ 
+ #include "button.h"
+ 
+Index: gst-mixer/src/volume.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gst-mixer/src/volume.c,v
+retrieving revision 1.7
+retrieving revision 1.7.2.1
+diff -u -p -r1.7 -r1.7.2.1
+--- gst-mixer/src/volume.c	10 Jan 2006 12:55:52 -0000	1.7
++++ gst-mixer/src/volume.c	13 Jan 2006 15:07:52 -0000	1.7.2.1
+@@ -29,11 +29,10 @@
+ #include <gnome.h>
+ #include <gdk/gdkx.h>
+ #include <gtk/gtk.h>
+-#include <gst/mixer/mixer.h>
+ 
++#include "volume.h"
+ #include "button.h"
+ #include "stock.h"
+-#include "volume.h"
+ 
+ static void	gnome_volume_control_volume_class_init	(GnomeVolumeControlVolumeClass *klass);
+ static void	gnome_volume_control_volume_init	(GnomeVolumeControlVolume *el);
+Index: gst-mixer/src/volume.h
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gst-mixer/src/volume.h,v
+retrieving revision 1.2
+retrieving revision 1.2.6.1
+diff -u -p -r1.2 -r1.2.6.1
+--- gst-mixer/src/volume.h	11 Jan 2005 15:10:21 -0000	1.2
++++ gst-mixer/src/volume.h	13 Jan 2006 15:07:52 -0000	1.2.6.1
+@@ -24,7 +24,7 @@
+ 
+ #include <glib.h>
+ #include <gtk/gtkfixed.h>
+-#include <gst/mixer/mixer.h>
++#include <gst/interfaces/mixer.h>
+ 
+ G_BEGIN_DECLS
+ 
+Index: gst-mixer/src/window.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gst-mixer/src/window.c,v
+retrieving revision 1.9
+retrieving revision 1.9.4.1
+diff -u -p -r1.9 -r1.9.4.1
+--- gst-mixer/src/window.c	21 Dec 2005 14:57:01 -0000	1.9
++++ gst-mixer/src/window.c	13 Jan 2006 15:07:52 -0000	1.9.4.1
+@@ -276,9 +276,7 @@ gnome_volume_control_window_dispose (GOb
+       GstElement *element = GST_ELEMENT (item->data);
+ 
+       gst_element_set_state (element, GST_STATE_NULL);
+-      g_free (g_object_get_data (G_OBJECT (element),
+-				 "gnome-volume-control-name"));
+-      gst_object_unref (GST_OBJECT (element));
++      gst_object_unref (element);
+     }
+     g_list_free (win->elements);
+     win->elements = NULL;
+Index: gstreamer-properties/Makefile.am
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gstreamer-properties/Makefile.am,v
+retrieving revision 1.10
+retrieving revision 1.10.6.1
+diff -u -p -r1.10 -r1.10.6.1
+--- gstreamer-properties/Makefile.am	9 Nov 2004 17:21:53 -0000	1.10
++++ gstreamer-properties/Makefile.am	13 Jan 2006 15:07:53 -0000	1.10.6.1
+@@ -28,7 +28,7 @@ INCLUDES   = \
+ 	-DGSTPROPS_ICONDIR=\""$(iconsdir)"\" \
+ 	-DDATADIR=\""$(datadir)"\" \
+ 	-DGNOMELOCALEDIR="${prefix}/${DATADIRNAME}/locale" \
+-	-DG_LOG_DOMAIN="gstreamer-properties"
++	-DG_LOG_DOMAIN="\"gstreamer-properties\""
+ 
+ CLEANFILES = $(GSTPROPS_CLEANFILES) $(desktop_DATA)
+ EXTRA_DIST = $(icons_DATA) $(glade_DATA) $(Desktop_in_files)
+Index: gstreamer-properties/gstreamer-properties.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gstreamer-properties/gstreamer-properties.c,v
+retrieving revision 1.14
+retrieving revision 1.14.4.1
+diff -u -p -r1.14 -r1.14.4.1
+--- gstreamer-properties/gstreamer-properties.c	8 Jun 2005 09:00:46 -0000	1.14
++++ gstreamer-properties/gstreamer-properties.c	13 Jan 2006 15:07:53 -0000	1.14.4.1
+@@ -3,6 +3,7 @@
+ 
+ /* gstreamer-properties.c
+  * Copyright (C) 2002 Jan Schmidt
++ * Copyright (C) 2005 Tim-Philipp Müller <tim centricular net>
+  *
+  * Written by: Jan Schmidt <thaytan@mad.scientist.com>
+  *
+@@ -29,9 +30,9 @@
+ #include <locale.h>
+ #include <string.h>
+ #include <gnome.h>
+-#include <gst/gconf/gconf.h>
+ #include <glade/glade.h>
+ #include <gtk/gtk.h>
++#include <gconf/gconf-client.h>
+ #include <gst/gst.h>
+ #include "gstreamer-properties-structs.h"
+ #include "pipeline-tests.h"
+@@ -43,303 +44,415 @@ static GtkDialog *main_window;
+ static gchar pipeline_editor_property[] = "gstp-editor";
+ static gchar pipeline_desc_property[] = "gstp-pipe-desc";
+ 
++static gchar *
++gst_properties_gconf_get_full_key (const gchar * key)
++{
++  return g_strdup_printf ("/system/gstreamer/%d.%d/%s",
++      GST_VERSION_MAJOR, GST_VERSION_MINOR, key);
++}
++
++gchar *
++gst_properties_gconf_get_string (const gchar * key)
++{
++  GConfClient *client;
++  GError *error = NULL;
++  gchar *value = NULL;
++  gchar *full_key;
++
++  full_key = gst_properties_gconf_get_full_key (key);
++
++  client = gconf_client_get_default ();
++
++  value = gconf_client_get_string (client, full_key, &error);
++  g_free (full_key);
++
++  if (error) {
++    g_warning ("%s() error: %s", __FUNCTION__, error->message);
++    g_error_free (error);
++    return NULL;
++  }
++
++  return value;
++}
++
++void
++gst_properties_gconf_set_string (const gchar * key, const gchar * value)
++{
++  GConfClient *client;
++  GError *error = NULL;
++  gchar *full_key;
++
++  full_key = gst_properties_gconf_get_full_key (key);
++  client = gconf_client_get_default ();
++
++  gconf_client_set_string (client, full_key, value, &error);
++  g_free (full_key);
++
++  if (error) {
++    g_warning ("%s() error: %s", __FUNCTION__, error->message);
++    g_error_free (error);
++  }
++}
++
+ static void
+ dialog_response (GtkDialog * widget, gint response_id, GladeXML * dialog)
+ {
+-	if (response_id == GTK_RESPONSE_HELP)
+-		gnome_help_display ("gstreamer-properties.xml", NULL, NULL);
+-	else
+-		gtk_main_quit ();
++  if (response_id == GTK_RESPONSE_HELP)
++    gnome_help_display ("gstreamer-properties.xml", NULL, NULL);
++  else
++    gtk_main_quit ();
+ }
+ 
+ static void
+ test_button_clicked (GtkButton * button, gpointer user_data)
+ {
+-	GSTPPipelineEditor* editor = (GSTPPipelineEditor*)(user_data);
+-	GSTPPipelineDescription *pipeline_desc = editor->pipeline_desc + editor->cur_pipeline_index;
+-	if (pipeline_desc->is_custom) {
+-		GtkEntry* entry = editor->entry;
+-		pipeline_desc->pipeline = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
+-	}
+-	
+-	user_test_pipeline(interface_xml, GTK_WINDOW(main_window), pipeline_desc);
+-	
+-	if (pipeline_desc->is_custom) {
+-		g_free(pipeline_desc->pipeline);
+-		pipeline_desc->pipeline = NULL;
+-	}
++  GSTPPipelineEditor *editor = (GSTPPipelineEditor *) (user_data);
++  GSTPPipelineDescription *pipeline_desc =
++      editor->pipeline_desc + editor->cur_pipeline_index;
++  if (pipeline_desc->is_custom) {
++    GtkEntry *entry = editor->entry;
++
++    pipeline_desc->pipeline = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
++  }
++
++  user_test_pipeline (interface_xml, GTK_WINDOW (main_window), pipeline_desc);
++
++  if (pipeline_desc->is_custom) {
++    g_free (pipeline_desc->pipeline);
++    pipeline_desc->pipeline = NULL;
++  }
++}
++
++static void
++update_from_option (GSTPPipelineEditor * editor,
++    GSTPPipelineDescription * pipeline_desc)
++{
++  /* optionmenu changed, update the edit box, 
++   * and the appropriate GConf key */
++  /* FIXME g_return_if_fail(editor); */
++  /* g_return_if_fail(pipeline_desc); */
++
++  editor->cur_pipeline_index = pipeline_desc->index;
++
++  if (pipeline_desc->is_custom == FALSE) {
++    if (pipeline_desc->pipeline)
++      gtk_entry_set_text (editor->entry, pipeline_desc->pipeline);
++    gtk_widget_set_sensitive (GTK_WIDGET (editor->entry), FALSE);
++
++    /* Update GConf */
++    gst_properties_gconf_set_string (editor->gconf_key,
++        pipeline_desc->pipeline);
++  } else {
++    gtk_widget_set_sensitive (GTK_WIDGET (editor->entry), TRUE);
++  }
+ }
+ 
+ static void
+-update_from_option (GSTPPipelineEditor* editor,
+-		    GSTPPipelineDescription* pipeline_desc)
++set_menuitem_by_pipeline (GtkWidget * widget, gpointer data)
+ {
+-	/* optionmenu changed, update the edit box, 
+-	 * and the appropriate GConf key */	
+-	/* FIXME g_return_if_fail(editor); */
+-	/* g_return_if_fail(pipeline_desc); */
+-	
+-	editor->cur_pipeline_index = pipeline_desc->index;
+-	
+-	if (pipeline_desc->is_custom == FALSE)
+-	{
+-		if (pipeline_desc->pipeline)
+-			gtk_entry_set_text (editor->entry, pipeline_desc->pipeline);
+-		gtk_widget_set_sensitive (GTK_WIDGET (editor->entry), FALSE);
+-
+-		/* Update GConf */
+-		gst_gconf_set_string (editor->gconf_key, pipeline_desc->pipeline);
+-	}
+-	else
+-	{
+-		gtk_widget_set_sensitive (GTK_WIDGET (editor->entry), TRUE);
+-	}
++  GSTPPipelineEditor *editor = (GSTPPipelineEditor *) (data);
++
++  if (GTK_IS_MENU_ITEM (widget)) {
++    GtkMenuItem *mi = GTK_MENU_ITEM (widget);
++    GSTPPipelineDescription *pipeline_desc =
++        (GSTPPipelineDescription *) (g_object_get_data (G_OBJECT (mi),
++            pipeline_desc_property));
++    if (pipeline_desc == (editor->pipeline_desc + editor->cur_pipeline_index)) {
++      GtkMenuShell *menu =
++          GTK_MENU_SHELL (gtk_option_menu_get_menu (editor->optionmenu));
++      gtk_option_menu_set_history (editor->optionmenu,
++          g_list_index (menu->children, mi));
++    }
++  }
+ }
+ 
+ static void
+-set_menuitem_by_pipeline (GtkWidget *widget, gpointer data)
++update_from_gconf (GSTPPipelineEditor * editor, const gchar * pipeline_str)
+ {
+-	GSTPPipelineEditor* editor = (GSTPPipelineEditor*)(data);
+-	if (GTK_IS_MENU_ITEM(widget)) {
+-		GtkMenuItem* mi = GTK_MENU_ITEM(widget);
+-		GSTPPipelineDescription* pipeline_desc =
+-			(GSTPPipelineDescription*) (g_object_get_data (G_OBJECT (mi), pipeline_desc_property));
+-		if (pipeline_desc == (editor->pipeline_desc + editor->cur_pipeline_index)) {
+-			GtkMenuShell* menu = GTK_MENU_SHELL(gtk_option_menu_get_menu(editor->optionmenu));
+-			gtk_option_menu_set_history(editor->optionmenu, g_list_index(menu->children, mi));
+-		}
+-	}
+-}
+-
+-static void 
+-update_from_gconf(GSTPPipelineEditor* editor,
+-				  const gchar* pipeline_str)
+-{
+-	/* Iterate over the pipelines in the editor, and locate the one 
+-	   matching this pipeline_str. If none, then use 'Custom' entry */
+-	int i = 0;
+-	gint custom_desc = -1;
+-	
+-	/* g_return_if_fail (editor != NULL);*/
+-	
+-	editor->cur_pipeline_index = -1;
+-	for (i = 0; i < editor->n_pipeline_desc; i++) {
+-		GSTPPipelineDescription *pipeline_desc = editor->pipeline_desc + i;
+-
+-		if (pipeline_desc->is_custom == TRUE) {
+-			custom_desc = i;
+-		}
+-		else if (!strcmp(pipeline_desc->pipeline, pipeline_str)) {
+-			editor->cur_pipeline_index = i;
+-			break;
+-		}
+-	}
+-	
+-	if (editor->cur_pipeline_index < 0) {
+-		editor->cur_pipeline_index = custom_desc;
+-		if (custom_desc >= 0) {
+-			gtk_entry_set_text (editor->entry, pipeline_str);
+-			if (pipeline_str == NULL || *pipeline_str == '\0')
+-				gtk_widget_set_sensitive (GTK_WIDGET(editor->test_button), FALSE);
+-		}
+-	}
+-	
+-	if (editor->cur_pipeline_index >= 0) {
+-		GtkMenu* menu = GTK_MENU(gtk_option_menu_get_menu(editor->optionmenu));
+-		gtk_container_foreach(GTK_CONTAINER(menu), set_menuitem_by_pipeline, editor);
+-    update_from_option (editor, editor->pipeline_desc + editor->cur_pipeline_index);
+-	}
++  /* Iterate over the pipelines in the editor, and locate the one 
++     matching this pipeline_str. If none, then use 'Custom' entry */
++  int i = 0;
++  gint custom_desc = -1;
++
++  /* g_return_if_fail (editor != NULL); */
++
++  editor->cur_pipeline_index = -1;
++  for (i = 0; i < editor->n_pipeline_desc; i++) {
++    GSTPPipelineDescription *pipeline_desc = editor->pipeline_desc + i;
++
++    if (pipeline_desc->is_custom == TRUE) {
++      custom_desc = i;
++    } else if (!strcmp (pipeline_desc->pipeline, pipeline_str)) {
++      editor->cur_pipeline_index = i;
++      break;
++    }
++  }
++
++  if (editor->cur_pipeline_index < 0) {
++    editor->cur_pipeline_index = custom_desc;
++    if (custom_desc >= 0) {
++      gtk_entry_set_text (editor->entry, pipeline_str);
++      if (pipeline_str == NULL || *pipeline_str == '\0')
++        gtk_widget_set_sensitive (GTK_WIDGET (editor->test_button), FALSE);
++    }
++  }
++
++  if (editor->cur_pipeline_index >= 0) {
++    GtkMenu *menu = GTK_MENU (gtk_option_menu_get_menu (editor->optionmenu));
++
++    gtk_container_foreach (GTK_CONTAINER (menu), set_menuitem_by_pipeline,
++        editor);
++    update_from_option (editor,
++        editor->pipeline_desc + editor->cur_pipeline_index);
++  }
+ }
+ 
+ static void
+ pipeline_option_changed (GtkOptionMenu * optionmenu, gpointer user_data)
+ {
+-	GSTPPipelineEditor* editor = (GSTPPipelineEditor*)(user_data);
+-	GtkMenu *menu = NULL;
+-	GtkMenuItem *mi = NULL;
+-	GSTPPipelineDescription *pipeline_desc = NULL;
+-	/* Determine which option changed, retrieve the pipeline desc,
+-	 * and call update_from_option */
+-	menu = GTK_MENU (gtk_option_menu_get_menu (optionmenu));
+-	/*FIXME: g_return_if_fail (menu != NULL); */
+-	mi = GTK_MENU_ITEM (gtk_menu_get_active (menu));
+-	pipeline_desc =
+-		(GSTPPipelineDescription*) (g_object_get_data (G_OBJECT (mi), pipeline_desc_property));
+-	
+-	update_from_option (editor, pipeline_desc);
++  GSTPPipelineEditor *editor = (GSTPPipelineEditor *) (user_data);
++  GtkMenu *menu = NULL;
++  GtkMenuItem *mi = NULL;
++  GSTPPipelineDescription *pipeline_desc = NULL;
++
++  /* Determine which option changed, retrieve the pipeline desc,
++   * and call update_from_option */
++  menu = GTK_MENU (gtk_option_menu_get_menu (optionmenu));
++  /*FIXME: g_return_if_fail (menu != NULL); */
++  mi = GTK_MENU_ITEM (gtk_menu_get_active (menu));
++  pipeline_desc =
++      (GSTPPipelineDescription *) (g_object_get_data (G_OBJECT (mi),
++          pipeline_desc_property));
++
++  update_from_option (editor, pipeline_desc);
+ }
+ 
+ static void
+-entry_changed (GtkEditable *editable, gpointer user_data)
++entry_changed (GtkEditable * editable, gpointer user_data)
+ {
+-	GSTPPipelineEditor* editor = (GSTPPipelineEditor*)(user_data);
+-	const gchar* new_text = gtk_entry_get_text(GTK_ENTRY(editable));
++  GSTPPipelineEditor *editor = (GSTPPipelineEditor *) (user_data);
++  const gchar *new_text = gtk_entry_get_text (GTK_ENTRY (editable));
+ 
+-	if (new_text == NULL || *new_text == '\0') {
+-		/* disable test button */
+-		gtk_widget_set_sensitive (GTK_WIDGET(editor->test_button), FALSE);
+-	} else {
+-		gtk_widget_set_sensitive (GTK_WIDGET(editor->test_button), TRUE);
+-	}
+-	/* Update GConf */
+-	gst_gconf_set_string (editor->gconf_key, new_text);
+-}
+-
+-static GtkOptionMenu *create_pipeline_menu (GladeXML * dialog, GSTPPipelineEditor* editor)
+-{
+-	GtkOptionMenu *option = NULL;
+-	gint i;
+-	GSTPPipelineDescription *pipeline_desc = editor->pipeline_desc;
+-
+-	
+-	option = GTK_OPTION_MENU (WID (editor->optionmenu_name));
+-	if (option)
+-	{
+-		GtkMenu *menu = GTK_MENU (gtk_menu_new ());
+-		GtkMenuItem *mi = NULL;
+-		
+-		for (i = 0; i < editor->n_pipeline_desc; i++)
+-		{
+-			GSTPPipelineDescription *cur_pipeline_desc = &(pipeline_desc[i]);
+-			GstElement *pipeline;
+-			GError     *error = NULL;
+-
+-			if (cur_pipeline_desc->pipeline != NULL) {
+-				pipeline = gst_parse_launch (cur_pipeline_desc->pipeline, &error);
+-				if (pipeline != NULL) {
+-					gst_object_unref (GST_OBJECT (pipeline));
+-				}
+-				if (error != NULL) {
+-					g_error_free (error);
+-					continue;
+-				}
+-			}
+-			
+-			mi = GTK_MENU_ITEM (gtk_menu_item_new_with_label(_(cur_pipeline_desc->name)));
+-			cur_pipeline_desc->index = i;
+-			g_object_set_data (G_OBJECT (mi), pipeline_desc_property,
+-					   (gpointer) (cur_pipeline_desc));
+-			gtk_widget_show (GTK_WIDGET (mi));
+-			gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (mi));
+-		}
++  if (new_text == NULL || *new_text == '\0') {
++    /* disable test button */
++    gtk_widget_set_sensitive (GTK_WIDGET (editor->test_button), FALSE);
++  } else {
++    gtk_widget_set_sensitive (GTK_WIDGET (editor->test_button), TRUE);
++  }
++  /* Update GConf */
++  gst_properties_gconf_set_string (editor->gconf_key, new_text);
++}
+ 
+-		gtk_option_menu_set_menu (option, GTK_WIDGET (menu));
+-	}
++static gboolean
++element_available (const gchar * pipeline)
++{
++  gboolean res = FALSE;
++  gchar *p, *first_space;
++
++  if (pipeline == NULL || *pipeline == '\0')
++    return FALSE;
++
++  p = g_strdup (pipeline);
++
++  g_strstrip (p);
++
++  /* skip the check and pretend all is fine if it's something that does
++   * not look like an element name (e.g. parentheses to signify a bin) */
++  if (!g_ascii_isalpha (*p)) {
++    g_free (p);
++    return TRUE;
++  }
++
++  /* just the element name, no arguments */
++  first_space = strchr (p, ' ');
++  if (first_space != NULL)
++    *first_space = '\0';
++
++  /* check if element is available */
++  res = gst_default_registry_check_feature_version (p, GST_VERSION_MAJOR,
++      GST_VERSION_MINOR, 0);
++
++  g_free (p);
++  return res;
++}
++
++static GtkOptionMenu *
++create_pipeline_menu (GladeXML * dialog, GSTPPipelineEditor * editor)
++{
++  GtkOptionMenu *option = NULL;
++  gint i;
++  GSTPPipelineDescription *pipeline_desc = editor->pipeline_desc;
++
++
++  option = GTK_OPTION_MENU (WID (editor->optionmenu_name));
++  if (option) {
++    GtkMenu *menu = GTK_MENU (gtk_menu_new ());
++    GtkMenuItem *mi = NULL;
++
++    for (i = 0; i < editor->n_pipeline_desc; i++) {
++      if (element_available (pipeline_desc[i].pipeline)) {
++        GstElement *pipeline;
++        GError *error = NULL;
++
++        pipeline = gst_parse_launch (pipeline_desc[i].pipeline, &error);
++        if (pipeline != NULL) {
++          gst_object_unref (pipeline);
++        }
++        if (error != NULL) {
++          g_error_free (error);
++          continue;
++        }
++      } else if (pipeline_desc[i].pipeline != NULL) {
++        /* FIXME: maybe we should show those in the
++         * combo box, but make them insensitive? Or is
++         * that more confusing than helpful for users? */
++        g_message ("Skipping unavailable plugin '%s'",
++            pipeline_desc[i].pipeline);
++        continue;
++      } else {
++        /* This is probably the 'Custom' pipeline */
++      }
++
++      mi = GTK_MENU_ITEM (gtk_menu_item_new_with_label (_(pipeline_desc[i].
++                  name)));
++      pipeline_desc[i].index = i;
++      g_object_set_data (G_OBJECT (mi), pipeline_desc_property,
++          (gpointer) & pipeline_desc[i]);
++      gtk_widget_show (GTK_WIDGET (mi));
++      gtk_menu_shell_append (GTK_MENU_SHELL (menu), GTK_WIDGET (mi));
++    }
++
++    gtk_option_menu_set_menu (option, GTK_WIDGET (menu));
++  }
+ 
+-	return option;
++  return option;
+ }
+ 
+ static void
+-init_pipeline_editor(GladeXML * dialog, GSTPPipelineEditor* editor)
++init_pipeline_editor (GladeXML * dialog, GSTPPipelineEditor * editor)
++{
++  gchar *gconf_init_pipe = NULL;
++
++  /* g_return_if_fail(editor != NULL); */
++
++  editor->optionmenu = create_pipeline_menu (dialog, editor);
++  editor->entry = GTK_ENTRY (WID (editor->entry_name));
++  editor->test_button = GTK_BUTTON (WID (editor->test_button_name));
++
++  /* g_return_if_fail (editor->entry && editor->optionmenu && editor->test_button); */
++  if (!(editor->entry && editor->optionmenu && editor->test_button))
++    return;
++
++  g_object_set_data (G_OBJECT (editor->optionmenu), pipeline_editor_property,
++      (gpointer) (editor));
++  g_signal_connect (G_OBJECT (editor->optionmenu), "changed",
++      (GCallback) pipeline_option_changed, (gpointer) (editor));
++  g_object_set_data (G_OBJECT (editor->entry), pipeline_editor_property,
++      (gpointer) (editor));
++  g_signal_connect (G_OBJECT (editor->entry), "changed",
++      (GCallback) entry_changed, (gpointer) (editor));
++  g_object_set_data (G_OBJECT (editor->test_button), pipeline_editor_property,
++      (gpointer) (editor));
++  g_signal_connect (G_OBJECT (editor->test_button), "clicked",
++      (GCallback) test_button_clicked, (gpointer) (editor));
++
++  gconf_init_pipe = gst_properties_gconf_get_string (editor->gconf_key);
++
++  if (gconf_init_pipe) {
++    update_from_gconf (editor, gconf_init_pipe);
++    g_free (gconf_init_pipe);
++  }
++}
++
++void
++create_dialog (void)
+ {
+-	gchar* gconf_init_pipe = NULL;
+-	
+-	/* g_return_if_fail(editor != NULL); */
+-	
+-	editor->optionmenu = create_pipeline_menu (dialog, editor);
+-	editor->entry = GTK_ENTRY (WID (editor->entry_name));
+-	editor->test_button = GTK_BUTTON (WID (editor->test_button_name));
+-	
+-	/* g_return_if_fail (editor->entry && editor->optionmenu && editor->test_button); */
+-	if (!(editor->entry && editor->optionmenu && editor->test_button))
+-		return;
+-
+-	g_object_set_data (G_OBJECT (editor->optionmenu), pipeline_editor_property, (gpointer) (editor));
+-	g_signal_connect (G_OBJECT (editor->optionmenu), "changed",  (GCallback) pipeline_option_changed, (gpointer) (editor));
+-	g_object_set_data (G_OBJECT (editor->entry), pipeline_editor_property, (gpointer) (editor));
+-	g_signal_connect (G_OBJECT (editor->entry), "changed",  (GCallback) entry_changed, (gpointer) (editor));
+-	g_object_set_data (G_OBJECT (editor->test_button), pipeline_editor_property, (gpointer) (editor));
+-	g_signal_connect (G_OBJECT (editor->test_button), "clicked",  (GCallback) test_button_clicked, (gpointer) (editor));
+-	
+-	gconf_init_pipe = gst_gconf_get_string (editor->gconf_key);
+-	
+-	if (gconf_init_pipe) {
+-		update_from_gconf(editor, gconf_init_pipe);
+-		g_free(gconf_init_pipe);
+-	}
+-}
+-
+-void create_dialog (void)
+-{
+-	int i = 0;
+-	GdkPixbuf* icon = NULL;
+-	
+-	for (i = 0; i < pipeline_editors_count; i++) {
+-		init_pipeline_editor(interface_xml, pipeline_editors + i);
+-	}
+-	
+-	main_window = GTK_DIALOG(WID("gst_properties_dialog"));
+-	if (!main_window) {
+-		/* Fatal error */
+-		gnome_app_error (GNOME_APP (gnome_program_get ()), _("Failure instantiating main window"));
+-		return;
+-	}
+-	
+-	g_signal_connect (G_OBJECT (main_window),
+-			  "response", (GCallback) dialog_response, interface_xml);
+-	icon = gdk_pixbuf_new_from_file(GSTPROPS_ICONDIR"/gstreamer-properties.png", NULL);
+-	if (icon) {
+-		gtk_window_set_icon(GTK_WINDOW(main_window), icon);
+-	}
+-	else {
+-		/* FIXME:warning */
+-		g_print("Error loading main window icon %s", GSTPROPS_ICONDIR "/gstreamer-properties.png\n");
+-	}
+-	gtk_widget_show (GTK_WIDGET (main_window));
++  int i = 0;
++  GdkPixbuf *icon = NULL;
++
++  for (i = 0; i < pipeline_editors_count; i++) {
++    init_pipeline_editor (interface_xml, pipeline_editors + i);
++  }
++
++  main_window = GTK_DIALOG (WID ("gst_properties_dialog"));
++  if (!main_window) {
++    /* Fatal error */
++    gnome_app_error (GNOME_APP (gnome_program_get ()),
++        _("Failure instantiating main window"));
++    return;
++  }
++
++  g_signal_connect (G_OBJECT (main_window),
++      "response", (GCallback) dialog_response, interface_xml);
++  icon =
++      gdk_pixbuf_new_from_file (GSTPROPS_ICONDIR "/gstreamer-properties.png",
++      NULL);
++  if (icon) {
++    gtk_window_set_icon (GTK_WINDOW (main_window), icon);
++  } else {
++    g_warning ("Error loading main window icon %s",
++        GSTPROPS_ICONDIR "/gstreamer-properties.png\n");
++  }
++  gtk_widget_show (GTK_WIDGET (main_window));
+ }
+ 
+ int
+ main (int argc, char **argv)
+ {
+-	/* bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); */
+-	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+-	textdomain (GETTEXT_PACKAGE);
+-
+-	gnome_program_init ("gstreamer-properties", VERSION, LIBGNOMEUI_MODULE,
+-			    argc, argv, GNOME_PARAM_APP_DATADIR, DATADIR, NULL);
+-	gst_init_with_popt_table (&argc, &argv, NULL);
+-
+-	if (!gst_scheduler_factory_get_default_name ()) {
+-		GtkWidget *dialog;
+-
+-		dialog = gtk_message_dialog_new (NULL,
+-						 0,
+-						 GTK_MESSAGE_ERROR,
+-						 GTK_BUTTONS_CLOSE,
+-						 _("Registry is not present or it is corrupted, please update it by running gst-register."));
+-
+-		gtk_dialog_run (GTK_DIALOG (dialog));
+-		gtk_widget_destroy (dialog);
+-
+-		exit (1);
+-	}
+-
+-	/* FIXME: hardcode uninstalled path here */
+-	if (g_file_test("gstreamer-properties.glade", G_FILE_TEST_EXISTS) == TRUE) {
+-		interface_xml = glade_xml_new ("gstreamer-properties.glade", NULL, NULL);
+-	}
+-	else if (g_file_test(GSTPROPS_GLADEDIR "/gstreamer-properties.glade", G_FILE_TEST_EXISTS) == TRUE) {
+-		interface_xml = glade_xml_new (GSTPROPS_GLADEDIR"/gstreamer-properties.glade", NULL, NULL);
+-	}
+-	
+-	if (!interface_xml) {
+-		GtkWidget *dialog;
+-
+-		dialog = gtk_message_dialog_new (NULL,
+-						 0,
+-						 GTK_MESSAGE_ERROR,
+-						 GTK_BUTTONS_CLOSE,
+-						 _("Failed to load glade file; please check your installation."));
+-
+-		gtk_dialog_run (GTK_DIALOG (dialog));
+-		gtk_widget_destroy (dialog);
+-
+-		exit (1);
+-	}
+-	
+-	create_dialog ();
+-	if (main_window)
+-		gtk_main ();
++  /* bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); */
++  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
++  textdomain (GETTEXT_PACKAGE);
++
++/* FIXME: remove when bumping requirements to 2.14 */
++#ifdef GNOME_PARAM_GOPTION_CONTEXT
++  if (1) {
++    GOptionContext *ctx;
++    GOptionGroup *group;
++
++    ctx = g_option_context_new ("gstreamer-properties");
++    g_option_context_add_group (ctx, gst_init_get_option_group ());
++
++    gnome_program_init ("gstreamer-properties", VERSION,
++        LIBGNOMEUI_MODULE, argc, argv,
++        GNOME_PARAM_GOPTION_CONTEXT, ctx,
++        GNOME_PARAM_APP_DATADIR, DATADIR, NULL);
++  }
++#else /* GNOME_PARAM_GOPTION_CONTEXT */
++  gst_init (&argc, &argv);
++
++  gnome_program_init ("gstreamer-properties", VERSION,
++      LIBGNOMEUI_MODULE, argc, argv, GNOME_PARAM_APP_DATADIR, DATADIR, NULL);
++#endif /* GNOME_PARAM_GOPTION_CONTEXT */
++
++  /* FIXME: hardcode uninstalled path here */
++  if (g_file_test ("gstreamer-properties.glade", G_FILE_TEST_EXISTS) == TRUE) {
++    interface_xml = glade_xml_new ("gstreamer-properties.glade", NULL, NULL);
++  } else if (g_file_test (GSTPROPS_GLADEDIR "/gstreamer-properties.glade",
++          G_FILE_TEST_EXISTS) == TRUE) {
++    interface_xml =
++        glade_xml_new (GSTPROPS_GLADEDIR "/gstreamer-properties.glade", NULL,
++        NULL);
++  }
++
++  if (!interface_xml) {
++    GtkWidget *dialog;
++
++    dialog = gtk_message_dialog_new (NULL,
++        0,
++        GTK_MESSAGE_ERROR,
++        GTK_BUTTONS_CLOSE,
++        _("Failed to load glade file; please check your installation."));
++
++    gtk_dialog_run (GTK_DIALOG (dialog));
++    gtk_widget_destroy (dialog);
++
++    exit (1);
++  }
++
++  create_dialog ();
++
++  if (main_window)
++    gtk_main ();
+ 
+-	return 0;
++  return 0;
+ }
+Index: gstreamer-properties/pipeline-constants.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gstreamer-properties/pipeline-constants.c,v
+retrieving revision 1.12
+retrieving revision 1.12.4.1
+diff -u -p -r1.12 -r1.12.4.1
+--- gstreamer-properties/pipeline-constants.c	1 Jul 2005 08:41:09 -0000	1.12
++++ gstreamer-properties/pipeline-constants.c	13 Jan 2006 15:07:53 -0000	1.12.4.1
+@@ -28,10 +28,11 @@
+ #include "gstreamer-properties-structs.h"
+ #include <gtk/gtk.h>
+ #include <bonobo/bonobo-i18n.h>
+- 
++
+ /* Test specified inputs for pipelines */
+ /* static const gchar audiosink_test_pipe[] = "afsrc location=\"" TEST_MEDIA_FILE "\""; FIXME*/
+-static gchar audiosink_test_pipe[] = "sinesrc freq=512";
++static gchar audiosink_test_pipe[] = "audiotestsrc wave=sine freq=512";
++
+ /* ffmpegcolorspace is the ripped colorspace element in gst-plugins */
+ static gchar videosink_test_pipe[] = "videotestsrc";
+ 
+@@ -46,122 +47,140 @@ extern GSTPPipelineDescription audiosrc_
+ extern GSTPPipelineDescription videosrc_pipelines[];
+ 
+ GSTPPipelineDescription audiosink_pipelines[] = {
+-	{PIPE_TYPE_AUDIOSINK, 0,"Autodetect", "autoaudiosink", FALSE,
+-	 TEST_PIPE_SUPPLIED, audiosink_test_pipe, FALSE},
+-	{PIPE_TYPE_AUDIOSINK, 0,"ALSA - Advanced Linux Sound Architecture",
+-	 "alsasink", FALSE, TEST_PIPE_SUPPLIED, audiosink_test_pipe, FALSE},
+-	{PIPE_TYPE_AUDIOSINK, 0,"Artsd - ART Sound Daemon", 
+-	 "artsdsink", FALSE, TEST_PIPE_SUPPLIED, audiosink_test_pipe, FALSE},
+-	{PIPE_TYPE_AUDIOSINK, 0,"ESD - Enlightenment Sound Daemon", 
+-	 "esdsink", FALSE, TEST_PIPE_SUPPLIED, audiosink_test_pipe, FALSE},
+-#if 0 /* Disabled this until it works */
+-	{PIPE_TYPE_AUDIOSINK, 0,"Jack", "jackbin.( jacksink )", FALSE, 
+-	 TEST_PIPE_SUPPLIED, audiosink_test_pipe, FALSE},
++  {PIPE_TYPE_AUDIOSINK, 0, "Autodetect", "autoaudiosink", FALSE,
++      TEST_PIPE_SUPPLIED, audiosink_test_pipe, FALSE},
++  {PIPE_TYPE_AUDIOSINK, 0, "ALSA - Advanced Linux Sound Architecture",
++      "alsasink", FALSE, TEST_PIPE_SUPPLIED, audiosink_test_pipe, FALSE},
++#if 0
++  {PIPE_TYPE_AUDIOSINK, 0,
++        "ALSA - Advanced Linux Sound Architecture (Default Device)",
++      "alsasink", FALSE, TEST_PIPE_SUPPLIED, audiosink_test_pipe, FALSE},
++  {PIPE_TYPE_AUDIOSINK, 0,
++        "ALSA - Advanced Linux Sound Architecture (Sound Card #1 Direct)",
++        "alsasink device=hw:0", FALSE, TEST_PIPE_SUPPLIED,
++      audiosink_test_pipe, FALSE},
++  {PIPE_TYPE_AUDIOSINK, 0,
++        "ALSA - Advanced Linux Sound Architecture (Sound Card #1 DMix)",
++        "alsasink device=dmix:0", FALSE, TEST_PIPE_SUPPLIED,
++      audiosink_test_pipe, FALSE},
+ #endif
+-	{PIPE_TYPE_AUDIOSINK, 0,"OSS - Open Sound System", 
+-	 "osssink", FALSE, TEST_PIPE_SUPPLIED, audiosink_test_pipe, TRUE},
+-	{PIPE_TYPE_AUDIOSINK, 0,"Polypaudio Sound Server", 
+-	 "polypsink", FALSE, TEST_PIPE_SUPPLIED, audiosink_test_pipe, FALSE},
+-	{PIPE_TYPE_AUDIOSINK, 0, N_("Custom"), NULL, TRUE, TEST_PIPE_SUPPLIED,
+-	 audiosink_test_pipe, TRUE}
++  {PIPE_TYPE_AUDIOSINK, 0, "Artsd - ART Sound Daemon",
++      "artsdsink", FALSE, TEST_PIPE_SUPPLIED, audiosink_test_pipe, FALSE},
++  {PIPE_TYPE_AUDIOSINK, 0, "ESD - Enlightenment Sound Daemon",
++      "esdsink", FALSE, TEST_PIPE_SUPPLIED, audiosink_test_pipe, FALSE},
++#if 0                           /* Disabled this until it works */
++  {PIPE_TYPE_AUDIOSINK, 0, "Jack", "jackbin.( jacksink )", FALSE,
++      TEST_PIPE_SUPPLIED, audiosink_test_pipe, FALSE},
++#endif
++  {PIPE_TYPE_AUDIOSINK, 0, "OSS - Open Sound System",
++      "osssink", FALSE, TEST_PIPE_SUPPLIED, audiosink_test_pipe, TRUE},
++  {PIPE_TYPE_AUDIOSINK, 0, "Polypaudio Sound Server",
++      "polypsink", FALSE, TEST_PIPE_SUPPLIED, audiosink_test_pipe, FALSE},
++  {PIPE_TYPE_AUDIOSINK, 0, N_("Custom"), NULL, TRUE, TEST_PIPE_SUPPLIED,
++      audiosink_test_pipe, TRUE}
+ };
+ 
+ GSTPPipelineDescription videosink_pipelines[] = {
+-	{PIPE_TYPE_VIDEOSINK, 0,"Autodetect", "autovideosink", FALSE,
+-	 TEST_PIPE_SUPPLIED, videosink_test_pipe, FALSE},
++  {PIPE_TYPE_VIDEOSINK, 0, "Autodetect", "autovideosink", FALSE,
++      TEST_PIPE_SUPPLIED, videosink_test_pipe, FALSE},
+ #if 0
+   /*
+    * aasink is disabled because it is not a serious alternative.
+    */
+-	{PIPE_TYPE_VIDEOSINK, 0,"Ascii Art - X11", "aasink driver=0", FALSE,
+-	 TEST_PIPE_SUPPLIED, videosink_test_pipe, FALSE},
+-	{PIPE_TYPE_VIDEOSINK, 0,"Ascii Art - console", "aasink driver=1", FALSE,
+-	 TEST_PIPE_SUPPLIED, videosink_test_pipe, FALSE},
++  {PIPE_TYPE_VIDEOSINK, 0, "Ascii Art - X11", "aasink driver=0", FALSE,
++      TEST_PIPE_SUPPLIED, videosink_test_pipe, FALSE},
++  {PIPE_TYPE_VIDEOSINK, 0, "Ascii Art - console", "aasink driver=1", FALSE,
++      TEST_PIPE_SUPPLIED, videosink_test_pipe, FALSE},
+ #endif
+-#if 0 
+- /* Leaving this one disabled, because of a bug in cacasink that
+-  * pops up a window in NULL state
+-  */
+-	{PIPE_TYPE_VIDEOSINK, 0,"Colour Ascii Art", "cacasink", FALSE,
+-	 TEST_PIPE_SUPPLIED, videosink_test_pipe, FALSE},
++#if 0
++  /* Leaving this one disabled, because of a bug in cacasink that
++   * pops up a window in NULL state
++   */
++  {PIPE_TYPE_VIDEOSINK, 0, "Colour Ascii Art", "cacasink", FALSE,
++      TEST_PIPE_SUPPLIED, videosink_test_pipe, FALSE},
+ #endif
+-	{PIPE_TYPE_VIDEOSINK, 0,"SDL - Simple DirectMedia Layer", "sdlvideosink",
+-	 FALSE, TEST_PIPE_SUPPLIED, videosink_test_pipe, FALSE},
+-	{PIPE_TYPE_VIDEOSINK, 0,"XWindows (No Xv)",
+-	 "ximagesink", FALSE, TEST_PIPE_SUPPLIED, videosink_test_pipe, FALSE},
+-	{PIPE_TYPE_VIDEOSINK, 0,"XWindows (X11/XShm/Xv)", "xvimagesink", FALSE,
+-	 TEST_PIPE_SUPPLIED, videosink_test_pipe, FALSE},
+-	{PIPE_TYPE_VIDEOSINK, 0, N_("Custom"), NULL, TRUE, TEST_PIPE_SUPPLIED,
+-	 videosink_test_pipe, TRUE}
++  {PIPE_TYPE_VIDEOSINK, 0, "SDL - Simple DirectMedia Layer", "sdlvideosink",
++      FALSE, TEST_PIPE_SUPPLIED, videosink_test_pipe, FALSE},
++  {PIPE_TYPE_VIDEOSINK, 0, "XWindows (No Xv)",
++      "ximagesink", FALSE, TEST_PIPE_SUPPLIED, videosink_test_pipe, FALSE},
++  {PIPE_TYPE_VIDEOSINK, 0, "XWindows (X11/XShm/Xv)", "xvimagesink", FALSE,
++      TEST_PIPE_SUPPLIED, videosink_test_pipe, FALSE},
++  {PIPE_TYPE_VIDEOSINK, 0, N_("Custom"), NULL, TRUE, TEST_PIPE_SUPPLIED,
++      videosink_test_pipe, TRUE}
+ };
+ 
+ GSTPPipelineDescription audiosrc_pipelines[] = {
+-	{PIPE_TYPE_AUDIOSRC, 0,"ALSA - Advanced Linux Sound Architecture",
+-	 "alsasrc", FALSE, TEST_PIPE_AUDIOSINK, NULL, FALSE},
+-	{PIPE_TYPE_AUDIOSRC, 0,"ESD - Enlightenment Sound Daemon", "esdmon",
+-	 FALSE, TEST_PIPE_AUDIOSINK, NULL, FALSE},
+-#if 0 /* Disabled this until it works */
+-	{PIPE_TYPE_AUDIOSRC, 0,"Jack", "jackbin{ jacksrc }", FALSE, TEST_PIPE_AUDIOSINK,
+-	 NULL, FALSE},
++  {PIPE_TYPE_AUDIOSRC, 0, "ALSA - Advanced Linux Sound Architecture",
++      "alsasrc", FALSE, TEST_PIPE_AUDIOSINK, NULL, FALSE},
++  {PIPE_TYPE_AUDIOSRC, 0, "ESD - Enlightenment Sound Daemon", "esdmon",
++      FALSE, TEST_PIPE_AUDIOSINK, NULL, FALSE},
++#if 0                           /* Disabled this until it works */
++  {PIPE_TYPE_AUDIOSRC, 0, "Jack", "jackbin{ jacksrc }", FALSE,
++        TEST_PIPE_AUDIOSINK,
++      NULL, FALSE},
+ #endif
+-	{PIPE_TYPE_AUDIOSRC, 0,"OSS - Open Sound System", "osssrc", FALSE,
+-	 TEST_PIPE_AUDIOSINK, NULL, FALSE},
+-	{PIPE_TYPE_AUDIOSRC, 0,"Polypaudio Sound Server", "polypsrc", FALSE,
+-	 TEST_PIPE_AUDIOSINK, NULL, FALSE},
+-	{PIPE_TYPE_AUDIOSRC, 0,"Silence", "silence", FALSE, TEST_PIPE_AUDIOSINK,
+-	 NULL, FALSE},
+-	{PIPE_TYPE_AUDIOSRC, 0, N_("Custom"), NULL, TRUE, TEST_PIPE_AUDIOSINK, NULL,
+-	 TRUE}
++  {PIPE_TYPE_AUDIOSRC, 0, "OSS - Open Sound System", "osssrc", FALSE,
++      TEST_PIPE_AUDIOSINK, NULL, FALSE},
++  {PIPE_TYPE_AUDIOSRC, 0, "Polypaudio Sound Server", "polypsrc", FALSE,
++      TEST_PIPE_AUDIOSINK, NULL, FALSE},
++  /* Note: using triangle instead of sine for test sound so we
++   * can test the vorbis encoder as well (otherwise it'd compress too well) */
++  {PIPE_TYPE_AUDIOSRC, 0, "Test Sound", "audiotestsrc wave=triangle is-live=true", FALSE,
++      TEST_PIPE_AUDIOSINK, NULL, FALSE},
++  {PIPE_TYPE_AUDIOSRC, 0, "Silence", "audiotestsrc wave=silence is-live=true", FALSE,
++      TEST_PIPE_AUDIOSINK, NULL, FALSE},
++  {PIPE_TYPE_AUDIOSRC, 0, N_("Custom"), NULL, TRUE, TEST_PIPE_AUDIOSINK, NULL,
++      TRUE}
+ };
+ 
+ GSTPPipelineDescription videosrc_pipelines[] = {
+-	{PIPE_TYPE_VIDEOSRC, 0,"MJPEG (e.g. Zoran v4l device)", "v4lmjpegsrc", FALSE,
+-	 TEST_PIPE_VIDEOSINK, NULL, FALSE},
+-	{PIPE_TYPE_VIDEOSRC, 0,"QCAM", "qcamsrc", FALSE, TEST_PIPE_VIDEOSINK,
+-	 NULL, FALSE},
+-	{PIPE_TYPE_VIDEOSRC, 0,"Test Input", "videotestsrc", FALSE,
+-	 TEST_PIPE_VIDEOSINK, NULL, FALSE},
+-	{PIPE_TYPE_VIDEOSRC, 0,"Video for Linux (v4l)", "v4lsrc", FALSE,
+-	 TEST_PIPE_VIDEOSINK, NULL, FALSE},
+-	{PIPE_TYPE_VIDEOSRC, 0,"Video for Linux 2 (v4l2)", "v4l2src", FALSE,
+-	 TEST_PIPE_VIDEOSINK, NULL, FALSE},
+-	{PIPE_TYPE_VIDEOSRC, 0, N_("Custom"), NULL, TRUE, TEST_PIPE_VIDEOSINK, NULL,
+-	 TRUE}
++  {PIPE_TYPE_VIDEOSRC, 0, "MJPEG (e.g. Zoran v4l device)", "v4lmjpegsrc", FALSE,
++      TEST_PIPE_VIDEOSINK, NULL, FALSE},
++  {PIPE_TYPE_VIDEOSRC, 0, "QCAM", "qcamsrc", FALSE, TEST_PIPE_VIDEOSINK,
++      NULL, FALSE},
++  {PIPE_TYPE_VIDEOSRC, 0, "Test Input", "videotestsrc is-live=true", FALSE,
++      TEST_PIPE_VIDEOSINK, NULL, FALSE},
++  {PIPE_TYPE_VIDEOSRC, 0, "Video for Linux (v4l)", "v4lsrc", FALSE,
++      TEST_PIPE_VIDEOSINK, NULL, FALSE},
++  {PIPE_TYPE_VIDEOSRC, 0, "Video for Linux 2 (v4l2)", "v4l2src", FALSE,
++      TEST_PIPE_VIDEOSINK, NULL, FALSE},
++  {PIPE_TYPE_VIDEOSRC, 0, N_("Custom"), NULL, TRUE, TEST_PIPE_VIDEOSINK, NULL,
++      TRUE}
+ };
+ 
+ GSTPPipelineEditor pipeline_editors[] = {
+-	/* audiosink pipelines */
+-	{
+-	 G_N_ELEMENTS(audiosink_pipelines),
+-	 (GSTPPipelineDescription *)(audiosink_pipelines), 0,
+-	 GSTPROPS_KEY_DEFAULT_AUDIOSINK,
+-	 "audiosink_optionmenu", "audiosink_pipeline_entry",
+-	 "audiosink_test_button",
+-	 NULL, NULL, NULL},
+-	/* videosink pipelines */
+-	{
+-	 G_N_ELEMENTS(videosink_pipelines),
+-	 (GSTPPipelineDescription *)(videosink_pipelines), 0,
+-	 GSTPROPS_KEY_DEFAULT_VIDEOSINK,
+-	 "videosink_optionmenu", "videosink_pipeline_entry",
+-	 "videosink_test_button",
+-	 NULL, NULL, NULL},
+-	/* videosrc pipelines */
+-	{
+-	 G_N_ELEMENTS(videosrc_pipelines),
+-	 (GSTPPipelineDescription *)(videosrc_pipelines), 0,
+-	 GSTPROPS_KEY_DEFAULT_VIDEOSRC,
+-	 "videosrc_optionmenu", "videosrc_pipeline_entry",
+-	 "videosrc_test_button",
+-	 NULL, NULL, NULL},
+-	/* audiosrc pipelines */
+-	{
+-	 G_N_ELEMENTS(audiosrc_pipelines),
+-	 (GSTPPipelineDescription *)(audiosrc_pipelines), 0, 
+-	 GSTPROPS_KEY_DEFAULT_AUDIOSRC,
+-	 "audiosrc_optionmenu", "audiosrc_pipeline_entry",
+-	 "audiosrc_test_button",
+-	 NULL, NULL, NULL}
++  /* audiosink pipelines */
++  {
++        G_N_ELEMENTS (audiosink_pipelines),
++        (GSTPPipelineDescription *) (audiosink_pipelines), 0,
++        GSTPROPS_KEY_DEFAULT_AUDIOSINK,
++        "audiosink_optionmenu", "audiosink_pipeline_entry",
++        "audiosink_test_button",
++      NULL, NULL, NULL},
++  /* videosink pipelines */
++  {
++        G_N_ELEMENTS (videosink_pipelines),
++        (GSTPPipelineDescription *) (videosink_pipelines), 0,
++        GSTPROPS_KEY_DEFAULT_VIDEOSINK,
++        "videosink_optionmenu", "videosink_pipeline_entry",
++        "videosink_test_button",
++      NULL, NULL, NULL},
++  /* videosrc pipelines */
++  {
++        G_N_ELEMENTS (videosrc_pipelines),
++        (GSTPPipelineDescription *) (videosrc_pipelines), 0,
++        GSTPROPS_KEY_DEFAULT_VIDEOSRC,
++        "videosrc_optionmenu", "videosrc_pipeline_entry",
++        "videosrc_test_button",
++      NULL, NULL, NULL},
++  /* audiosrc pipelines */
++  {
++        G_N_ELEMENTS (audiosrc_pipelines),
++        (GSTPPipelineDescription *) (audiosrc_pipelines), 0,
++        GSTPROPS_KEY_DEFAULT_AUDIOSRC,
++        "audiosrc_optionmenu", "audiosrc_pipeline_entry",
++        "audiosrc_test_button",
++      NULL, NULL, NULL}
+ };
+ 
+-gint pipeline_editors_count = G_N_ELEMENTS(pipeline_editors);
++gint pipeline_editors_count = G_N_ELEMENTS (pipeline_editors);
+Index: gstreamer-properties/pipeline-tests.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gstreamer-properties/pipeline-tests.c,v
+retrieving revision 1.5
+retrieving revision 1.5.6.1
+diff -u -p -r1.5 -r1.5.6.1
+--- gstreamer-properties/pipeline-tests.c	1 Nov 2004 08:14:39 -0000	1.5
++++ gstreamer-properties/pipeline-tests.c	13 Jan 2006 15:07:53 -0000	1.5.6.1
+@@ -3,6 +3,7 @@
+ 
+ /* pipeline-tests.c
+  * Copyright (C) 2002 Jan Schmidt
++ * Copyright (C) 2005 Tim-Philipp Müller <tim centricular net>
+  *
+  * Written by: Jan Schmidt <thaytan@mad.scientist.com>
+  *
+@@ -31,169 +32,204 @@
+ #include <glade/glade.h>
+ #include <gtk/gtk.h>
+ #include <gst/gst.h>
+-#include <gst/gconf/gconf.h>
+ 
+ #include "pipeline-tests.h"
+ #define WID(s) glade_xml_get_widget (interface_xml, s)
+ static gint timeout_tag;
+ 
+ static GstElement *gst_test_pipeline;
+-static GstClock *s_clock;
+ 
+-static void pipeline_error_dlg(GtkWindow * parent,
+-                GSTPPipelineDescription * pipeline_desc);
++static void pipeline_error_dlg (GtkWindow * parent,
++    GSTPPipelineDescription * pipeline_desc, const gchar * error_message);
++
+ /* User responded in the dialog */
+ static void
+-user_test_pipeline_response(GtkDialog * widget, gint response_id,
+-			    GladeXML * dialog)
++user_test_pipeline_response (GtkDialog * widget, gint response_id,
++    GladeXML * dialog)
+ {
+   /* Close the window causing the test to end */
+-  gtk_widget_hide(GTK_WIDGET(widget));
++  gtk_widget_hide (GTK_WIDGET (widget));
+ }
+ 
+ /* Timer timeout has been occurred */
+-static gint user_test_pipeline_timeout( gpointer data )
++static gint
++user_test_pipeline_timeout (gpointer data)
+ {
+-  gtk_progress_bar_pulse(GTK_PROGRESS_BAR(data));
++  gtk_progress_bar_pulse (GTK_PROGRESS_BAR (data));
+   return TRUE;
+ }
+ 
+ /* Build the pipeline */
+ static gboolean
+-build_test_pipeline(GSTPPipelineDescription * pipeline_desc)
++build_test_pipeline (GSTPPipelineDescription * pipeline_desc, GError ** p_err)
+ {
++  const gchar *in_between = NULL;
+   gboolean return_val = FALSE;
+-  GError *error = NULL;
+-  gchar* test_pipeline_str = NULL;
+-  gchar* full_pipeline_str = NULL;
+-  gchar *in_between = NULL;
++  gchar *test_pipeline_str = NULL;
++  gchar *full_pipeline_str = NULL;
++
++  g_assert (p_err != NULL);
+ 
+   switch (pipeline_desc->test_type) {
+     case TEST_PIPE_AUDIOSINK:
+-      test_pipeline_str = gst_gconf_get_string ("default/audiosink");
++      test_pipeline_str = gst_properties_gconf_get_string ("default/audiosink");
+       break;
+     case TEST_PIPE_VIDEOSINK:
+-      test_pipeline_str = gst_gconf_get_string ("default/videosink");
++      test_pipeline_str = gst_properties_gconf_get_string ("default/videosink");
+       break;
+     case TEST_PIPE_SUPPLIED:
+-      test_pipeline_str = pipeline_desc->test_pipe;
++      test_pipeline_str = g_strdup (pipeline_desc->test_pipe);
+       break;
+   }
+-  if (pipeline_desc->type == PIPE_TYPE_AUDIOSINK ||
+-      pipeline_desc->type == PIPE_TYPE_AUDIOSRC) {
+-    in_between = "audioconvert ! audioscale";
+-  } else {
+-    in_between = "ffmpegcolorspace";
++
++  switch (pipeline_desc->type) {
++    case PIPE_TYPE_AUDIOSINK:
++    case PIPE_TYPE_AUDIOSRC:
++      in_between = "audioconvert ! audioresample";
++      break;
++    default:
++      in_between = "ffmpegcolorspace";
++      break;
+   }
++
+   switch (pipeline_desc->type) {
+     case PIPE_TYPE_AUDIOSINK:
+     case PIPE_TYPE_VIDEOSINK:
+-      full_pipeline_str = g_strdup_printf("{ %s ! %s ! %s }",
++      full_pipeline_str = g_strdup_printf ("%s ! %s ! %s",
+           test_pipeline_str, in_between, pipeline_desc->pipeline);
+       break;
+     case PIPE_TYPE_AUDIOSRC:
+     case PIPE_TYPE_VIDEOSRC:
+-      full_pipeline_str = g_strdup_printf("{ %s ! %s ! %s }",
++      full_pipeline_str = g_strdup_printf ("%s ! %s ! %s",
+           pipeline_desc->pipeline, in_between, test_pipeline_str);
+       break;
+   }
++
+   if (full_pipeline_str) {
+-    gst_test_pipeline = (GstElement *)gst_parse_launch(full_pipeline_str, &error);
+-    if (!error) {
++    gst_test_pipeline = gst_parse_launch (full_pipeline_str, p_err);
++
++    if (*p_err == NULL && gst_test_pipeline != NULL)
+       return_val = TRUE;
+-    }
+-    else {
+-      /* FIXME display the error? */
+-      g_error_free(error);
+-    }
+- 
+-    g_free(full_pipeline_str);
+   }
++
++done:
++  g_free (test_pipeline_str);
++  g_free (full_pipeline_str);
++
+   return return_val;
+ }
+ 
+ static void
+-pipeline_error_dlg(GtkWindow * parent,
+-		   GSTPPipelineDescription * pipeline_desc)
++pipeline_error_dlg (GtkWindow * parent,
++    GSTPPipelineDescription * pipeline_desc, const gchar * error_message)
+ {
+-  gchar *errstr = g_strdup_printf( _("Failed to construct test pipeline for '%s'"),
+-		  pipeline_desc->name);
+-    if (parent == NULL) {
+-	    g_print(errstr);
+-    }
+-    else {
+-      GtkDialog *dialog = GTK_DIALOG(gtk_message_dialog_new(parent,
+-							  GTK_DIALOG_DESTROY_WITH_PARENT,
+-							  GTK_MESSAGE_ERROR,
+-							  GTK_BUTTONS_CLOSE,
+-							  errstr));
+-      gtk_dialog_run(GTK_DIALOG(dialog));
+-      gtk_widget_destroy(GTK_WIDGET(dialog));
+-    }
+-    g_free(errstr);
++  gchar *errstr;
++
++  if (error_message) {
++    errstr = g_strdup_printf ("%s: %s", pipeline_desc->name, error_message);
++  } else {
++    errstr = g_strdup_printf (_("Failed to construct test pipeline for '%s'"),
++        pipeline_desc->name);
++  }
++
++  if (parent == NULL) {
++    g_printerr ("%s", errstr);
++  } else {
++    GtkWidget *dialog;
++
++    dialog = gtk_message_dialog_new (parent,
++        GTK_DIALOG_DESTROY_WITH_PARENT,
++        GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", errstr);
++
++    gtk_dialog_run (GTK_DIALOG (dialog));
++    gtk_widget_destroy (dialog);
++  }
++
++  g_free (errstr);
+ }
+ 
+-/* Construct and iterate the pipeline. Use the indicated parent
+-   for any user interaction window.
+-*/
++/* Construct and run the pipeline. Use the indicated parent
++ * for any user interaction window.
++ */
+ void
+-user_test_pipeline(GladeXML * interface_xml,
+-		   GtkWindow * parent,
+-		   GSTPPipelineDescription * pipeline_desc)
++user_test_pipeline (GladeXML * interface_xml,
++    GtkWindow * parent, GSTPPipelineDescription * pipeline_desc)
+ {
++  GstStateChangeReturn ret;
+   GtkDialog *dialog = NULL;
++  GstMessage *msg;
++  GError *err = NULL;
++  GstBus *bus;
++
+   gst_test_pipeline = NULL;
+-  s_clock = NULL;
+ 
+   /* Build the pipeline */
+-  if (!build_test_pipeline(pipeline_desc)) {
++  if (!build_test_pipeline (pipeline_desc, &err)) {
+     /* Show the error pipeline */
+-    pipeline_error_dlg(parent, pipeline_desc);
++    pipeline_error_dlg (parent, pipeline_desc, (err) ? err->message : NULL);
++    if (err)
++      g_error_free (err);
+     return;
+   }
+ 
+   /* Setup the 'click ok when done' dialog */
+   if (parent) {
+-    dialog = GTK_DIALOG(WID("test_pipeline"));
++    dialog = GTK_DIALOG (WID ("test_pipeline"));
+     /* g_return_if_fail(dialog != NULL); */
+-    gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+-    gtk_window_set_transient_for(GTK_WINDOW(dialog), parent);
+-    g_signal_connect(G_OBJECT(dialog), "response",
+-         (GCallback) user_test_pipeline_response,
+-         interface_xml);
+-  }
+-
+-  /* Start the pipeline */
+-  if (gst_element_set_state(gst_test_pipeline, GST_STATE_PLAYING) !=
+-    GST_STATE_SUCCESS) {
+-    pipeline_error_dlg(parent, pipeline_desc);
+-    return;
++    gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
++    gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
++    g_signal_connect (G_OBJECT (dialog), "response",
++        (GCallback) user_test_pipeline_response, interface_xml);
++  }
++
++  /* Start the pipeline and wait for max. 3 seconds for it to start up */
++  gst_element_set_state (gst_test_pipeline, GST_STATE_PLAYING);
++  ret = gst_element_get_state (gst_test_pipeline, NULL, NULL, 3 * GST_SECOND);
++
++  /* Check if any error messages were posted on the bus */
++  bus = gst_element_get_bus (gst_test_pipeline);
++  msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0);
++  gst_object_unref (bus);
++
++  if (msg != NULL) {
++    gchar *dbg = NULL;
++
++    gst_message_parse_error (msg, &err, &dbg);
++    gst_message_unref (msg);
++
++    g_message ("Error running pipeline '%s': %s [%s]", pipeline_desc,
++        err->message, (dbg) ? dbg : "no additional debugging details");
++    pipeline_error_dlg (parent, pipeline_desc, err->message);
++    g_error_free (err);
++    g_free (dbg);
++  } else if (ret != GST_STATE_CHANGE_SUCCESS) {
++    pipeline_error_dlg (parent, pipeline_desc, NULL);
++  } else {
++    /* Show the dialog */
++    if (dialog) {
++      gtk_window_present (GTK_WINDOW (dialog));
++      timeout_tag =
++          gtk_timeout_add (50, user_test_pipeline_timeout,
++          WID ("test_pipeline_progress"));
++      gtk_dialog_run (GTK_DIALOG (dialog));
++      gtk_timeout_remove (timeout_tag);
++      gtk_widget_hide (GTK_WIDGET (dialog));
++    } else {
++      gint secs;
++
++      /* A bit hacky: No parent dialog, run in limited test mode */
++      for (secs = 0; secs < 5; ++secs) {
++        g_print (".");
++        g_usleep (G_USEC_PER_SEC);      /* 1 second */
++      }
++    }
+   }
+ 
+-  s_clock = gst_bin_get_clock(GST_BIN(gst_test_pipeline));
+-  /* Show the dialog */
+-  if (dialog) {
+-    gtk_window_present(GTK_WINDOW(dialog));
+-    timeout_tag = gtk_timeout_add(50, user_test_pipeline_timeout, WID("test_pipeline_progress"));    
+-    gtk_dialog_run(GTK_DIALOG(dialog));
+-    gtk_timeout_remove( timeout_tag );
+-    gtk_widget_hide(GTK_WIDGET(dialog));
+-  }
+-  else {
+-    gboolean busy;
+-    gint secs = 0, max_secs = 5; /* A bit hacky: No parent dialog, run in limited test mode */
+-    do {
+-      secs++;
+-      g_print(".");
+-      g_usleep(1000000); // 1 sec
+-      busy = (secs < max_secs);
+-    } while (busy);
+-  }
++done:
+ 
+   if (gst_test_pipeline) {
+-    gst_element_set_state(gst_test_pipeline, GST_STATE_NULL);
+-    /* Free up the pipeline */
+-    gst_object_unref(GST_OBJECT(gst_test_pipeline));
++    gst_element_set_state (gst_test_pipeline, GST_STATE_NULL);
++    gst_object_unref (gst_test_pipeline);
+     gst_test_pipeline = NULL;
+   }
+ }
+Index: gstreamer-properties/pipeline-tests.h
+===================================================================
+RCS file: /cvs/gnome/gnome-media/gstreamer-properties/pipeline-tests.h,v
+retrieving revision 1.1
+retrieving revision 1.1.14.1
+diff -u -p -r1.1 -r1.1.14.1
+--- gstreamer-properties/pipeline-tests.h	1 Dec 2002 03:32:13 -0000	1.1
++++ gstreamer-properties/pipeline-tests.h	13 Jan 2006 15:07:53 -0000	1.1.14.1
+@@ -31,5 +31,10 @@
+ void user_test_pipeline(GladeXML *interface_xml,
+ 		    GtkWindow *parent,
+ 		    GSTPPipelineDescription *pipeline_desc);
++
++void gst_properties_gconf_set_string (const gchar * key, const gchar * value);
++
++gchar *gst_properties_gconf_get_string (const gchar * key);
++
+ 			
+ #endif	
+Index: po/POTFILES.in
+===================================================================
+RCS file: /cvs/gnome/gnome-media/po/POTFILES.in,v
+retrieving revision 1.62
+retrieving revision 1.62.4.1
+diff -u -p -r1.62 -r1.62.4.1
+--- po/POTFILES.in	8 Jun 2005 14:42:29 -0000	1.62
++++ po/POTFILES.in	15 Jan 2006 20:12:54 -0000	1.62.4.1
+@@ -15,7 +15,7 @@ gnome-cd/eggtrayicon.c
+ gnome-cd/gnome-cd.c
+ gnome-cd/gnome-cd.desktop.in
+ gnome-cd/gnome-cd.schemas.in.in
+-gnome-cd/gst-cdparanoia-cdrom.c
++gnome-cd/gst-cdrom.c
+ gnome-cd/preferences.c
+ grecord/gnome-sound-recorder.desktop.in
+ grecord/gnome-sound-recorder.schemas.in.in
+Index: profiles/audio-profile-choose.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/profiles/audio-profile-choose.c,v
+retrieving revision 1.11
+retrieving revision 1.11.2.1
+diff -u -p -r1.11 -r1.11.2.1
+--- profiles/audio-profile-choose.c	13 Jun 2005 09:38:43 -0000	1.11
++++ profiles/audio-profile-choose.c	13 Jan 2006 15:07:53 -0000	1.11.2.1
+@@ -28,6 +28,8 @@
+ #include "audio-profile.h"
+ #include <gtk/gtk.h>
+ #include <glade/glade-xml.h>
++#include <libgnomevfs/gnome-vfs-mime-handlers.h>
++#include <libgnomevfs/gnome-vfs-mime.h>
+ 
+ enum
+ {
+Index: profiles/audio-profiles-edit.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/profiles/audio-profiles-edit.c,v
+retrieving revision 1.9
+retrieving revision 1.9.2.3
+diff -u -p -r1.9 -r1.9.2.3
+--- profiles/audio-profiles-edit.c	24 Jul 2005 08:55:30 -0000	1.9
++++ profiles/audio-profiles-edit.c	14 Jan 2006 20:25:09 -0000	1.9.2.3
+@@ -125,6 +125,35 @@ gm_audio_profile_manage_register_stock (
+ }
+ 
+ /* widget callbacks */
++
++static void
++count_selected_profiles_func (GtkTreeModel      *model,
++                              GtkTreePath       *path,
++                              GtkTreeIter       *iter,
++                              gpointer           data)
++{
++  int *count = data;
++
++  *count += 1;
++}
++
++static void
++selection_changed_callback (GtkTreeSelection *selection,
++                            GMAudioProfilesEditPrivate *priv)
++{
++  int count;
++
++  count = 0;
++  gtk_tree_selection_selected_foreach (selection,
++                                       count_selected_profiles_func,
++                                       &count);
++
++  gtk_widget_set_sensitive (priv->edit_button,
++                            count == 1);
++  gtk_widget_set_sensitive (priv->delete_button,
++                            count > 0);
++}
++
+ static void
+ profile_activated_callback (GtkTreeView       *tree_view,
+                             GtkTreePath       *path,
+@@ -147,12 +176,15 @@ profile_activated_callback (GtkTreeView 
+                       COLUMN_PROFILE_OBJECT,
+                       &profile,
+                       -1);
+-  if (profile)
+-  /* FIXME: is this the right function name ? */
+-  edit_dialog = gm_audio_profile_edit_new ((GConfClient *) profile, gm_audio_profile_get_id (profile));
+-  g_return_if_fail (edit_dialog != NULL);
+-  gtk_widget_show_all (GTK_WIDGET (edit_dialog));
+-  gtk_dialog_run (GTK_DIALOG (edit_dialog));
++  if (profile) {
++    /* FIXME: is this the right function name ? */
++    edit_dialog = gm_audio_profile_edit_new ((GConfClient *) profile, gm_audio_profile_get_id (profile));
++    g_return_if_fail (edit_dialog != NULL);
++    gtk_widget_show_all (GTK_WIDGET (edit_dialog));
++    gtk_dialog_run (GTK_DIALOG (edit_dialog));
++  } else {
++    g_warning ("Could not retrieve profile");
++  }
+ }
+ 
+ static void
+@@ -603,7 +635,7 @@ gm_audio_profiles_edit_init (GMAudioProf
+                                  NULL);
+   */
+                                  // FIXME: GTK_DIALOG_DESTROY_WITH_PARENT,
+-  gtk_window_set_title (GTK_WINDOW (dialog), _("Edit GMAudio Profiles"));
++  gtk_window_set_title (GTK_WINDOW (dialog), _("Edit GNOME Audio Profiles"));
+   gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+                                  GTK_STOCK_HELP,
+                                  GTK_RESPONSE_HELP,
+@@ -717,6 +749,7 @@ gm_audio_profiles_edit_init (GMAudioProf
+                      button, FALSE, FALSE, 0);
+   g_signal_connect (G_OBJECT (button), "clicked",
+                     G_CALLBACK (edit_button_clicked), dialog);
++  gtk_widget_set_sensitive (button, FALSE);
+   dialog->priv->edit_button = button;
+ /*
+   terminal_util_set_atk_name_description (app->manage_profiles_edit_button, NULL,
+@@ -729,6 +762,7 @@ gm_audio_profiles_edit_init (GMAudioProf
+                       button, FALSE, FALSE, 0);
+   g_signal_connect (G_OBJECT (button), "clicked",
+                     G_CALLBACK (delete_button_clicked), dialog);
++  gtk_widget_set_sensitive (button, FALSE);
+   dialog->priv->delete_button = button;
+ /*
+   terminal_util_set_atk_name_description (app->manage_profiles_delete_button, NULL,
+@@ -747,15 +781,15 @@ gm_audio_profiles_edit_init (GMAudioProf
+                                MIN (req.height + 190, 400));
+ 
+   gtk_widget_grab_focus (dialog->priv->manage_profiles_list);
+-  g_object_unref (G_OBJECT (size_group));       /* Monitor selection for sensitivity */
++  g_object_unref (G_OBJECT (size_group));
++
++  /* Monitor selection for sensitivity */
+   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->manage_profiles_list));
+-  /* FIXME: callback for changed
+-  selection_changed_callback (selection, app);
++
++  selection_changed_callback (selection, dialog->priv);
+   g_signal_connect (G_OBJECT (selection), "changed",
+                     G_CALLBACK (selection_changed_callback),
+-                    app);
+-  */
+-
++                    dialog->priv);
+ }
+ 
+ static void
+Index: profiles/gmp-conf.h
+===================================================================
+RCS file: /cvs/gnome/gnome-media/profiles/gmp-conf.h,v
+retrieving revision 1.1
+retrieving revision 1.1.8.1
+diff -u -p -r1.1 -r1.1.8.1
+--- profiles/gmp-conf.h	12 Dec 2003 18:28:38 -0000	1.1
++++ profiles/gmp-conf.h	16 Jan 2006 17:48:46 -0000	1.1.8.1
+@@ -20,7 +20,7 @@
+  */
+ 
+ /* #define DEBUG */
+-#define CONF_PREFIX "/system/gstreamer/audio"
+-#define CONF_GLOBAL_PREFIX CONF_PREFIX"/global"
+-#define CONF_PROFILES_PREFIX CONF_PREFIX"/profiles"
++#define CONF_PREFIX "/system/gstreamer/" GST_MAJORMINOR_QUOTED "/audio"
++#define CONF_GLOBAL_PREFIX CONF_PREFIX "/global"
++#define CONF_PROFILES_PREFIX CONF_PREFIX "/profiles"
+ 
+Index: profiles/gnome-audio-profiles-test.c
+===================================================================
+RCS file: /cvs/gnome/gnome-media/profiles/gnome-audio-profiles-test.c,v
+retrieving revision 1.2
+retrieving revision 1.2.6.1
+diff -u -p -r1.2 -r1.2.6.1
+--- profiles/gnome-audio-profiles-test.c	29 Aug 2004 20:25:43 -0000	1.2
++++ profiles/gnome-audio-profiles-test.c	13 Jan 2006 15:07:53 -0000	1.2.6.1
+@@ -5,28 +5,29 @@
+ #include <libgnomeui/libgnomeui.h>
+ #include <profiles/gnome-media-profiles.h>
+ 
+-static gboolean
+-edit_cb (GtkButton *button, GtkWindow *window)
++static void
++edit_clicked_cb (GtkButton *button, GtkWindow *window)
+ {
+   GtkWidget *edit_dialog = NULL;
+   edit_dialog = gm_audio_profiles_edit_new (gconf_client_get_default (), window);
+   g_assert (edit_dialog != NULL);
+   gtk_widget_show_all (GTK_WIDGET (edit_dialog));
+-
+-  return FALSE;
+ }
+ 
+-static gboolean
+-test_cb (GtkButton *button, GtkWidget *combo)
++static void
++test_clicked_cb (GtkButton *button, GtkWidget *combo)
+ {
++  GstStateChangeReturn ret;
+   gchar *partialpipe = NULL;
+   gchar *extension = NULL;
+   gchar *pipeline_desc;
+   GError *error = NULL;
+-  int i;
+-  GstElement *pipeline;
+   GMAudioProfile *profile;
++  GstElement *pipeline = NULL;
++  GstMessage *msg = NULL;
++  GstBus *bus = NULL;
+ 
++  gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
+ 
+   profile = gm_audio_profile_choose_get_active (combo);
+   extension = g_strdup (gm_audio_profile_get_extension (profile));
+@@ -36,28 +37,84 @@ test_cb (GtkButton *button, GtkWidget *c
+            gm_audio_profile_get_name (profile),
+            gm_audio_profile_get_pipeline (profile));
+ 
+-  pipeline_desc = g_strdup_printf ("sinesrc ! audioconvert ! %s ! filesink location=test.%s",
++  pipeline_desc = g_strdup_printf ("audiotestsrc wave=sine num-buffers=4096 "
++                                   " ! audioconvert "
++                                   " ! %s "
++                                   " ! filesink location=test.%s",
+                                    partialpipe, extension);
++
+   g_print ("Going to run pipeline %s\n", pipeline_desc);
+ 
+   pipeline = gst_parse_launch (pipeline_desc, &error);
+   if (error)
+   {
+-    g_print ("Error parsing pipeline: %s\n", error->message);
+-    g_error_free (error);
+-    return FALSE;
++    g_warning ("Error parsing pipeline: %s", error->message);
++    goto done;
+   }
+ 
++  bus = gst_element_get_bus (pipeline);
++
+   gst_element_set_state (pipeline, GST_STATE_PLAYING);
+-  g_print ("Writing test sound to test.%s\n", extension);
+-  for (i = 0; i < 100; ++i)
+-    gst_bin_iterate (GST_BIN (pipeline));
+-  gst_element_set_state (pipeline, GST_STATE_NULL);
+-  g_free (pipeline);
+-  g_free (extension);
++
++  /* wait for state change to complete or to have failed */
++  ret = gst_element_get_state (pipeline, NULL, NULL, -1);
++  if (ret == GST_STATE_CHANGE_FAILURE) {
++    /* check if an error was posted on the bus */
++    if ((msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0))) {
++      gst_message_parse_error (msg, &error, NULL);
++    }
++	                  
++    g_warning ("Error starting pipeline: %s",
++        (error) ? error->message : "UNKNOWN ERROR");
++
++    goto done;
++  }  
++
++  g_print ("Writing test sound to test.%s ...\n", extension);
++
++  /* wait for it finish (error or EOS), but no more than 30 secs */
++  msg = gst_bus_poll (bus, GST_MESSAGE_ERROR | GST_MESSAGE_EOS, 30*GST_SECOND);
++
++  if (msg) {
++    switch (GST_MESSAGE_TYPE (msg)) {
++      case GST_MESSAGE_EOS:
++        g_print ("Test finished successfully.\n");
++        break;
++      case GST_MESSAGE_ERROR:
++        gst_message_parse_error (msg, &error, NULL);
++        g_warning ("Error starting pipeline: %s",
++            (error) ? error->message : "UNKNOWN ERROR");
++        break;
++      default:
++        g_assert_not_reached ();
++    }
++  } else {
++    g_warning ("Test did not finish within 30 seconds!\n");
++  }
++
++done:
++
++  g_print ("==============================================================\n");
++
++  if (error)
++    g_error_free (error);
++
++  if (pipeline) {
++    gst_element_set_state (pipeline, GST_STATE_NULL);
++    gst_object_unref (pipeline);
++  }
++
++  if (msg)
++    gst_message_unref (msg);
++
++  if (bus)
++    gst_object_unref (bus);
++
++  g_free (pipeline_desc);
+   g_free (partialpipe);
++  g_free (extension);
+ 
+-  return FALSE;
++  gtk_widget_set_sensitive (GTK_WIDGET (button), TRUE);
+ }
+ 
+ int
+@@ -79,8 +136,8 @@ main (int argc, char **argv)
+ 
+   edit = gtk_button_new_with_mnemonic ("_Edit Profiles");
+   test = gtk_button_new_with_mnemonic ("_Test");
+-  g_signal_connect (edit, "clicked", (GCallback) edit_cb, window);
+-  g_signal_connect (test, "clicked", (GCallback) test_cb, combo);
++  g_signal_connect (edit, "clicked", (GCallback) edit_clicked_cb, window);
++  g_signal_connect (test, "clicked", (GCallback) test_clicked_cb, combo);
+   g_signal_connect (edit, "destroy", (GCallback) gtk_main_quit, NULL);
+ 
+   hbox = gtk_hbox_new (FALSE, 7);
+Index: profiles/gnome-audio-profiles.schemas.in.in
+===================================================================
+RCS file: /cvs/gnome/gnome-media/profiles/gnome-audio-profiles.schemas.in.in,v
+retrieving revision 1.6
+retrieving revision 1.6.6.3
+diff -u -p -r1.6 -r1.6.6.3
+--- profiles/gnome-audio-profiles.schemas.in.in	9 May 2004 19:04:23 -0000	1.6
++++ profiles/gnome-audio-profiles.schemas.in.in	16 Jan 2006 17:48:46 -0000	1.6.6.3
+@@ -3,25 +3,25 @@
+   <schemalist>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/global/profile_list</key>
+-      <applyto>/system/gstreamer/audio/global/profile_list</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/global/profile_list</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/global/profile_list</applyto>
+       <owner>gnome-media</owner>
+       <type>list</type>
+       <list_type>string</list_type>
+-      <default>[cdlossy,cdlossless,voice]</default>
++      <default>[cdlossy,cdlossless,voicelossy,voicelossless]</default>
+       <locale name="C">
+         <short>List of profiles</short>
+         <long>
+           List of audio recording profiles.  The list contains
+           strings naming subdirectories relative to
+-          /system/gstreamer/audio/profiles.
++          /system/gstreamer/@GST_MAJORMINOR@/audio/profiles.
+         </long>
+       </locale>
+     </schema>
+ 
+ <!-- template schema for each of the profiles -->
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/name</key>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/name</key>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <default></default>
+@@ -35,7 +35,7 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/description</key>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/description</key>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <default></default>
+@@ -49,7 +49,7 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/pipeline</key>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/pipeline</key>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <default></default>
+@@ -62,7 +62,7 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/extension</key>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/extension</key>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <default></default>
+@@ -76,7 +76,7 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/active</key>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/active</key>
+       <owner>gnome-media</owner>
+       <type>bool</type>
+       <default>true</default>
+@@ -91,8 +91,8 @@
+ <!-- each of the profiles we supply by default -->
+     <!-- CD quality, lossy compression -->
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/cdlossy/name</key>
+-      <applyto>/system/gstreamer/audio/profiles/cdlossy/name</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossy/name</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossy/name</applyto>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <locale name="C">
+@@ -106,8 +106,8 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/cdlossy/description</key>
+-      <applyto>/system/gstreamer/audio/profiles/cdlossy/description</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossy/description</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossy/description</applyto>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <locale name="C">
+@@ -121,11 +121,11 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/cdlossy/pipeline</key>
+-      <applyto>/system/gstreamer/audio/profiles/cdlossy/pipeline</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossy/pipeline</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossy/pipeline</applyto>
+       <owner>gnome-media</owner>
+       <type>string</type>
+-      <default> audio/x-raw-int,rate=44100,channels=2 ! vorbisenc name=enc quality=0.5</default>
++      <default> audio/x-raw-float,rate=44100,channels=2 ! vorbisenc name=enc quality=0.5 ! oggmux</default>
+       <locale name="C">
+         <short>The partial GStreamer pipeline used</short>
+         <long>
+@@ -135,8 +135,8 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/cdlossy/extension</key>
+-      <applyto>/system/gstreamer/audio/profiles/cdlossy/extension</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossy/extension</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossy/extension</applyto>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <default>ogg</default>
+@@ -150,8 +150,8 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/active</key>
+-      <applyto>/system/gstreamer/audio/profiles/cdlossy/active</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/active</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossy/active</applyto>
+       <owner>gnome-media</owner>
+       <type>bool</type>
+       <default>true</default>
+@@ -165,8 +165,8 @@
+ 
+     <!-- CD quality, lossless compression -->
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/cdlossless/name</key>
+-      <applyto>/system/gstreamer/audio/profiles/cdlossless/name</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossless/name</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossless/name</applyto>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <locale name="C">
+@@ -180,8 +180,8 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/cdlossless/description</key>
+-      <applyto>/system/gstreamer/audio/profiles/cdlossless/description</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossless/description</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossless/description</applyto>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <locale name="C">
+@@ -195,8 +195,8 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/cdlossless/pipeline</key>
+-      <applyto>/system/gstreamer/audio/profiles/cdlossless/pipeline</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossless/pipeline</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossless/pipeline</applyto>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <default>audio/x-raw-int,rate=44100,channels=2 ! flacenc name=enc</default>
+@@ -209,8 +209,8 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/cdlossless/extension</key>
+-      <applyto>/system/gstreamer/audio/profiles/cdlossless/extension</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossless/extension</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossless/extension</applyto>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <default>flac</default>
+@@ -224,8 +224,8 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/active</key>
+-      <applyto>/system/gstreamer/audio/profiles/cdlossless/active</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/active</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/cdlossless/active</applyto>
+       <owner>gnome-media</owner>
+       <type>bool</type>
+       <default>true</default>
+@@ -238,14 +238,14 @@
+     </schema>
+ 
+ 
+-    <!-- Voice quality -->
++    <!-- Voice quality, lossless compression -->
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/voice/name</key>
+-      <applyto>/system/gstreamer/audio/profiles/voice/name</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossless/name</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossless/name</applyto>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <locale name="C">
+-        <default>Voice</default>
++        <default>Voice, Lossless</default>
+         <short>A short name for the audio profile</short>
+         <long>
+           A short name for the audio profile, to be used in selections
+@@ -255,12 +255,12 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/voice/description</key>
+-      <applyto>/system/gstreamer/audio/profiles/voice/description</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossless/description</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossless/description</applyto>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <locale name="C">
+-        <default>Used for converting to voice-quality audio. Use this for recording speech.</default>
++        <default>Used for converting to lossless voice-quality audio. Use this for recording and editing speech.</default>
+         <short>A description for the audio profile</short>
+         <long>
+           A description of the profile, containing more information and
+@@ -270,8 +270,8 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/voice/pipeline</key>
+-      <applyto>/system/gstreamer/audio/profiles/voice/pipeline</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossless/pipeline</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossless/pipeline</applyto>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <default>audio/x-raw-int,rate=22050,channels=1 ! wavenc name=enc</default>
+@@ -284,8 +284,8 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/voice/extension</key>
+-      <applyto>/system/gstreamer/audio/profiles/voice/extension</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossless/extension</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossless/extension</applyto>
+       <owner>gnome-media</owner>
+       <type>string</type>
+       <default>wav</default>
+@@ -299,8 +299,82 @@
+     </schema>
+ 
+     <schema>
+-      <key>/schemas/system/gstreamer/audio/profiles/active</key>
+-      <applyto>/system/gstreamer/audio/profiles/voice/active</applyto>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/active</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossless/active</applyto>
++      <owner>gnome-media</owner>
++      <type>bool</type>
++      <default>true</default>
++      <locale name="C">
++        <short>Whether or not this profile is to be used</short>
++        <long>
++          Whether or not to use and display this profile.
++        </long>
++      </locale>
++    </schema>
++
++    <!-- Voice quality, lossy compression -->
++    <schema>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossy/name</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossy/name</applyto>
++      <owner>gnome-media</owner>
++      <type>string</type>
++      <locale name="C">
++        <default>Voice, Lossy</default>
++        <short>A short name for the audio profile</short>
++        <long>
++          A short name for the audio profile, to be used in selections
++          and uniquely identifying the profile.
++        </long>
++      </locale>
++    </schema>
++
++    <schema>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossy/description</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossy/description</applyto>
++      <owner>gnome-media</owner>
++      <type>string</type>
++      <locale name="C">
++        <default>Used for converting to lossy voice-quality audio. Use this for recording speech that doesn't need to be edited.</default>
++        <short>A description for the audio profile</short>
++        <long>
++          A description of the profile, containing more information and
++          describing when to use this profile.
++        </long>
++      </locale>
++    </schema>
++
++    <schema>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossy/pipeline</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossy/pipeline</applyto>
++      <owner>gnome-media</owner>
++      <type>string</type>
++      <default>speexenc name=enc ! oggmux</default>
++      <locale name="C">
++        <short>The partial GStreamer pipeline used</short>
++        <long>
++          A partial GStreamer pipeline to use for this profile.
++        </long>
++      </locale>
++    </schema>
++
++    <schema>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossy/extension</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossy/extension</applyto>
++      <owner>gnome-media</owner>
++      <type>string</type>
++      <default>ogg</default>
++      <locale name="C">
++        <short>The default file extension for this profile</short>
++        <long>
++          A filename extension to be used when storing files encoded
++          with this profile.
++        </long>
++      </locale>
++    </schema>
++
++    <schema>
++      <key>/schemas/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/active</key>
++      <applyto>/system/gstreamer/@GST_MAJORMINOR@/audio/profiles/voicelossy/active</applyto>
+       <owner>gnome-media</owner>
+       <type>bool</type>
+       <default>true</default>
Index: transmogrify-into-gstreamer-0.10
===================================================================
RCS file: transmogrify-into-gstreamer-0.10
diff -N transmogrify-into-gstreamer-0.10
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ transmogrify-into-gstreamer-0.10	16 Jan 2006 22:27:59 -0000
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# this script transmogrifies the gnome-media tarball into one building
+# with GStreamer 0.10
+
+patch -p0 < gstreamer-0.10.patch
