From ba8bcf6520eb4cbcdf93393ecdeda4e6c0bc5846 Mon Sep 17 00:00:00 2001
From: Alexander Gavriliuk <alexandrgproductengine@lindenlab.com>
Date: Mon, 3 Apr 2023 22:19:33 +0200
Subject: SL-19042: Replace FMOD with VLC for parcel audio

---
 indra/llaudio/llaudioengine.cpp            | 103 ++++++++++++++---------------
 indra/llaudio/llaudioengine.h              |  13 ++--
 indra/llaudio/llaudioengine_fmodstudio.cpp |  11 +--
 indra/llaudio/llaudioengine_fmodstudio.h   |   1 +
 indra/newview/app_settings/cmd_line.xml    |   6 ++
 indra/newview/app_settings/settings.xml    |  11 +++
 indra/newview/llstartup.cpp                |  27 ++++----
 indra/newview/llvieweraudio.cpp            |  38 +++++------
 8 files changed, 113 insertions(+), 97 deletions(-)

diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp
index 008e1827c5..29e96ec4d4 100644
--- a/indra/llaudio/llaudioengine.cpp
+++ b/indra/llaudio/llaudioengine.cpp
@@ -206,7 +206,8 @@ std::string LLAudioEngine::getInternetStreamURL()
 {
 	if (mStreamingAudioImpl)
 		return mStreamingAudioImpl->getURL();
-	else return std::string();
+
+	return std::string();
 }
 
 
@@ -347,42 +348,43 @@ void LLAudioEngine::idle()
 			}
 			continue;
 		}
-		else
+
+		// Check to see if the current sound is done playing.
+		if (!channelp->isPlaying())
 		{
-			// Check to see if the current sound is done playing, or looped.
-			if (!channelp->isPlaying())
+			sourcep->mCurrentDatap = sourcep->mQueuedDatap;
+			sourcep->mQueuedDatap = NULL;
+
+			// Reset the timer so the source doesn't die.
+			sourcep->mAgeTimer.reset();
+
+			// Make sure we have the buffer set up if we just decoded the data
+			if (sourcep->mCurrentDatap)
 			{
-				sourcep->mCurrentDatap = sourcep->mQueuedDatap;
-				sourcep->mQueuedDatap = NULL;
+				updateBufferForData(sourcep->mCurrentDatap);
+			}
 
-				// Reset the timer so the source doesn't die.
-				sourcep->mAgeTimer.reset();
+			// Actually play the associated data.
+			sourcep->setupChannel();
+			channelp->updateBuffer();
+			sourcep->getChannel()->play();
+			continue;
+		}
 
-				// Make sure we have the buffer set up if we just decoded the data
-				if (sourcep->mCurrentDatap)
-				{
-					updateBufferForData(sourcep->mCurrentDatap);
-				}
+		// Check to see if the current sound is looped.
+		if (sourcep->isLoop())
+		{
+			// It's a loop, we need to check and see if we're done with it.
+			if (channelp->mLoopedThisFrame)
+			{
+				sourcep->mCurrentDatap = sourcep->mQueuedDatap;
+				sourcep->mQueuedDatap = NULL;
 
-				// Actually play the associated data.
+				// Actually, should do a time sync so if we're a loop master/slave
+				// we don't drift away.
 				sourcep->setupChannel();
-				channelp->updateBuffer();
 				sourcep->getChannel()->play();
 			}
-			else if (sourcep->isLoop())
-			{
-				// It's a loop, we need to check and see if we're done with it.
-				if (channelp->mLoopedThisFrame)
-				{
-					sourcep->mCurrentDatap = sourcep->mQueuedDatap;
-					sourcep->mQueuedDatap = NULL;
-
-					// Actually, should do a time sync so if we're a loop master/slave
-					// we don't drift away.
-					sourcep->setupChannel();
-					sourcep->getChannel()->play();
-				}
-			}
 		}
 	}
 
@@ -398,18 +400,11 @@ void LLAudioEngine::idle()
 	for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter)
 	{
 		LLAudioSource *sourcep = iter->second;
-		if (sourcep->isMuted())
-		{
-			continue;
-		}
-		if (sourcep->isSyncMaster())
+		if (!sourcep->isMuted() && sourcep->isSyncMaster() && sourcep->getPriority() > max_sm_priority)
 		{
-			if (sourcep->getPriority() > max_sm_priority)
-			{
-				sync_masterp = sourcep;
-				master_channelp = sync_masterp->getChannel();
-				max_sm_priority = sourcep->getPriority();
-			}
+			sync_masterp = sourcep;
+			master_channelp = sync_masterp->getChannel();
+			max_sm_priority = sourcep->getPriority();
 		}
 	}
 
@@ -739,7 +734,7 @@ F64 LLAudioEngine::mapWindVecToGain(LLVector3 wind_vec)
 	}
 
 	return (gain);
