From c31aa6bcdb408e28fba0b2ab151da428ad420ba5 Mon Sep 17 00:00:00 2001 From: beholder Date: Thu, 12 Oct 2017 21:56:59 +0300 Subject: [PATCH 01/10] 8213 Keyboard Input Field: Reveals Passwords --- .../resources/qml/controls-uit/Keyboard.qml | 13 ++++-- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 46 +++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/controls-uit/Keyboard.qml b/interface/resources/qml/controls-uit/Keyboard.qml index 81579d9f71..5b3a69e487 100644 --- a/interface/resources/qml/controls-uit/Keyboard.qml +++ b/interface/resources/qml/controls-uit/Keyboard.qml @@ -13,6 +13,7 @@ import "." Rectangle { id: keyboardBase + objectName: "keyboard" anchors.left: parent.left anchors.right: parent.right @@ -27,6 +28,8 @@ Rectangle { readonly property int mirrorTextHeight: keyboardRowHeight + property bool password: false + property alias mirroredText: mirrorText.text property bool showMirrorText: true readonly property int raisedHeight: 200 @@ -112,16 +115,20 @@ Rectangle { color: "#252525" anchors.horizontalCenter: parent.horizontalCenter - TextEdit { + TextInput { id: mirrorText visible: showMirrorText - size: 13.5 + FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; } + font.family: ralewaySemiBold.name + font.pointSize: 13.5 + verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter color: "#FFFFFF"; anchors.fill: parent wrapMode: Text.WordWrap - readOnly: false // we need to leave this property read-only to allow control to accept QKeyEvent + readOnly: false // we need this to allow control to accept QKeyEvent selectByMouse: false + echoMode: password ? TextInput.Password : TextInput.Normal Keys.onPressed: { if (event.key == Qt.Key_Return) { diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 6cf8a927ff..69d6b8d6ab 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -1030,6 +1030,52 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n // if HMD is being worn, allow keyboard to open. allow it to close, HMD or not. if (!raised || qApp->property(hifi::properties::HMD).toBool()) { QQuickItem* item = dynamic_cast(object); + if (!item) + return; + + auto echoMode = item->property("echoMode"); + bool isPasswordField = echoMode.isValid() && echoMode.toInt() == 2 /* TextInput.Password */; + + // we need to somehow pass 'isPasswordField' to visible keyboard so it will change its 'mirror text' to asterixes + // the issue in some cases there might be more than one keyboard in object tree and it is hard to understand which one is being used at the moment + // unfortunately attempts to check for visibility failed becuase visibility is not updated yet. So... I don't see other way than just update properties for all the keyboards + struct Local { + static void forEachKeyboard(QQuickItem* item, std::function function) { + QObject* itemObject = item; + while (itemObject) { + if (itemObject->parent()) { + itemObject = itemObject->parent(); + } + else { + break; + } + } + + auto keyboards = itemObject->findChildren("keyboard"); + + for (auto keyboardObject : keyboards) { + auto keyboard = qobject_cast(keyboardObject); + if (keyboard == nullptr) { + continue; + } + + if (function) { + function(keyboard); + } + } + } + }; + + Local::forEachKeyboard(item, [&](QQuickItem* keyboard) { + keyboard->setProperty("mirroredText", QVariant::fromValue(QString(""))); + keyboard->setProperty("password", isPasswordField); + }); + + // for future probably makes sense to consider one of the following: + // 1. make keyboard a singleton, which will be dynamically re-parented before showing + // 2. track currently visible keyboard somewhere, allow to subscribe for this signal + // any of above should also eliminate need in duplicated properties and code below + while (item) { // Numeric value may be set in parameter from HTML UI; for QML UI, detect numeric fields here. numeric = numeric || QString(item->metaObject()->className()).left(7) == "SpinBox"; From 01c3ca17eeda77ce21f5a00a651bc5cc662c6a43 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 13 Oct 2017 11:05:27 +0200 Subject: [PATCH 02/10] Fixed cube map conversion from equirectangular maps when done after HDR conversion --- libraries/image/src/image/Image.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index 59ec4776a6..5959714cd8 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -983,6 +983,9 @@ public: glm::vec2 dstCoord; glm::ivec2 srcPixel; for (int y = 0; y < faceWidth; ++y) { + QRgb* destScanLineBegin = reinterpret_cast( image.scanLine(y) ); + QRgb* destPixelIterator = destScanLineBegin; + dstCoord.y = 1.0f - (y + 0.5f) * dstInvSize.y; // Fill cube face images from top to bottom for (int x = 0; x < faceWidth; ++x) { dstCoord.x = (x + 0.5f) * dstInvSize.x; @@ -995,13 +998,19 @@ public: srcPixel.y = floor((1.0f - srcCoord.y) * srcFaceHeight); if (((uint32)srcPixel.x < (uint32)source.width()) && ((uint32)srcPixel.y < (uint32)source.height())) { - image.setPixel(x, y, source.pixel(QPoint(srcPixel.x, srcPixel.y))); + // We can't directly use the pixel() method because that launches a pixel color conversion to output + // a correct RGBA8 color. But in our case we may have stored HDR values encoded in a RGB30 format which + // are not convertible by Qt. The same goes with the setPixel method, by the way. + const QRgb* sourcePixelIterator = reinterpret_cast(source.scanLine(srcPixel.y)); + sourcePixelIterator += srcPixel.x; + *destPixelIterator = *sourcePixelIterator; // Keep for debug, this is showing the dir as a color // glm::u8vec4 rgba((xyzDir.x + 1.0)*0.5 * 256, (xyzDir.y + 1.0)*0.5 * 256, (xyzDir.z + 1.0)*0.5 * 256, 256); // unsigned int val = 0xff000000 | (rgba.r) | (rgba.g << 8) | (rgba.b << 16); - // image.setPixel(x, y, val); + // *destPixelIterator = val; } + ++destPixelIterator; } } return image; @@ -1192,6 +1201,10 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage& if ((srcImage.width() > 0) && (srcImage.height() > 0)) { QImage image = processSourceImage(srcImage, true); + if (image.format() != QIMAGE_HDR_FORMAT) { + image = convertToHDRFormat(image, HDR_FORMAT); + } + gpu::Element formatMip; gpu::Element formatGPU; if (isCubeTexturesCompressionEnabled()) { @@ -1229,13 +1242,6 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage& faces.push_back(faceImage); } } - - if (image.format() != QIMAGE_HDR_FORMAT) { - for (auto& face : faces) { - face = convertToHDRFormat(face, HDR_FORMAT); - } - } - } else { qCDebug(imagelogging) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str()); return nullptr; From e4e37e65e61d457ab765bdc515b24452e77e4f84 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Fri, 13 Oct 2017 08:19:30 -0700 Subject: [PATCH 03/10] Handle packets in-flight during audio codec startup --- libraries/audio/src/InboundAudioStream.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index da8997895c..b7d01c844d 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -161,12 +161,18 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead()); parseAudioData(message.getType(), afterProperties); } else { - qDebug(audio) << "Codec mismatch: expected" << _selectedCodecName << "got" << codecInPacket << "writing silence"; + qDebug(audio) << "Codec mismatch: expected" << _selectedCodecName << "got" << codecInPacket; - // Since the data in the stream is using a codec that we aren't prepared for, - // we need to let the codec know that we don't have data for it, this will - // allow the codec to interpolate missing data and produce a fade to silence. - lostAudioData(1); + if (packetPCM) { + // If there are PCM packets in-flight while the codec is changed, use them. + auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead()); + _ringBuffer.writeData(afterProperties.data(), afterProperties.size()); + } else { + // Since the data in the stream is using a codec that we aren't prepared for, + // we need to let the codec know that we don't have data for it, this will + // allow the codec to interpolate missing data and produce a fade to silence. + lostAudioData(1); + } // inform others of the mismatch auto sendingNode = DependencyManager::get()->nodeWithUUID(message.getSourceID()); From a2a6cd0c7a92339d7da6b302f8d4eb367c456ac2 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 13 Oct 2017 14:28:23 -0700 Subject: [PATCH 04/10] Reduce present traffic on main thread event queue. In an effort to diagnose the root cause of several deadlocks, it seems possible that the main thread event queue can grow to a size where it can take many seconds to drain. This PR attempts to address this in two ways: * Change the connection between the DisplayPlugin::presented signal and the Application::onPresent slot to be a DirectConnection. This should prevent the main thread from filling up with signal events. * Within Applicaiton::onPresent use an atomic counter to prevent the main thread from filling up with repeated Idle events. --- interface/src/Application.cpp | 60 ++++++++++++++++++++++++---- interface/src/Application.h | 3 ++ interface/src/Application_render.cpp | 6 +++ 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e5d5e696a1..60b0d536e8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -207,6 +207,17 @@ #if defined(Q_OS_WIN) #include +#ifdef DEBUG_EVENT_QUEUE +// This is a HACK that uses private headers included with the qt source distrubution. +// To use this feature you need to add these directores to your include path: +// E:/Qt/5.9.1/Src/qtbase/include/QtCore/5.9.1/QtCore +// E:/Qt/5.9.1/Src/qtbase/include/QtCore/5.9.1 +#define QT_BOOTSTRAPPED +#include +#include +#undef QT_BOOTSTRAPPED +#endif + extern "C" { _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; } @@ -264,9 +275,7 @@ private: switch ((int)event->type()) { case ApplicationEvent::Render: render(); - // Ensure we never back up the render events. Each render should be triggered only in response - // to the NEXT render event after the last render occured - QCoreApplication::removePostedEvents(this, ApplicationEvent::Render); + qApp->_pendingRenderEventCount--; return true; default: @@ -2712,9 +2721,15 @@ bool Application::importFromZIP(const QString& filePath) { return true; } +// thread-safe void Application::onPresent(quint32 frameCount) { - postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority); - if (_renderEventHandler && !isAboutToQuit()) { + if (_pendingIdleEventCount.load() == 0) { + _pendingIdleEventCount++; + postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority); + } + + if (_renderEventHandler && !isAboutToQuit() && _pendingRenderEventCount.load() == 0) { + _pendingRenderEventCount++; postEvent(_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render)); } } @@ -2781,7 +2796,26 @@ bool Application::handleFileOpenEvent(QFileOpenEvent* fileEvent) { return false; } +#ifdef DEBUG_EVENT_QUEUE +static int getEventQueueSize(QThread* thread) { + auto threadData = QThreadData::get2(thread); + QMutexLocker locker(&threadData->postEventList.mutex); + return threadData->postEventList.size(); +} + +static void dumpEventQueue(QThread* thread) { + auto threadData = QThreadData::get2(thread); + QMutexLocker locker(&threadData->postEventList.mutex); + qDebug() << "AJT: event list, size =" << threadData->postEventList.size(); + for (auto& postEvent : threadData->postEventList) { + QEvent::Type type = (postEvent.event ? postEvent.event->type() : QEvent::None); + qDebug() << "AJT: " << type; + } +} +#endif // DEBUG_EVENT_QUEUE + bool Application::event(QEvent* event) { + if (!Menu::getInstance()) { return false; } @@ -2801,8 +2835,18 @@ bool Application::event(QEvent* event) { // see (windowMinimizedChanged) case ApplicationEvent::Idle: idle(); - // Don't process extra idle events that arrived in the event queue while we were doing this idle - QCoreApplication::removePostedEvents(this, ApplicationEvent::Idle); + +#ifdef DEBUG_EVENT_QUEUE + { + int count = getEventQueueSize(QThread::currentThread()); + if (count > 400) { + dumpEventQueue(QThread::currentThread()); + } + } +#endif // DEBUG_EVENT_QUEUE + + _pendingIdleEventCount--; + return true; case QEvent::MouseMove: @@ -7203,7 +7247,7 @@ void Application::updateDisplayMode() { _offscreenContext->makeCurrent(); getApplicationCompositor().setDisplayPlugin(newDisplayPlugin); _displayPlugin = newDisplayPlugin; - connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent); + connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent, Qt::DirectConnection); auto desktop = offscreenUi->getDesktop(); if (desktop) { desktop->setProperty("repositionLocked", wasRepositionLocked); diff --git a/interface/src/Application.h b/interface/src/Application.h index 772646f379..e683adc26b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -717,5 +717,8 @@ private: LaserPointerManager _laserPointerManager; friend class RenderEventHandler; + + std::atomic _pendingIdleEventCount { 0 }; + std::atomic _pendingRenderEventCount { 0 }; }; #endif // hifi_Application_h diff --git a/interface/src/Application_render.cpp b/interface/src/Application_render.cpp index 541197a660..44d9dfee03 100644 --- a/interface/src/Application_render.cpp +++ b/interface/src/Application_render.cpp @@ -72,6 +72,12 @@ void Application::paintGL() { { QMutexLocker viewLocker(&_renderArgsMutex); renderArgs = _appRenderArgs._renderArgs; + + // don't render if there is no context. + if (!_appRenderArgs._renderArgs._context) { + return; + } + HMDSensorPose = _appRenderArgs._headPose; eyeToWorld = _appRenderArgs._eyeToWorld; sensorToWorld = _appRenderArgs._sensorToWorld; From 67d43b4fac11f90ee26342e1b771e8aea3a02b3e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 13 Oct 2017 16:03:56 -0700 Subject: [PATCH 05/10] Use atomic and compare_exchange_strong --- interface/src/Application.cpp | 13 ++++++------- interface/src/Application.h | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 60b0d536e8..f9ad6ec7ff 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -275,7 +275,7 @@ private: switch ((int)event->type()) { case ApplicationEvent::Render: render(); - qApp->_pendingRenderEventCount--; + qApp->_pendingRenderEvent.store(false); return true; default: @@ -2723,13 +2723,12 @@ bool Application::importFromZIP(const QString& filePath) { // thread-safe void Application::onPresent(quint32 frameCount) { - if (_pendingIdleEventCount.load() == 0) { - _pendingIdleEventCount++; + bool expected = false; + if (_pendingIdleEvent.compare_exchange_strong(expected, true)) { postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority); } - - if (_renderEventHandler && !isAboutToQuit() && _pendingRenderEventCount.load() == 0) { - _pendingRenderEventCount++; + expected = false; + if (_renderEventHandler && !isAboutToQuit() && _pendingRenderEvent.compare_exchange_strong(expected, true)) { postEvent(_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render)); } } @@ -2845,7 +2844,7 @@ bool Application::event(QEvent* event) { } #endif // DEBUG_EVENT_QUEUE - _pendingIdleEventCount--; + _pendingIdleEvent.store(false); return true; diff --git a/interface/src/Application.h b/interface/src/Application.h index e683adc26b..b6c09bbd87 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -718,7 +718,7 @@ private: friend class RenderEventHandler; - std::atomic _pendingIdleEventCount { 0 }; - std::atomic _pendingRenderEventCount { 0 }; + std::atomic _pendingIdleEvent { false }; + std::atomic _pendingRenderEvent { false }; }; #endif // hifi_Application_h From f83040c572249d9a823d7b3f50b8f8f043ddda13 Mon Sep 17 00:00:00 2001 From: beholder Date: Fri, 13 Oct 2017 22:23:38 +0300 Subject: [PATCH 06/10] updating code accordingly to the comments --- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 60 ++++++++++----------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 69d6b8d6ab..01026ae5ff 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -1018,6 +1018,32 @@ void OffscreenQmlSurface::synthesizeKeyPress(QString key, QObject* targetOverrid } } +static void forEachKeyboard(QQuickItem* item, std::function function) { + QObject* itemObject = item; + while (itemObject) { + if (itemObject->parent()) { + itemObject = itemObject->parent(); + } else { + break; + } + } + + auto keyboards = itemObject->findChildren("keyboard"); + + for (auto keyboardObject : keyboards) { + auto keyboard = qobject_cast(keyboardObject); + if (keyboard == nullptr) { + continue; + } + + if (function) { + function(keyboard); + } + } +} + +static const int TEXTINPUT_PASSWORD = 2; + void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric) { #if Q_OS_ANDROID return; @@ -1030,43 +1056,17 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n // if HMD is being worn, allow keyboard to open. allow it to close, HMD or not. if (!raised || qApp->property(hifi::properties::HMD).toBool()) { QQuickItem* item = dynamic_cast(object); - if (!item) + if (!item) { return; + } auto echoMode = item->property("echoMode"); - bool isPasswordField = echoMode.isValid() && echoMode.toInt() == 2 /* TextInput.Password */; + bool isPasswordField = echoMode.isValid() && echoMode.toInt() == TEXTINPUT_PASSWORD; // we need to somehow pass 'isPasswordField' to visible keyboard so it will change its 'mirror text' to asterixes // the issue in some cases there might be more than one keyboard in object tree and it is hard to understand which one is being used at the moment // unfortunately attempts to check for visibility failed becuase visibility is not updated yet. So... I don't see other way than just update properties for all the keyboards - struct Local { - static void forEachKeyboard(QQuickItem* item, std::function function) { - QObject* itemObject = item; - while (itemObject) { - if (itemObject->parent()) { - itemObject = itemObject->parent(); - } - else { - break; - } - } - - auto keyboards = itemObject->findChildren("keyboard"); - - for (auto keyboardObject : keyboards) { - auto keyboard = qobject_cast(keyboardObject); - if (keyboard == nullptr) { - continue; - } - - if (function) { - function(keyboard); - } - } - } - }; - - Local::forEachKeyboard(item, [&](QQuickItem* keyboard) { + forEachKeyboard(item, [&](QQuickItem* keyboard) { keyboard->setProperty("mirroredText", QVariant::fromValue(QString(""))); keyboard->setProperty("password", isPasswordField); }); From a702c5a0e42c50444491fa8a5a68a94323d490e9 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Mon, 16 Oct 2017 11:41:40 -0700 Subject: [PATCH 07/10] Fix audio glitches caused by initial burst of SelectedAudioFormat packets. Temporary codec mismatch is expected during audio codec startup, due to packets already in-flight. --- libraries/audio/src/InboundAudioStream.cpp | 31 +++++++++++++++++----- libraries/audio/src/InboundAudioStream.h | 1 + 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index b7d01c844d..8f64cafc7e 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -46,6 +46,10 @@ static const int STATS_FOR_STATS_PACKET_WINDOW_SECONDS = 30; // _currentJitterBufferFrames is updated with the time-weighted avg and the running time-weighted avg is reset. static const quint64 FRAMES_AVAILABLE_STAT_WINDOW_USECS = 10 * USECS_PER_SECOND; +// When the audio codec is switched, temporary codec mismatch is expected due to packets in-flight. +// A SelectedAudioFormat packet is not sent until this threshold is exceeded. +static const int MAX_MISMATCHED_AUDIO_CODEC_COUNT = 10; + InboundAudioStream::InboundAudioStream(int numChannels, int numFrames, int numBlocks, int numStaticJitterBlocks) : _ringBuffer(numChannels * numFrames, numBlocks), _numChannels(numChannels), @@ -134,6 +138,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { switch (arrivalInfo._status) { case SequenceNumberStats::Unreasonable: { lostAudioData(1); + qDebug(audio) << "Sequence Unreasonable (LOST)"; break; } case SequenceNumberStats::Early: { @@ -143,6 +148,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { // fall through to the "on time" logic to actually handle this packet int packetsDropped = arrivalInfo._seqDiffFromExpected; lostAudioData(packetsDropped); + qDebug(audio) << "Sequence Early (LOST)"; // fall through to OnTime case } @@ -153,6 +159,8 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { // If we recieved a SilentAudioFrame from our sender, we might want to drop // some of the samples in order to catch up to our desired jitter buffer size. writeDroppableSilentFrames(networkFrames); + qDebug(audio) << "OnTime (SILENT)"; + } else { // note: PCM and no codec are identical bool selectedPCM = _selectedCodecName == "pcm" || _selectedCodecName == ""; @@ -160,11 +168,15 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { if (codecInPacket == _selectedCodecName || (packetPCM && selectedPCM)) { auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead()); parseAudioData(message.getType(), afterProperties); + qDebug(audio) << "OnTime (DECODE:" << codecInPacket << afterProperties.size() << ")"; + _mismatchedAudioCodecCount = 0; + } else { + _mismatchedAudioCodecCount++; qDebug(audio) << "Codec mismatch: expected" << _selectedCodecName << "got" << codecInPacket; if (packetPCM) { - // If there are PCM packets in-flight while the codec is changed, use them. + // If there are PCM packets in-flight after the codec is changed, use them. auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead()); _ringBuffer.writeData(afterProperties.data(), afterProperties.size()); } else { @@ -174,12 +186,16 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { lostAudioData(1); } - // inform others of the mismatch - auto sendingNode = DependencyManager::get()->nodeWithUUID(message.getSourceID()); - if (sendingNode) { - emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket); - } + if (_mismatchedAudioCodecCount > MAX_MISMATCHED_AUDIO_CODEC_COUNT) { + _mismatchedAudioCodecCount = 0; + // inform others of the mismatch + auto sendingNode = DependencyManager::get()->nodeWithUUID(message.getSourceID()); + if (sendingNode) { + emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket); + qDebug(audio) << "Codec mismatch threshold exceeded, SelectedAudioFormat(" << _selectedCodecName << " ) sent"; + } + } } } break; @@ -515,6 +531,7 @@ float calculateRepeatedFrameFadeFactor(int indexOfRepeat) { } void InboundAudioStream::setupCodec(CodecPluginPointer codec, const QString& codecName, int numChannels) { + qDebug(audio) << "Setup Codec:" << codecName; cleanupCodec(); // cleanup any previously allocated coders first _codec = codec; _selectedCodecName = codecName; @@ -525,6 +542,8 @@ void InboundAudioStream::setupCodec(CodecPluginPointer codec, const QString& cod void InboundAudioStream::cleanupCodec() { // release any old codec encoder/decoder first... + qDebug(audio) << "Cleanup Codec:" << _selectedCodecName; + if (_codec) { if (_decoder) { _codec->releaseDecoder(_decoder); diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index 9494b2f204..ecd1a118f9 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -186,6 +186,7 @@ protected: CodecPluginPointer _codec; QString _selectedCodecName; Decoder* _decoder { nullptr }; + int _mismatchedAudioCodecCount { 0 }; }; float calculateRepeatedFrameFadeFactor(int indexOfRepeat); From 7c14d5bbdf985cf7ad58b12c866da5a6a2db8538 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Mon, 16 Oct 2017 11:43:52 -0700 Subject: [PATCH 08/10] Remove debug logging --- libraries/audio/src/InboundAudioStream.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 8f64cafc7e..addf572cc3 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -138,7 +138,6 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { switch (arrivalInfo._status) { case SequenceNumberStats::Unreasonable: { lostAudioData(1); - qDebug(audio) << "Sequence Unreasonable (LOST)"; break; } case SequenceNumberStats::Early: { @@ -148,7 +147,6 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { // fall through to the "on time" logic to actually handle this packet int packetsDropped = arrivalInfo._seqDiffFromExpected; lostAudioData(packetsDropped); - qDebug(audio) << "Sequence Early (LOST)"; // fall through to OnTime case } @@ -159,7 +157,6 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { // If we recieved a SilentAudioFrame from our sender, we might want to drop // some of the samples in order to catch up to our desired jitter buffer size. writeDroppableSilentFrames(networkFrames); - qDebug(audio) << "OnTime (SILENT)"; } else { // note: PCM and no codec are identical @@ -168,7 +165,6 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { if (codecInPacket == _selectedCodecName || (packetPCM && selectedPCM)) { auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead()); parseAudioData(message.getType(), afterProperties); - qDebug(audio) << "OnTime (DECODE:" << codecInPacket << afterProperties.size() << ")"; _mismatchedAudioCodecCount = 0; } else { From bd82f47c66dfc67e29201abab1e3838a25a31a7a Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Mon, 16 Oct 2017 12:11:50 -0700 Subject: [PATCH 09/10] Remove debug logging --- libraries/audio/src/InboundAudioStream.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index addf572cc3..72acc7fcf6 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -527,7 +527,6 @@ float calculateRepeatedFrameFadeFactor(int indexOfRepeat) { } void InboundAudioStream::setupCodec(CodecPluginPointer codec, const QString& codecName, int numChannels) { - qDebug(audio) << "Setup Codec:" << codecName; cleanupCodec(); // cleanup any previously allocated coders first _codec = codec; _selectedCodecName = codecName; @@ -538,8 +537,6 @@ void InboundAudioStream::setupCodec(CodecPluginPointer codec, const QString& cod void InboundAudioStream::cleanupCodec() { // release any old codec encoder/decoder first... - qDebug(audio) << "Cleanup Codec:" << _selectedCodecName; - if (_codec) { if (_decoder) { _codec->releaseDecoder(_decoder); From 97c255c59ef0eaa6377641c13f250c902f0bc02b Mon Sep 17 00:00:00 2001 From: milad Date: Mon, 16 Oct 2017 16:12:54 -0400 Subject: [PATCH 10/10] Fix for fogbugz:8382 to shutdown debug window on reload scripts --- scripts/developer/debugging/debugWindow.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/developer/debugging/debugWindow.js b/scripts/developer/debugging/debugWindow.js index 6dd116089a..b16739b2b8 100644 --- a/scripts/developer/debugging/debugWindow.js +++ b/scripts/developer/debugging/debugWindow.js @@ -53,4 +53,8 @@ ScriptDiscoveryService.clearDebugWindow.connect(function() { window.clearDebugWindow(); }); +Script.scriptEnding.connect(function () { + window.close(); +}) + }());