diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp
index 1eb3676e01..db34ffc19e 100644
--- a/indra/llaudio/llaudioengine_fmodex.cpp
+++ b/indra/llaudio/llaudioengine_fmodex.cpp
@@ -48,42 +48,77 @@
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
-// FIRE-11266 / BUG-3549 / MAINT-2983: Changing audio device now requires relog to restore sounds
-#if LL_WINDOWS
+// Output device selection
+static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string);
+
+LLUUID FMOD_GUID_to_LLUUID(FMOD_GUID guid)
+{
+ return LLUUID(llformat("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid.Data1, guid.Data2, guid.Data3,
+ guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]));
+}
+
+void set_device(FMOD::System* system, const LLUUID& device_uuid)
+{
+ LL_INFOS() << "LLAudioEngine_FMODEX::setDevice with device_uuid=" << device_uuid << LL_ENDL;
+
+ int drivercount;
+ if (!Check_FMOD_Error(system->getNumDrivers(&drivercount), "FMOD::System::getNumDrivers") && drivercount > 0)
+ {
+ if (device_uuid.isNull())
+ {
+ LL_INFOS() << "Setting driver \"Default\"" << LL_ENDL;
+ Check_FMOD_Error(system->setDriver(0), "FMOD::System::setDriver");
+ }
+ else
+ {
+ FMOD_GUID guid;
+
+ for (int i = 0; i < drivercount; ++i)
+ {
+ system->getDriverInfo(i, NULL, 0, &guid);
+ LLUUID driver_guid = FMOD_GUID_to_LLUUID(guid);
+
+ if (driver_guid == device_uuid)
+ {
+ LL_INFOS() << "Setting driver " << i << ": " << driver_guid << LL_ENDL;
+ Check_FMOD_Error(system->setDriver(i), "FMOD::System::setDriver");
+ return;
+ }
+ }
+
+ LL_INFOS() << "Device not available (anymore) - falling back to default" << LL_ENDL;
+ Check_FMOD_Error(system->setDriver(0), "FMOD::System::setDriver");
+ }
+ }
+}
+
FMOD_RESULT F_CALLBACK systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACKTYPE type, void *commanddata1, void *commanddata2)
{
- FMOD::System *sys = (FMOD::System *)system;
- FMOD_RESULT result;
+ FMOD::System* sys = (FMOD::System*)system;
+ LLAudioEngine_FMODEX* audio_engine = NULL;
+ if (sys)
+ {
+ void* userdata = NULL;
+ Check_FMOD_Error(sys->getUserData(&userdata), "FMOD::System::getUserData");
+ audio_engine = (LLAudioEngine_FMODEX*)userdata;
+ }
+
switch (type)
{
case FMOD_SYSTEM_CALLBACKTYPE_DEVICELISTCHANGED:
- {
- int drivers;
- sys->getNumDrivers(&drivers);
-
- if (drivers <= 0)
+ LL_DEBUGS() << "FMOD system callback FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED" << LL_ENDL;
+ if (sys && audio_engine)
{
- break;
- }
-
- for (int i = 0; i < drivers; ++i)
- {
- result = sys->setDriver(i);
- if (result == FMOD_OK)
- {
- break;
- }
+ set_device(sys, audio_engine->getSelectedDeviceUUID());
+ audio_engine->OnOutputDeviceListChanged(audio_engine->getDevices());
}
break;
- }
-
default:
break;
}
return FMOD_OK;
}
-#endif
-//
+// >
FMOD::ChannelGroup *LLAudioEngine_FMODEX::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0};
@@ -95,6 +130,7 @@ LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler)
mSystem = NULL;
mEnableProfiler = enable_profiler;
mWindDSPDesc = new FMOD_DSP_DESCRIPTION();
+ mSelectedDeviceUUID == LLUUID::null; // Output device selection
}
@@ -182,12 +218,10 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
result = mSystem->setSoftwareChannels(num_channels + 2);
Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels");
- // FIRE-11266 / BUG-3549 / MAINT-2983: Changing audio device now requires relog to restore sounds
- #if LL_WINDOWS
- result = mSystem->setCallback(systemCallback);
- Check_FMOD_Error(result, "FMOD::System::setCallback");
- #endif
- //
+ // Output device selection
+ Check_FMOD_Error(mSystem->setCallback(systemCallback), "FMOD::System::setCallback");
+ Check_FMOD_Error(mSystem->setUserData(this), "FMOD::System::setUserData");
+ //
U32 fmod_flags = FMOD_INIT_NORMAL;
if(mEnableProfiler)
@@ -369,9 +403,45 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): initialization complete." << LL_ENDL;
+ // Output device selection
+ getDevices(); // Purely to print out available devices for debugging reasons
+
return true;
}
+// Output device selection
+//virtual
+LLAudioEngine_FMODEX::output_device_map_t LLAudioEngine_FMODEX::getDevices()
+{
+ output_device_map_t driver_map;
+
+ int drivercount;
+ char r_name[512];
+ FMOD_GUID guid;
+
+ if (!Check_FMOD_Error(mSystem->getNumDrivers(&drivercount), "FMOD::System::getNumDrivers"))
+ {
+ for (int i = 0; i < drivercount; ++i)
+ {
+ memset(r_name, 0, 512);
+ mSystem->getDriverInfo(i, r_name, 511, &guid);
+ LLUUID driver_guid = FMOD_GUID_to_LLUUID(guid);
+ driver_map.insert(std::make_pair(driver_guid, r_name));
+
+ LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::getDevices(): r_name=\"" << r_name << "\" - guid: " << driver_guid << LL_ENDL;
+ }
+ }
+
+ return driver_map;
+}
+
+//virtual
+void LLAudioEngine_FMODEX::setDevice(const LLUUID& device_uuid)
+{
+ mSelectedDeviceUUID = device_uuid;
+ set_device(mSystem, device_uuid);
+}
+//
std::string LLAudioEngine_FMODEX::getDriverName(bool verbose)
{
diff --git a/indra/llaudio/llaudioengine_fmodex.h b/indra/llaudio/llaudioengine_fmodex.h
index ca389d489f..d0de2d602a 100644
--- a/indra/llaudio/llaudioengine_fmodex.h
+++ b/indra/llaudio/llaudioengine_fmodex.h
@@ -65,6 +65,14 @@ public:
typedef F32 MIXBUFFERFORMAT;
FMOD::System *getSystem() const {return mSystem;}
+
+ // Output device selection
+ /*virtual*/ std::map getDevices();
+ /*virtual*/ void setDevice(const LLUUID& device_uuid);
+
+ LLUUID getSelectedDeviceUUID() const { return mSelectedDeviceUUID; }
+ //
+
protected:
/*virtual*/ LLAudioBuffer *createBuffer(); // Get a free buffer, or flush an existing one if you have to.
/*virtual*/ LLAudioChannel *createChannel(); // Create a new audio channel.
@@ -80,6 +88,9 @@ protected:
FMOD::System *mSystem;
bool mEnableProfiler;
+ // Output device selection
+ LLUUID mSelectedDeviceUUID;
+
public:
static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT];
};
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index ddc3ef675c..23f74eba39 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -5952,7 +5952,7 @@ BOOL FSPanelPreferenceSounds::postBuild()
mOutputDevicePanel = findChild("output_device_settings_panel");
mOutputDeviceComboBox = findChild("sound_output_device");
-#ifdef LL_FMODSTUDIO
+#if LL_FMODSTUDIO || LL_FMODEX
if (gAudiop && mOutputDevicePanel && mOutputDeviceComboBox)
{
gSavedSettings.getControl("FSOutputDeviceUUID")->getSignal()->connect(boost::bind(&FSPanelPreferenceSounds::onOutputDeviceChanged, this, _2));