diff --git a/doc/contributions.txt b/doc/contributions.txt
index 988410701b741e0022592b6a1ca9c3305585a816..0f7f458a81451db89f6d4ef45be32a11a4f7ea0f 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -581,6 +581,7 @@ Jonathan Yap
 	STORM-1639
 	STORM-910
 	STORM-1642
+	STORM-591
 Kadah Coba
 	STORM-1060
 Jondan Lundquist
@@ -913,6 +914,7 @@ Robin Cornelius
 	SNOW-599
 	SNOW-747
 	STORM-422
+	STORM-591
 	STORM-960
 	STORM-1019
 	STORM-1095
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 3c53a9d44c3767aec23e9de601a076bdc165eb26..c7300cc1bb799f0c7a75109e44eafd523fe456b6 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -192,6 +192,28 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>AudioMusicFadeIn</key>
+    <map>
+      <key>Comment</key>
+      <string>Fade in time in seconds for music streams</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>5.0</real>
+    </map>
+    <key>AudioMusicFadeOut</key>
+    <map>
+      <key>Comment</key>
+      <string>Fade out time in seconds for music streams</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>5.0</real>
+    </map>
     <key>AudioLevelAmbient</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/lloverlaybar.cpp b/indra/newview/lloverlaybar.cpp
deleted file mode 100644
index c2bbec04700ed77ec65745199c7d76c6cb9033d9..0000000000000000000000000000000000000000
--- a/indra/newview/lloverlaybar.cpp
+++ /dev/null
@@ -1,378 +0,0 @@
-/** 
- * @file lloverlaybar.cpp
- * @brief LLOverlayBar class implementation
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-// Temporary buttons that appear at the bottom of the screen when you
-// are in a mode.
-
-#include "llviewerprecompiledheaders.h"
-
-#include "lloverlaybar.h"
-
-#include "llaudioengine.h"
-#include "llrender.h"
-#include "llagent.h"
-#include "llbutton.h"
-#include "llfocusmgr.h"
-#include "llimview.h"
-#include "llmediaremotectrl.h"
-#include "llparcel.h"
-#include "lltextbox.h"
-#include "llui.h"
-#include "llviewercontrol.h"
-#include "llviewertexturelist.h"
-#include "llviewerjoystick.h"
-#include "llviewermedia.h"
-#include "llviewermenu.h"	// handle_reset_view()
-#include "llviewermedia.h"
-#include "llviewerparcelmedia.h"
-#include "llviewerparcelmgr.h"
-#include "lluictrlfactory.h"
-#include "llviewerwindow.h"
-#include "llvoiceclient.h"
-#include "llvoavatarself.h"
-#include "llvoiceremotectrl.h"
-#include "llmediactrl.h"
-#include "llselectmgr.h"
-
-//
-// Globals
-//
-
-LLOverlayBar *gOverlayBar = NULL;
-
-extern S32 MENU_BAR_HEIGHT;
-
-//
-// Functions
-//
-
-
-
-void* LLOverlayBar::createMediaRemote(void* userdata)
-{
-	LLOverlayBar *self = (LLOverlayBar*)userdata;	
-	self->mMediaRemote =  new LLMediaRemoteCtrl ();
-	return self->mMediaRemote;
-}
-
-void* LLOverlayBar::createVoiceRemote(void* userdata)
-{
-	LLOverlayBar *self = (LLOverlayBar*)userdata;	
-	self->mVoiceRemote = new LLVoiceRemoteCtrl();
-	return self->mVoiceRemote;
-}
-
-LLOverlayBar::LLOverlayBar()
-	:	LLPanel(),
-		mMediaRemote(NULL),
-		mVoiceRemote(NULL),
-		mMusicState(STOPPED)
-{
-	setMouseOpaque(FALSE);
-	setIsChrome(TRUE);
-
-	mBuilt = false;
-
-	mFactoryMap["media_remote"] = LLCallbackMap(LLOverlayBar::createMediaRemote, this);
-	mFactoryMap["voice_remote"] = LLCallbackMap(LLOverlayBar::createVoiceRemote, this);
-	
-	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_overlaybar.xml");
-}
-
-BOOL LLOverlayBar::postBuild()
-{
-	childSetAction("Set Not Busy",onClickSetNotBusy,this);
-	childSetAction("Mouselook",onClickMouselook,this);
-	childSetAction("Stand Up",onClickStandUp,this);
- 	childSetAction("Flycam",onClickFlycam,this);
-	childSetVisible("chat_bar", gSavedSettings.getBOOL("ChatVisible"));
-
-	mVoiceRemote->expandOrCollapse();
-	mMediaRemote->expandOrCollapse();
-
-	setFocusRoot(TRUE);
-	mBuilt = true;
-
-	layoutButtons();
-	return TRUE;
-}
-
-LLOverlayBar::~LLOverlayBar()
-{
-	// LLView destructor cleans up children
-}
-
-// virtual
-void LLOverlayBar::reshape(S32 width, S32 height, BOOL called_from_parent)
-{
-	LLView::reshape(width, height, called_from_parent);
-
-	if (mBuilt) 
-	{
-		layoutButtons();
-	}
-}
-
-void LLOverlayBar::layoutButtons()
-{
-	LLView* state_buttons_panel = getChildView("state_buttons");
-
-	if (state_buttons_panel->getVisible())
-	{
-		LLViewQuery query;
-		LLWidgetTypeFilter<LLButton> widget_filter;
-		query.addPreFilter(LLEnabledFilter::getInstance());
-		query.addPreFilter(&widget_filter);
-
-		child_list_t button_list = query(state_buttons_panel);
-
-		const S32 MAX_BAR_WIDTH = 600;
-		S32 bar_width = llclamp(state_buttons_panel->getRect().getWidth(), 0, MAX_BAR_WIDTH);
-
-		// calculate button widths
-		const S32 MAX_BUTTON_WIDTH = 150;
-		const S32 STATUS_BAR_PAD = 10;
-		S32 segment_width = llclamp(lltrunc((F32)(bar_width) / (F32)button_list.size()), 0, MAX_BUTTON_WIDTH);
-		S32 btn_width = segment_width - STATUS_BAR_PAD;
-
-		// Evenly space all buttons, starting from left
-		S32 left = 0;
-		S32 bottom = 1;
-
-		for (child_list_reverse_iter_t child_iter = button_list.rbegin();
-			child_iter != button_list.rend(); ++child_iter)
-		{
-			LLView *view = *child_iter;
-			LLRect r = view->getRect();
-			r.setOriginAndSize(left, bottom, btn_width, r.getHeight());
-			view->setRect(r);
-			left += segment_width;
-		}
-	}
-}
-
-// Per-frame updates of visibility
-void LLOverlayBar::refresh()
-{
-	BOOL buttons_changed = FALSE;
-
-	BOOL im_received = gIMMgr->getIMReceived();
-	LLButton* button = getChild<LLButton>("IM Received");
-	if (button && button->getVisible() != im_received)
-	{
-		button->setVisible(im_received);
-		sendChildToFront(button);
-		moveChildToBackOfTabGroup(button);
-		buttons_changed = TRUE;
-	}
-
-	BOOL busy = gAgent.getBusy();
-	button = getChild<LLButton>("Set Not Busy");
-	if (button && button->getVisible() != busy)
-	{
-		button->setVisible(busy);
-		sendChildToFront(button);
-		moveChildToBackOfTabGroup(button);
-		buttons_changed = TRUE;
-	}
-
-	BOOL flycam = LLViewerJoystick::getInstance()->getOverrideCamera();
-	button = getChild<LLButton>("Flycam");
-	if (button && button->getVisible() != flycam)
-	{
-		button->setVisible(flycam);
-		sendChildToFront(button);
-		moveChildToBackOfTabGroup(button);
-		buttons_changed = TRUE;
-	}		
-
-	BOOL mouselook_grabbed;
-	mouselook_grabbed = gAgent.isControlGrabbed(CONTROL_ML_LBUTTON_DOWN_INDEX)
-		|| gAgent.isControlGrabbed(CONTROL_ML_LBUTTON_UP_INDEX);
-	button = getChild<LLButton>("Mouselook");
-
-	if (button && button->getVisible() != mouselook_grabbed)
-	{
-		button->setVisible(mouselook_grabbed);
-		sendChildToFront(button);
-		moveChildToBackOfTabGroup(button);
-		buttons_changed = TRUE;
-	}
-
-	BOOL sitting = FALSE;
-	if (gAgent.getAvatarObject())
-	{
-		sitting = gAgent.getAvatarObject()->isSitting();
-	}
-	button = getChild<LLButton>("Stand Up");
-
-	if (button && button->getVisible() != sitting)
-	{
-		button->setVisible(sitting);
-		sendChildToFront(button);
-		moveChildToBackOfTabGroup(button);
-		buttons_changed = TRUE;
-	}
-
-
-	moveChildToBackOfTabGroup(mMediaRemote);
-	moveChildToBackOfTabGroup(mVoiceRemote);
-
-	// turn off the whole bar in mouselook
-	if (gAgent.cameraMouselook())
-	{
-		childSetVisible("media_remote_container", FALSE);
-		childSetVisible("voice_remote_container", FALSE);
-		childSetVisible("state_buttons", FALSE);
-	}
-	else
-	{
-		// update "remotes"
-		childSetVisible("media_remote_container", TRUE);
-		childSetVisible("voice_remote_container", LLVoiceClient::getInstance()->voiceEnabled());
-		childSetVisible("state_buttons", TRUE);
-	}
-
-	// always let user toggle into and out of chatbar
-	childSetVisible("chat_bar", gSavedSettings.getBOOL("ChatVisible"));
-
-	if (buttons_changed)
-	{
-		layoutButtons();
-	}
-}
-
-//-----------------------------------------------------------------------
-// Static functions
-//-----------------------------------------------------------------------
-
-// static
-void LLOverlayBar::onClickSetNotBusy(void*)
-{
-	gAgent.clearBusy();
-}
-
-
-// static
-void LLOverlayBar::onClickFlycam(void*)
-{
-	LLViewerJoystick::getInstance()->toggleFlycam();
-}
-
-// static
-void LLOverlayBar::onClickResetView(void* data)
-{
-	handle_reset_view();
-}
-
-//static
-void LLOverlayBar::onClickMouselook(void*)
-{
-	gAgent.changeCameraToMouselook();
-}
-
-//static
-void LLOverlayBar::onClickStandUp(void*)
-{
-	LLSelectMgr::getInstance()->deselectAllForStandingUp();
-	gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// static media helpers
-// *TODO: Move this into an audio manager abstraction
-//static
-void LLOverlayBar::mediaStop(void*)
-{
-	if (!gOverlayBar)
-	{
-		// return;
-	}
-	LLViewerParcelMedia::stop();
-}
-//static
-void LLOverlayBar::toggleMediaPlay(void*)
-{
-	if (!gOverlayBar)
-	{
-		// return;
-	}
-
-	
-	if (LLViewerParcelMedia::getStatus() == LLViewerMediaImpl::MEDIA_PAUSED)
-	{
-		LLViewerParcelMedia::start();
-	}
-	else if(LLViewerParcelMedia::getStatus() == LLViewerMediaImpl::MEDIA_PLAYING)
-	{
-		LLViewerParcelMedia::pause();
-	}
-	else
-	{
-		LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-		if (parcel)
-		{
-			LLViewerParcelMedia::play(parcel);
-		}
-	}
-}
-
-//static
-void LLOverlayBar::toggleMusicPlay(void*)
-{
-	if (gAudiop->isInternetStreamPlaying() != 1)
-	{
-		if (gAudiop)
-		{
-			LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-			if ( parcel )
-			{
-				// this doesn't work properly when crossing parcel boundaries - even when the 
-				// stream is stopped, it doesn't return the right thing - commenting out for now.
-	// 			if ( gAudiop->isInternetStreamPlaying() == 0 )
-				{
-					gAudiop->startInternetStream(parcel->getMusicURL());
-				}
-			}
-		}
-	}
-	//else
-	//{
-	//	gOverlayBar->mMusicState = PAUSED; // desired state
-	//	if (gAudiop)
-	//	{
-	//		gAudiop->pauseInternetStream(1);
-	//	}
-	//}
-	else
-	{
-		if (gAudiop)
-		{
-			gAudiop->stopInternetStream();
-		}
-	}
-}
-
diff --git a/indra/newview/lloverlaybar.h b/indra/newview/lloverlaybar.h
deleted file mode 100644
index b36f5ebb731cc756bb991667f715dca770946b33..0000000000000000000000000000000000000000
--- a/indra/newview/lloverlaybar.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/** 
- * @file lloverlaybar.h
- * @brief LLOverlayBar class definition
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLOVERLAYBAR_H
-#define LL_LLOVERLAYBAR_H
-
-#include "llpanel.h"
-
-// "Constants" loaded from settings.xml at start time
-extern S32 STATUS_BAR_HEIGHT;
-
-class LLButton;
-class LLLineEditor;
-class LLMediaRemoteCtrl;
-class LLMessageSystem;
-class LLTextBox;
-class LLTextEditor;
-class LLUICtrl;
-class LLUUID;
-class LLFrameTimer;
-class LLStatGraph;
-class LLSlider;
-class LLVoiceRemoteCtrl;
-
-class LLOverlayBar
-:	public LLPanel
-{
-public:
-	LLOverlayBar();
-	~LLOverlayBar();
-
-	/*virtual*/ void refresh();
-	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
-	/*virtual*/ BOOL postBuild();
-
-	void layoutButtons();
-
-	// helpers for returning desired state
-	BOOL musicPlaying() { return mMusicState == PLAYING; }
-	
-	static void onClickSetNotBusy(void* data);
-	static void onClickMouselook(void* data);
-	static void onClickStandUp(void* data);
-	static void onClickResetView(void* data);
- 	static void onClickFlycam(void* data);
-
-	//static media helper functions
-	static void toggleMediaPlay(void*);
-	static void toggleMusicPlay(void*);
-	static void musicPause(void*);
-	static void musicStop(void*);
-	static void mediaStop(void*);
-
-	static void toggleAudioVolumeFloater(void*);
-
-protected:	
-	static void* createMediaRemote(void* userdata);
-	static void* createVoiceRemote(void* userdata);
-
-	void enableMediaButtons();
-
-protected:
-	LLMediaRemoteCtrl*	mMediaRemote;
-	LLVoiceRemoteCtrl*	mVoiceRemote;
-	bool mBuilt;	// dialog constructed yet?
-	enum { STOPPED=0, PLAYING=1, PAUSED=2 };
-	S32 mMusicState;
-};
-
-extern LLOverlayBar* gOverlayBar;
-
-#endif
diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp
index 2bbd15ae1175eb31200dada6f5d3405865e33c0d..53fc64f089fac7e2db4e92024797d6e3384b5c6d 100644
--- a/indra/newview/llpanelnearbymedia.cpp
+++ b/indra/newview/llpanelnearbymedia.cpp
@@ -52,6 +52,7 @@
 #include "llvovolume.h"
 #include "llstatusbar.h"
 #include "llsdutil.h"
