mirror of
https://github.com/overte-org/overte.git
synced 2025-07-26 01:36:55 +02:00
Merge branch 'config-pucks' into vive-head-input
This commit is contained in:
commit
2ee71d3002
4 changed files with 85 additions and 74 deletions
|
@ -1688,7 +1688,6 @@ void Application::updateHeartbeat() const {
|
||||||
|
|
||||||
void Application::aboutToQuit() {
|
void Application::aboutToQuit() {
|
||||||
emit beforeAboutToQuit();
|
emit beforeAboutToQuit();
|
||||||
DependencyManager::get<AudioClient>()->beforeAboutToQuit();
|
|
||||||
|
|
||||||
foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
|
foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
|
||||||
if (inputPlugin->isActive()) {
|
if (inputPlugin->isActive()) {
|
||||||
|
@ -1789,14 +1788,13 @@ void Application::cleanupBeforeQuit() {
|
||||||
_snapshotSoundInjector->stop();
|
_snapshotSoundInjector->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop audio after QML, as there are unexplained audio crashes originating in qtwebengine
|
// FIXME: something else is holding a reference to AudioClient,
|
||||||
|
// so it must be explicitly synchronously stopped here
|
||||||
// stop the AudioClient, synchronously
|
|
||||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(),
|
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(),
|
||||||
"stop", Qt::BlockingQueuedConnection);
|
"cleanupBeforeQuit", Qt::BlockingQueuedConnection);
|
||||||
|
|
||||||
|
|
||||||
// destroy Audio so it and its threads have a chance to go down safely
|
// destroy Audio so it and its threads have a chance to go down safely
|
||||||
|
// this must happen after QML, as there are unexplained audio crashes originating in qtwebengine
|
||||||
DependencyManager::destroy<AudioClient>();
|
DependencyManager::destroy<AudioClient>();
|
||||||
DependencyManager::destroy<AudioInjectorManager>();
|
DependencyManager::destroy<AudioInjectorManager>();
|
||||||
|
|
||||||
|
|
|
@ -76,42 +76,58 @@ using Mutex = std::mutex;
|
||||||
using Lock = std::unique_lock<Mutex>;
|
using Lock = std::unique_lock<Mutex>;
|
||||||
static Mutex _deviceMutex;
|
static Mutex _deviceMutex;
|
||||||
|
|
||||||
// background thread that continuously polls for device changes
|
class BackgroundThread : public QThread {
|
||||||
class CheckDevicesThread : public QThread {
|
|
||||||
public:
|
public:
|
||||||
const unsigned long DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000;
|
BackgroundThread(AudioClient* client) : QThread((QObject*)client), _client(client) {}
|
||||||
|
virtual void join() = 0;
|
||||||
|
protected:
|
||||||
|
AudioClient* _client;
|
||||||
|
};
|
||||||
|
|
||||||
CheckDevicesThread(AudioClient* audioClient)
|
// background thread continuously polling device changes
|
||||||
: _audioClient(audioClient) {
|
class CheckDevicesThread : public BackgroundThread {
|
||||||
}
|
public:
|
||||||
|
CheckDevicesThread(AudioClient* client) : BackgroundThread(client) {}
|
||||||
void beforeAboutToQuit() {
|
|
||||||
Lock lock(_checkDevicesMutex);
|
void join() override {
|
||||||
_quit = true;
|
_shouldQuit = true;
|
||||||
|
std::unique_lock<std::mutex> lock(_joinMutex);
|
||||||
|
_joinCondition.wait(lock, [&]{ return !_isRunning; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
void run() override {
|
void run() override {
|
||||||
while (true) {
|
while (!_shouldQuit) {
|
||||||
{
|
_client->checkDevices();
|
||||||
Lock lock(_checkDevicesMutex);
|
|
||||||
if (_quit) {
|
const unsigned long DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000;
|
||||||
break;
|
|
||||||
}
|
|
||||||
_audioClient->checkDevices();
|
|
||||||
}
|
|
||||||
QThread::msleep(DEVICE_CHECK_INTERVAL_MSECS);
|
QThread::msleep(DEVICE_CHECK_INTERVAL_MSECS);
|
||||||
}
|
}
|
||||||
|
std::lock_guard<std::mutex> lock(_joinMutex);
|
||||||
|
_isRunning = false;
|
||||||
|
_joinCondition.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AudioClient* _audioClient { nullptr };
|
std::atomic<bool> _shouldQuit { false };
|
||||||
Mutex _checkDevicesMutex;
|
bool _isRunning { true };
|
||||||
bool _quit { false };
|
std::mutex _joinMutex;
|
||||||
|
std::condition_variable _joinCondition;
|
||||||
};
|
};
|
||||||
|
|
||||||
void AudioInjectorsThread::prepare() {
|
// background thread buffering local injectors
|
||||||
_audio->prepareLocalAudioInjectors();
|
class LocalInjectorsThread : public BackgroundThread {
|
||||||
}
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
LocalInjectorsThread(AudioClient* client) : BackgroundThread(client) {}
|
||||||
|
|
||||||
|
void join() override { return; }
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void prepare() { _client->prepareLocalAudioInjectors(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "AudioClient.moc"
|
||||||
|
|
||||||
static void channelUpmix(int16_t* source, int16_t* dest, int numSamples, int numExtraChannels) {
|
static void channelUpmix(int16_t* source, int16_t* dest, int numSamples, int numExtraChannels) {
|
||||||
for (int i = 0; i < numSamples/2; i++) {
|
for (int i = 0; i < numSamples/2; i++) {
|
||||||
|
@ -179,7 +195,6 @@ AudioClient::AudioClient() :
|
||||||
_inputToNetworkResampler(NULL),
|
_inputToNetworkResampler(NULL),
|
||||||
_networkToOutputResampler(NULL),
|
_networkToOutputResampler(NULL),
|
||||||
_localToOutputResampler(NULL),
|
_localToOutputResampler(NULL),
|
||||||
_localAudioThread(this),
|
|
||||||
_audioLimiter(AudioConstants::SAMPLE_RATE, OUTPUT_CHANNEL_COUNT),
|
_audioLimiter(AudioConstants::SAMPLE_RATE, OUTPUT_CHANNEL_COUNT),
|
||||||
_outgoingAvatarAudioSequenceNumber(0),
|
_outgoingAvatarAudioSequenceNumber(0),
|
||||||
_audioOutputIODevice(_localInjectorsStream, _receivedAudioStream, this),
|
_audioOutputIODevice(_localInjectorsStream, _receivedAudioStream, this),
|
||||||
|
@ -210,13 +225,14 @@ AudioClient::AudioClient() :
|
||||||
|
|
||||||
// start a thread to detect any device changes
|
// start a thread to detect any device changes
|
||||||
_checkDevicesThread = new CheckDevicesThread(this);
|
_checkDevicesThread = new CheckDevicesThread(this);
|
||||||
_checkDevicesThread->setObjectName("CheckDevices Thread");
|
_checkDevicesThread->setObjectName("AudioClient CheckDevices Thread");
|
||||||
_checkDevicesThread->setPriority(QThread::LowPriority);
|
_checkDevicesThread->setPriority(QThread::LowPriority);
|
||||||
_checkDevicesThread->start();
|
_checkDevicesThread->start();
|
||||||
|
|
||||||
// start a thread to process local injectors
|
// start a thread to process local injectors
|
||||||
_localAudioThread.setObjectName("LocalAudio Thread");
|
_localInjectorsThread = new LocalInjectorsThread(this);
|
||||||
_localAudioThread.start();
|
_localInjectorsThread->setObjectName("AudioClient LocalInjectors Thread");
|
||||||
|
_localInjectorsThread->start();
|
||||||
|
|
||||||
configureReverb();
|
configureReverb();
|
||||||
|
|
||||||
|
@ -231,18 +247,32 @@ AudioClient::AudioClient() :
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioClient::~AudioClient() {
|
AudioClient::~AudioClient() {
|
||||||
delete _checkDevicesThread;
|
|
||||||
stop();
|
|
||||||
if (_codec && _encoder) {
|
if (_codec && _encoder) {
|
||||||
_codec->releaseEncoder(_encoder);
|
_codec->releaseEncoder(_encoder);
|
||||||
_encoder = nullptr;
|
_encoder = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::beforeAboutToQuit() {
|
void AudioClient::customDeleter() {
|
||||||
static_cast<CheckDevicesThread*>(_checkDevicesThread)->beforeAboutToQuit();
|
deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioClient::cleanupBeforeQuit() {
|
||||||
|
// FIXME: this should be put in customDeleter, but there is still a reference to this when it is called,
|
||||||
|
// so this must be explicitly, synchronously stopped
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
if (_checkDevicesThread) {
|
||||||
|
static_cast<BackgroundThread*>(_checkDevicesThread)->join();
|
||||||
|
delete _checkDevicesThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_localInjectorsThread) {
|
||||||
|
static_cast<BackgroundThread*>(_localInjectorsThread)->join();
|
||||||
|
delete _localInjectorsThread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AudioClient::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) {
|
void AudioClient::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) {
|
||||||
qCDebug(audioclient) << __FUNCTION__ << "sendingNode:" << *node << "currentCodec:" << currentCodec << "recievedCodec:" << recievedCodec;
|
qCDebug(audioclient) << __FUNCTION__ << "sendingNode:" << *node << "currentCodec:" << currentCodec << "recievedCodec:" << recievedCodec;
|
||||||
|
@ -1328,7 +1358,7 @@ bool AudioClient::outputLocalInjector(AudioInjector* injector) {
|
||||||
|
|
||||||
// move local buffer to the LocalAudioThread to avoid dataraces with AudioInjector (like stop())
|
// move local buffer to the LocalAudioThread to avoid dataraces with AudioInjector (like stop())
|
||||||
injectorBuffer->setParent(nullptr);
|
injectorBuffer->setParent(nullptr);
|
||||||
injectorBuffer->moveToThread(&_localAudioThread);
|
injectorBuffer->moveToThread(_localInjectorsThread);
|
||||||
} else {
|
} else {
|
||||||
qCDebug(audioclient) << "injector exists in active list already";
|
qCDebug(audioclient) << "injector exists in active list already";
|
||||||
}
|
}
|
||||||
|
@ -1530,8 +1560,8 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice
|
||||||
_outputScratchBuffer = new int16_t[_outputPeriod];
|
_outputScratchBuffer = new int16_t[_outputPeriod];
|
||||||
|
|
||||||
// size local output mix buffer based on resampled network frame size
|
// size local output mix buffer based on resampled network frame size
|
||||||
_networkPeriod = _localToOutputResampler->getMaxOutput(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO);
|
int networkPeriod = _localToOutputResampler->getMaxOutput(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO);
|
||||||
_localOutputMixBuffer = new float[_networkPeriod];
|
_localOutputMixBuffer = new float[networkPeriod];
|
||||||
int localPeriod = _outputPeriod * 2;
|
int localPeriod = _outputPeriod * 2;
|
||||||
_localInjectorsStream.resizeForFrameSize(localPeriod);
|
_localInjectorsStream.resizeForFrameSize(localPeriod);
|
||||||
|
|
||||||
|
@ -1698,7 +1728,7 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare injectors for the next callback
|
// prepare injectors for the next callback
|
||||||
QMetaObject::invokeMethod(&_audio->_localAudioThread, "prepare", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(_audio->_localInjectorsThread, "prepare", Qt::QueuedConnection);
|
||||||
|
|
||||||
int samplesPopped = std::max(networkSamplesPopped, injectorSamplesPopped);
|
int samplesPopped = std::max(networkSamplesPopped, injectorSamplesPopped);
|
||||||
int framesPopped = samplesPopped / AudioConstants::STEREO;
|
int framesPopped = samplesPopped / AudioConstants::STEREO;
|
||||||
|
|
|
@ -71,19 +71,6 @@ class QIODevice;
|
||||||
class Transform;
|
class Transform;
|
||||||
class NLPacket;
|
class NLPacket;
|
||||||
|
|
||||||
class AudioInjectorsThread : public QThread {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
AudioInjectorsThread(AudioClient* audio) : _audio(audio) {}
|
|
||||||
|
|
||||||
public slots :
|
|
||||||
void prepare();
|
|
||||||
|
|
||||||
private:
|
|
||||||
AudioClient* _audio;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AudioClient : public AbstractAudioInterface, public Dependency {
|
class AudioClient : public AbstractAudioInterface, public Dependency {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
SINGLETON_DEPENDENCY
|
SINGLETON_DEPENDENCY
|
||||||
|
@ -169,6 +156,7 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
|
void cleanupBeforeQuit();
|
||||||
|
|
||||||
void handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessage> message);
|
void handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessage> message);
|
||||||
void handleAudioDataPacket(QSharedPointer<ReceivedMessage> message);
|
void handleAudioDataPacket(QSharedPointer<ReceivedMessage> message);
|
||||||
|
@ -184,8 +172,6 @@ public slots:
|
||||||
void audioMixerKilled();
|
void audioMixerKilled();
|
||||||
void toggleMute();
|
void toggleMute();
|
||||||
|
|
||||||
void beforeAboutToQuit();
|
|
||||||
|
|
||||||
virtual void setIsStereoInput(bool stereo) override;
|
virtual void setIsStereoInput(bool stereo) override;
|
||||||
|
|
||||||
void toggleAudioNoiseReduction() { _isNoiseGateEnabled = !_isNoiseGateEnabled; }
|
void toggleAudioNoiseReduction() { _isNoiseGateEnabled = !_isNoiseGateEnabled; }
|
||||||
|
@ -242,9 +228,7 @@ protected:
|
||||||
AudioClient();
|
AudioClient();
|
||||||
~AudioClient();
|
~AudioClient();
|
||||||
|
|
||||||
virtual void customDeleter() override {
|
virtual void customDeleter() override;
|
||||||
deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void outputFormatChanged();
|
void outputFormatChanged();
|
||||||
|
@ -337,19 +321,17 @@ private:
|
||||||
// for network audio (used by network audio thread)
|
// for network audio (used by network audio thread)
|
||||||
int16_t _networkScratchBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_AMBISONIC];
|
int16_t _networkScratchBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_AMBISONIC];
|
||||||
|
|
||||||
// for local audio (used by audio injectors thread)
|
|
||||||
int _networkPeriod { 0 };
|
|
||||||
float _localMixBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO];
|
|
||||||
int16_t _localScratchBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_AMBISONIC];
|
|
||||||
float* _localOutputMixBuffer { NULL };
|
|
||||||
AudioInjectorsThread _localAudioThread;
|
|
||||||
Mutex _localAudioMutex;
|
|
||||||
|
|
||||||
// for output audio (used by this thread)
|
// for output audio (used by this thread)
|
||||||
int _outputPeriod { 0 };
|
int _outputPeriod { 0 };
|
||||||
float* _outputMixBuffer { NULL };
|
float* _outputMixBuffer { NULL };
|
||||||
int16_t* _outputScratchBuffer { NULL };
|
int16_t* _outputScratchBuffer { NULL };
|
||||||
|
|
||||||
|
// for local audio (used by audio injectors thread)
|
||||||
|
float _localMixBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_STEREO];
|
||||||
|
int16_t _localScratchBuffer[AudioConstants::NETWORK_FRAME_SAMPLES_AMBISONIC];
|
||||||
|
float* _localOutputMixBuffer { NULL };
|
||||||
|
Mutex _localAudioMutex;
|
||||||
|
|
||||||
AudioLimiter _audioLimiter;
|
AudioLimiter _audioLimiter;
|
||||||
|
|
||||||
// Adds Reverb
|
// Adds Reverb
|
||||||
|
@ -392,12 +374,13 @@ private:
|
||||||
QString _selectedCodecName;
|
QString _selectedCodecName;
|
||||||
Encoder* _encoder { nullptr }; // for outbound mic stream
|
Encoder* _encoder { nullptr }; // for outbound mic stream
|
||||||
|
|
||||||
QThread* _checkDevicesThread { nullptr };
|
|
||||||
|
|
||||||
RateCounter<> _silentOutbound;
|
RateCounter<> _silentOutbound;
|
||||||
RateCounter<> _audioOutbound;
|
RateCounter<> _audioOutbound;
|
||||||
RateCounter<> _silentInbound;
|
RateCounter<> _silentInbound;
|
||||||
RateCounter<> _audioInbound;
|
RateCounter<> _audioInbound;
|
||||||
|
|
||||||
|
QThread* _checkDevicesThread { nullptr };
|
||||||
|
QThread* _localInjectorsThread { nullptr };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ void releaseOpenVrSystem();
|
||||||
|
|
||||||
|
|
||||||
static const char* CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b";
|
static const char* CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b";
|
||||||
const quint64 CALIBRATION_TIMELAPSE = 3 * USECS_PER_SECOND;
|
const quint64 CALIBRATION_TIMELAPSE = 2 * USECS_PER_SECOND;
|
||||||
|
|
||||||
static const char* MENU_PARENT = "Avatar";
|
static const char* MENU_PARENT = "Avatar";
|
||||||
static const char* MENU_NAME = "Vive Controllers";
|
static const char* MENU_NAME = "Vive Controllers";
|
||||||
|
@ -297,12 +297,12 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr
|
||||||
// done
|
// done
|
||||||
} else if (_config == Config::FeetAndHips) {
|
} else if (_config == Config::FeetAndHips) {
|
||||||
_jointToPuckMap[controller::HIPS] = _validTrackedObjects[HIP].first;
|
_jointToPuckMap[controller::HIPS] = _validTrackedObjects[HIP].first;
|
||||||
_pucksOffset[_validTrackedObjects[2].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHips, _validTrackedObjects[2].second);
|
_pucksOffset[_validTrackedObjects[HIP].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHips, _validTrackedObjects[HIP].second);
|
||||||
} else if (_config == Config::FeetHipsAndChest) {
|
} else if (_config == Config::FeetHipsAndChest) {
|
||||||
_jointToPuckMap[controller::HIPS] = _validTrackedObjects[HIP].first;
|
_jointToPuckMap[controller::HIPS] = _validTrackedObjects[HIP].first;
|
||||||
_pucksOffset[_validTrackedObjects[2].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHips, _validTrackedObjects[2].second);
|
_pucksOffset[_validTrackedObjects[HIP].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHips, _validTrackedObjects[HIP].second);
|
||||||
_jointToPuckMap[controller::SPINE2] = _validTrackedObjects[CHEST].first;
|
_jointToPuckMap[controller::SPINE2] = _validTrackedObjects[CHEST].first;
|
||||||
_pucksOffset[_validTrackedObjects[3].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultSpine2, _validTrackedObjects[3].second);
|
_pucksOffset[_validTrackedObjects[CHEST].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultSpine2, _validTrackedObjects[CHEST].second);
|
||||||
}
|
}
|
||||||
_calibrated = true;
|
_calibrated = true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue