diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index dbb1620252..dd48c9daa7 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -33,12 +33,17 @@ #include "Agent.h" +static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10; + Agent::Agent(const QByteArray& packet) : ThreadedAssignment(packet), _voxelEditSender(), _particleEditSender(), _modelEditSender(), - _receivedAudioStream(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, 1, false, 1, 0, false), + _receivedAudioStream(NETWORK_BUFFER_LENGTH_SAMPLES_STEREO, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, + InboundAudioStream::Settings(0, false, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, false, + DEFAULT_WINDOW_STARVE_THRESHOLD, DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES, + DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION)), _avatarHashMap() { // be the parent of the script engine so it gets moved when we do diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 5900e1f151..fc223ab850 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -67,9 +67,7 @@ void attachNewNodeDataToNode(Node *newNode) { } } -bool AudioMixer::_useDynamicJitterBuffers = false; -int AudioMixer::_staticDesiredJitterBufferFrames = 0; -int AudioMixer::_maxFramesOverDesired = 0; +InboundAudioStream::Settings AudioMixer::_streamSettings; AudioMixer::AudioMixer(const QByteArray& packet) : ThreadedAssignment(packet), @@ -332,7 +330,7 @@ void AudioMixer::readPendingDatagrams() { void AudioMixer::sendStatsPacket() { static QJsonObject statsObject; - statsObject["useDynamicJitterBuffers"] = _useDynamicJitterBuffers; + statsObject["useDynamicJitterBuffers"] = _streamSettings._dynamicJitterBuffers; statsObject["trailing_sleep_percentage"] = _trailingSleepRatio * 100.0f; statsObject["performance_throttling_ratio"] = _performanceThrottlingRatio; @@ -421,36 +419,62 @@ void AudioMixer::run() { if (settingsObject.contains(AUDIO_GROUP_KEY)) { QJsonObject audioGroupObject = settingsObject[AUDIO_GROUP_KEY].toObject(); - // check the payload to see if we have asked for dynamicJitterBuffer support - const QString DYNAMIC_JITTER_BUFFER_JSON_KEY = "A-dynamic-jitter-buffer"; - bool shouldUseDynamicJitterBuffers = audioGroupObject[DYNAMIC_JITTER_BUFFER_JSON_KEY].toBool(); - if (shouldUseDynamicJitterBuffers) { - qDebug() << "Enable dynamic jitter buffers."; - _useDynamicJitterBuffers = true; - } else { - qDebug() << "Dynamic jitter buffers disabled."; - _useDynamicJitterBuffers = false; - } - bool ok; - const QString DESIRED_JITTER_BUFFER_FRAMES_KEY = "B-desired-jitter-buffer-frames"; - _staticDesiredJitterBufferFrames = audioGroupObject[DESIRED_JITTER_BUFFER_FRAMES_KEY].toString().toInt(&ok); - if (!ok) { - _staticDesiredJitterBufferFrames = DEFAULT_DESIRED_JITTER_BUFFER_FRAMES; + // check the payload to see if we have asked for dynamicJitterBuffer support + const QString DYNAMIC_JITTER_BUFFER_JSON_KEY = "A-dynamic-jitter-buffer"; + _streamSettings._dynamicJitterBuffers = audioGroupObject[DYNAMIC_JITTER_BUFFER_JSON_KEY].toBool(); + if (_streamSettings._dynamicJitterBuffers) { + qDebug() << "Enable dynamic jitter buffers."; + } else { + qDebug() << "Dynamic jitter buffers disabled."; } - qDebug() << "Static desired jitter buffer frames:" << _staticDesiredJitterBufferFrames; + + const QString DESIRED_JITTER_BUFFER_FRAMES_KEY = "B-desired-jitter-buffer-frames"; + _streamSettings._staticDesiredJitterBufferFrames = audioGroupObject[DESIRED_JITTER_BUFFER_FRAMES_KEY].toString().toInt(&ok); + if (!ok) { + _streamSettings._staticDesiredJitterBufferFrames = DEFAULT_STATIC_DESIRED_JITTER_BUFFER_FRAMES; + } + qDebug() << "Static desired jitter buffer frames:" << _streamSettings._staticDesiredJitterBufferFrames; const QString MAX_FRAMES_OVER_DESIRED_JSON_KEY = "C-max-frames-over-desired"; - _maxFramesOverDesired = audioGroupObject[MAX_FRAMES_OVER_DESIRED_JSON_KEY].toString().toInt(&ok); + _streamSettings._maxFramesOverDesired = audioGroupObject[MAX_FRAMES_OVER_DESIRED_JSON_KEY].toString().toInt(&ok); if (!ok) { - _maxFramesOverDesired = DEFAULT_MAX_FRAMES_OVER_DESIRED; + _streamSettings._maxFramesOverDesired = DEFAULT_MAX_FRAMES_OVER_DESIRED; } - qDebug() << "Max frames over desired:" << _maxFramesOverDesired; + qDebug() << "Max frames over desired:" << _streamSettings._maxFramesOverDesired; + + const QString USE_STDEV_FOR_DESIRED_CALC_JSON_KEY = "D-use-stdev-for-desired-calc"; + _streamSettings._useStDevForJitterCalc = audioGroupObject[USE_STDEV_FOR_DESIRED_CALC_JSON_KEY].toBool(); + if (_streamSettings._useStDevForJitterCalc) { + qDebug() << "Using Philip's stdev method for jitter calc if dynamic jitter buffers enabled"; + } else { + qDebug() << "Using Fred's max-gap method for jitter calc if dynamic jitter buffers enabled"; + } + + const QString WINDOW_STARVE_THRESHOLD_JSON_KEY = "E-window-starve-threshold"; + _streamSettings._windowStarveThreshold = audioGroupObject[WINDOW_STARVE_THRESHOLD_JSON_KEY].toString().toInt(&ok); + if (!ok) { + _streamSettings._windowStarveThreshold = DEFAULT_WINDOW_STARVE_THRESHOLD; + } + qDebug() << "Window A starve threshold:" << _streamSettings._windowStarveThreshold; + + const QString WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES_JSON_KEY = "F-window-seconds-for-desired-calc-on-too-many-starves"; + _streamSettings._windowSecondsForDesiredCalcOnTooManyStarves = audioGroupObject[WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES_JSON_KEY].toString().toInt(&ok); + if (!ok) { + _streamSettings._windowSecondsForDesiredCalcOnTooManyStarves = DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES; + } + qDebug() << "Window A length:" << _streamSettings._windowSecondsForDesiredCalcOnTooManyStarves << "seconds"; + + const QString WINDOW_SECONDS_FOR_DESIRED_REDUCTION_JSON_KEY = "G-window-seconds-for-desired-reduction"; + _streamSettings._windowSecondsForDesiredReduction = audioGroupObject[WINDOW_SECONDS_FOR_DESIRED_REDUCTION_JSON_KEY].toString().toInt(&ok); + if (!ok) { + _streamSettings._windowSecondsForDesiredReduction = DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION; + } + qDebug() << "Window B length:" << _streamSettings._windowSecondsForDesiredReduction << "seconds"; - - const QString UNATTENUATED_ZONE_KEY = "D-unattenuated-zone"; + const QString UNATTENUATED_ZONE_KEY = "Z-unattenuated-zone"; QString unattenuatedZoneString = audioGroupObject[UNATTENUATED_ZONE_KEY].toString(); if (!unattenuatedZoneString.isEmpty()) { diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 83769a4209..3df2bce682 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -37,9 +37,7 @@ public slots: void sendStatsPacket(); - static bool getUseDynamicJitterBuffers() { return _useDynamicJitterBuffers; } - static int getStaticDesiredJitterBufferFrames() { return _staticDesiredJitterBufferFrames; } - static int getMaxFramesOverDesired() { return _maxFramesOverDesired; } + static const InboundAudioStream::Settings& getStreamSettings() { return _streamSettings; } private: /// adds one stream to the mix for a listening node @@ -62,9 +60,7 @@ private: AABox* _sourceUnattenuatedZone; AABox* _listenerUnattenuatedZone; - static bool _useDynamicJitterBuffers; - static int _staticDesiredJitterBufferFrames; - static int _maxFramesOverDesired; + static InboundAudioStream::Settings _streamSettings; quint64 _lastSendAudioStreamStatsTime; }; diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index ecb4d29171..333357fbf4 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -73,9 +73,7 @@ int AudioMixerClientData::parseData(const QByteArray& packet) { quint8 channelFlag = *(reinterpret_cast(channelFlagAt)); bool isStereo = channelFlag == 1; - _audioStreams.insert(nullUUID, - matchingStream = new AvatarAudioStream(isStereo, AudioMixer::getUseDynamicJitterBuffers(), - AudioMixer::getStaticDesiredJitterBufferFrames(), AudioMixer::getMaxFramesOverDesired())); + _audioStreams.insert(nullUUID, matchingStream = new AvatarAudioStream(isStereo, AudioMixer::getStreamSettings())); } else { matchingStream = _audioStreams.value(nullUUID); } @@ -87,9 +85,8 @@ int AudioMixerClientData::parseData(const QByteArray& packet) { QUuid streamIdentifier = QUuid::fromRfc4122(packet.mid(bytesBeforeStreamIdentifier, NUM_BYTES_RFC4122_UUID)); if (!_audioStreams.contains(streamIdentifier)) { - _audioStreams.insert(streamIdentifier, - matchingStream = new InjectedAudioStream(streamIdentifier, AudioMixer::getUseDynamicJitterBuffers(), - AudioMixer::getStaticDesiredJitterBufferFrames(), AudioMixer::getMaxFramesOverDesired())); + // we don't have this injected stream yet, so add it + _audioStreams.insert(streamIdentifier, matchingStream = new InjectedAudioStream(streamIdentifier, AudioMixer::getStreamSettings())); } else { matchingStream = _audioStreams.value(streamIdentifier); } diff --git a/assignment-client/src/audio/AvatarAudioStream.cpp b/assignment-client/src/audio/AvatarAudioStream.cpp index fcb78d7a6c..877d1a37c7 100644 --- a/assignment-client/src/audio/AvatarAudioStream.cpp +++ b/assignment-client/src/audio/AvatarAudioStream.cpp @@ -13,8 +13,8 @@ #include "AvatarAudioStream.h" -AvatarAudioStream::AvatarAudioStream(bool isStereo, bool dynamicJitterBuffer, int staticDesiredJitterBufferFrames, int maxFramesOverDesired) : - PositionalAudioStream(PositionalAudioStream::Microphone, isStereo, dynamicJitterBuffer, staticDesiredJitterBufferFrames, maxFramesOverDesired) +AvatarAudioStream::AvatarAudioStream(bool isStereo, const InboundAudioStream::Settings& settings) : + PositionalAudioStream(PositionalAudioStream::Microphone, isStereo, settings) { } diff --git a/assignment-client/src/audio/AvatarAudioStream.h b/assignment-client/src/audio/AvatarAudioStream.h index ebad4585e0..2eb0e674b0 100644 --- a/assignment-client/src/audio/AvatarAudioStream.h +++ b/assignment-client/src/audio/AvatarAudioStream.h @@ -18,7 +18,7 @@ class AvatarAudioStream : public PositionalAudioStream { public: - AvatarAudioStream(bool isStereo, bool dynamicJitterBuffer, int staticDesiredJitterBufferFrames, int maxFramesOverDesired); + AvatarAudioStream(bool isStereo, const InboundAudioStream::Settings& settings); private: // disallow copying of AvatarAudioStream objects diff --git a/domain-server/resources/web/settings/describe.json b/domain-server/resources/web/settings/describe.json index f4920a7b50..59d99eab11 100644 --- a/domain-server/resources/web/settings/describe.json +++ b/domain-server/resources/web/settings/describe.json @@ -21,7 +21,31 @@ "placeholder": "10", "default": "10" }, - "D-unattenuated-zone": { + "D-use-stdev": { + "type": "checkbox", + "label": "Use Stdev for Desired Jitter Frames Calc:", + "help": "If checked, Philip's method (stdev of timegaps) is used to calculate desired jitter frames. Otherwise, Fred's method (max timegap) is used", + "default": false + } + "E-window-starve-threshold": { + "label": "Window Starve Threshold", + "help": "If this many starves occur in an N-second window (N is the number in the next field), then the desired jitter frames will be re-evaluated using Window A.", + "placeholder": "3", + "default": "3" + }, + "F-window-seconds-for-desired-calc-on-too-many-starves": { + "label": "Timegaps Window (A) Seconds:", + "help": "Window A contains a history of timegaps. Its max timegap is used to re-evaluate the desired jitter frames when too many starves occur within it.", + "placeholder": "50", + "default": "50" + }, + "G-window-seconds-for-desired-reduction": { + "label": "Timegaps Window (B) Seconds:", + "help": "Window B contains a history of timegaps. Its max timegap is used as a ceiling for the desired jitter frames value.", + "placeholder": "10", + "default": "10" + }, + "Z-unattenuated-zone": { "label": "Unattenuated Zone", "help": "Boxes for source and listener (corner x, corner y, corner z, size x, size y, size z, corner x, corner y, corner z, size x, size y, size z)", "placeholder": "no zone", diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7eb087c531..a7d6cd9f3b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1763,14 +1763,7 @@ void Application::init() { _lastTimeUpdated.start(); Menu::getInstance()->loadSettings(); - if (Menu::getInstance()->getAudioJitterBufferFrames() != 0) { - _audio.setDynamicJitterBuffers(false); - _audio.setStaticDesiredJitterBufferFrames(Menu::getInstance()->getAudioJitterBufferFrames()); - } else { - _audio.setDynamicJitterBuffers(true); - } - - _audio.setMaxFramesOverDesired(Menu::getInstance()->getMaxFramesOverDesired()); + _audio.setReceivedAudioStreamSettings(Menu::getInstance()->getReceivedAudioStreamSettings()); qDebug("Loaded settings"); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 6ff053e5db..9244788de8 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -73,7 +73,7 @@ Audio::Audio(QObject* parent) : _proceduralAudioOutput(NULL), _proceduralOutputDevice(NULL), _inputRingBuffer(0), - _receivedAudioStream(0, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, true, 0, 0, true), + _receivedAudioStream(0, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, InboundAudioStream::Settings()), _isStereoInput(false), _averagedLatency(0.0), _lastInputLoudness(0), @@ -840,12 +840,11 @@ void Audio::parseAudioStreamStatsPacket(const QByteArray& packet) { void Audio::sendDownstreamAudioStatsPacket() { - // since this function is called every second, we'll sample some of our stats here - + // since this function is called every second, we'll sample for some of our stats here _inputRingBufferMsecsAvailableStats.update(getInputRingBufferMsecsAvailable()); - _audioOutputMsecsUnplayedStats.update(getAudioOutputMsecsUnplayed()); + // also, call _receivedAudioStream's per-second callback _receivedAudioStream.perSecondCallbackForUpdatingStats(); char packet[MAX_PACKET_SIZE]; diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 8fae6f3bdd..a93b8c5be7 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -71,10 +71,7 @@ public: virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen); virtual void startDrumSound(float volume, float frequency, float duration, float decay); - void setDynamicJitterBuffers(bool dynamicJitterBuffers) { _receivedAudioStream.setDynamicJitterBuffers(dynamicJitterBuffers); } - void setStaticDesiredJitterBufferFrames(int staticDesiredJitterBufferFrames) { _receivedAudioStream.setStaticDesiredJitterBufferFrames(staticDesiredJitterBufferFrames); } - - void setMaxFramesOverDesired(int maxFramesOverDesired) { _receivedAudioStream.setMaxFramesOverDesired(maxFramesOverDesired); } + void setReceivedAudioStreamSettings(const InboundAudioStream::Settings& settings) { _receivedAudioStream.setSettings(settings); } int getDesiredJitterBufferFrames() const { return _receivedAudioStream.getDesiredJitterBufferFrames(); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 43d9fde01a..ecf28bcb17 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -82,8 +82,7 @@ const int CONSOLE_HEIGHT = 200; Menu::Menu() : _actionHash(), - _audioJitterBufferFrames(0), - _maxFramesOverDesired(0), + _receivedAudioStreamSettings(), _bandwidthDialog(NULL), _fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES), _realWorldFieldOfView(DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES), @@ -632,8 +631,14 @@ void Menu::loadSettings(QSettings* settings) { lockedSettings = true; } - _audioJitterBufferFrames = loadSetting(settings, "audioJitterBufferFrames", 0); - _maxFramesOverDesired = loadSetting(settings, "maxFramesOverDesired", DEFAULT_MAX_FRAMES_OVER_DESIRED); + _receivedAudioStreamSettings._dynamicJitterBuffers = settings->value("dynamicJitterBuffers", DEFAULT_DYNAMIC_JITTER_BUFFERS).toBool(); + _receivedAudioStreamSettings._maxFramesOverDesired = settings->value("maxFramesOverDesired", DEFAULT_MAX_FRAMES_OVER_DESIRED).toInt(); + _receivedAudioStreamSettings._staticDesiredJitterBufferFrames = settings->value("staticDesiredJitterBufferFrames", DEFAULT_STATIC_DESIRED_JITTER_BUFFER_FRAMES).toInt(); + _receivedAudioStreamSettings._useStDevForJitterCalc = settings->value("useStDevForJitterCalc", DEFAULT_USE_STDEV_FOR_JITTER_CALC).toBool(); + _receivedAudioStreamSettings._windowStarveThreshold = settings->value("windowStarveThreshold", DEFAULT_WINDOW_STARVE_THRESHOLD).toInt(); + _receivedAudioStreamSettings._windowSecondsForDesiredCalcOnTooManyStarves = settings->value("windowSecondsForDesiredCalcOnTooManyStarves", DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES).toInt(); + _receivedAudioStreamSettings._windowSecondsForDesiredReduction = settings->value("windowSecondsForDesiredReduction", DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION).toInt(); + _fieldOfView = loadSetting(settings, "fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES); _realWorldFieldOfView = loadSetting(settings, "realWorldFieldOfView", DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES); _faceshiftEyeDeflection = loadSetting(settings, "faceshiftEyeDeflection", DEFAULT_FACESHIFT_EYE_DEFLECTION); @@ -683,8 +688,14 @@ void Menu::saveSettings(QSettings* settings) { lockedSettings = true; } - settings->setValue("audioJitterBufferFrames", _audioJitterBufferFrames); - settings->setValue("maxFramesOverDesired", _maxFramesOverDesired); + settings->setValue("dynamicJitterBuffers", _receivedAudioStreamSettings._dynamicJitterBuffers); + settings->setValue("maxFramesOverDesired", _receivedAudioStreamSettings._maxFramesOverDesired); + settings->setValue("staticDesiredJitterBufferFrames", _receivedAudioStreamSettings._staticDesiredJitterBufferFrames); + settings->setValue("useStDevForJitterCalc", _receivedAudioStreamSettings._useStDevForJitterCalc); + settings->setValue("windowStarveThreshold", _receivedAudioStreamSettings._windowStarveThreshold); + settings->setValue("windowSecondsForDesiredCalcOnTooManyStarves", _receivedAudioStreamSettings._windowSecondsForDesiredCalcOnTooManyStarves); + settings->setValue("windowSecondsForDesiredReduction", _receivedAudioStreamSettings._windowSecondsForDesiredReduction); + settings->setValue("fieldOfView", _fieldOfView); settings->setValue("faceshiftEyeDeflection", _faceshiftEyeDeflection); settings->setValue("maxVoxels", _maxVoxels); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3bef306bef..20097989df 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -85,10 +85,8 @@ public: void triggerOption(const QString& menuOption); QAction* getActionForOption(const QString& menuOption); - float getAudioJitterBufferFrames() const { return _audioJitterBufferFrames; } - void setAudioJitterBufferFrames(float audioJitterBufferSamples) { _audioJitterBufferFrames = audioJitterBufferSamples; } - int getMaxFramesOverDesired() const { return _maxFramesOverDesired; } - void setMaxFramesOverDesired(int maxFramesOverDesired) { _maxFramesOverDesired = maxFramesOverDesired; } + const InboundAudioStream::Settings& getReceivedAudioStreamSettings() const { return _receivedAudioStreamSettings; } + void getReceivedAudioStreamSettings(const InboundAudioStream::Settings& receivedAudioStreamSettings) { _receivedAudioStreamSettings = receivedAudioStreamSettings; } float getFieldOfView() const { return _fieldOfView; } void setFieldOfView(float fieldOfView) { _fieldOfView = fieldOfView; } float getRealWorldFieldOfView() const { return _realWorldFieldOfView; } @@ -259,8 +257,7 @@ private: QHash _actionHash; - int _audioJitterBufferFrames; /// number of extra samples to wait before starting audio playback - int _maxFramesOverDesired; + InboundAudioStream::Settings _receivedAudioStreamSettings; BandwidthDialog* _bandwidthDialog; float _fieldOfView; /// in Degrees, doesn't apply to HMD like Oculus float _realWorldFieldOfView; // The actual FOV set by the user's monitor size and view distance diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 4ebd5f4c1a..7189a74579 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -149,9 +149,21 @@ void PreferencesDialog::loadPreferences() { ui.faceshiftEyeDeflectionSider->setValue(menuInstance->getFaceshiftEyeDeflection() * ui.faceshiftEyeDeflectionSider->maximum()); - ui.audioJitterSpin->setValue(menuInstance->getAudioJitterBufferFrames()); + const InboundAudioStream::Settings& streamSettings = menuInstance->getReceivedAudioStreamSettings(); - ui.maxFramesOverDesiredSpin->setValue(menuInstance->getMaxFramesOverDesired()); + ui.dynamicJitterBuffersCheckBox->setChecked(streamSettings._dynamicJitterBuffers); + + ui.staticDesiredJitterBufferFramesSpin->setValue(streamSettings._staticDesiredJitterBufferFrames); + + ui.maxFramesOverDesiredSpin->setValue(streamSettings._maxFramesOverDesired); + + ui.useStdevForJitterCalcCheckBox->setChecked(streamSettings._useStDevForJitterCalc); + + ui.windowStarveThresholdSpin->setValue(streamSettings._windowStarveThreshold); + + ui.windowSecondsForDesiredCalcOnTooManyStarvesSpin->setValue(streamSettings._windowSecondsForDesiredCalcOnTooManyStarves); + + ui.windowSecondsForDesiredReductionSpin->setValue(streamSettings._windowSecondsForDesiredReduction); ui.realWorldFieldOfViewSpin->setValue(menuInstance->getRealWorldFieldOfView()); @@ -241,16 +253,17 @@ void PreferencesDialog::savePreferences() { Menu::getInstance()->setInvertSixenseButtons(ui.invertSixenseButtonsCheckBox->isChecked()); - Menu::getInstance()->setAudioJitterBufferFrames(ui.audioJitterSpin->value()); - if (Menu::getInstance()->getAudioJitterBufferFrames() != 0) { - Application::getInstance()->getAudio()->setDynamicJitterBuffers(false); - Application::getInstance()->getAudio()->setStaticDesiredJitterBufferFrames(Menu::getInstance()->getAudioJitterBufferFrames()); - } else { - Application::getInstance()->getAudio()->setDynamicJitterBuffers(true); - } + InboundAudioStream::Settings streamSettings; + streamSettings._dynamicJitterBuffers = ui.dynamicJitterBuffersCheckBox->isChecked(); + streamSettings._staticDesiredJitterBufferFrames = ui.staticDesiredJitterBufferFramesSpin->value(); + streamSettings._maxFramesOverDesired = ui.maxFramesOverDesiredSpin->value(); + streamSettings._useStDevForJitterCalc = ui.useStdevForJitterCalcCheckBox->isChecked(); + streamSettings._windowStarveThreshold = ui.windowStarveThresholdSpin->value(); + streamSettings._windowSecondsForDesiredCalcOnTooManyStarves = ui.windowSecondsForDesiredCalcOnTooManyStarvesSpin->value(); + streamSettings._windowSecondsForDesiredReduction = ui.windowSecondsForDesiredReductionSpin->value(); - Menu::getInstance()->setMaxFramesOverDesired(ui.maxFramesOverDesiredSpin->value()); - Application::getInstance()->getAudio()->setMaxFramesOverDesired(Menu::getInstance()->getMaxFramesOverDesired()); + Menu::getInstance()->getReceivedAudioStreamSettings(streamSettings); + Application::getInstance()->getAudio()->setReceivedAudioStreamSettings(streamSettings); Application::getInstance()->resizeGL(Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height()); diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index 566c24e4e3..cddc0f1299 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -1464,6 +1464,97 @@ padding: 10px;margin-top:10px + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + color: rgb(51, 51, 51) + + + Enable Dynamic Jitter Buffers + + + 15 + + + dynamicJitterBuffersCheckBox + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 32 + 0 + + + + + 0 + 0 + + + + + + + + 32 + 32 + + + + + + + + + @@ -1489,13 +1580,13 @@ padding: 10px;margin-top:10px color: rgb(51, 51, 51) - Audio Jitter Buffer Frames (0 for automatic) + Static Jitter Buffer Frames 15 - audioJitterSpin + staticDesiredJitterBufferFramesSpin @@ -1518,7 +1609,7 @@ padding: 10px;margin-top:10px - + 0 @@ -1555,6 +1646,7 @@ padding: 10px;margin-top:10px + @@ -1646,7 +1738,378 @@ padding: 10px;margin-top:10px - + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + color: rgb(51, 51, 51) + + + Use Stdev for Dynamic Jitter Calc + + + 15 + + + useStdevForJitterCalcCheckBox + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 32 + 0 + + + + + 0 + 0 + + + + + + + + 32 + 32 + + + + + + + + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + color: rgb(51, 51, 51) + + + Window A Starve Threshold + + + 15 + + + windowStarveThresholdSpin + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 95 + 36 + + + + + 70 + 16777215 + + + + + Arial + + + + 0 + + + 10000 + + + 1 + + + + + + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + color: rgb(51, 51, 51) + + + Window A (raise desired on N starves) Seconds + + + 15 + + + windowSecondsForDesiredCalcOnTooManyStarvesSpin + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 95 + 36 + + + + + 70 + 16777215 + + + + + Arial + + + + 0 + + + 10000 + + + 1 + + + + + + + + + + + + 0 + + + 10 + + + 0 + + + 10 + + + + + + Arial + + + + color: rgb(51, 51, 51) + + + Window B (desired ceiling) Seconds + + + 15 + + + windowSecondsForDesiredReductionSpin + + + + + + + + Arial + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 95 + 36 + + + + + 70 + 16777215 + + + + + Arial + + + + 0 + + + 10000 + + + 1 + + + + + diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index f59070ee83..55322d6f32 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -38,6 +38,7 @@ InboundAudioStream::InboundAudioStream(int numFrameSamples, int numFramesCapacit _timeGapStatsForDesiredReduction(0, settings._windowSecondsForDesiredReduction), _starveHistoryWindowSeconds(settings._windowSecondsForDesiredCalcOnTooManyStarves), _starveHistory(STARVE_HISTORY_CAPACITY), + _starveThreshold(settings._windowStarveThreshold), _framesAvailableStat(), _currentJitterBufferFrames(0), _timeGapStatsForStatsPacket(0, STATS_FOR_STATS_PACKET_WINDOW_SECONDS) @@ -237,6 +238,16 @@ void InboundAudioStream::setToStarved() { _isStarved = (_ringBuffer.framesAvailable() < _desiredJitterBufferFrames); } +void InboundAudioStream::setSettings(const Settings& settings) { + setMaxFramesOverDesired(settings._maxFramesOverDesired); + setDynamicJitterBuffers(settings._dynamicJitterBuffers); + setStaticDesiredJitterBufferFrames(settings._staticDesiredJitterBufferFrames); + setUseStDevForJitterCalc(settings._useStDevForJitterCalc); + setWindowStarveThreshold(settings._windowStarveThreshold); + setWindowSecondsForDesiredCalcOnTooManyStarves(settings._windowSecondsForDesiredCalcOnTooManyStarves); + setWindowSecondsForDesiredReduction(settings._windowSecondsForDesiredReduction); +} + void InboundAudioStream::setDynamicJitterBuffers(bool dynamicJitterBuffers) { if (!dynamicJitterBuffers) { _desiredJitterBufferFrames = _staticDesiredJitterBufferFrames; @@ -255,6 +266,15 @@ void InboundAudioStream::setStaticDesiredJitterBufferFrames(int staticDesiredJit } } +void InboundAudioStream::setWindowSecondsForDesiredCalcOnTooManyStarves(int windowSecondsForDesiredCalcOnTooManyStarves) { + _timeGapStatsForDesiredCalcOnTooManyStarves.setWindowIntervals(windowSecondsForDesiredCalcOnTooManyStarves); +} + +void InboundAudioStream::setWindowSecondsForDesiredReduction(int windowSecondsForDesiredReduction) { + _timeGapStatsForDesiredReduction.setWindowIntervals(windowSecondsForDesiredReduction); +} + + int InboundAudioStream::clampDesiredJitterBufferFramesValue(int desired) const { const int MIN_FRAMES_DESIRED = 0; const int MAX_FRAMES_DESIRED = _ringBuffer.getFrameCapacity(); diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index 88760a35cb..791886ab5e 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -39,7 +39,9 @@ const int FRAMES_AVAILABLE_STAT_WINDOW_USECS = 2 * USECS_PER_SECOND; const int INBOUND_RING_BUFFER_FRAME_CAPACITY = 100; const int DEFAULT_MAX_FRAMES_OVER_DESIRED = 10; -const int DEFAULT_DESIRED_JITTER_BUFFER_FRAMES = 1; +const bool DEFAULT_DYNAMIC_JITTER_BUFFERS = true; +const int DEFAULT_STATIC_DESIRED_JITTER_BUFFER_FRAMES = 1; +const bool DEFAULT_USE_STDEV_FOR_JITTER_CALC = false; const int DEFAULT_WINDOW_STARVE_THRESHOLD = 3; const int DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES = 50; @@ -52,14 +54,26 @@ public: public: Settings() : _maxFramesOverDesired(DEFAULT_MAX_FRAMES_OVER_DESIRED), - _dynamicJitterBuffers(true), - _staticDesiredJitterBufferFrames(DEFAULT_DESIRED_JITTER_BUFFER_FRAMES), - _useStDevForJitterCalc(false), + _dynamicJitterBuffers(DEFAULT_DYNAMIC_JITTER_BUFFERS), + _staticDesiredJitterBufferFrames(DEFAULT_STATIC_DESIRED_JITTER_BUFFER_FRAMES), + _useStDevForJitterCalc(DEFAULT_USE_STDEV_FOR_JITTER_CALC), _windowStarveThreshold(DEFAULT_WINDOW_STARVE_THRESHOLD), _windowSecondsForDesiredCalcOnTooManyStarves(DEFAULT_WINDOW_SECONDS_FOR_DESIRED_CALC_ON_TOO_MANY_STARVES), _windowSecondsForDesiredReduction(DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION) {} + Settings(int maxFramesOverDesired, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, + bool useStDevForJitterCalc, int windowStarveThreshold, int windowSecondsForDesiredCalcOnTooManyStarves, + int _windowSecondsForDesiredReduction) + : _maxFramesOverDesired(maxFramesOverDesired), + _dynamicJitterBuffers(dynamicJitterBuffers), + _staticDesiredJitterBufferFrames(staticDesiredJitterBufferFrames), + _useStDevForJitterCalc(useStDevForJitterCalc), + _windowStarveThreshold(windowStarveThreshold), + _windowSecondsForDesiredCalcOnTooManyStarves(windowSecondsForDesiredCalcOnTooManyStarves), + _windowSecondsForDesiredReduction(windowSecondsForDesiredCalcOnTooManyStarves) + {} + // max number of frames over desired in the ringbuffer. int _maxFramesOverDesired; @@ -95,15 +109,17 @@ public: void setToStarved(); - - void setDynamicJitterBuffers(bool dynamicJitterBuffers); - void setStaticDesiredJitterBufferFrames(int staticDesiredJitterBufferFrames); - - /// this function should be called once per second to ensure the seq num stats history spans ~30 seconds - //AudioStreamStats updateSeqHistoryAndGetAudioStreamStats(); + void setSettings(const Settings& settings); void setMaxFramesOverDesired(int maxFramesOverDesired) { _maxFramesOverDesired = maxFramesOverDesired; } + void setDynamicJitterBuffers(bool setDynamicJitterBuffers); + void setStaticDesiredJitterBufferFrames(int staticDesiredJitterBufferFrames); + void setUseStDevForJitterCalc(bool useStDevForJitterCalc) { _useStDevForJitterCalc = useStDevForJitterCalc; } + void setWindowStarveThreshold(int windowStarveThreshold) { _starveThreshold = windowStarveThreshold; } + void setWindowSecondsForDesiredCalcOnTooManyStarves(int windowSecondsForDesiredCalcOnTooManyStarves); + void setWindowSecondsForDesiredReduction(int windowSecondsForDesiredReduction); + virtual AudioStreamStats getAudioStreamStats() const; @@ -205,6 +221,7 @@ protected: int _starveHistoryWindowSeconds; RingBufferHistory _starveHistory; + int _starveThreshold; TimeWeightedAvg _framesAvailableStat; diff --git a/libraries/audio/src/InjectedAudioStream.cpp b/libraries/audio/src/InjectedAudioStream.cpp index 5c1c2ed269..9a757b774e 100644 --- a/libraries/audio/src/InjectedAudioStream.cpp +++ b/libraries/audio/src/InjectedAudioStream.cpp @@ -19,8 +19,8 @@ #include "InjectedAudioStream.h" -InjectedAudioStream::InjectedAudioStream(const QUuid& streamIdentifier, bool dynamicJitterBuffer, int staticDesiredJitterBufferFrames, int maxFramesOverDesired) : - PositionalAudioStream(PositionalAudioStream::Injector, false, dynamicJitterBuffer, staticDesiredJitterBufferFrames, maxFramesOverDesired), +InjectedAudioStream::InjectedAudioStream(const QUuid& streamIdentifier, const InboundAudioStream::Settings& settings) : + PositionalAudioStream(PositionalAudioStream::Injector, false, settings), _streamIdentifier(streamIdentifier), _radius(0.0f), _attenuationRatio(0) diff --git a/libraries/audio/src/InjectedAudioStream.h b/libraries/audio/src/InjectedAudioStream.h index d8d9a54c6e..f3840b1029 100644 --- a/libraries/audio/src/InjectedAudioStream.h +++ b/libraries/audio/src/InjectedAudioStream.h @@ -18,7 +18,7 @@ class InjectedAudioStream : public PositionalAudioStream { public: - InjectedAudioStream(const QUuid& streamIdentifier, bool dynamicJitterBuffer, int staticDesiredJitterBufferFrames, int maxFramesOverDesired); + InjectedAudioStream(const QUuid& streamIdentifier, const InboundAudioStream::Settings& settings); float getRadius() const { return _radius; } float getAttenuationRatio() const { return _attenuationRatio; } diff --git a/libraries/audio/src/MixedAudioStream.cpp b/libraries/audio/src/MixedAudioStream.cpp index 38c4ae641d..0041348d26 100644 --- a/libraries/audio/src/MixedAudioStream.cpp +++ b/libraries/audio/src/MixedAudioStream.cpp @@ -11,8 +11,8 @@ #include "MixedAudioStream.h" -MixedAudioStream::MixedAudioStream(int numFrameSamples, int numFramesCapacity, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, int maxFramesOverDesired, bool useStDevForJitterCalc) - : InboundAudioStream(numFrameSamples, numFramesCapacity, dynamicJitterBuffers, staticDesiredJitterBufferFrames, maxFramesOverDesired, useStDevForJitterCalc) +MixedAudioStream::MixedAudioStream(int numFrameSamples, int numFramesCapacity, const InboundAudioStream::Settings& settings) + : InboundAudioStream(numFrameSamples, numFramesCapacity, settings) { } diff --git a/libraries/audio/src/MixedAudioStream.h b/libraries/audio/src/MixedAudioStream.h index d19f19af07..0b1979003d 100644 --- a/libraries/audio/src/MixedAudioStream.h +++ b/libraries/audio/src/MixedAudioStream.h @@ -17,7 +17,7 @@ class MixedAudioStream : public InboundAudioStream { public: - MixedAudioStream(int numFrameSamples, int numFramesCapacity, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, int maxFramesOverDesired, bool useStDevForJitterCalc); + MixedAudioStream(int numFrameSamples, int numFramesCapacity, const InboundAudioStream::Settings& settings); float getNextOutputFrameLoudness() const { return _ringBuffer.getNextOutputFrameLoudness(); } diff --git a/libraries/audio/src/MixedProcessedAudioStream.cpp b/libraries/audio/src/MixedProcessedAudioStream.cpp index 49990dcd22..52581bd096 100644 --- a/libraries/audio/src/MixedProcessedAudioStream.cpp +++ b/libraries/audio/src/MixedProcessedAudioStream.cpp @@ -11,8 +11,8 @@ #include "MixedProcessedAudioStream.h" -MixedProcessedAudioStream ::MixedProcessedAudioStream (int numFrameSamples, int numFramesCapacity, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, int maxFramesOverDesired, bool useStDevForJitterCalc) - : InboundAudioStream(numFrameSamples, numFramesCapacity, dynamicJitterBuffers, staticDesiredJitterBufferFrames, maxFramesOverDesired, useStDevForJitterCalc) +MixedProcessedAudioStream::MixedProcessedAudioStream(int numFrameSamples, int numFramesCapacity, const InboundAudioStream::Settings& settings) + : InboundAudioStream(numFrameSamples, numFramesCapacity, settings) { } diff --git a/libraries/audio/src/MixedProcessedAudioStream.h b/libraries/audio/src/MixedProcessedAudioStream.h index 5a5b73115d..e033297362 100644 --- a/libraries/audio/src/MixedProcessedAudioStream.h +++ b/libraries/audio/src/MixedProcessedAudioStream.h @@ -17,7 +17,7 @@ class MixedProcessedAudioStream : public InboundAudioStream { Q_OBJECT public: - MixedProcessedAudioStream (int numFrameSamples, int numFramesCapacity, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, int maxFramesOverDesired, bool useStDevForJitterCalc); + MixedProcessedAudioStream(int numFrameSamples, int numFramesCapacity, const InboundAudioStream::Settings& settings); signals: diff --git a/libraries/audio/src/PositionalAudioStream.cpp b/libraries/audio/src/PositionalAudioStream.cpp index 7b407ba62c..d2c1ade85c 100644 --- a/libraries/audio/src/PositionalAudioStream.cpp +++ b/libraries/audio/src/PositionalAudioStream.cpp @@ -21,10 +21,9 @@ #include #include -PositionalAudioStream::PositionalAudioStream(PositionalAudioStream::Type type, bool isStereo, bool dynamicJitterBuffers, - int staticDesiredJitterBufferFrames, int maxFramesOverDesired) : +PositionalAudioStream::PositionalAudioStream(PositionalAudioStream::Type type, bool isStereo, const InboundAudioStream::Settings& settings) : InboundAudioStream(isStereo ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL, - AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY, dynamicJitterBuffers, staticDesiredJitterBufferFrames, maxFramesOverDesired), + AUDIOMIXER_INBOUND_RING_BUFFER_FRAME_CAPACITY, settings), _type(type), _position(0.0f, 0.0f, 0.0f), _orientation(0.0f, 0.0f, 0.0f, 0.0f), diff --git a/libraries/audio/src/PositionalAudioStream.h b/libraries/audio/src/PositionalAudioStream.h index f99dc3a464..d1d5e013e7 100644 --- a/libraries/audio/src/PositionalAudioStream.h +++ b/libraries/audio/src/PositionalAudioStream.h @@ -27,8 +27,7 @@ public: Injector }; - PositionalAudioStream(PositionalAudioStream::Type type, bool isStereo, bool dynamicJitterBuffers, int staticDesiredJitterBufferFrames, - int maxFramesOverDesired); + PositionalAudioStream(PositionalAudioStream::Type type, bool isStereo, const InboundAudioStream::Settings& settings); virtual AudioStreamStats getAudioStreamStats() const; diff --git a/libraries/shared/src/MovingMinMaxAvg.h b/libraries/shared/src/MovingMinMaxAvg.h index 9ac9ec9006..469ec1b3ef 100644 --- a/libraries/shared/src/MovingMinMaxAvg.h +++ b/libraries/shared/src/MovingMinMaxAvg.h @@ -103,6 +103,15 @@ public: _newStatsAvailable = false; } + void setWindowIntervals(int windowIntervals) { + _windowIntervals = windowIntervals; + _overallStats.reset(); + _windowStats.reset(); + _currentIntervalStats.reset(); + _intervalStats.setCapacity(_windowIntervals); + _newStatsAvailable = false; + } + void update(T newSample) { // update overall stats _overallStats.update(newSample); diff --git a/libraries/shared/src/RingBufferHistory.h b/libraries/shared/src/RingBufferHistory.h index 339f390cd5..9534b2f1db 100644 --- a/libraries/shared/src/RingBufferHistory.h +++ b/libraries/shared/src/RingBufferHistory.h @@ -35,6 +35,14 @@ public: _numEntries = 0; } + void setCapacity(int capacity) { + _size = capacity + 1; + _capacity = capacity; + _newestEntryAtIndex = 0; + _numEntries = 0; + _buffer.resize(_size); + } + void insert(const T& entry) { // increment newest entry index cyclically _newestEntryAtIndex = (_newestEntryAtIndex == _size - 1) ? 0 : _newestEntryAtIndex + 1;