From adfb4287962f908ea35d9fed29729a95fc03f75a Mon Sep 17 00:00:00 2001
From: David Rowe <david@ctrlaltstudio.com>
Date: Thu, 20 May 2021 09:43:18 +1200
Subject: [PATCH 1/5] Distinguish use of WebRTC features - audio versus data
 channel

---
 libraries/audio-client/src/AudioClient.cpp | 11 ++++++-----
 libraries/audio-client/src/AudioClient.h   |  8 +++++++-
 libraries/shared/src/shared/WebRTC.h       | 22 +++++++++++++---------
 3 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index 38635870fd..c03f37576d 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -4,6 +4,7 @@
 //
 //  Created by Stephen Birarda on 1/22/13.
 //  Copyright 2013 High Fidelity, Inc.
+//  Copyright 2021 Vircadia contributors.
 //
 //  Distributed under the Apache License, Version 2.0.
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@@ -363,7 +364,7 @@ AudioClient::AudioClient() {
 
     configureReverb();
 
-#if defined(WEBRTC_ENABLED)
+#if defined(WEBRTC_AUDIO)
     configureWebrtc();
 #endif
 
@@ -1142,7 +1143,7 @@ void AudioClient::setReverbOptions(const AudioEffectOptions* options) {
     }
 }
 