+#include "llvieweraudio.h"
 
 #include "llfloaterreg.h"
 #include "llfloaterpreference.h" // for the gear icon
@@ -808,7 +809,7 @@ bool LLPanelNearByMedia::setDisabled(const LLUUID &row_id, bool disabled)
 	if (row_id == PARCEL_AUDIO_LIST_ITEM_UUID)
 	{
 		if (disabled) onClickParcelAudioStop();
-		else onClickParcelAudioStart();
+		else onClickParcelAudioPlay();
 		return true;
 	}
 	else if (row_id == PARCEL_MEDIA_LIST_ITEM_UUID)
@@ -857,24 +858,11 @@ void LLPanelNearByMedia::onClickParcelMediaPause()
 	LLViewerParcelMedia::pause();
 }
 
-void LLPanelNearByMedia::onClickParcelAudioStart()
-{
-	// User *explicitly* started the internet stream, so keep the stream
-	// playing and updated as they cross to other parcels etc.
-	mParcelAudioAutoStart = true;
-		
-	if (!gAudiop)
-		return;
-	
-	gAudiop->startInternetStream(LLViewerMedia::getParcelAudioURL());
-}
-
 void LLPanelNearByMedia::onClickParcelAudioPlay()
 {
 	// User *explicitly* started the internet stream, so keep the stream
 	// playing and updated as they cross to other parcels etc.
 	mParcelAudioAutoStart = true;
-
 	if (!gAudiop)
 		return;
 
@@ -883,8 +871,9 @@ void LLPanelNearByMedia::onClickParcelAudioPlay()
 		// 'false' means unpause
 		gAudiop->pauseInternetStream(false);
 	}
