diff --git a/libbanshee/banshee-player-pipeline.c b/libbanshee/banshee-player-pipeline.c
index d246c92..2253989 100644
--- a/libbanshee/banshee-player-pipeline.c
+++ b/libbanshee/banshee-player-pipeline.c
@@ -54,7 +54,6 @@ bp_pipeline_process_tag (const GstTagList *tag_list, const gchar *tag_name, Bans
     value = gst_tag_list_get_value_index (tag_list, tag_name, 0);
 
     if (value != NULL) {
-        _bp_replaygain_process_tag (player, tag_name, value);
     
         if (player->tag_found_cb != NULL) {
             player->tag_found_cb (player, tag_name, value);
@@ -83,7 +82,6 @@ bp_pipeline_bus_callback (GstBus *bus, GstMessage *message, gpointer userdata)
             gst_message_parse_state_changed (message, &old, &new, &pending);
             
             _bp_missing_elements_handle_state_changed (player, old, new);
-            _bp_replaygain_handle_state_changed (player, old, new, pending);
             
             if (player->state_changed_cb != NULL) {
                 player->state_changed_cb (player, old, new, pending);
@@ -208,7 +206,7 @@ _bp_pipeline_construct (BansheePlayer *player)
     }
     
     g_return_val_if_fail (audiosink != NULL, FALSE);
-        
+
     // Set the profile to "music and movies" (gst-plugins-good 0.10.3)
     if (g_object_class_find_property (G_OBJECT_GET_CLASS (audiosink), "profile")) {
         g_object_set (G_OBJECT (audiosink), "profile", 1, NULL);
@@ -221,6 +219,10 @@ _bp_pipeline_construct (BansheePlayer *player)
     // Our audio sink is a tee, so plugins can attach their own pipelines
     player->audiotee = gst_element_factory_make ("tee", "audiotee");
     g_return_val_if_fail (player->audiotee != NULL, FALSE);
+
+    // Create a volume control with low latency
+    player->volume = gst_element_factory_make ("volume", NULL);
+    g_return_val_if_fail (player->volume != NULL, FALSE);
     
     audiosinkqueue = gst_element_factory_make ("queue", "audiosinkqueue");
     g_return_val_if_fail (audiosinkqueue != NULL, FALSE);
@@ -232,9 +234,10 @@ _bp_pipeline_construct (BansheePlayer *player)
         eq_audioconvert2 = gst_element_factory_make ("audioconvert", "audioconvert2");
         player->preamp = gst_element_factory_make ("volume", "preamp");
     }
-    
+
     // Add elements to custom audio sink
     gst_bin_add (GST_BIN (player->audiobin), player->audiotee);
+    gst_bin_add (GST_BIN (player->audiobin), player->volume);
     
     if (player->equalizer != NULL) {
         gst_bin_add (GST_BIN (player->audiobin), eq_audioconvert);
@@ -242,7 +245,7 @@ _bp_pipeline_construct (BansheePlayer *player)
         gst_bin_add (GST_BIN (player->audiobin), player->equalizer);
         gst_bin_add (GST_BIN (player->audiobin), player->preamp);
     }
-    
+
     gst_bin_add (GST_BIN (player->audiobin), audiosinkqueue);
     gst_bin_add (GST_BIN (player->audiobin), audiosink);
    
@@ -255,12 +258,18 @@ _bp_pipeline_construct (BansheePlayer *player)
     if (player->equalizer != NULL) {
         // link in equalizer, preamp and audioconvert.
         gst_element_link_many (audiosinkqueue, eq_audioconvert, player->preamp, 
-            player->equalizer, eq_audioconvert2, audiosink, NULL);
+                               player->equalizer, eq_audioconvert2,
+                               player->volume, audiosink, NULL);
+        player->before_rgvolume = player->volume;
     } else {
         // link the queue with the real audio sink
-        gst_element_link (audiosinkqueue, audiosink);
+        gst_element_link_many (audiosinkqueue, player->volume, audiosink, NULL);
     }
-    
+
+    player->before_rgvolume = player->volume;
+    player->after_rgvolume = audiosink;
+    player->rgvolume_in_pipeline = FALSE;
+
     _bp_vis_pipeline_setup (player);
     
     // Now that our internal audio sink is constructed, tell playbin to use it
@@ -312,3 +321,57 @@ _bp_pipeline_destroy (BansheePlayer *player)
     
     player->playbin = NULL;
 }
+
+static void
+pad_block_cb (GstPad *pad, gboolean blocked, gpointer user_data) {
+
+    if (blocked == FALSE) {
+        return;
+    }
+
+    BansheePlayer* player = (BansheePlayer*) user_data;
+    GstPad* srcPad = pad;
+
+    if (player->rgvolume_in_pipeline == TRUE) {
+        g_return_if_fail (player->rgvolume != NULL);
+        gst_element_unlink(player->before_rgvolume, player->rgvolume);
+        gst_element_unlink(player->rgvolume, player->after_rgvolume);
+    } else {
+        gst_element_unlink(player->before_rgvolume, player->after_rgvolume);
+    }
+
+    if (player->rgvolume == NULL && player->replaygain_enabled == TRUE) {
+        player->rgvolume = gst_element_factory_make ("rgvolume", NULL);
+        gst_bin_add (GST_BIN (player->audiobin), player->rgvolume);
+    }
+
+    if (player->replaygain_enabled == TRUE) {
+        gst_element_sync_state_with_parent(player->rgvolume);
+
+        // link in rgvolume and connect to the real audio sink.
+        gst_element_link (player->before_rgvolume, player->rgvolume);
+        gst_element_link (player->rgvolume, player->after_rgvolume);
+        player->rgvolume_in_pipeline = TRUE;
+    } else {
+        // link the queue with the real audio sink
+        gst_element_link (player->before_rgvolume, player->after_rgvolume);
+        player->rgvolume_in_pipeline = FALSE;
+    }
+
+    if (gst_pad_is_blocked (srcPad) == TRUE) {
+        gst_pad_set_blocked_async(srcPad, FALSE, &pad_block_cb, player);
+    }
+
+    _bp_rgvolume_print_volume(player);
+}
+
+void _bp_pipeline_rebuild (BansheePlayer* player)
+{
+    GstPad* srcPad = gst_element_get_static_pad(player->before_rgvolume, "src");
+
+    if (gst_pad_is_active(srcPad) == TRUE && gst_pad_is_blocked (srcPad) == FALSE) {
+        gst_pad_set_blocked_async(srcPad, TRUE, &pad_block_cb, player);
+    } else if (srcPad->block_callback == NULL) {
+        pad_block_cb(srcPad, TRUE, player);
+    }
+}
diff --git a/libbanshee/banshee-player-pipeline.h b/libbanshee/banshee-player-pipeline.h
index 6a0b9aa..7f5c00f 100644
--- a/libbanshee/banshee-player-pipeline.h
+++ b/libbanshee/banshee-player-pipeline.h
@@ -33,5 +33,6 @@
 
 gboolean  _bp_pipeline_construct (BansheePlayer *player);
 void      _bp_pipeline_destroy   (BansheePlayer *player);
+void      _bp_pipeline_rebuild   (BansheePlayer* player);
 
 #endif /* _BANSHEE_PLAYER_PIPELINE_H */
diff --git a/libbanshee/banshee-player-private.h b/libbanshee/banshee-player-private.h
index 6528060..32f9036 100644
--- a/libbanshee/banshee-player-private.h
+++ b/libbanshee/banshee-player-private.h
@@ -101,6 +101,13 @@ struct BansheePlayer {
     GstElement *audiobin;
     GstElement *equalizer;
     GstElement *preamp;
+    GstElement *volume;
+    GstElement *rgvolume;
+
+    GstElement *before_rgvolume;
+    GstElement *after_rgvolume;
+    gboolean   rgvolume_in_pipeline;
+
     gint equalizer_status;
     gdouble current_volume;
     
diff --git a/libbanshee/banshee-player-replaygain.c b/libbanshee/banshee-player-replaygain.c
index 78fe083..ba73d0b 100644
--- a/libbanshee/banshee-player-replaygain.c
+++ b/libbanshee/banshee-player-replaygain.c
@@ -28,128 +28,46 @@
 
 #include <math.h>
 #include "banshee-player-replaygain.h"
+#include "banshee-player-pipeline.h"
 
 // ---------------------------------------------------------------------------
 // Private Functions
 // ---------------------------------------------------------------------------
 
-static inline void
-bp_replaygain_debug (BansheePlayer *player)
+static gdouble
+bp_replaygain_db_to_linear(gdouble value)
 {
-    gint i;
-    for (i = 0; i < 11; i++) {
-       printf ("%g ", player->volume_scale_history[i]);
-    }
-    printf ("\n");
-}
-
-static void
-bp_replaygain_update_pipeline (BansheePlayer *player, 
-    gdouble album_gain, gdouble album_peak,
-    gdouble track_gain, gdouble track_peak)
-{
-    gdouble gain = album_gain == 0.0 ? album_gain : track_gain;
-    gdouble peak = album_peak == 0.0 ? album_peak : track_peak;
-    gdouble scale = 0.0;
-    
-    g_return_if_fail (IS_BANSHEE_PLAYER (player));
-    
-    if (gain == 0.0) {
-        gint i;
-        player->current_scale_from_history = TRUE;
-        // Compute the average scale from history
-        for (i = 1; i <= 10; i++) {
-            scale += player->volume_scale_history[i] / 10.0;
-        }
-    } else {
-        player->current_scale_from_history = FALSE;
-        scale = pow (10.0, gain / 20.0);
-        
-        if (peak != 0.0 && scale * peak > 1.0) {
-            scale = 1.0 / peak;
-        }
-        
-        if (scale > 15.0) {
-            scale = 15.0;
-        }
-    }
-    
-    player->volume_scale_history[0] = scale;
-    _bp_replaygain_update_volume (player);
+    return pow(10, value / 20.0);
 }
 
 // ---------------------------------------------------------------------------
 // Internal Functions
 // ---------------------------------------------------------------------------
 
-void
-_bp_replaygain_process_tag (BansheePlayer *player, const gchar *tag_name, const GValue *value)
-{
-    if (strcmp (tag_name, GST_TAG_ALBUM_GAIN) == 0) {
-        player->album_gain = g_value_get_double (value);
-    } else if (strcmp (tag_name, GST_TAG_ALBUM_PEAK) == 0) {
-        player->album_peak = g_value_get_double (value);
-    } else if (strcmp (tag_name, GST_TAG_TRACK_GAIN) == 0) {
-        player->track_gain = g_value_get_double (value);
-    } else if (strcmp (tag_name, GST_TAG_TRACK_PEAK) == 0) {
-        player->track_peak = g_value_get_double (value);
-    }
-}
 
-void 
-_bp_replaygain_handle_state_changed (BansheePlayer *player, GstState old, GstState new, GstState pending)
+GstElement* _bp_rgvolume_new (BansheePlayer *player)
 {
-    if (old == GST_STATE_READY && new == GST_STATE_NULL && 
-        pending == GST_STATE_VOID_PENDING && player->volume_scale_history_shift) {
-        
-        memmove (player->volume_scale_history + 1, 
-            player->volume_scale_history, sizeof (gdouble) * 10);
-            
-        if (player->current_scale_from_history) {
-            player->volume_scale_history[1] = 1.0;
-        }
-        
-        player->volume_scale_history[0] = 1.0;
-        player->volume_scale_history_shift = FALSE;
-        
-        player->album_gain = player->album_peak = 0.0;
-        player->track_gain = player->track_peak = 0.0;
-    } else if (old == GST_STATE_READY && new == GST_STATE_PAUSED && 
-        pending == GST_STATE_PLAYING &&  !player->volume_scale_history_shift) {
-        
-        player->volume_scale_history_shift = TRUE;
-        
-        bp_replaygain_update_pipeline (player, 
-            player->album_gain, player->album_peak, 
-            player->track_gain, player->track_peak);
+    GstElement *rgvolume = gst_element_factory_make ("rgvolume", NULL);
+
+    if (rgvolume == NULL) {
+        bp_debug ("Loading ReplayGain plugin failed.");
     }
+
+    return rgvolume;
 }
 
-void
-_bp_replaygain_update_volume (BansheePlayer *player)
+void _bp_rgvolume_print_volume(BansheePlayer *player)
 {
-    GParamSpec *volume_spec;
-    GValue value = { 0, };
-    gdouble scale;
-    
-    if (player == NULL || player->playbin == NULL) {
-        return;
-    }
-    
-    scale = player->replaygain_enabled ? player->volume_scale_history[0] : 1.0;
-    
-    volume_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (player->playbin), "volume");
-    g_value_init (&value, G_TYPE_DOUBLE);
-    g_value_set_double (&value, player->current_volume * scale);
-    g_param_value_validate (volume_spec, &value);
-    
-    if (player->replaygain_enabled) {
-        bp_debug ("scaled volume: %f (ReplayGain) * %f (User) = %f", scale, player->current_volume, 
-            g_value_get_double (&value));
+    g_return_if_fail (IS_BANSHEE_PLAYER (player));
+    if ((player->replaygain_enabled == TRUE) && (player->rgvolume != NULL)) {
+	gdouble scale;
+
+	g_object_get (G_OBJECT (player->rgvolume), "result-gain", &scale, NULL);
+
+	bp_debug ("scaled volume: %.2f (ReplayGain) * %.2f (User) = %.2f",
+		  bp_replaygain_db_to_linear(scale), player->current_volume,
+		  bp_replaygain_db_to_linear(scale) * player->current_volume);
     }
-    
-    g_object_set_property (G_OBJECT (player->playbin), "volume", &value);
-    g_value_unset (&value);
 }
 
 // ---------------------------------------------------------------------------
@@ -162,7 +80,7 @@ bp_replaygain_set_enabled (BansheePlayer *player, gboolean enabled)
     g_return_if_fail (IS_BANSHEE_PLAYER (player));
     player->replaygain_enabled = enabled;
     bp_debug ("%s ReplayGain", enabled ? "Enabled" : "Disabled");
-    _bp_replaygain_update_volume (player);
+    _bp_pipeline_rebuild(player);
 }
 
 P_INVOKE gboolean
diff --git a/libbanshee/banshee-player-replaygain.h b/libbanshee/banshee-player-replaygain.h
index b552c2d..8c38148 100644
--- a/libbanshee/banshee-player-replaygain.h
+++ b/libbanshee/banshee-player-replaygain.h
@@ -31,18 +31,7 @@
 
 #include "banshee-player-private.h"
 
-void _bp_replaygain_process_tag          (BansheePlayer *player, const gchar *tag_name, const GValue *value);
-void _bp_replaygain_handle_state_changed (BansheePlayer *player, GstState old, GstState new, GstState pending);
-void _bp_replaygain_update_volume        (BansheePlayer *player);
-
-static inline void
-_bp_replaygain_init (BansheePlayer *player)
-{
-    gint i;
-    for (i = 0; i < 11; i++) {
-        player->volume_scale_history[i] = 1.0;
-    }
-    
-}
+GstElement* _bp_rgvolume_new          (BansheePlayer *player);
+void        _bp_rgvolume_print_volume (BansheePlayer *player);
 
 #endif /* _BANSHEE_PLAYER_REPLAYGAIN_H */
diff --git a/libbanshee/banshee-player.c b/libbanshee/banshee-player.c
index 4052d06..023f917 100644
--- a/libbanshee/banshee-player.c
+++ b/libbanshee/banshee-player.c
@@ -89,6 +89,26 @@ bp_pipeline_set_state (BansheePlayer *player, GstState state)
     }
 }
 