-#if defined(WEBRTC_ENABLED)
+#if defined(WEBRTC_AUDIO)
 
 static void deinterleaveToFloat(const int16_t* src, float* const* dst, int numFrames, int numChannels) {
     for (int i = 0; i < numFrames; i++) {
@@ -1261,7 +1262,7 @@ void AudioClient::processWebrtcNearEnd(int16_t* samples, int numFrames, int numC
     }
 }
 
-#endif // WEBRTC_ENABLED
+#endif // WEBRTC_AUDIO
 
 void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
     // If there is server echo, reverb will be applied to the recieved audio stream so no need to have it here.
@@ -1462,7 +1463,7 @@ void AudioClient::handleMicAudioInput() {
         }
         isClipping = (_timeSinceLastClip >= 0.0f) && (_timeSinceLastClip < 2.0f);  // 2 second hold time
 
-#if defined(WEBRTC_ENABLED)
+#if defined(WEBRTC_AUDIO)
         if (_isAECEnabled) {
             processWebrtcNearEnd(inputAudioSamples.get(), inputSamplesRequired / _inputFormat.channelCount(),
                                  _inputFormat.channelCount(), _inputFormat.sampleRate());
@@ -2420,7 +2421,7 @@ qint64 AudioClient::AudioOutputIODevice::readData(char * data, qint64 maxSize) {
     // limit the audio
     _audio->_audioLimiter.render(mixBuffer, scratchBuffer, framesPopped);
 
-#if defined(WEBRTC_ENABLED)
+#if defined(WEBRTC_AUDIO)
     if (_audio->_isAECEnabled) {
         _audio->processWebrtcFarEnd(scratchBuffer, framesPopped, OUTPUT_CHANNEL_COUNT, _audio->_outputFormat.sampleRate());
     }
diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h
index a5de9bd4ca..19ccb587a4 100644
--- a/libraries/audio-client/src/AudioClient.h
+++ b/libraries/audio-client/src/AudioClient.h
@@ -4,6 +4,7 @@
 //
 //  Created by Stephen Birarda on 1/22/13.
 //  Copyright 2013 High Fidelity, Inc.
+//  Copyright 2021 Vircadia contributors.
 //
 //  Distributed under the Apache License, Version 2.0.
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@@ -56,6 +57,11 @@
 #include "AudioFileWav.h"
 #include "HifiAudioDeviceInfo.h"
 
+#if defined(WEBRTC_AUDIO)
+#  include <modules/audio_processing/include/audio_processing.h>
+#  include "modules/audio_processing/audio_processing_impl.h"
+#endif
+
 #ifdef _WIN32
 #pragma warning( push )
 #pragma warning( disable : 4273 )
@@ -450,7 +456,7 @@ private:
     void updateReverbOptions();
     void handleLocalEchoAndReverb(QByteArray& inputByteArray);
 
-#if defined(WEBRTC_ENABLED)
+#if defined(WEBRTC_AUDIO)
     static const int WEBRTC_SAMPLE_RATE_MAX = 96000;
     static const int WEBRTC_CHANNELS_MAX = 2;
     static const int WEBRTC_FRAMES_MAX = webrtc::AudioProcessing::kChunkSizeMs * WEBRTC_SAMPLE_RATE_MAX / 1000;
diff --git a/libraries/shared/src/shared/WebRTC.h b/libraries/shared/src/shared/WebRTC.h
index 2f0e444bff..e99c643045 100644
--- a/libraries/shared/src/shared/WebRTC.h
+++ b/libraries/shared/src/shared/WebRTC.h
@@ -3,6 +3,7 @@
 //  libraries/shared/src/shared/
 //
 //  Copyright 2019 High Fidelity, Inc.
+//  Copyright 2021 Vircadia contributors.
 //
 //  Distributed under the Apache License, Version 2.0.
 //  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@@ -11,26 +12,29 @@
 #ifndef hifi_WebRTC_h
 #define hifi_WebRTC_h
 
+#ifndef QSYSTEMDETECTION_H
+#include <qsystemdetection.h>
+#endif
+
+// WEBRTC_AUDIO: WebRTC audio features, e.g., echo canceling.
+// WEBRTC_DATA_CHANNEL: WebRTC client-server connections in parallel with UDP.
+
 #if defined(Q_OS_MAC)
-#  define WEBRTC_ENABLED 1
+#  define WEBRTC_AUDIO 1
 #  define WEBRTC_POSIX 1
 #elif defined(Q_OS_WIN)
-#  define WEBRTC_ENABLED 1
+#  define WEBRTC_AUDIO 1
+#  define WEBRTC_DATA_CHANNEL 1
 #  define WEBRTC_WIN 1
 #  define NOMINMAX 1
 #  define WIN32_LEAN_AND_MEAN 1
 #elif defined(Q_OS_ANDROID)
 // I don't yet have a working libwebrtc for android
-// #  define WEBRTC_ENABLED 1
+// #  define WEBRTC_AUDIO 1
 // #  define WEBRTC_POSIX 1
 #elif defined(Q_OS_LINUX)
-#  define WEBRTC_ENABLED 1
+#  define WEBRTC_AUDIO 1
 #  define WEBRTC_POSIX 1
 #endif
 
-#if defined(WEBRTC_ENABLED)
-#  include <modules/audio_processing/include/audio_processing.h>
-#  include "modules/audio_processing/audio_processing_impl.h"
-#endif
-
 #endif // hifi_WebRTC_h

From 6afb8044ea02bbee35bcc74811ae8eebec354d25 Mon Sep 17 00:00:00 2001
From: David Rowe <david@ctrlaltstudio.com>
Date: Thu, 20 May 2021 09:51:14 +1200
Subject: [PATCH 2/5] Add WebRTC signaling channel

---
 domain-server/src/DomainServer.cpp            |   6 +-
 domain-server/src/DomainServer.h              |   6 +
 libraries/networking/CMakeLists.txt           |   6 +-
 libraries/networking/src/DomainHandler.h      |  10 +-
 libraries/networking/src/NetworkLogging.cpp   |   1 +
 libraries/networking/src/NetworkLogging.h     |   1 +
 libraries/networking/src/NodeList.cpp         |   1 -
 .../src/webrtc/WebRTCSignalingServer.cpp      |  96 ++++++++++++++++
 .../src/webrtc/WebRTCSignalingServer.h        | 104 ++++++++++++++++++
 9 files changed, 227 insertions(+), 4 deletions(-)
 create mode 100644 libraries/networking/src/webrtc/WebRTCSignalingServer.cpp
 create mode 100644 libraries/networking/src/webrtc/WebRTCSignalingServer.h

diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp
index 3acd17f6af..02fd810b0e 100644
--- a/domain-server/src/DomainServer.cpp
+++ b/domain-server/src/DomainServer.cpp
@@ -165,7 +165,11 @@ bool DomainServer::forwardMetaverseAPIRequest(HTTPConnection* connection,
 DomainServer::DomainServer(int argc, char* argv[]) :
     QCoreApplication(argc, argv),
     _gatekeeper(this),
-    _httpManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this)
+#ifdef WEBRTC_DATA_CHANNEL
+    _webrtcSignalingServer(QHostAddress::AnyIPv4, DEFAULT_DOMAIN_SERVER_WS_PORT, this),
+#endif
+    _httpManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTP_PORT,
+        QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this)
 {
     if (_parentPID != -1) {
         watchParentProcess(_parentPID);
diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h
index 11d04cb255..29142505a8 100644
--- a/domain-server/src/DomainServer.h
+++ b/domain-server/src/DomainServer.h
@@ -27,6 +27,8 @@
 #include <Assignment.h>
 #include <HTTPSConnection.h>
 #include <LimitedNodeList.h>
+#include <shared/WebRTC.h>
+#include <webrtc/WebRTCSignalingServer.h>
 
 #include "AssetsBackupHandler.h"
 #include "DomainGatekeeper.h"
@@ -311,6 +313,10 @@ private:
     std::unordered_map<int, std::unique_ptr<QTemporaryFile>> _pendingContentFiles;
 
     QThread _assetClientThread;
+
+#ifdef WEBRTC_DATA_CHANNEL
+    WebRTCSignalingServer _webrtcSignalingServer;
+#endif
 };
 
 
diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt
index 9f63f2cb00..50382cda99 100644
--- a/libraries/networking/CMakeLists.txt
+++ b/libraries/networking/CMakeLists.txt
@@ -1,9 +1,13 @@
 set(TARGET_NAME networking)
-setup_hifi_library(Network)
+setup_hifi_library(Network WebSockets)
 link_hifi_libraries(shared platform)
 
 target_openssl()
 target_tbb()
+if (WIN32)
+    # WEBRTC TODO: Add UNIX.
+    target_webrtc()
+endif ()
 
 if (WIN32)
     # we need ws2_32.lib on windows, but it's static so we don't bubble it up
diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h
index a56d3162bd..a8c316572a 100644
--- a/libraries/networking/src/DomainHandler.h
+++ b/libraries/networking/src/DomainHandler.h
@@ -40,7 +40,15 @@ const unsigned short DEFAULT_DOMAIN_SERVER_PORT =
         ? QProcessEnvironment::systemEnvironment()
             .value("HIFI_DOMAIN_SERVER_PORT")
             .toUShort()
-        : 40102;
+        : 40102;  // UDP
+
+const unsigned short DEFAULT_DOMAIN_SERVER_WS_PORT =
+    QProcessEnvironment::systemEnvironment()
+    .contains("HIFI_DOMAIN_SERVER_WS_PORT")
+        ? QProcessEnvironment::systemEnvironment()
+            .value("HIFI_DOMAIN_SERVER_WS_PORT")
+            .toUShort()
+        : 40102;  // TCP
 
 const unsigned short DEFAULT_DOMAIN_SERVER_DTLS_PORT =
     QProcessEnvironment::systemEnvironment()
diff --git a/libraries/networking/src/NetworkLogging.cpp b/libraries/networking/src/NetworkLogging.cpp
index 3d7c2fc5d5..daa8c8c416 100644
--- a/libraries/networking/src/NetworkLogging.cpp
+++ b/libraries/networking/src/NetworkLogging.cpp
@@ -16,3 +16,4 @@ Q_LOGGING_CATEGORY(networking_ice, "hifi.networking.ice")
 Q_LOGGING_CATEGORY(resourceLog, "hifi.networking.resource")
 Q_LOGGING_CATEGORY(asset_client, "hifi.networking.asset_client")
 Q_LOGGING_CATEGORY(messages_client, "hifi.networking.messages_client")
+Q_LOGGING_CATEGORY(networking_webrtc, "hifi.networking.webrtc")
diff --git a/libraries/networking/src/NetworkLogging.h b/libraries/networking/src/NetworkLogging.h
index 8247c60096..906947b7c4 100644
--- a/libraries/networking/src/NetworkLogging.h
+++ b/libraries/networking/src/NetworkLogging.h
@@ -19,5 +19,6 @@ Q_DECLARE_LOGGING_CATEGORY(networking)
 Q_DECLARE_LOGGING_CATEGORY(networking_ice)
 Q_DECLARE_LOGGING_CATEGORY(asset_client)
 Q_DECLARE_LOGGING_CATEGORY(messages_client)
+Q_DECLARE_LOGGING_CATEGORY(networking_webrtc)
 
 #endif // hifi_NetworkLogging_h
diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp
index a975302699..31534f34f4 100644
--- a/libraries/networking/src/NodeList.cpp
+++ b/libraries/networking/src/NodeList.cpp
@@ -409,7 +409,6 @@ void NodeList::sendDomainServerCheckIn() {
         if (domainPacketType == PacketType::DomainConnectRequest) {
 
 #if (PR_BUILD || DEV_BUILD)
-            // #######
             if (_shouldSendNewerVersion) {
                 domainPacket->setVersion(versionForPacketType(domainPacketType) + 1);
             }
diff --git a/libraries/networking/src/webrtc/WebRTCSignalingServer.cpp b/libraries/networking/src/webrtc/WebRTCSignalingServer.cpp
new file mode 100644
index 0000000000..66b1d6616c
--- /dev/null
+++ b/libraries/networking/src/webrtc/WebRTCSignalingServer.cpp
@@ -0,0 +1,96 @@
+//
+//  WebRTCSignalingServer.cpp
+//  libraries/networking/src/webrtc
+//
+//  Created by David Rowe on 16 May 2021.
+//  Copyright 2021 Vircadia contributors.
+//
+
+#include "WebRTCSignalingServer.h"
+
+#if defined(WEBRTC_DATA_CHANNEL)
+
+#include <QtCore>
+#include <QWebSocket>
+
+#include "../NetworkLogging.h"
+#include "../NodeType.h"
+
+
+const int WEBRTC_SOCKET_CHECK_INTERVAL_IN_MS = 30000;
+
+WebRTCSignalingServer::WebRTCSignalingServer(const QHostAddress& address, quint16 port, QObject* parent) :
+    QObject(parent),
+    _address(address),
+    _port(port),
+    _webSocketServer(new QWebSocketServer(QStringLiteral("WebRTC Signaling Server"), QWebSocketServer::NonSecureMode, this))
+{
+    connect(_webSocketServer, &QWebSocketServer::newConnection, this, &WebRTCSignalingServer::newWebSocketConnection);
+
+    bindSocket();
+
+    // Automatically recover from network interruptions.
+    _isWebSocketServerListeningTimer = new QTimer(this);
+    connect(_isWebSocketServerListeningTimer, &QTimer::timeout, this, &WebRTCSignalingServer::checkWebSocketServerIsListening);
+    _isWebSocketServerListeningTimer->start(WEBRTC_SOCKET_CHECK_INTERVAL_IN_MS);
+}
+
+void WebRTCSignalingServer::checkWebSocketServerIsListening() {
+    if (!_webSocketServer->isListening()) {
+        qCWarning(networking_webrtc) << "WebSocket on port " << QString::number(_port) << " is no longer listening";
+        _webSockets.clear();
+        bindSocket();
+    }
+}
+
+void WebRTCSignalingServer::bindSocket() {
+    if (!_webSocketServer->listen(_address, _port)) {
+        qCWarning(networking_webrtc) << "Failed to open WebSocket for WebRTC signaling.";
+    }
+}
+
+void WebRTCSignalingServer::webSocketTextMessageReceived(const QString& message) {
+    auto source = qobject_cast<QWebSocket*>(sender());
+    if (source) {
+        QJsonObject json = QJsonDocument::fromJson(message.toUtf8()).object();
+        // WEBRTC TODO: Move domain server echoing into domain server.
+        if (json.keys().contains("echo") && json.value("to").toString() == QString(QChar(NodeType::DomainServer))) {
+            // Domain server echo request - echo message back to sender.
+            json.remove("to");
+            json.insert("from", QString(QChar(NodeType::DomainServer)));
+            QString echo = QJsonDocument(json).toJson();
+            source->sendTextMessage(echo);
+        } else {
+            // WebRTC message or assignment client echo request. (Send both to target.)
+            json.insert("from", source->peerPort());
+            emit messageReceived(json);
+        }
+    } else {
+        qCWarning(networking_webrtc) << "Failed to find WebSocket for incoming WebRTC signaling message.";
+    }
+}
+
+void WebRTCSignalingServer::sendMessage(const QJsonObject& message) {
+    quint16 destinationPort = message.value("to").toInt();
+    if (_webSockets.contains(destinationPort)) {
+        _webSockets.value(destinationPort)->sendTextMessage(QString(QJsonDocument(message).toJson()));
+    } else {
+        qCWarning(networking_webrtc) << "Failed to find WebSocket for outgoing WebRTC signaling message.";
+    }
+}
+
+void WebRTCSignalingServer::webSocketDisconnected() {
+    auto source = qobject_cast<QWebSocket*>(sender());
+    if (source) {
+        _webSockets.remove(source->peerPort());
+    }
+}
+
+void WebRTCSignalingServer::newWebSocketConnection() {
+    auto webSocket = _webSocketServer->nextPendingConnection();
+    connect(webSocket, &QWebSocket::textMessageReceived, this, &WebRTCSignalingServer::webSocketTextMessageReceived);
+    connect(webSocket, &QWebSocket::disconnected, this, &WebRTCSignalingServer::webSocketDisconnected);
+    _webSockets.insert(webSocket->peerPort(), webSocket);
+}
+
+#endif // WEBRTC_DATA_CHANNEL
diff --git a/libraries/networking/src/webrtc/WebRTCSignalingServer.h b/libraries/networking/src/webrtc/WebRTCSignalingServer.h
new file mode 100644
index 0000000000..41d79dbd57
--- /dev/null
+++ b/libraries/networking/src/webrtc/WebRTCSignalingServer.h
@@ -0,0 +1,104 @@
+//
+//  WebRTCSignalingServer.h
+//  libraries/networking/src/webrtc
+//
+//  Provides a signaling channel for setting up WebRTC connections between the Web app and the domain servers and mixers.
+//
+//  Created by David Rowe on 16 May 2021.
+//  Copyright 2021 Vircadia contributors.
+//
+
+#ifndef vircadia_SignalingServer_h
+#define vircadia_SignalingServer_h
+
+#include <shared/WebRTC.h>
+
+#if defined(WEBRTC_DATA_CHANNEL)
+
+#include <QObject>
+#include <QtCore/QTimer>
+#include <QWebSocketServer>
+
+#include "../HifiSockAddr.h"
+
+/// @brief WebRTC signaling server that Interface clients can use to initiate WebRTC connections to the domain server and
+/// assignment clients.
+/// 
+/// @details The signaling server is expected to be hosted in the domain server. It provides a WebSocket for Interface clients
+/// to use in the WebRTC signaling handshake process to establish WebRTC data channel connections to each of the domain server
+/// and the assignment clients (i.e., separate WebRTC data channels for each but only a single signaling WebSocket). The
+/// assignment client signaling messages are expected to be relayed - by the domain server - via Vircadia protocol messages on
+/// the UDP connections between the domain server and assignment clients.
+/// 
+/// Additionally, for debugging purposes, instead of containing a WebRTC payload a signaling message may be an echo request.
+/// This is bounced back to the client from the WebRTCSignalingServer if the domain server was the target, otherwise it is
+/// expected to be bounced back upon receipt by the relevant assignment client.
+///
+/// The signaling messages are sent and received as JSON objects, with `to` and `from` fields in addition to either the WebRTC
+/// signaling `data` payload or an `echo` request:
+///
+/// | Interface -> Server ||
+/// | -------- | -----------------------|
+/// | `to`     | NodeType               |
+/// | `from`   | WebSocket port number* |
+/// | [`data`] | WebRTC payload         |
+/// | [`echo`] | Echo request           |
+/// * The `from` field is filled in by the WebRTCSignalingServer.
+///
+/// | Server -> Interface ||
+/// | -------- | ---------------------  |
+/// | `to`     | WebSocket port number  |
+/// | `from`   | NodeType               |
+/// | [`data`] | WebRTC payload         |
+/// | [`echo`] | Echo request           |
+///
+class WebRTCSignalingServer : public QObject {
+    Q_OBJECT
+
+public:
+
+    /// @brief Constructs a new WebRTCSignalingServer.
+    /// @param address The IP address to use for the WebSocket.
+    /// @param port The port to use for the WebSocket.
+    /// @param parent Qt parent object.
+    WebRTCSignalingServer(const QHostAddress& address, quint16 port, QObject* parent = nullptr);
+
+public slots:
+
+    /// @brief Send a WebRTC signaling channel message to an Interface client.
+    /// @param message The message to send to the Interface client. Includes details of the sender and the destination in
+    /// addition to the WebRTC signaling channel payload.
+    void sendMessage(const QJsonObject& message);
+
+signals:
+
+    /// @brief A WebRTC signaling channel message was received from an Interface client.
+    /// @param message The message received from the Interface client. Includes details of the sender and the destination in
+    /// addition to the WebRTC signaling channel payload.\n
+    /// Not emitted if the message was an echo request for the domain server.
+    void messageReceived(const QJsonObject& message);
+
+private slots:
+
+    void newWebSocketConnection();
+    void webSocketTextMessageReceived(const QString& message);
+    void webSocketDisconnected();
+
+private:
+
+    void checkWebSocketServerIsListening();
+    void bindSocket();
+
+    QWebSocketServer* _webSocketServer;
+    QHostAddress _address;
+    const quint16 _port;
+
+    QHash<quint16, QWebSocket*> _webSockets;  // client WebSocket port, client WebSocket object
+
+    QTimer* _isWebSocketServerListeningTimer;
+};
+
+
+#endif // WEBRTC_DATA_CHANNEL
+
+#endif // vircadia_SignalingServer_h

From 6e3c68048755e7b88511cf39ed46d5cf0ce4992a Mon Sep 17 00:00:00 2001
From: David Rowe <david@ctrlaltstudio.com>
Date: Thu, 20 May 2021 09:51:51 +1200
Subject: [PATCH 3/5] Add Doxygen comments information

---
 CODING_STANDARD.md      | 10 +++++++++-
 tools/doxygen/README.md |  5 +++++
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/CODING_STANDARD.md b/CODING_STANDARD.md
index 1c2f3cb27e..3d4516f99f 100644
--- a/CODING_STANDARD.md
+++ b/CODING_STANDARD.md
@@ -948,7 +948,7 @@ In an international environment English is the preferred language.
 
 #### [4.3.2] Use // for all comments, including multi-line comments.
 
-An exception to this rule applies for jsdoc or Doxygen comments.
+An exception to this rule applies to JSDoc and Doxygen comments.
 
 ```cpp
 // Comment spanning
@@ -1008,3 +1008,11 @@ These types of comments are explicitly not allowed. If you need to break up sect
 //--------------------------------------------------------------------------------
 ```
 
+#### [4.3.6] Doxygen comments should use "///"
+
+Use the `///` style of [Doxygen](https://www.doxygen.nl/index.html) comments when documenting public interfaces.
+
+Some editors can automatically create a Doxygen documentation stub if you type `///` in the line above the item to be
+documented.
+
+**Visual Studio:** To configure Visual Studio's Doxygen commenting behavior, search for "Doxygen" in Tools > Options.
diff --git a/tools/doxygen/README.md b/tools/doxygen/README.md
index 34d12c1d8a..40f444ca07 100644
--- a/tools/doxygen/README.md
+++ b/tools/doxygen/README.md
@@ -12,6 +12,11 @@ Make a `/build/doxygen/` directory.
 If you want to run Doxygen from a command prompt, add the Doxygen install's `/bin` directory to your system PATH.
 
 
+## Documenting
+
+See section 4.3.6 of the [*Coding Standard*](../../CODING_STANDARD.md).
+
+
 ## Running
 
 ### Using the Doxywizard GUI

From 9472d689c80bae18a1ebc2cea33ad85979d4d923 Mon Sep 17 00:00:00 2001
From: David Rowe <david@ctrlaltstudio.com>
Date: Fri, 21 May 2021 11:51:30 +1200
Subject: [PATCH 4/5] Update to the latest Vircadia-Web master

---
 vircadia-web | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/vircadia-web b/vircadia-web
index d2e383cab8..ac1f13a39c 160000
--- a/vircadia-web
+++ b/vircadia-web
@@ -1 +1 @@
-Subproject commit d2e383cab811018422433fe0d8f224e53e0506cf
+Subproject commit ac1f13a39c702ee54bf2cda8bc35e5d34f7f0756

From aa1c32ec53142f436529e9e079178c7a8aeec332 Mon Sep 17 00:00:00 2001
From: David Rowe <david@ctrlaltstudio.com>
Date: Sat, 29 May 2021 09:25:15 +1200
Subject: [PATCH 5/5] Rename new domain server environment variable

---
 libraries/networking/src/DomainHandler.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h
index a8c316572a..05cf8f26d5 100644
--- a/libraries/networking/src/DomainHandler.h
+++ b/libraries/networking/src/DomainHandler.h
@@ -44,9 +44,9 @@ const unsigned short DEFAULT_DOMAIN_SERVER_PORT =
 
 const unsigned short DEFAULT_DOMAIN_SERVER_WS_PORT =
     QProcessEnvironment::systemEnvironment()
-    .contains("HIFI_DOMAIN_SERVER_WS_PORT")
+    .contains("VIRCADIA_DOMAIN_SERVER_WS_PORT")
         ? QProcessEnvironment::systemEnvironment()
-            .value("HIFI_DOMAIN_SERVER_WS_PORT")
+            .value("VIRCADIA_DOMAIN_SERVER_WS_PORT")
             .toUShort()
         : 40102;  // TCP