diff --git a/interface/resources/html/createGlobalEventBridge.js b/interface/resources/html/createGlobalEventBridge.js index bccbdfaf7c..b85aa33e33 100644 --- a/interface/resources/html/createGlobalEventBridge.js +++ b/interface/resources/html/createGlobalEventBridge.js @@ -65,21 +65,23 @@ var EventBridge; // we need to listen to events that might precede the addition of this elements. // A more robust hack will be to add a setInterval that look for DOM changes every 100-300 ms (low performance?) - window.onload = function(){ + window.addEventListener("load",function(event) { setTimeout(function() { EventBridge.forceHtmlAudioOutputDeviceUpdate(); }, 1200); - }; - document.onclick = function(){ + }, false); + + document.addEventListener("click",function(){ setTimeout(function() { EventBridge.forceHtmlAudioOutputDeviceUpdate(); }, 1200); - }; - document.onchange = function(){ + }, false); + + document.addEventListener("change",function(){ setTimeout(function() { EventBridge.forceHtmlAudioOutputDeviceUpdate(); }, 1200); - }; + }, false); tempEventBridge._callbacks.forEach(function (callback) { EventBridge.scriptEventReceived.connect(callback); diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 7bc88d73f6..9a591018f5 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -121,63 +121,58 @@ uint64_t uvec2ToUint64(const uvec2& v) { class AudioHandler : public QObject, QRunnable { Q_OBJECT public: - AudioHandler(QObject* container, const QString& deviceName, int runDelayMs = 0, QObject* parent = nullptr) : QObject(parent) { - _container = container; + AudioHandler(QSharedPointer surface, const QString& deviceName, QObject* parent = nullptr) : QObject(parent) { _newTargetDevice = deviceName; - _runDelayMs = runDelayMs; + _surface = surface; setAutoDelete(true); - QThreadPool::globalInstance()->start(this); + if (deviceName.size() > 0) { + QThreadPool::globalInstance()->start(this); + } } virtual ~AudioHandler() { qDebug() << "Audio Handler Destroyed"; } void run() override { - if (_newTargetDevice.isEmpty()) { - return; - } - if (_runDelayMs > 0) { - QThread::msleep(_runDelayMs); - } - auto audioIO = DependencyManager::get(); - QString deviceName = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName(); - for (auto player : _container->findChildren()) { - auto mediaState = player->state(); - QMediaService *svc = player->service(); - if (nullptr == svc) { - return; - } - QAudioOutputSelectorControl *out = qobject_cast - (svc->requestControl(QAudioOutputSelectorControl_iid)); - if (nullptr == out) { - return; - } - QString deviceOuput; - auto outputs = out->availableOutputs(); - for (int i = 0; i < outputs.size(); i++) { - QString output = outputs[i]; - QString description = out->outputDescription(output); - if (description == deviceName) { - deviceOuput = output; - break; + if (!_surface.isNull() && _surface->getRootItem() && !_surface->getCleaned()) { + for (auto player : _surface->getRootItem()->findChildren()) { + auto mediaState = player->state(); + QMediaService *svc = player->service(); + if (nullptr == svc) { + return; + } + QAudioOutputSelectorControl *out = qobject_cast + (svc->requestControl(QAudioOutputSelectorControl_iid)); + if (nullptr == out) { + return; + } + QString deviceOuput; + auto outputs = out->availableOutputs(); + for (int i = 0; i < outputs.size(); i++) { + QString output = outputs[i]; + QString description = out->outputDescription(output); + if (description == _newTargetDevice) { + deviceOuput = output; + break; + } + } + out->setActiveOutput(deviceOuput); + svc->releaseControl(out); + // if multimedia was paused, it will start playing automatically after changing audio device + // this will reset it back to a paused state + if (mediaState == QMediaPlayer::State::PausedState) { + player->pause(); + } + else if (mediaState == QMediaPlayer::State::StoppedState) { + player->stop(); } } - out->setActiveOutput(deviceOuput); - svc->releaseControl(out); - // if multimedia was paused, it will start playing automatically after changing audio device - // this will reset it back to a paused state - if (mediaState == QMediaPlayer::State::PausedState) { - player->pause(); - } else if (mediaState == QMediaPlayer::State::StoppedState) { - player->stop(); - } } - qDebug() << "QML Audio changed to " << deviceName; + qDebug() << "QML Audio changed to " << _newTargetDevice; } private: QString _newTargetDevice; - QObject* _container; - int _runDelayMs; + QSharedPointer _surface; }; class OffscreenTextures { @@ -502,6 +497,7 @@ QOpenGLContext* OffscreenQmlSurface::getSharedContext() { } void OffscreenQmlSurface::cleanup() { + _isCleaned = true; _canvas->makeCurrent(); _renderControl->invalidate(); @@ -600,6 +596,7 @@ OffscreenQmlSurface::OffscreenQmlSurface() { OffscreenQmlSurface::~OffscreenQmlSurface() { QObject::disconnect(&_updateTimer); + disconnectAudioOutputTimer(); QObject::disconnect(qApp); cleanup(); @@ -613,6 +610,15 @@ OffscreenQmlSurface::~OffscreenQmlSurface() { void OffscreenQmlSurface::onAboutToQuit() { _paused = true; QObject::disconnect(&_updateTimer); + disconnectAudioOutputTimer(); + +} + +void OffscreenQmlSurface::disconnectAudioOutputTimer() { + if (_audioOutputUpdateTimer.isActive()) { + _audioOutputUpdateTimer.stop(); + } + QObject::disconnect(&_audioOutputUpdateTimer); } void OffscreenQmlSurface::create() { @@ -671,6 +677,14 @@ void OffscreenQmlSurface::create() { } }); + // Setup the update of the QML media components with the current audio output device + QObject::connect(&_audioOutputUpdateTimer, &QTimer::timeout, this, [this]() { + new AudioHandler(sharedFromThis(), _currentAudioOutputDevice); + }); + int waitForAudioQmlMs = 200; + _audioOutputUpdateTimer.setInterval(waitForAudioQmlMs); + _audioOutputUpdateTimer.setSingleShot(true); + // When Quick says there is a need to render, we will not render immediately. Instead, // a timer with a small interval is used to get better performance. QObject::connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick); @@ -699,10 +713,11 @@ void OffscreenQmlSurface::forceQmlAudioOutputDeviceUpdate() { QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection); } else { auto audioIO = DependencyManager::get(); - QString deviceName = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName(); - int waitForAudioQmlMs = 500; - // The audio device need to be change using oth - new AudioHandler(_rootItem, deviceName, waitForAudioQmlMs); + _currentAudioOutputDevice = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName(); + if (_audioOutputUpdateTimer.isActive()) { + _audioOutputUpdateTimer.stop(); + } + _audioOutputUpdateTimer.start(); } } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 44c6c3c77b..4c23c62c12 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -40,7 +40,7 @@ class QQuickItem; using QmlContextCallback = std::function; -class OffscreenQmlSurface : public QObject { +class OffscreenQmlSurface : public QObject, public QEnableSharedFromThis { Q_OBJECT Q_PROPERTY(bool focusText READ isFocusText NOTIFY focusTextChanged) public: @@ -75,6 +75,7 @@ public: void pause(); void resume(); bool isPaused() const; + bool getCleaned() { return _isCleaned; } void setBaseUrl(const QUrl& baseUrl); QQuickItem* getRootItem(); @@ -116,6 +117,7 @@ public slots: void changeAudioOutputDevice(const QString& deviceName, bool isHtmlUpdate = false); void forceHtmlAudioOutputDeviceUpdate(); void forceQmlAudioOutputDeviceUpdate(); + signals: void audioOutputDeviceChanged(const QString& deviceName); @@ -147,6 +149,7 @@ private: void render(); void cleanup(); QJsonObject getGLContextData(); + void disconnectAudioOutputTimer(); private slots: void updateQuick(); @@ -170,6 +173,9 @@ private: uint64_t _lastRenderTime { 0 }; uvec2 _size; + QTimer _audioOutputUpdateTimer; + QString _currentAudioOutputDevice; + // Texture management TextureAndFence _latestTextureAndFence { 0, 0 }; @@ -177,6 +183,7 @@ private: bool _polish { true }; bool _paused { true }; bool _focusText { false }; + bool _isCleaned{ false }; uint8_t _maxFps { 60 }; MouseTranslator _mouseTranslator { [](const QPointF& p) { return p.toPoint(); } }; QWindow* _proxyWindow { nullptr }; diff --git a/scripts/system/controllers/controllerModules/hudOverlayPointer.js b/scripts/system/controllers/controllerModules/hudOverlayPointer.js index 38ee29ae3b..a1faacbdd6 100644 --- a/scripts/system/controllers/controllerModules/hudOverlayPointer.js +++ b/scripts/system/controllers/controllerModules/hudOverlayPointer.js @@ -62,7 +62,7 @@ this.pointingAtTablet = function(controllerData) { var rayPick = controllerData.rayPicks[this.hand]; - return (rayPick.objectID === HMD.tabletScreenID || rayPick.objectID === HMD.homeButtonID); + return (HMD.tabletScreenID && HMD.homeButtonID && (rayPick.objectID === HMD.tabletScreenID || rayPick.objectID === HMD.homeButtonID)); }; this.getOtherModule = function() { diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index 26bebc9247..01c8424e0c 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -81,7 +81,8 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); }; this.otherHandIsParent = function(props) { - return this.getOtherModule().thisHandIsParent(props); + var otherModule = this.getOtherModule(); + return (otherModule.thisHandIsParent(props) && otherModule.grabbing); }; this.startNearParentingGrabEntity = function (controllerData, targetProps) {