-	else {
-		gAudiop->startInternetStream(LLViewerMedia::getParcelAudioURL());
+	else
+	{
+		LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLViewerMedia::getParcelAudioURL());
 	}
 }
 
@@ -894,11 +883,10 @@ void LLPanelNearByMedia::onClickParcelAudioStop()
 	// re-start audio when i.e. they move to another parcel, until
 	// they explicitly start it again.
 	mParcelAudioAutoStart = false;
-
 	if (!gAudiop)
 		return;
 
-	gAudiop->stopInternetStream();
+	LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade();
 }
 
 void LLPanelNearByMedia::onClickParcelAudioPause()
diff --git a/indra/newview/llpanelnearbymedia.h b/indra/newview/llpanelnearbymedia.h
index be4d3137435fcc39b4b632e4fe3665da0c4182e5..c3634de9b47eec37311078efdd8db35377c372b6 100644
--- a/indra/newview/llpanelnearbymedia.h
+++ b/indra/newview/llpanelnearbymedia.h
@@ -115,7 +115,6 @@ class LLPanelNearByMedia : public LLPanel
 	void onClickParcelMediaPause();
 	void onClickParcelAudioPlay();
 	void onClickParcelAudioStop();
-	void onClickParcelAudioStart();
 	void onClickParcelAudioPause();
 	void onCheckAutoPlay();
 	void onAdvancedButtonClick();	
diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp
index f7fa5690d69989061bdb8207fc5e9bd04822317a..8fd1ca38076c5c6bd0dbdf8e3c01fa0ab0ee7809 100644
--- a/indra/newview/llvieweraudio.cpp
+++ b/indra/newview/llvieweraudio.cpp
@@ -37,9 +37,212 @@
 #include "llvoiceclient.h"
 #include "llviewermedia.h"
 #include "llprogressview.h"
+#include "llcallbacklist.h"
 
 /////////////////////////////////////////////////////////
 
+LLViewerAudio::LLViewerAudio() :
+	mDone(true),
+	mFadeState(FADE_IDLE),
+	mFadeTime(),
+    mIdleListnerActive(false)
+{
+}
+
+LLViewerAudio::~LLViewerAudio()
+{
+}
+
+void LLViewerAudio::registerIdleListener()
+{
+	if(mIdleListnerActive==false)
+	{
+		mIdleListnerActive = true;
+		doOnIdleRepeating(boost::bind(boost::bind(&LLViewerAudio::onIdleUpdate, this)));
+	}
+
+}
+
+void LLViewerAudio::startInternetStreamWithAutoFade(std::string streamURI)
+{
+	llinfos << "DBG streamURI: " << streamURI << llendl;
+	llinfos << "DBG mNextStreamURI: " << mNextStreamURI << llendl;
+	if (mFadeState == FADE_OUT) {llinfos << "DBG mFadeState: FADE_OUT " << llendl;}
+	if (mFadeState == FADE_IN) {llinfos << "DBG mFadeState: FADE_IN " << llendl;}
+	if (mFadeState == FADE_IDLE) {llinfos << "DBG mFadeState: FADE_IDLE " << llendl;}
+
+	// Old and new stream are identical
+	if (mNextStreamURI == streamURI)
+	{
+		return;
+	}
+
+	// Record the URI we are going to be switching to	
+	mNextStreamURI = streamURI;
+
+	if (mFadeState == FADE_IDLE)
+	{
+		// If a stream is playing fade it out first
+		if (!gAudiop->getInternetStreamURL().empty())
+		{
+			mFadeState = FADE_OUT;
+llinfos << "DBG new mFadeState: OUT" << llendl;
+		}
+		// Otherwise the new stream can be faded in
+		else
+		{
+			mFadeState = FADE_IN;
+llinfos << "DBG new mFadeState: IN" << llendl;
+
+			gAudiop->startInternetStream(mNextStreamURI);
+			startFading();
+			registerIdleListener();
+			return;
+		}
+	}
+
+	if (mFadeState == FADE_OUT)
+	{
+		startFading();
+		registerIdleListener();
+		return;
+	}
+
+	if (mFadeState == FADE_IN)
+	{
+		registerIdleListener();
+		return;
+	}
+}
+
+// We want onIdleUpdate callback to keep firing whilst we are fading out. Once we have completed the fade
+// out, we switch the stream and start a fade in, and we don't care about idle updates anymore.
+// A return of false from onIdleUpdate means it will be called again next idle update.
+// A return of true means we have finished with it and the callback will be deleted.
+bool LLViewerAudio::onIdleUpdate()
+{
+	if (mDone)
+	{
+		if (mFadeState == FADE_OUT) {llinfos << "DBG mFadeState: FADE_OUT " << llendl;}
+		if (mFadeState == FADE_IN) {llinfos << "DBG mFadeState: FADE_IN " << llendl;}
+		if (mFadeState == FADE_IDLE) {llinfos << "DBG mFadeState: FADE_IDLE " << llendl;}
+
+		//  This should be a rare or never occurring state.
+		if (mFadeState == FADE_IDLE)
+		{
+			deregisterIdleListener();
+			return true; // Stop calling onIdleUpdate
+		}
+
+		// we have finished the current fade operation
+		if (mFadeState == FADE_OUT)
+		{
+			// Clear URI
+			gAudiop->startInternetStream(LLStringUtil::null);
+			gAudiop->stopInternetStream();
+				
+			if (!mNextStreamURI.empty())
+			{
+				mFadeState = FADE_IN;
+llinfos << "DBG new mFadeState: IN" << llendl;
+				gAudiop->startInternetStream(mNextStreamURI);
+				startFading();
+				return false;
+			}
+			else
+			{
+				mFadeState = FADE_IDLE;
+llinfos << "DBG new mFadeState: IDLE" << llendl;
+				deregisterIdleListener();
+				return true; // Stop calling onIdleUpdate
+			}
+		}
+		else if (mFadeState == FADE_IN)
+		{
+			if (mNextStreamURI != gAudiop->getInternetStreamURL())
+			{
+				mFadeState = FADE_OUT;
+				startFading();
+				return false;
+llinfos << "DBG new mFadeState: OUT" << llendl;
+			}
+			else
+			{
+				mFadeState = FADE_IDLE;
+llinfos << "DBG new mFadeState: IDLE" << llendl;
+				deregisterIdleListener();
+				return true; // Stop calling onIdleUpdate
+			}
+		}
+	}
+
+	return false;
+}
+
+void LLViewerAudio::stopInternetStreamWithAutoFade()
+{
+llinfos << "DBG stopping stream" << llendl;
+	mFadeState = FADE_IDLE;
+llinfos << "DBG new mFadeState: IDLE" << llendl;
+	mNextStreamURI = LLStringUtil::null;
+	mDone = true;
+llinfos << "DBG mDone: true" << llendl;
+
+	gAudiop->startInternetStream(LLStringUtil::null);
+	gAudiop->stopInternetStream();
+}
+
+void LLViewerAudio::startFading()
+{
+llinfos << "DBG startFading" << llendl;
+
+	if(mDone)
+	{
+		// The fade state here should only be one of FADE_IN or FADE_OUT, but, in case it is not,
+		// rather than check for both states assume a fade in and check for the fade out case.
+		mFadeTime = llmax(0.0f, gSavedSettings.getF32("AudioMusicFadeIn"));
+		if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT)
+		{
+			mFadeTime = llmax(0.0f, gSavedSettings.getF32("AudioMusicFadeOut"));
+		}
+		stream_fade_timer.reset();
+		stream_fade_timer.setTimerExpirySec(mFadeTime);
+		mDone = false;
+llinfos << "DBG mDone: false" << llendl;
+	}
+}
+
+F32 LLViewerAudio::getFadeVolume()
+{
+	F32 fade_volume = 1.0f;
+
+	if (stream_fade_timer.hasExpired())
+	{
+		mDone = true;
+		// If we have been fading out set volume to 0 until the next fade state occurs to prevent
+		// an audio transient.
+		if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT)
+		{
+			fade_volume = 0.0f;
+		}
+	}
+
+	if (!mDone)
+	{
+		// Calculate how far we are into the fade time
+		fade_volume = stream_fade_timer.getElapsedTimeF32() / mFadeTime;
+		
+		if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT)
+		{
+			// If we are not fading in then we are fading out, so invert the fade
+			// direction; start loud and move towards zero volume.
+			fade_volume = 1.0f - fade_volume;
+		}
+	}
+
+	return fade_volume;
+}
+
 void init_audio() 
 {
 	if (!gAudiop) 
@@ -145,9 +348,11 @@ void audio_update_volume(bool force_update)
 	{		
 		F32 music_volume = gSavedSettings.getF32("AudioLevelMusic");
 		BOOL music_muted = gSavedSettings.getBOOL("MuteMusic");
-		music_volume = mute_volume * master_volume * music_volume;
-		gAudiop->setInternetStreamGain ( music_muted || progress_view_visible ? 0.f : music_volume );
-	
+		F32 fade_volume = LLViewerAudio::getInstance()->getFadeVolume();
+llinfos << "DBG fade_volume:" << fade_volume << llendl;
+
+		music_volume = mute_volume * master_volume * music_volume * fade_volume;
+		gAudiop->setInternetStreamGain (music_muted ? 0.f : music_volume);
 	}
 
 	// Streaming Media
diff --git a/indra/newview/llvieweraudio.h b/indra/newview/llvieweraudio.h
index e5916285fba26684ed391bd8c8507bee3e9fcc29..316d7b32d2ba8d294302223694336b03e45e18fa 100644
--- a/indra/newview/llvieweraudio.h
+++ b/indra/newview/llvieweraudio.h
@@ -27,6 +27,10 @@
 #ifndef LL_VIEWERAUDIO_H
 #define LL_VIEWERAUDIO_H
 
+#include "llframetimer.h"
+#include "llthread.h"
+#include "llsingleton.h"
+
 // comment out to turn off wind
 #define kAUDIO_ENABLE_WIND 
 //#define kAUDIO_ENABLE_WATER 1	// comment out to turn off water
@@ -38,4 +42,41 @@ void audio_update_volume(bool force_update = true);
 void audio_update_listener();
 void audio_update_wind(bool force_update = true);
 
+class LLViewerAudio : public LLSingleton<LLViewerAudio>
+{
+public:
+
+	enum EFadeState
+	{
+		FADE_IDLE,
+		FADE_IN,
+		FADE_OUT,
+	};
+
+	LLViewerAudio();
+	virtual ~LLViewerAudio();
+	
+	void startInternetStreamWithAutoFade(std::string streamURI);
+	void stopInternetStreamWithAutoFade();
+	
+	bool LLViewerAudio::onIdleUpdate();
+
+	EFadeState getFadeState() { return mFadeState; }
+	bool isDone() { return mDone; };
+	F32 getFadeVolume();
+
+private:
+
+	bool mDone;
+	F32 mFadeTime;
+	std::string mNextStreamURI;
+	EFadeState mFadeState;
+	LLFrameTimer stream_fade_timer;
+	bool mIdleListnerActive;
+
+	void registerIdleListener();
+	void deregisterIdleListener() { mIdleListnerActive = false; };
+	void startFading();
+};
+
 #endif //LL_VIEWER_H
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 41b4dc01e8dc0f252a35d6d00123d5b57baf769f..148bfbf0801b37e8379cd848d56648b09764588d 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -66,7 +66,7 @@
 //#include "llfirstuse.h"
 #include "llviewernetwork.h"
 #include "llwindow.h"
-
+#include "llvieweraudio.h"
 
 #include "llfloatermediabrowser.h"	// for handling window close requests and geometry change requests in media browser windows.
 #include "llfloaterwebcontent.h"	// for handling window close requests and geometry change requests in media browser windows.
@@ -967,7 +967,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg)
 		{
 			if(LLViewerMedia::isParcelAudioPlaying() && gAudiop && LLViewerMedia::hasParcelAudio())
 			{
-				gAudiop->stopInternetStream();
+				LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade();
 			}
 		}
 		pimpl->setPriority(new_priority);
