Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion domain-server/resources/describe-settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": 2.5,
"version": 2.6,
"settings": [
{
"name": "metaverse",
Expand Down Expand Up @@ -73,6 +73,28 @@
}
]
},
{
"name": "webrtc",
"label": "Networking / WebRTC",
"settings": [
{
"name": "enable_webrtc",
"label": "Enable WebRTC Client Connections",
"help": "Allow web clients to connect over WebRTC data channels.",
"type": "checkbox",
"default": false,
"advanced": true
},
{
"name": "enable_webrtc_websocket_ssl",
"label": "Enable WebRTC WebSocket SSL",
"help": "Use secure WebSocket (wss:// protocol) for WebRTC signaling channel. If \"on\", the key, cert, and CA files are expected to be in the local Vircadia app directory, in a /domain-server/ subdirectory with filenames vircadia-cert.key, vircadia-cert.crt, and vircadia-crt-ca.crt.",
"type": "checkbox",
"default": false,
"advanced": true
}
]
},
{
"name": "authentication",
"label": "Networking / WordPress OAuth2",
Expand Down
31 changes: 22 additions & 9 deletions domain-server/src/DomainServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,6 @@ DomainServer::DomainServer(int argc, char* argv[]) :
_gatekeeper(this),
_httpManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTP_PORT,
QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this)
#if defined(WEBRTC_DATA_CHANNELS)
,
_webrtcSignalingServer(this)
#endif
{
if (_parentPID != -1) {
watchParentProcess(_parentPID);
Expand Down Expand Up @@ -275,14 +271,30 @@ DomainServer::DomainServer(int argc, char* argv[]) :

_settingsManager.apiRefreshGroupInformation();

#if defined(WEBRTC_DATA_CHANNELS)
const QString WEBRTC_ENABLE = "webrtc.enable_webrtc";
Comment thread
daleglass marked this conversation as resolved.
bool isWebRTCEnabled = _settingsManager.valueForKeyPath(WEBRTC_ENABLE).toBool();
qCDebug(domain_server) << "WebRTC enabled:" << isWebRTCEnabled;
// The domain server's WebRTC signaling server is used by the domain server and the assignment clients, so disabling it
// disables WebRTC for the server as a whole.
if (isWebRTCEnabled) {
const QString WEBRTC_WSS_ENABLE = "webrtc.enable_webrtc_websocket_ssl";
Comment thread
daleglass marked this conversation as resolved.
bool isWebRTCEnabled = _settingsManager.valueForKeyPath(WEBRTC_WSS_ENABLE).toBool();
qCDebug(domain_server) << "WebRTC WSS enabled:" << isWebRTCEnabled;
_webrtcSignalingServer.reset(new WebRTCSignalingServer(this, isWebRTCEnabled));
}
#endif

setupNodeListAndAssignments();

updateReplicatedNodes();
updateDownstreamNodes();
updateUpstreamNodes();

#if defined(WEBRTC_DATA_CHANNELS)
setUpWebRTCSignalingServer();
if (isWebRTCEnabled) {
setUpWebRTCSignalingServer();
}
#endif

if (_type != NonMetaverse) {
Expand Down Expand Up @@ -889,7 +901,7 @@ void DomainServer::setupNodeListAndAssignments() {
// Sets up the WebRTC signaling server that's hosted by the domain server.
void DomainServer::setUpWebRTCSignalingServer() {
// Bind the WebRTC signaling server's WebSocket to its port.
bool isBound = _webrtcSignalingServer.bind(QHostAddress::AnyIPv4, DEFAULT_DOMAIN_SERVER_WS_PORT);
bool isBound = _webrtcSignalingServer->bind(QHostAddress::AnyIPv4, DEFAULT_DOMAIN_SERVER_WS_PORT);
Comment thread
daleglass marked this conversation as resolved.
if (!isBound) {
qWarning() << "WebRTC signaling server not bound to port. WebRTC connections are not supported.";
return;
Expand All @@ -898,21 +910,22 @@ void DomainServer::setUpWebRTCSignalingServer() {
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();

// Route inbound WebRTC signaling messages received from user clients.
connect(&_webrtcSignalingServer, &WebRTCSignalingServer::messageReceived,
connect(_webrtcSignalingServer.get(), &WebRTCSignalingServer::messageReceived,
this, &DomainServer::routeWebRTCSignalingMessage);

// Route domain server signaling messages.
auto webrtcSocket = limitedNodeList->getWebRTCSocket();
connect(this, &DomainServer::webrtcSignalingMessageForDomainServer, webrtcSocket, &WebRTCSocket::onSignalingMessage);
connect(webrtcSocket, &WebRTCSocket::sendSignalingMessage, &_webrtcSignalingServer, &WebRTCSignalingServer::sendMessage);
connect(webrtcSocket, &WebRTCSocket::sendSignalingMessage,
_webrtcSignalingServer.get(), &WebRTCSignalingServer::sendMessage);

// Forward signaling messages received from assignment clients to user client.
PacketReceiver& packetReceiver = limitedNodeList->getPacketReceiver();
packetReceiver.registerListener(PacketType::WebRTCSignaling,
PacketReceiver::makeUnsourcedListenerReference<DomainServer>(this,
&DomainServer::forwardAssignmentClientSignalingMessageToUserClient));
connect(this, &DomainServer::webrtcSignalingMessageForUserClient,
&_webrtcSignalingServer, &WebRTCSignalingServer::sendMessage);
_webrtcSignalingServer.get(), &WebRTCSignalingServer::sendMessage);
}

// Routes an inbound WebRTC signaling message received from a client app to the appropriate recipient.
Expand Down
2 changes: 1 addition & 1 deletion domain-server/src/DomainServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ private slots:
QThread _assetClientThread;

#if defined(WEBRTC_DATA_CHANNELS)
WebRTCSignalingServer _webrtcSignalingServer;
std::unique_ptr<WebRTCSignalingServer> _webrtcSignalingServer { nullptr };
#endif
};

Expand Down
2 changes: 2 additions & 0 deletions domain-server/src/DomainServerSettingsManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,8 @@ void DomainServerSettingsManager::setupConfigMap(const QString& userConfigFilena
packPermissions();
}

// No migration needed to version 2.6.

// write the current description version to our settings
*versionVariant = _descriptionVersion;

Expand Down
6 changes: 5 additions & 1 deletion interface/src/avatar/OtherAvatar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ void OtherAvatar::removeOrb() {
void OtherAvatar::updateOrbPosition() {
if (!_otherAvatarOrbMeshPlaceholderID.isNull()) {
EntityItemProperties properties;
properties.setPosition(getHead()->getPosition());
glm::vec3 headPosition;
if (!_skeletonModel->getHeadPosition(headPosition)) {
headPosition = getWorldPosition();
}
properties.setPosition(headPosition);
DependencyManager::get<EntityScriptingInterface>()->editEntity(_otherAvatarOrbMeshPlaceholderID, properties);
}
}
Expand Down
102 changes: 81 additions & 21 deletions libraries/networking/src/webrtc/WebRTCDataChannels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@
// - https://webrtc.github.io/webrtc-org/native-code/native-apis/
// - https://webrtc.googlesource.com/src/+/master/api/peer_connection_interface.h

const std::string ICE_SERVER_URI = "stun://ice.vircadia.com:7337";
// FIXME: stun:ice.vircadia.com:7337 doesn't work for WebRTC.
// Firefox warns: "WebRTC: Using more than two STUN/TURN servers slows down discovery"
const std::list<std::string> ICE_SERVER_URIS = {
"stun:stun1.l.google.com:19302",
"stun:stun.schlund.de"
};
const int MAX_WEBRTC_BUFFER_SIZE = 16777216; // 16MB

// #define WEBRTC_DEBUG
Expand Down Expand Up @@ -66,15 +71,15 @@ WDCPeerConnectionObserver::WDCPeerConnectionObserver(WDCConnection* parent) :

void WDCPeerConnectionObserver::OnSignalingChange(PeerConnectionInterface::SignalingState newState) {
#ifdef WEBRTC_DEBUG
QStringList states{
QStringList states {
"Stable",
"HaveLocalOffer",
"HaveLocalPrAnswer",
"HaveRemoteOffer",
"HaveRemotePrAnswer",
"Closed"
};
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnSignalingChange()" << newState << states[newState];
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnSignalingChange() :" << newState << states[newState];
#endif
}

Expand All @@ -86,7 +91,12 @@ void WDCPeerConnectionObserver::OnRenegotiationNeeded() {

void WDCPeerConnectionObserver::OnIceGatheringChange(PeerConnectionInterface::IceGatheringState newState) {
#ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnIceGatheringChange()" << newState;
QStringList states {
"New",
"Gathering",
"Complete"
};
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnIceGatheringChange() :" << newState << states[newState];
#endif
}

Expand All @@ -97,6 +107,39 @@ void WDCPeerConnectionObserver::OnIceCandidate(const IceCandidateInterface* cand
_parent->sendIceCandidate(candidate);
}

void WDCPeerConnectionObserver::OnIceConnectionChange(PeerConnectionInterface::IceConnectionState newState) {
#ifdef WEBRTC_DEBUG
QStringList states {
"New",
"Checking",
"Connected",
"Completed",
"Failed",
"Disconnected",
"Closed",
"Max"
};
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnIceConnectionChange() :" << newState << states[newState];
#endif
}

void WDCPeerConnectionObserver::OnStandardizedIceConnectionChange(PeerConnectionInterface::IceConnectionState newState) {
#ifdef WEBRTC_DEBUG
QStringList states {
"New",
"Checking",
"Connected",
"Completed",
"Failed",
"Disconnected",
"Closed",
"Max"
};
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnStandardizedIceConnectionChange() :" << newState
<< states[newState];
#endif
}

void WDCPeerConnectionObserver::OnDataChannel(rtc::scoped_refptr<DataChannelInterface> dataChannel) {
#ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnDataChannel()";
Expand All @@ -106,7 +149,16 @@ void WDCPeerConnectionObserver::OnDataChannel(rtc::scoped_refptr<DataChannelInte

void WDCPeerConnectionObserver::OnConnectionChange(PeerConnectionInterface::PeerConnectionState newState) {
#ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnConnectionChange()" << (uint)newState;
QStringList states {
"New",
"Connecting",
"Connected",
"Disconnected",
"Failed",
"Closed"
};
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnConnectionChange() :" << (uint)newState
<< states[(uint)newState];
#endif
_parent->onPeerConnectionStateChanged(newState);
}
Expand Down Expand Up @@ -262,15 +314,15 @@ void WDCConnection::sendIceCandidate(const IceCandidateInterface* candidate) {

void WDCConnection::onPeerConnectionStateChanged(PeerConnectionInterface::PeerConnectionState state) {
#ifdef WEBRTC_DEBUG
const char* STATES[] = {
QStringList states {
"New",
"Connecting",
"Connected",
"Disconnected",
"Failed",
"Closed"
};
qCDebug(networking_webrtc) << "WDCConnection::onPeerConnectionStateChanged() :" << (int)state << STATES[(int)state];
qCDebug(networking_webrtc) << "WDCConnection::onPeerConnectionStateChanged() :" << (int)state << states[(int)state];
#endif
}

Expand Down Expand Up @@ -303,13 +355,11 @@ void WDCConnection::onDataChannelStateChanged() {
<< DataChannelInterface::DataStateString(state);
#endif
if (state == DataChannelInterface::kClosed) {
// Close data channel.
// Finish with the data channel.
_dataChannel->UnregisterObserver();
// Don't set _dataChannel = nullptr because it is a scoped_refptr.
_dataChannelObserver = nullptr;
_dataChannel = nullptr;
#ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "Disposed of data channel";
#endif

// Close peer connection.
_parent->closePeerConnection(this);
}
Expand Down Expand Up @@ -344,17 +394,21 @@ qint64 WDCConnection::getBufferedAmount() const {
#ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "WDCConnection::getBufferedAmount()";
#endif
return _dataChannel ? _dataChannel->buffered_amount() : 0;
return _dataChannel && _dataChannel->state() != DataChannelInterface::kClosing
&& _dataChannel->state() != DataChannelInterface::kClosed
? _dataChannel->buffered_amount() : 0;
}

bool WDCConnection::sendDataMessage(const DataBuffer& buffer) {
#ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "WDCConnection::sendDataMessage()";
if (!_dataChannel) {
if (!_dataChannel || _dataChannel->state() == DataChannelInterface::kClosing
|| _dataChannel->state() == DataChannelInterface::kClosed) {
qCDebug(networking_webrtc) << "No data channel to send on";
}
#endif
if (!_dataChannel) {
if (!_dataChannel || _dataChannel->state() == DataChannelInterface::kClosing
|| _dataChannel->state() == DataChannelInterface::kClosed) {
// Data channel may have been closed while message to send was being prepared.
return false;
} else if (_dataChannel->buffered_amount() + buffer.size() > MAX_WEBRTC_BUFFER_SIZE) {
Expand All @@ -367,10 +421,10 @@ bool WDCConnection::sendDataMessage(const DataBuffer& buffer) {

void WDCConnection::closePeerConnection() {
#ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "WDCConnection::closePeerConnection()";
qCDebug(networking_webrtc) << "WDCConnection::closePeerConnection() :" << (int)_peerConnection->peer_connection_state();
#endif
_peerConnection->Close();
_peerConnection = nullptr;
// Don't set _peerConnection = nullptr because it is a scoped_refptr.
_peerConnectionObserver = nullptr;
#ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "Disposed of peer connection";
Expand Down Expand Up @@ -425,6 +479,9 @@ WebRTCDataChannels::~WebRTCDataChannels() {
}

void WebRTCDataChannels::reset() {
#ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "WebRTCDataChannels::reset() :" << _connectionsByID.count();
#endif
QHashIterator<QString, WDCConnection*> i(_connectionsByID);
while (i.hasNext()) {
i.next();
Expand Down Expand Up @@ -484,7 +541,8 @@ void WebRTCDataChannels::onSignalingMessage(const QJsonObject& message) {

// Add a remote ICE candidate.
if (data.contains("candidate")) {
connection->addIceCandidate(data);
auto candidate = data.value("candidate").toObject();
connection->addIceCandidate(candidate);
}

}
Expand Down Expand Up @@ -545,9 +603,11 @@ rtc::scoped_refptr<PeerConnectionInterface> WebRTCDataChannels::createPeerConnec
#endif

PeerConnectionInterface::RTCConfiguration configuration;
PeerConnectionInterface::IceServer iceServer;
iceServer.uri = ICE_SERVER_URI;
configuration.servers.push_back(iceServer);
for (const auto& uri : ICE_SERVER_URIS) {
PeerConnectionInterface::IceServer iceServer;
iceServer.uri = uri;
configuration.servers.push_back(iceServer);
}

#ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "2. Create a new peer connection";
Expand Down
8 changes: 8 additions & 0 deletions libraries/networking/src/webrtc/WebRTCDataChannels.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,14 @@ class WDCPeerConnectionObserver : public webrtc::PeerConnectionObserver {
/// @param candidate The new ICE candidate.
void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override;

/// @brief Called when the legacy ICE connection state changes.
/// @param new_state The new ICE connection state.
virtual void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState newState) override;

/// @brief Called when the standards-compliant ICE connection state changes.
/// @param new_state The new ICE connection state.
virtual void OnStandardizedIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState newState) override;

/// @brief Called when a remote peer opens a data channel.
/// @param dataChannel The data channel.
void OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel) override;
Expand Down
Loading