Fix "default" audio device handling.
Windows and Mac/Linux behave slightly differently with respect to Default devices, in that mac/linux (I think) simply assumes the device at index 0 is the default one, and windows has a separate API for enabling the default device.master
parent
c6e673cda1
commit
c826aea079
|
|
@ -40,6 +40,11 @@
|
|||
namespace llwebrtc
|
||||
{
|
||||
|
||||
static int16_t PLAYOUT_DEVICE_DEFAULT = -1;
|
||||
static int16_t PLAYOUT_DEVICE_BAD = -2;
|
||||
static int16_t RECORD_DEVICE_DEFAULT = -1;
|
||||
static int16_t RECORD_DEVICE_BAD = -2;
|
||||
|
||||
LLAudioDeviceObserver::LLAudioDeviceObserver() : mSumVector {0}, mMicrophoneEnergy(0.0) {}
|
||||
|
||||
float LLAudioDeviceObserver::getMicrophoneEnergy() { return mMicrophoneEnergy; }
|
||||
|
|
@ -189,10 +194,16 @@ void LLWebRTCImpl::init()
|
|||
std::unique_ptr<webrtc::AudioDeviceDataObserver>(mTuningAudioDeviceObserver));
|
||||
|
||||
mTuningDeviceModule->Init();
|
||||
mTuningDeviceModule->SetStereoRecording(true);
|
||||
mTuningDeviceModule->SetStereoPlayout(true);
|
||||
mTuningDeviceModule->SetPlayoutDevice(mPlayoutDevice);
|
||||
mTuningDeviceModule->SetRecordingDevice(mRecordingDevice);
|
||||
mTuningDeviceModule->EnableBuiltInAEC(false);
|
||||
mTuningDeviceModule->SetAudioDeviceSink(this);
|
||||
mTuningDeviceModule->InitMicrophone();
|
||||
mTuningDeviceModule->InitSpeaker();
|
||||
mTuningDeviceModule->InitRecording();
|
||||
mTuningDeviceModule->InitPlayout();
|
||||
mTuningDeviceModule->SetStereoRecording(true);
|
||||
mTuningDeviceModule->SetStereoPlayout(true);
|
||||
updateDevices();
|
||||
});
|
||||
|
||||
|
|
@ -207,13 +218,13 @@ void LLWebRTCImpl::init()
|
|||
mPeerDeviceModule->Init();
|
||||
mPeerDeviceModule->SetPlayoutDevice(mPlayoutDevice);
|
||||
mPeerDeviceModule->SetRecordingDevice(mRecordingDevice);
|
||||
mPeerDeviceModule->SetStereoRecording(true);
|
||||
mPeerDeviceModule->SetStereoPlayout(true);
|
||||
mPeerDeviceModule->EnableBuiltInAEC(false);
|
||||
mPeerDeviceModule->InitMicrophone();
|
||||
mPeerDeviceModule->InitSpeaker();
|
||||
mPeerDeviceModule->InitRecording();
|
||||
mPeerDeviceModule->InitPlayout();
|
||||
mPeerDeviceModule->SetStereoRecording(true);
|
||||
mPeerDeviceModule->SetStereoPlayout(true);
|
||||
});
|
||||
|
||||
// The custom processor allows us to retrieve audio data (and levels)
|
||||
|
|
@ -375,145 +386,169 @@ void LLWebRTCImpl::unsetDevicesObserver(LLWebRTCDevicesObserver *observer)
|
|||
}
|
||||
}
|
||||
|
||||
static int16_t ll_get_device_module_capture_device(rtc::scoped_refptr<webrtc::AudioDeviceModule> device_module, const std::string &id)
|
||||
{
|
||||
int16_t recordingDevice = 0;
|
||||
int16_t captureDeviceCount = device_module->RecordingDevices();
|
||||
for (int16_t i = 0; i < captureDeviceCount; i++)
|
||||
{
|
||||
char name[webrtc::kAdmMaxDeviceNameSize];
|
||||
char guid[webrtc::kAdmMaxGuidSize];
|
||||
device_module->RecordingDeviceName(i, name, guid);
|
||||
if (id == guid || id == "Default") // first one in list is default
|
||||
{
|
||||
RTC_LOG(LS_INFO) << __FUNCTION__ << "Set recording device to " << name << " " << guid << " " << i;
|
||||
recordingDevice = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return recordingDevice;
|
||||
}
|
||||
|
||||
void ll_set_device_module_capture_device(rtc::scoped_refptr<webrtc::AudioDeviceModule> device_module, int16_t device)
|
||||
{
|
||||
device_module->StopRecording();
|
||||
device_module->SetRecordingDevice(device);
|
||||
#if LL_WINDOWS
|
||||
if (device < 0)
|
||||
{
|
||||
device_module->SetRecordingDevice(webrtc::AudioDeviceModule::kDefaultDevice);
|
||||
}
|
||||
else
|
||||
{
|
||||
device_module->SetRecordingDevice(device);
|
||||
}
|
||||
#else
|
||||
// passed in default is -1, but the device list
|
||||
// has it at 0
|
||||
device_module->SetPlayoutDevice(device + 1);
|
||||
#endif
|
||||
device_module->InitMicrophone();
|
||||
device_module->SetStereoRecording(false);
|
||||
device_module->InitRecording();
|
||||
device_module->SetStereoRecording(false);
|
||||
device_module->StartRecording();
|
||||
}
|
||||
|
||||
void LLWebRTCImpl::setCaptureDevice(const std::string &id)
|
||||
{
|
||||
|
||||
mWorkerThread->PostTask(
|
||||
[this, id]()
|
||||
{
|
||||
int16_t recordingDevice = ll_get_device_module_capture_device(mTuningDeviceModule, id);
|
||||
if (recordingDevice != mRecordingDevice)
|
||||
{
|
||||
mRecordingDevice = recordingDevice;
|
||||
if (mTuningMode)
|
||||
{
|
||||
ll_set_device_module_capture_device(mTuningDeviceModule, recordingDevice);
|
||||
}
|
||||
else
|
||||
{
|
||||
ll_set_device_module_capture_device(mPeerDeviceModule, recordingDevice);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static int16_t ll_get_device_module_render_device(
|
||||
rtc::scoped_refptr<webrtc::AudioDeviceModule> device_module,
|
||||
const std::string &id)
|
||||
{
|
||||
int16_t playoutDevice = 0;
|
||||
int16_t playoutDeviceCount = device_module->PlayoutDevices();
|
||||
for (int16_t i = 0; i < playoutDeviceCount; i++)
|
||||
int16_t recordingDevice = RECORD_DEVICE_DEFAULT;
|
||||
if (id != "Default")
|
||||
{
|
||||
char name[webrtc::kAdmMaxDeviceNameSize];
|
||||
char guid[webrtc::kAdmMaxGuidSize];
|
||||
device_module->PlayoutDeviceName(i, name, guid);
|
||||
if (id == guid || id == "Default") // first one in list is default
|
||||
for (int16_t i = 0; i < mRecordingDeviceList.size(); i++)
|
||||
{
|
||||
RTC_LOG(LS_INFO) << __FUNCTION__ << "Set recording device to " << name << " " << guid << " " << i;
|
||||
playoutDevice = i;
|
||||
break;
|
||||
if (mRecordingDeviceList[i].mID == id)
|
||||
{
|
||||
recordingDevice = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return playoutDevice;
|
||||
if (recordingDevice == mRecordingDevice)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mRecordingDevice = recordingDevice;
|
||||
if (mTuningMode)
|
||||
{
|
||||
mWorkerThread->PostTask([this, recordingDevice]() { ll_set_device_module_capture_device(mTuningDeviceModule, recordingDevice); });
|
||||
}
|
||||
else
|
||||
{
|
||||
mWorkerThread->PostTask([this, recordingDevice]() { ll_set_device_module_capture_device(mPeerDeviceModule, recordingDevice); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ll_set_device_module_render_device(rtc::scoped_refptr<webrtc::AudioDeviceModule> device_module, int16_t device)
|
||||
{
|
||||
device_module->StopPlayout();
|
||||
device_module->SetPlayoutDevice(device);
|
||||
#if LL_WINDOWS
|
||||
if (device < 0)
|
||||
{
|
||||
device_module->SetPlayoutDevice(webrtc::AudioDeviceModule::kDefaultDevice);
|
||||
}
|
||||
else
|
||||
{
|
||||
device_module->SetPlayoutDevice(device);
|
||||
}
|
||||
#else
|
||||
device_module->SetPlayoutDevice(device + 1);
|
||||
#endif
|
||||
device_module->InitSpeaker();
|
||||
device_module->SetStereoPlayout(false);
|
||||
device_module->InitPlayout();
|
||||
device_module->StartPlayout();
|
||||
device_module->SetStereoPlayout(true);
|
||||
}
|
||||
|
||||
void LLWebRTCImpl::setRenderDevice(const std::string &id)
|
||||
{
|
||||
mWorkerThread->PostTask(
|
||||
[this, id]()
|
||||
{
|
||||
int16_t playoutDevice = ll_get_device_module_render_device(mTuningDeviceModule, id);
|
||||
if (playoutDevice != mPlayoutDevice)
|
||||
int16_t playoutDevice = PLAYOUT_DEVICE_DEFAULT;
|
||||
if (id != "Default")
|
||||
{
|
||||
for (int16_t i = 0; i < mPlayoutDeviceList.size(); i++)
|
||||
{
|
||||
if (mPlayoutDeviceList[i].mID == id)
|
||||
{
|
||||
mPlayoutDevice = playoutDevice;
|
||||
if (mTuningMode)
|
||||
{
|
||||
ll_set_device_module_render_device(mTuningDeviceModule, playoutDevice);
|
||||
}
|
||||
else
|
||||
{
|
||||
ll_set_device_module_render_device(mPeerDeviceModule, playoutDevice);
|
||||
}
|
||||
playoutDevice = i;
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (playoutDevice == mPlayoutDevice)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mPlayoutDevice = playoutDevice;
|
||||
|
||||
if (mTuningMode)
|
||||
{
|
||||
mWorkerThread->PostTask(
|
||||
[this, playoutDevice]()
|
||||
{
|
||||
ll_set_device_module_render_device(mTuningDeviceModule, playoutDevice);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
mWorkerThread->PostTask(
|
||||
[this, playoutDevice]()
|
||||
{
|
||||
ll_set_device_module_render_device(mPeerDeviceModule, playoutDevice);
|
||||
mPeerDeviceModule->StartPlayout();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// updateDevices needs to happen on the worker thread.
|
||||
void LLWebRTCImpl::updateDevices()
|
||||
{
|
||||
int16_t renderDeviceCount = mTuningDeviceModule->PlayoutDevices();
|
||||
int16_t currentRenderDeviceIndex = mTuningDeviceModule->GetPlayoutDevice();
|
||||
int16_t renderDeviceCount = mTuningDeviceModule->PlayoutDevices();
|
||||
|
||||
LLWebRTCVoiceDeviceList renderDeviceList;
|
||||
for (int16_t index = 0; index < renderDeviceCount; index++)
|
||||
mPlayoutDeviceList.clear();
|
||||
#if LL_WINDOWS
|
||||
int16_t index = 0;
|
||||
#else
|
||||
// index zero is always "Default" for darwin/linux,
|
||||
// which is a special case, so skip it.
|
||||
int16_t index = 1;
|
||||
#endif
|
||||
for (; index < renderDeviceCount; index++)
|
||||
{
|
||||
char name[webrtc::kAdmMaxDeviceNameSize];
|
||||
char guid[webrtc::kAdmMaxGuidSize];
|
||||
mTuningDeviceModule->PlayoutDeviceName(index, name, guid);
|
||||
renderDeviceList.emplace_back(name, guid);
|
||||
mPlayoutDeviceList.emplace_back(name, guid);
|
||||
}
|
||||
|
||||
int16_t captureDeviceCount = mTuningDeviceModule->RecordingDevices();
|
||||
int16_t currentCaptureDeviceIndex = mTuningDeviceModule->GetRecordingDevice();
|
||||
int16_t captureDeviceCount = mTuningDeviceModule->RecordingDevices();
|
||||
|
||||
LLWebRTCVoiceDeviceList captureDeviceList;
|
||||
for (int16_t index = 0; index < captureDeviceCount; index++)
|
||||
mRecordingDeviceList.clear();
|
||||
#if LL_WINDOWS
|
||||
index = 0;
|
||||
#else
|
||||
// index zero is always "Default" for darwin/linux,
|
||||
// which is a special case, so skip it.
|
||||
index = 1;
|
||||
#endif
|
||||
for (; index < captureDeviceCount; index++)
|
||||
{
|
||||
char name[webrtc::kAdmMaxDeviceNameSize];
|
||||
char guid[webrtc::kAdmMaxGuidSize];
|
||||
mTuningDeviceModule->RecordingDeviceName(index, name, guid);
|
||||
captureDeviceList.emplace_back(name, guid);
|
||||
mRecordingDeviceList.emplace_back(name, guid);
|
||||
}
|
||||
|
||||
for (auto &observer : mVoiceDevicesObserverList)
|
||||
{
|
||||
observer->OnDevicesChanged(renderDeviceList,
|
||||
captureDeviceList);
|
||||
observer->OnDevicesChanged(mPlayoutDeviceList, mRecordingDeviceList);
|
||||
}
|
||||
}
|
||||
|
||||
void LLWebRTCImpl::OnDevicesUpdated()
|
||||
{
|
||||
// reset these to a bad value so an update is forced
|
||||
mRecordingDevice = RECORD_DEVICE_BAD;
|
||||
mPlayoutDevice = PLAYOUT_DEVICE_BAD;
|
||||
|
||||
updateDevices();
|
||||
}
|
||||
|
||||
|
|
@ -529,17 +564,24 @@ void LLWebRTCImpl::setTuningMode(bool enable)
|
|||
mPeerDeviceModule->StopPlayout();
|
||||
ll_set_device_module_render_device(mTuningDeviceModule, mPlayoutDevice);
|
||||
ll_set_device_module_capture_device(mTuningDeviceModule, mRecordingDevice);
|
||||
mTuningDeviceModule->InitPlayout();
|
||||
mTuningDeviceModule->InitRecording();
|
||||
mTuningDeviceModule->StartRecording();
|
||||
mTuningDeviceModule->StartPlayout();
|
||||
// TODO: Starting Playout on the TDM appears to create an audio artifact (click)
|
||||
// in this case, so disabling it for now. We may have to do something different
|
||||
// if we enable 'echo playback' via the TDM when tuning.
|
||||
//mTuningDeviceModule->StartPlayout();
|
||||
}
|
||||
else
|
||||
{
|
||||
mTuningDeviceModule->StopRecording();
|
||||
mTuningDeviceModule->StopPlayout();
|
||||
//mTuningDeviceModule->StopPlayout();
|
||||
ll_set_device_module_render_device(mPeerDeviceModule, mPlayoutDevice);
|
||||
ll_set_device_module_capture_device(mPeerDeviceModule, mRecordingDevice);
|
||||
mPeerDeviceModule->StartRecording();
|
||||
mPeerDeviceModule->InitPlayout();
|
||||
mPeerDeviceModule->InitRecording();
|
||||
mPeerDeviceModule->StartPlayout();
|
||||
mPeerDeviceModule->StartRecording();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -244,8 +244,12 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS
|
|||
|
||||
// accessors in native webrtc for devices aren't apparently implemented yet.
|
||||
bool mTuningMode;
|
||||
int32_t mPlayoutDevice;
|
||||
int32_t mRecordingDevice;
|
||||
LLWebRTCVoiceDeviceList mRecordingDeviceList;
|
||||
|
||||
int32_t mPlayoutDevice;
|
||||
LLWebRTCVoiceDeviceList mPlayoutDeviceList;
|
||||
|
||||
bool mMute;
|
||||
|
||||
LLAudioDeviceObserver * mTuningAudioDeviceObserver;
|
||||
|
|
|
|||
|
|
@ -294,19 +294,31 @@ void LLWebRTCVoiceClient::updateSettings()
|
|||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE
|
||||
|
||||
setVoiceEnabled(LLVoiceClient::getInstance()->voiceEnabled());
|
||||
setEarLocation(gSavedSettings.getS32("VoiceEarLocation"));
|
||||
static LLCachedControl<S32> sVoiceEarLocation(gSavedSettings, "VoiceEarLocation");
|
||||
setEarLocation(sVoiceEarLocation);
|
||||
|
||||
static LLCachedControl<std::string> sInputDevice(gSavedSettings, "VoiceInputAudioDevice");
|
||||
setCaptureDevice(sInputDevice);
|
||||
|
||||
static LLCachedControl<std::string> sOutputDevice(gSavedSettings, "VoiceOutputAudioDevice");
|
||||
setRenderDevice(sOutputDevice);
|
||||
|
||||
static LLCachedControl<F32> sMicLevel(gSavedSettings, "AudioLevelMic");
|
||||
setMicGain(sMicLevel);
|
||||
|
||||
std::string inputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
|
||||
setCaptureDevice(inputDevice);
|
||||
std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
|
||||
setRenderDevice(outputDevice);
|
||||
F32 mic_level = gSavedSettings.getF32("AudioLevelMic");
|
||||
setMicGain(mic_level);
|
||||
|
||||
llwebrtc::LLWebRTCDeviceInterface::AudioConfig config;
|
||||
config.mEchoCancellation = gSavedSettings.getBOOL("VoiceEchoCancellation");
|
||||
config.mAGC = gSavedSettings.getBOOL("VoiceAutomaticGainControl");
|
||||
config.mNoiseSuppressionLevel = (llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel)gSavedSettings.getU32("VoiceNoiseSuppressionLevel");
|
||||
|
||||
static LLCachedControl<bool> sEchoCancellation(gSavedSettings, "VoiceEchoCancellation", true);
|
||||
config.mEchoCancellation = sEchoCancellation;
|
||||
|
||||
static LLCachedControl<bool> sAGC(gSavedSettings, "VoiceAutomaticGainControl", true);
|
||||
config.mAGC = sAGC;
|
||||
|
||||
static LLCachedControl<U32> sNoiseSuppressionLevel(gSavedSettings,
|
||||
"VoiceNoiseSuppressionLevel",
|
||||
llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel::NOISE_SUPPRESSION_LEVEL_VERY_HIGH);
|
||||
config.mNoiseSuppressionLevel = (llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel) (U32)sNoiseSuppressionLevel;
|
||||
|
||||
mWebRTCDeviceInterface->setAudioConfig(config);
|
||||
|
||||
}
|
||||
|
|
@ -607,6 +619,7 @@ void LLWebRTCVoiceClient::setDevicesListUpdated(bool state)
|
|||
void LLWebRTCVoiceClient::OnDevicesChanged(const llwebrtc::LLWebRTCVoiceDeviceList& render_devices,
|
||||
const llwebrtc::LLWebRTCVoiceDeviceList& capture_devices)
|
||||
{
|
||||
|
||||
LL::WorkQueue::postMaybe(mMainQueue,
|
||||
[=]
|
||||
{
|
||||
|
|
@ -618,43 +631,25 @@ void LLWebRTCVoiceClient::OnDevicesChangedImpl(const llwebrtc::LLWebRTCVoiceDevi
|
|||
const llwebrtc::LLWebRTCVoiceDeviceList &capture_devices)
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE
|
||||
|
||||
std::string inputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
|
||||
std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
|
||||
|
||||
LL_DEBUGS("Voice") << "Setting devices to-input: '" << inputDevice << "' output: '" << outputDevice << "'" << LL_ENDL;
|
||||
clearRenderDevices();
|
||||
bool renderDeviceSet = false;
|
||||
for (auto &device : render_devices)
|
||||
{
|
||||
addRenderDevice(LLVoiceDevice(device.mDisplayName, device.mID));
|
||||
LL_DEBUGS("Voice") << "Checking render device" << "'" << device.mID << "'" << LL_ENDL;
|
||||
if (outputDevice == device.mID)
|
||||
{
|
||||
renderDeviceSet = true;
|
||||
}
|
||||
}
|
||||
if (!renderDeviceSet)
|
||||
{
|
||||
setRenderDevice("Default");
|
||||
}
|
||||
setRenderDevice(outputDevice);
|
||||
|
||||
clearCaptureDevices();
|
||||
bool captureDeviceSet = false;
|
||||
for (auto &device : capture_devices)
|
||||
{
|
||||
LL_DEBUGS("Voice") << "Checking capture device:'" << device.mID << "'" << LL_ENDL;
|
||||
|
||||
addCaptureDevice(LLVoiceDevice(device.mDisplayName, device.mID));
|
||||
if (inputDevice == device.mID)
|
||||
{
|
||||
captureDeviceSet = true;
|
||||
}
|
||||
}
|
||||
if (!captureDeviceSet)
|
||||
{
|
||||
setCaptureDevice("Default");
|
||||
}
|
||||
setCaptureDevice(inputDevice);
|
||||
|
||||
setDevicesListUpdated(true);
|
||||
}
|
||||
|
|
@ -1559,10 +1554,13 @@ F32 LLWebRTCVoiceClient::getUserVolume(const LLUUID& id)
|
|||
// Minimum volume will be returned for users with voice disabled
|
||||
F32 result = LLVoiceClient::VOLUME_MIN;
|
||||
|
||||
participantStatePtr_t participant(mSession->findParticipantByID(id));
|
||||
if(participant)
|
||||
if (mSession)
|
||||
{
|
||||
result = participant->mVolume;
|
||||
participantStatePtr_t participant(mSession->findParticipantByID(id));
|
||||
if (participant)
|
||||
{
|
||||
result = participant->mVolume;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
Loading…
Reference in New Issue