@@ -1069,13 +1069,24 @@ void LLViewerMedia::setAllMediaEnabled(bool val)
 			gAudiop && 
 			LLViewerMedia::hasParcelAudio())
 		{
-			gAudiop->startInternetStream(LLViewerMedia::getParcelAudioURL());
+			if (LLAudioEngine::AUDIO_PAUSED == gAudiop->isInternetStreamPlaying())
+			{
+				// 'false' means unpause
+				gAudiop->pauseInternetStream(false);
+			}
+			else
+			{
+				LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLViewerMedia::getParcelAudioURL());
+			}
 		}
 	}
 	else {
 		// This actually unloads the impl, as opposed to "stop"ping the media
 		LLViewerParcelMedia::stop();
-		if (gAudiop) gAudiop->stopInternetStream();
+		if (gAudiop)
+		{
+			LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade();
+		}
 	}
 }
 
@@ -1488,8 +1499,7 @@ void LLViewerMedia::setOpenIDCookie()
 			new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()),
 			headers);
 
-		// FUI: No longer perform the user_status query
-		//doOnetimeEarlyHTTPRequests();
+		doOnetimeEarlyHTTPRequests();
 	}
 }
 
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index 8db72da1eec547b45f9374dd77ff49900ccdf340..928a84e7eb82f962f2bde19694571527da457f69 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -67,6 +67,7 @@
 #include "llworld.h"
 #include "roles_constants.h"
 #include "llweb.h"