-} 
+}
 
 
 F64 LLAudioEngine::mapWindVecToPitch(LLVector3 wind_vec)
@@ -966,12 +961,11 @@ void LLAudioEngine::cleanupAudioSource(LLAudioSource *asp)
 	else
 	{
 		LL_DEBUGS("AudioEngine") << "Cleaning up audio sources for "<< asp->getID() <<LL_ENDL;
-	delete asp;
-	mAllSources.erase(iter);
-}
+		delete asp;
+		mAllSources.erase(iter);
+	}
 }
 
-
 bool LLAudioEngine::hasDecodedFile(const LLUUID &uuid)
 {
 	std::string uuid_str;
@@ -1690,20 +1684,19 @@ void LLAudioChannel::setSource(LLAudioSource *sourcep)
 	{
 		LL_DEBUGS("AudioEngine") << "( id: " << sourcep->getID() << ")" << LL_ENDL;
 
-	if (sourcep == mCurrentSourcep)
-	{
-		// Don't reallocate the channel, this will make FMOD goofy.
-		//LL_INFOS() << "Calling setSource with same source!" << LL_ENDL;
-	}
+		if (sourcep == mCurrentSourcep)
+		{
+			// Don't reallocate the channel, this will make FMOD goofy.
+			//LL_INFOS() << "Calling setSource with same source!" << LL_ENDL;
+		}
 
-	mCurrentSourcep = sourcep;
+		mCurrentSourcep = sourcep;
 
-	updateBuffer();
-	update3DPosition();
-}
+		updateBuffer();
+		update3DPosition();
+	}
 }
 
-
 bool LLAudioChannel::updateBuffer()
 {
 	if (!gAudiop)
diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h
index 0fe8b3d756..a133898969 100755
--- a/indra/llaudio/llaudioengine.h
+++ b/indra/llaudio/llaudioengine.h
@@ -90,6 +90,7 @@ public:
 	// initialization/startup/shutdown
 	virtual bool init(void *userdata, const std::string &app_title);
 	virtual std::string getDriverName(bool verbose) = 0;
+	virtual LLStreamingAudioInterface *createDefaultStreamingAudioImpl() const = 0;
 	virtual void shutdown();
 
 	// Used by the mechanics of the engine
@@ -468,13 +469,13 @@ struct SoundData
 		const LLUUID& owner_id, 
 		const F32 gain, 					  
 		const S32 type = LLAudioEngine::AUDIO_TYPE_NONE,
-		const LLVector3d &pos_global = LLVector3d::zero)
+		const LLVector3d &pos_global = LLVector3d::zero) :
+		audio_uuid(audio_uuid),
+		owner_id(owner_id),
+		gain(gain),
+		type(type),
+		pos_global(pos_global)
 	{
-		this->audio_uuid = audio_uuid;
-		this->owner_id = owner_id;
-		this->gain = gain;
-		this->type = type;
-		this->pos_global = pos_global;
 	}
 };
 
diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp
index ba743020b5..c6313ea289 100644
--- a/indra/llaudio/llaudioengine_fmodstudio.cpp
+++ b/indra/llaudio/llaudioengine_fmodstudio.cpp
@@ -208,10 +208,6 @@ bool LLAudioEngine_FMODSTUDIO::init(void* userdata, const std::string &app_title
     }
 #endif
 
-    // set up our favourite FMOD-native streaming audio implementation if none has already been added
-    if (!getStreamingAudioImpl()) // no existing implementation added
-        setStreamingAudioImpl(new LLStreamingAudio_FMODSTUDIO(mSystem));
-
     LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL;
 
     int r_numbuffers, r_samplerate, r_channels;
@@ -253,6 +249,13 @@ std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose)
 }
 
 
