From 2e73ac8bc116b23ba42e841c1d1d39b3a24f330d Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 8 Jul 2014 11:16:39 -0700 Subject: [PATCH 1/6] changed Audio.cpp to not overflow _audioOutput buffer, and 2 other things added _consecutiveNotMixedCount to prevent premature injector stream deletion; made silent-frame drop only occur in dynamic jitter buffer mode --- .../src/audio/AudioMixerClientData.cpp | 5 ++++- interface/src/Audio.cpp | 20 ++++++++++--------- .../audio/src/PositionalAudioRingBuffer.cpp | 10 +++++++--- .../audio/src/PositionalAudioRingBuffer.h | 6 +++--- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index f6437f9c97..d3883501d6 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -138,11 +138,14 @@ void AudioMixerClientData::pushBuffersAfterFrameSend() { // this was a used buffer, push the output pointer forwards PositionalAudioRingBuffer* audioBuffer = *i; + const int INJECTOR_CONSECUTIVE_NOT_MIXED_THRESHOLD = 100; + if (audioBuffer->willBeAddedToMix()) { audioBuffer->shiftReadPosition(audioBuffer->getSamplesPerFrame()); audioBuffer->setWillBeAddedToMix(false); } else if (audioBuffer->getType() == PositionalAudioRingBuffer::Injector - && audioBuffer->hasStarted() && audioBuffer->isStarved()) { + && audioBuffer->hasStarted() && audioBuffer->isStarved() + && audioBuffer->getConsecutiveNotMixedCount() > INJECTOR_CONSECUTIVE_NOT_MIXED_THRESHOLD) { // this is an empty audio buffer that has starved, safe to delete // also delete its sequence number stats QUuid streamIdentifier = ((InjectedAudioRingBuffer*)audioBuffer)->getStreamIdentifier(); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 6bbd769d25..c604040bc8 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -67,7 +67,7 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) : _proceduralAudioOutput(NULL), _proceduralOutputDevice(NULL), _inputRingBuffer(0), - _ringBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO), + _ringBuffer(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, false, 100), _isStereoInput(false), _averagedLatency(0.0), _measuredJitter(0), @@ -869,14 +869,11 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) { _numFramesDisplayStarve = 10; } - // if there is anything in the ring buffer, decide what to do - if (_ringBuffer.samplesAvailable() > 0) { - - int numNetworkOutputSamples = _ringBuffer.samplesAvailable(); - int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio; - - QByteArray outputBuffer; - outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); + int numSamplesAudioOutputRoomFor = _audioOutput->bytesFree() / sizeof(int16_t); + int numNetworkOutputSamples = std::min(_ringBuffer.samplesAvailable(), (int)(numSamplesAudioOutputRoomFor * networkOutputToOutputRatio)); + + // if there is data in the ring buffer and room in the audio output, decide what to do + if (numNetworkOutputSamples > 0) { int numSamplesNeededToStartPlayback = std::min(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO + (_jitterBufferSamples * 2), _ringBuffer.getSampleCapacity()); @@ -885,6 +882,11 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) { // We are still waiting for enough samples to begin playback // qDebug() << numNetworkOutputSamples << " samples so far, waiting for " << numSamplesNeededToStartPlayback; } else { + int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio; + + QByteArray outputBuffer; + outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); + // We are either already playing back, or we have enough audio to start playing back. //qDebug() << "pushing " << numNetworkOutputSamples; _ringBuffer.setIsStarved(false); diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 0fe75f1239..6b3a1eb94f 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -99,7 +99,8 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer:: _listenerUnattenuatedZone(NULL), _desiredJitterBufferFrames(1), _currentJitterBufferFrames(-1), - _dynamicJitterBuffers(dynamicJitterBuffers) + _dynamicJitterBuffers(dynamicJitterBuffers), + _consecutiveNotMixedCount(0) { } @@ -129,7 +130,7 @@ int PositionalAudioRingBuffer::parseData(const QByteArray& packet) { numSilentSamples = getSamplesPerFrame(); if (numSilentSamples > 0) { - if (_currentJitterBufferFrames > _desiredJitterBufferFrames) { + if (_dynamicJitterBuffers && _currentJitterBufferFrames > _desiredJitterBufferFrames) { // our current jitter buffer size exceeds its desired value, so ignore some silent // frames to get that size as close to desired as possible int samplesPerFrame = getSamplesPerFrame(); @@ -206,11 +207,12 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() { if (!isNotStarvedOrHasMinimumSamples(samplesPerFrame + desiredJitterBufferSamples)) { // if the buffer was starved, allow it to accrue at least the desired number of // jitter buffer frames before we start taking frames from it for mixing - + if (_shouldOutputStarveDebug) { _shouldOutputStarveDebug = false; } + _consecutiveNotMixedCount++; return false; } else if (samplesAvailable() < samplesPerFrame) { // if the buffer doesn't have a full frame of samples to take for mixing, it is starved @@ -222,6 +224,7 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() { // reset our _shouldOutputStarveDebug to true so the next is printed _shouldOutputStarveDebug = true; + _consecutiveNotMixedCount++; return false; } @@ -231,6 +234,7 @@ bool PositionalAudioRingBuffer::shouldBeAddedToMix() { // minus one (since a frame will be read immediately after this) is the length of the jitter buffer _currentJitterBufferFrames = samplesAvailable() / samplesPerFrame - 1; _isStarved = false; + _consecutiveNotMixedCount = 0; } // since we've read data from ring buffer at least once - we've started diff --git a/libraries/audio/src/PositionalAudioRingBuffer.h b/libraries/audio/src/PositionalAudioRingBuffer.h index 0322afb47b..31b0524b3b 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.h +++ b/libraries/audio/src/PositionalAudioRingBuffer.h @@ -83,6 +83,8 @@ public: int getDesiredJitterBufferFrames() const { return _desiredJitterBufferFrames; } int getCurrentJitterBufferFrames() const { return _currentJitterBufferFrames; } + int getConsecutiveNotMixedCount() const { return _consecutiveNotMixedCount; } + protected: // disallow copying of PositionalAudioRingBuffer objects PositionalAudioRingBuffer(const PositionalAudioRingBuffer&); @@ -107,9 +109,7 @@ protected: bool _dynamicJitterBuffers; // extra stats - int _starveCount; - int _silentFramesDropped; - + int _consecutiveNotMixedCount; }; #endif // hifi_PositionalAudioRingBuffer_h From 84aa4b9cda859f73751b3a3f8573bfb379d2cb60 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Jul 2014 11:59:10 -0700 Subject: [PATCH 2/6] use compiler default C++ Standard Library on OS X --- CMakeLists.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2451ab240a..b8566dd050 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,14 +32,6 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) -if (APPLE) - exec_program(uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION) - string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION}) - if (DARWIN_VERSION GREATER 12) - set(CMAKE_CXX_FLAGS "-stdlib=libstdc++") - endif (DARWIN_VERSION GREATER 12) -endif (APPLE) - # targets not supported on windows if (NOT WIN32) add_subdirectory(animation-server) From d1afe127c3e47db8d754ce2afc92900391de702d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 8 Jul 2014 12:06:43 -0700 Subject: [PATCH 3/6] updates to RtMidi find module to look for static or dynamic lib --- cmake/modules/FindRtMidi.cmake | 4 ++-- interface/CMakeLists.txt | 28 +++++++++++++--------------- interface/external/rtmidi/readme.txt | 4 +++- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/cmake/modules/FindRtMidi.cmake b/cmake/modules/FindRtMidi.cmake index a54cc483e1..ad1167c5d6 100644 --- a/cmake/modules/FindRtMidi.cmake +++ b/cmake/modules/FindRtMidi.cmake @@ -26,8 +26,8 @@ else () set(RTMIDI_SEARCH_DIRS "${RTMIDI_ROOT_DIR}" "$ENV{HIFI_LIB_DIR}/rtmidi") find_path(RTMIDI_INCLUDE_DIR RtMidi.h PATH_SUFFIXES include HINTS ${RTMIDI_SEARCH_DIRS}) - find_file(RTMIDI_CPP NAMES RtMidi.cpp PATH_SUFFIXES src HINTS ${RTMIDI_SEARCH_DIRS}) + find_library(RTMIDI_LIBRARY NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEARCH_DIRS}) include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(RTMIDI DEFAULT_MSG RTMIDI_INCLUDE_DIR RTMIDI_CPP) + find_package_handle_standard_args(RTMIDI DEFAULT_MSG RTMIDI_INCLUDE_DIR RTMIDI_LIBRARY) endif () \ No newline at end of file diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 68ba2761aa..49a6da7438 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -111,16 +111,6 @@ if (APPLE) SET(INTERFACE_SRCS ${INTERFACE_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/interface.icns") endif() -# RtMidi for scripted MIDI control -find_package(RtMidi) - -if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI) - add_definitions(-DHAVE_RTMIDI) - include_directories(SYSTEM ${RTMIDI_INCLUDE_DIR}) - - set(INTERFACE_SRCS ${INTERFACE_SRCS} "${RTMIDI_CPP}") -endif () - # create the executable, make it a bundle on OS X add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM}) @@ -151,6 +141,7 @@ find_package(Sixense) find_package(Visage) find_package(ZLIB) find_package(Qxmpp) +find_package(RtMidi) # include the Sixense library for Razer Hydra if available if (SIXENSE_FOUND AND NOT DISABLE_SIXENSE) @@ -223,11 +214,18 @@ if (QXMPP_FOUND AND NOT DISABLE_QXMPP) target_link_libraries(${TARGET_NAME} "${QXMPP_LIBRARY}") endif (QXMPP_FOUND AND NOT DISABLE_QXMPP) -# link CoreMIDI if we're using RtMidi -if (RTMIDI_FOUND AND APPLE) - find_library(CoreMIDI CoreMIDI) - add_definitions(-D__MACOSX_CORE__) - target_link_libraries(${TARGET_NAME} ${CoreMIDI}) +# and with RtMidi for RtMidi control +if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI) + + add_definitions(-DHAVE_RTMIDI) + include_directories(SYSTEM ${RTMIDI_INCLUDE_DIR}) + target_link_libraries(${TARGET_NAME} "${RTMIDI_LIBRARY}") + + if (APPLE) + find_library(CoreMIDI CoreMIDI) + add_definitions(-D__MACOSX_CORE__) + target_link_libraries(${TARGET_NAME} ${CoreMIDI}) + endif() endif() # include headers for interface and InterfaceConfig. diff --git a/interface/external/rtmidi/readme.txt b/interface/external/rtmidi/readme.txt index d83d0c293e..d0480fce4a 100644 --- a/interface/external/rtmidi/readme.txt +++ b/interface/external/rtmidi/readme.txt @@ -7,7 +7,9 @@ Stephen Birarda, June 30, 2014 2. Copy RtMidi.h to externals/rtmidi/include. -3. Copy RtMidi.cpp to externals/rtmidi/src +3. Compile the RtMidi library. + +3. Copy either librtmidi.dylib (dynamic) or librtmidi.a (static) to externals/rtmidi/lib 4. Delete your build directory, run cmake and build, and you should be all set. From 6ee52e97c80c584c0e0c959cb587dfc8620b4a16 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 8 Jul 2014 12:23:43 -0700 Subject: [PATCH 4/6] added dev menu option to disable _audioOutput overflow check --- interface/src/Audio.cpp | 11 ++++++++--- interface/src/Menu.cpp | 4 ++++ interface/src/Menu.h | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index c604040bc8..cc455c5544 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -869,9 +869,14 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) { _numFramesDisplayStarve = 10; } - int numSamplesAudioOutputRoomFor = _audioOutput->bytesFree() / sizeof(int16_t); - int numNetworkOutputSamples = std::min(_ringBuffer.samplesAvailable(), (int)(numSamplesAudioOutputRoomFor * networkOutputToOutputRatio)); - + int numNetworkOutputSamples; + if (Menu::getInstance()->isOptionChecked(MenuOption::DisableQAudioOutputOverflowCheck)) { + numNetworkOutputSamples = _ringBuffer.samplesAvailable(); + } else { + int numSamplesAudioOutputRoomFor = _audioOutput->bytesFree() / sizeof(int16_t); + numNetworkOutputSamples = std::min(_ringBuffer.samplesAvailable(), (int)(numSamplesAudioOutputRoomFor * networkOutputToOutputRatio)); + } + // if there is data in the ring buffer and room in the audio output, decide what to do if (numNetworkOutputSamples > 0) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6b32eb5770..69d95b34db 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -428,6 +428,10 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); + QMenu* audioOptionsMenu = developerMenu->addMenu("Audio Options"); + + addCheckableActionToQMenuAndActionHash(audioOptionsMenu, MenuOption::DisableQAudioOutputOverflowCheck, 0, false); + addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNackPackets, 0, false); addDisabledActionAndSeparator(developerMenu, "Testing"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 06b5c5c9f4..e8146f8038 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -343,6 +343,7 @@ namespace MenuOption { const QString DecreaseVoxelSize = "Decrease Voxel Size"; const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; const QString DisableNackPackets = "Disable NACK Packets"; + const QString DisableQAudioOutputOverflowCheck = "Disable QAudioOutput Overflow Check"; const QString DisplayFrustum = "Display Frustum"; const QString DisplayHands = "Display Hands"; const QString DisplayHandTargets = "Display Hand Targets"; From df1b4107fd92a88bc443312c4c234b05ed18e081 Mon Sep 17 00:00:00 2001 From: wangyix Date: Tue, 8 Jul 2014 13:01:05 -0700 Subject: [PATCH 5/6] moved qAudioOutput buffer overflow debug option to existing audio menu --- interface/src/Menu.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 69d95b34db..c0c25bb00d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -428,10 +428,6 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); - QMenu* audioOptionsMenu = developerMenu->addMenu("Audio Options"); - - addCheckableActionToQMenuAndActionHash(audioOptionsMenu, MenuOption::DisableQAudioOutputOverflowCheck, 0, false); - addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNackPackets, 0, false); addDisabledActionAndSeparator(developerMenu, "Testing"); @@ -579,6 +575,8 @@ Menu::Menu() : Qt::CTRL | Qt::SHIFT | Qt::Key_U, false); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::DisableQAudioOutputOverflowCheck, 0, false); + addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel, Qt::CTRL | Qt::SHIFT | Qt::Key_V, this, From bc785115a938c36763e418e8707c88475270c1c7 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 8 Jul 2014 16:33:31 -0700 Subject: [PATCH 6/6] Fix script errors not being reported Script.update event needs to be emitted after reporting any script errors. --- libraries/script-engine/src/ScriptEngine.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index e93a7125b9..f5f15331ac 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -515,8 +515,6 @@ void ScriptEngine::run() { qint64 now = usecTimestampNow(); float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; - emit update(deltaTime); - lastUpdate = now; if (_engine.hasUncaughtException()) { int line = _engine.uncaughtExceptionLineNumber(); @@ -524,6 +522,9 @@ void ScriptEngine::run() { emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + _engine.uncaughtException().toString()); _engine.clearExceptions(); } + + emit update(deltaTime); + lastUpdate = now; } emit scriptEnding();