+#include "llvieweraudio.h"
 
 const F32 PARCEL_COLLISION_DRAW_SECS = 1.f;
 
@@ -1725,7 +1726,11 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
 	}
 	else
 	{
-		// look for music.
+		// Check for video
+		LLViewerParcelMedia::update( parcel );
+
+		// Then check for music.  Do this last, as there may be a delay waiting for
+		// the stream fading thread to finish.
 		if (gAudiop)
 		{
 			if (parcel)
@@ -1736,46 +1741,36 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
 				std::string music_url = music_url_raw;
 				LLStringUtil::trim(music_url);
 
-				// On entering a new parcel, stop the last stream if the
-				// new parcel has a different music url.  (Empty URL counts
-				// as different.)
 				const std::string& stream_url = gAudiop->getInternetStreamURL();
 
-				if (music_url.empty() || music_url != stream_url)
+				// If there is a new music URL and it's valid, play it.
+				if (music_url.size() > 12)
 				{
-					// URL is different from one currently playing.
-					gAudiop->stopInternetStream();
-
-					// If there is a new music URL and it's valid, play it.
-					if (music_url.size() > 12)
+					if (music_url.substr(0,7) == "http://")
 					{
-						if (music_url.substr(0,7) == "http://")
-						{
-							optionally_start_music(music_url);
-						}
-						else
-						{
-							llinfos << "Stopping parcel music (invalid audio stream URL)" << llendl;
-							// clears the URL 
-							gAudiop->startInternetStream(LLStringUtil::null); 
-						}
+						optionally_start_music(music_url);
 					}
-					else if (!gAudiop->getInternetStreamURL().empty())
+					else
 					{
-						llinfos << "Stopping parcel music (parcel stream URL is empty)" << llendl;
-						gAudiop->startInternetStream(LLStringUtil::null);
+						llinfos << "Stopping parcel music (invalid audio stream URL)" << llendl;
+						// clears the URL 
+						// null value causes fade out
+						LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null);
 					}
 				}
+				else if (!gAudiop->getInternetStreamURL().empty())
+				{
+					llinfos << "Stopping parcel music (parcel stream URL is empty)" << llendl;
+					// null value causes fade out
+					LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null);
+				}
 			}
 			else
 			{
 				// Public land has no music
-				gAudiop->stopInternetStream();
+				LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade();
 			}
 		}//if gAudiop
-
-		// now check for video
-		LLViewerParcelMedia::update( parcel );
 	};
 }
 
@@ -1794,7 +1789,11 @@ void optionally_start_music(const std::string& music_url)
 			 gSavedSettings.getBOOL("MediaTentativeAutoPlay")))
 		{
 			llinfos << "Starting parcel music " << music_url << llendl;
-			gAudiop->startInternetStream(music_url);
+			LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(music_url);
+		}
+		else
+		{
+			LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null);
 		}
 	}
 }