+// create our favourite FMOD-native streaming audio implementation
+LLStreamingAudioInterface *LLAudioEngine_FMODSTUDIO::createDefaultStreamingAudioImpl() const
+{
+    return new LLStreamingAudio_FMODSTUDIO(mSystem);
+}
+
+
 void LLAudioEngine_FMODSTUDIO::allocateListener(void)
 {
     mListenerp = (LLListener *) new LLListener_FMODSTUDIO(mSystem);
diff --git a/indra/llaudio/llaudioengine_fmodstudio.h b/indra/llaudio/llaudioengine_fmodstudio.h
index d3d6d69685..29e7bc6bf0 100644
--- a/indra/llaudio/llaudioengine_fmodstudio.h
+++ b/indra/llaudio/llaudioengine_fmodstudio.h
@@ -53,6 +53,7 @@ public:
 	// initialization/startup/shutdown
 	virtual bool init(void *user_data, const std::string &app_title);
 	virtual std::string getDriverName(bool verbose);
+	virtual LLStreamingAudioInterface* createDefaultStreamingAudioImpl() const;
 	virtual void allocateListener();
 
 	virtual void shutdown();
diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml
index e16a5c7e76..340334aee8 100644
--- a/indra/newview/app_settings/cmd_line.xml
+++ b/indra/newview/app_settings/cmd_line.xml
@@ -209,6 +209,12 @@
       <string>NoAudio</string>
     </map>
 
+    <key>nofmod</key>
+    <map>
+      <key>map-to</key>
+      <string>UseMediaPluginsForStreamingAudio</string>
+    </map>
+
     <key>noninteractive</key>
     <map>
       <key>desc</key>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 411f77e6a7..c6dca39c99 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -7077,6 +7077,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>UseMediaPluginsForStreamingAudio</key>
+    <map>
+      <key>Comment</key>
+      <string>Use media plugins (VLC) for streaming audio.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>NoHardwareProbe</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 6883ead5ee..9cebce2609 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -660,9 +660,22 @@ bool idle_startup()
 #else
 				void* window_handle = NULL;
 #endif
-				bool init = gAudiop->init(window_handle, LLAppViewer::instance()->getSecondLifeTitle());
-				if(init)
+				if (gAudiop->init(window_handle, LLAppViewer::instance()->getSecondLifeTitle()))
 				{
+					if (FALSE == gSavedSettings.getBOOL("UseMediaPluginsForStreamingAudio"))
+					{
+						LL_INFOS("AppInit") << "Using default impl to render streaming audio" << LL_ENDL;
+						gAudiop->setStreamingAudioImpl(gAudiop->createDefaultStreamingAudioImpl());
+					}
+
+					// if the audio engine hasn't set up its own preferred handler for streaming audio
+					// then set up the generic streaming audio implementation which uses media plugins
+					if (NULL == gAudiop->getStreamingAudioImpl())
+					{
+						LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL;
+						gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins());
+					}
+
 					gAudiop->setMuted(TRUE);
 				}
 				else
@@ -671,16 +684,6 @@ bool idle_startup()
 					delete gAudiop;
 					gAudiop = NULL;
 				}
-
-				if (gAudiop)
-				{
-					// if the audio engine hasn't set up its own preferred handler for streaming audio then set up the generic streaming audio implementation which uses media plugins
-					if (NULL == gAudiop->getStreamingAudioImpl())
-					{
-						LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL;
-						gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins());
-					}
-				}
 			}
 		}
 		
diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp
index cc73f7ca80..6a0edbecb1 100644
--- a/indra/newview/llvieweraudio.cpp
+++ b/indra/newview/llvieweraudio.cpp
@@ -91,17 +91,18 @@ void LLViewerAudio::startInternetStreamWithAutoFade(const std::string &streamURI
 		return;
 	}
 
-	// Record the URI we are going to be switching to	
+	if (!gAudiop)
+	{
+		LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL;
+		return;
+	}
+
+	// Record the URI we are going to be switching to
 	mNextStreamURI = streamURI;
 
 	switch (mFadeState)
 	{
 	case FADE_IDLE:
-		if (!gAudiop)
-		{
-			LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL;
-			break;
-		}
 		// If a stream is playing fade it out first
 		if (!gAudiop->getInternetStreamURL().empty())
 		{
@@ -114,28 +115,28 @@ void LLViewerAudio::startInternetStreamWithAutoFade(const std::string &streamURI
 			mFadeState = FADE_IN;
 
 			LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl();
-			if(stream && stream->supportsAdjustableBufferSizes())
-				stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize"));
+			if (stream && stream->supportsAdjustableBufferSizes())
+				stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"), gSavedSettings.getU32("FMODExDecodeBufferSize"));
 
 			gAudiop->startInternetStream(mNextStreamURI);
-			startFading();
-			registerIdleListener();
-			break;
 		}
 
+		startFading();
+		break;
+
 	case FADE_OUT:
 		startFading();
-		registerIdleListener();
 		break;
 
 	case FADE_IN:
-		registerIdleListener();
 		break;
 
 	default:
 		LL_WARNS() << "Unknown fading state: " << mFadeState << LL_ENDL;
-		break;
+		return;
 	}
+
+	registerIdleListener();
 }
 
 // A return of false from onIdleUpdate means it will be called again next idle update.
@@ -236,15 +237,12 @@ void LLViewerAudio::startFading()
 	// This minimum fade time prevents divide by zero and negative times
 	const F32 AUDIO_MUSIC_MINIMUM_FADE_TIME = 0.01f;
 
-	if(mDone)
+	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 = AUDIO_MUSIC_FADE_IN_TIME;
-		if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT)
-		{
-			mFadeTime = AUDIO_MUSIC_FADE_OUT_TIME;
-		}
+		mFadeTime = LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT ?
+			AUDIO_MUSIC_FADE_OUT_TIME : AUDIO_MUSIC_FADE_IN_TIME;
 
 		// Prevent invalid fade time
 		mFadeTime = llmax(mFadeTime, AUDIO_MUSIC_MINIMUM_FADE_TIME);
-- 
cgit v1.2.3