+static void
+bp_update_volume (BansheePlayer *player)
+{
+    GParamSpec *volume_spec;
+    GValue value = { 0, };
+
+    if (player == NULL || player->volume == NULL) {
+        return;
+    }
+
+    volume_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (player->volume), "volume");
+    g_value_init (&value, G_TYPE_DOUBLE);
+    g_value_set_double (&value, player->current_volume);
+    g_param_value_validate (volume_spec, &value);
+
+    g_object_set_property (G_OBJECT (player->volume), "volume", &value);
+    g_value_unset (&value);
+    _bp_rgvolume_print_volume(player);
+}
+
 // ---------------------------------------------------------------------------
 // Public Functions
 // ---------------------------------------------------------------------------
@@ -124,8 +144,6 @@ bp_new ()
     
     player->mutex = g_mutex_new ();
     
-    _bp_replaygain_init (player); 
-    
     return player;
 }
 
@@ -276,7 +294,7 @@ bp_set_volume (BansheePlayer *player, gdouble volume)
 {
     g_return_if_fail (IS_BANSHEE_PLAYER (player));
     player->current_volume = CLAMP (volume, 0.0, 1.0);
-    _bp_replaygain_update_volume (player);
+    bp_update_volume (player);
 }
 
 P_INVOKE gdouble
