mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 04:44:11 +02:00
Merge pull request #1238 from ctrlaltdavid/dev/webrtc-datachannel
WebRTC Data Channel
This commit is contained in:
commit
5a2ca4869a
10 changed files with 926 additions and 21 deletions
|
@ -165,8 +165,9 @@ bool DomainServer::forwardMetaverseAPIRequest(HTTPConnection* connection,
|
|||
DomainServer::DomainServer(int argc, char* argv[]) :
|
||||
QCoreApplication(argc, argv),
|
||||
_gatekeeper(this),
|
||||
#ifdef WEBRTC_DATA_CHANNEL
|
||||
#ifdef WEBRTC_DATA_CHANNELS
|
||||
_webrtcSignalingServer(QHostAddress::AnyIPv4, DEFAULT_DOMAIN_SERVER_WS_PORT, this),
|
||||
_webrtcDataChannels(NodeType::DomainServer, this),
|
||||
#endif
|
||||
_httpManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTP_PORT,
|
||||
QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this)
|
||||
|
@ -251,6 +252,8 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
updateDownstreamNodes();
|
||||
updateUpstreamNodes();
|
||||
|
||||
setUpWebRTC();
|
||||
|
||||
if (_type != NonMetaverse) {
|
||||
// if we have a metaverse domain, we'll use an access token for API calls
|
||||
resetAccountManagerAccessToken();
|
||||
|
@ -3136,6 +3139,20 @@ void DomainServer::updateUpstreamNodes() {
|
|||
updateReplicationNodes(Upstream);
|
||||
}
|
||||
|
||||
void DomainServer::setUpWebRTC() {
|
||||
#ifdef WEBRTC_DATA_CHANNELS
|
||||
|
||||
// Inbound WebRTC signaling messages received from a client.
|
||||
connect(&_webrtcSignalingServer, &WebRTCSignalingServer::messageReceived,
|
||||
&_webrtcDataChannels, &WebRTCDataChannels::onSignalingMessage);
|
||||
|
||||
// Outbound WebRTC signaling messages being sent to a client.
|
||||
connect(&_webrtcDataChannels, &WebRTCDataChannels::signalingMessage,
|
||||
&_webrtcSignalingServer, &WebRTCSignalingServer::sendMessage);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void DomainServer::initializeExporter() {
|
||||
static const QString ENABLE_EXPORTER = "monitoring.enable_prometheus_exporter";
|
||||
static const QString EXPORTER_PORT = "monitoring.prometheus_exporter_port";
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
#include <HTTPSConnection.h>
|
||||
#include <LimitedNodeList.h>
|
||||
#include <shared/WebRTC.h>
|
||||
#if defined(WEBRTC_DATA_CHANNEL)
|
||||
#if defined(WEBRTC_DATA_CHANNELS)
|
||||
#include <webrtc/WebRTCDataChannels.h>
|
||||
#include <webrtc/WebRTCSignalingServer.h>
|
||||
#endif
|
||||
|
||||
|
@ -145,6 +146,9 @@ private slots:
|
|||
void updateReplicatedNodes();
|
||||
void updateDownstreamNodes();
|
||||
void updateUpstreamNodes();
|
||||
|
||||
void setUpWebRTC();
|
||||
|
||||
void initializeExporter();
|
||||
void initializeMetadataExporter();
|
||||
|
||||
|
@ -316,8 +320,9 @@ private:
|
|||
|
||||
QThread _assetClientThread;
|
||||
|
||||
#ifdef WEBRTC_DATA_CHANNEL
|
||||
#ifdef WEBRTC_DATA_CHANNELS
|
||||
WebRTCSignalingServer _webrtcSignalingServer;
|
||||
WebRTCDataChannels _webrtcDataChannels;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ endif ()
|
|||
|
||||
if (WIN32)
|
||||
# we need ws2_32.lib on windows, but it's static so we don't bubble it up
|
||||
target_link_libraries(${TARGET_NAME} ws2_32.lib)
|
||||
# Libraries needed for WebRTC: security.lib winmm.lib
|
||||
target_link_libraries(${TARGET_NAME} ws2_32.lib security.lib winmm.lib)
|
||||
elseif(APPLE)
|
||||
# IOKit is needed for getting machine fingerprint
|
||||
find_library(FRAMEWORK_IOKIT IOKit)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
//
|
||||
// Created by Stephen Birarda on 05/29/15.
|
||||
// Copyright 2015 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
|
||||
|
@ -14,6 +15,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
/// @file
|
||||
/// @brief NodeType
|
||||
|
||||
/// @brief An 8-bit value identifying the type of a node - domain server, audio mixer, etc.
|
||||
typedef quint8 NodeType_t;
|
||||
|
||||
namespace NodeType {
|
||||
|
@ -37,7 +42,6 @@ namespace NodeType {
|
|||
NodeType_t upstreamType(NodeType_t primaryType);
|
||||
NodeType_t downstreamType(NodeType_t primaryType);
|
||||
|
||||
|
||||
NodeType_t fromString(QString type);
|
||||
}
|
||||
|
||||
|
|
548
libraries/networking/src/webrtc/WebRTCDataChannels.cpp
Normal file
548
libraries/networking/src/webrtc/WebRTCDataChannels.cpp
Normal file
|
@ -0,0 +1,548 @@
|
|||
//
|
||||
// WebRTCDataChannels.cpp
|
||||
// libraries/networking/src/webrtc
|
||||
//
|
||||
// Created by David Rowe on 21 May 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
|
||||
#include "WebRTCDataChannels.h"
|
||||
|
||||
#if defined(WEBRTC_DATA_CHANNELS)
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "../NetworkLogging.h"
|
||||
|
||||
|
||||
// References:
|
||||
// - 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";
|
||||
const int MAX_WEBRTC_BUFFER_SIZE = 16777216; // 16MB
|
||||
|
||||
// #define WEBRTC_DEBUG
|
||||
|
||||
|
||||
void WDCSetSessionDescriptionObserver::OnSuccess() {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCSetSessionDescriptionObserver::OnSuccess()";
|
||||
#endif
|
||||
}
|
||||
|
||||
void WDCSetSessionDescriptionObserver::OnFailure(RTCError error) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCSetSessionDescriptionObserver::OnFailure() :" << error.message();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
WDCCreateSessionDescriptionObserver::WDCCreateSessionDescriptionObserver(WDCConnection* parent) :
|
||||
_parent(parent)
|
||||
{ }
|
||||
|
||||
void WDCCreateSessionDescriptionObserver::OnSuccess(SessionDescriptionInterface* description) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCCreateSessionDescriptionObserver::OnSuccess()";
|
||||
#endif
|
||||
_parent->sendAnswer(description);
|
||||
_parent->setLocalDescription(description);
|
||||
}
|
||||
|
||||
void WDCCreateSessionDescriptionObserver::OnFailure(RTCError error) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCCreateSessionDescriptionObserver::OnFailure() :" << error.message();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
WDCPeerConnectionObserver::WDCPeerConnectionObserver(WDCConnection* parent) :
|
||||
_parent(parent)
|
||||
{ }
|
||||
|
||||
void WDCPeerConnectionObserver::OnSignalingChange(PeerConnectionInterface::SignalingState newState) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
QStringList states{
|
||||
"Stable",
|
||||
"HaveLocalOffer",
|
||||
"HaveLocalPrAnswer",
|
||||
"HaveRemoteOffer",
|
||||
"HaveRemotePrAnswer",
|
||||
"Closed"
|
||||
};
|
||||
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnSignalingChange()" << newState << states[newState];
|
||||
#endif
|
||||
}
|
||||
|
||||
void WDCPeerConnectionObserver::OnRenegotiationNeeded() {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnRenegotiationNeeded()";
|
||||
#endif
|
||||
}
|
||||
|
||||
void WDCPeerConnectionObserver::OnIceGatheringChange(PeerConnectionInterface::IceGatheringState newState) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnIceGatheringChange()" << newState;
|
||||
#endif
|
||||
}
|
||||
|
||||
void WDCPeerConnectionObserver::OnIceCandidate(const IceCandidateInterface* candidate) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnIceCandidate()";
|
||||
#endif
|
||||
_parent->sendIceCandidate(candidate);
|
||||
}
|
||||
|
||||
void WDCPeerConnectionObserver::OnDataChannel(rtc::scoped_refptr<DataChannelInterface> dataChannel) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnDataChannel()";
|
||||
#endif
|
||||
_parent->onDataChannelOpened(dataChannel);
|
||||
}
|
||||
|
||||
void WDCPeerConnectionObserver::OnConnectionChange(PeerConnectionInterface::PeerConnectionState newState) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnConnectionChange()" << (uint)newState;
|
||||
#endif
|
||||
_parent->onPeerConnectionStateChanged(newState);
|
||||
}
|
||||
|
||||
|
||||
WDCDataChannelObserver::WDCDataChannelObserver(WDCConnection* parent) :
|
||||
_parent(parent)
|
||||
{ }
|
||||
|
||||
void WDCDataChannelObserver::OnStateChange() {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCDataChannelObserver::OnStateChange()";
|
||||
#endif
|
||||
_parent->onDataChannelStateChanged();
|
||||
}
|
||||
|
||||
void WDCDataChannelObserver::OnMessage(const DataBuffer& buffer) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCDataChannelObserver::OnMessage()";
|
||||
#endif
|
||||
_parent->onDataChannelMessageReceived(buffer);
|
||||
}
|
||||
|
||||
|
||||
WDCConnection::WDCConnection(WebRTCDataChannels* parent, quint16 webSocketID) :
|
||||
_parent(parent),
|
||||
_webSocketID(webSocketID)
|
||||
{
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCConnection::WDCConnection() :" << webSocketID;
|
||||
#endif
|
||||
|
||||
// Create observers.
|
||||
_setSessionDescriptionObserver = new rtc::RefCountedObject<WDCSetSessionDescriptionObserver>();
|
||||
_createSessionDescriptionObserver = new rtc::RefCountedObject<WDCCreateSessionDescriptionObserver>(this);
|
||||
_dataChannelObserver = std::make_shared<WDCDataChannelObserver>(this);
|
||||
_peerConnectionObserver = std::make_shared<WDCPeerConnectionObserver>(this);
|
||||
|
||||
// Create new peer connection.
|
||||
_peerConnection = _parent->createPeerConnection(_peerConnectionObserver);
|
||||
};
|
||||
|
||||
void WDCConnection::setRemoteDescription(QJsonObject& description) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCConnection::setRemoteDescription() :" << description;
|
||||
#endif
|
||||
|
||||
SdpParseError sdpParseError;
|
||||
auto sessionDescription = CreateSessionDescription(
|
||||
description.value("type").toString().toStdString(),
|
||||
description.value("sdp").toString().toStdString(),
|
||||
&sdpParseError);
|
||||
if (!sessionDescription) {
|
||||
qCWarning(networking_webrtc) << "Error creating WebRTC remote description:"
|
||||
<< QString::fromStdString(sdpParseError.description);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "3. Set remote description:" << sessionDescription;
|
||||
#endif
|
||||
_peerConnection->SetRemoteDescription(_setSessionDescriptionObserver, sessionDescription);
|
||||
}
|
||||
|
||||
void WDCConnection::createAnswer() {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCConnection::createAnswer()";
|
||||
qCDebug(networking_webrtc) << "4.a Create answer";
|
||||
#endif
|
||||
_peerConnection->CreateAnswer(_createSessionDescriptionObserver, PeerConnectionInterface::RTCOfferAnswerOptions());
|
||||
}
|
||||
|
||||
void WDCConnection::sendAnswer(SessionDescriptionInterface* description) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCConnection::sendAnswer()";
|
||||
qCDebug(networking_webrtc) << "4.b Send answer to the remote peer";
|
||||
#endif
|
||||
|
||||
QJsonObject jsonDescription;
|
||||
std::string descriptionString;
|
||||
description->ToString(&descriptionString);
|
||||
jsonDescription.insert("sdp", QString::fromStdString(descriptionString));
|
||||
jsonDescription.insert("type", "answer");
|
||||
|
||||
QJsonObject jsonWebRTCPayload;
|
||||
jsonWebRTCPayload.insert("description", jsonDescription);
|
||||
|
||||
QJsonObject jsonObject;
|
||||
jsonObject.insert("from", QString(_parent->getNodeType()));
|
||||
jsonObject.insert("to", _webSocketID);
|
||||
jsonObject.insert("data", jsonWebRTCPayload);
|
||||
|
||||
_parent->sendSignalingMessage(jsonObject);
|
||||
}
|
||||
|
||||
void WDCConnection::setLocalDescription(SessionDescriptionInterface* description) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCConnection::setLocalDescription()";
|
||||
qCDebug(networking_webrtc) << "5. Set local description";
|
||||
#endif
|
||||
_peerConnection->SetLocalDescription(_setSessionDescriptionObserver, description);
|
||||
}
|
||||
|
||||
void WDCConnection::addIceCandidate(QJsonObject& data) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCConnection::addIceCandidate()";
|
||||
#endif
|
||||
|
||||
SdpParseError sdpParseError;
|
||||
auto iceCandidate = CreateIceCandidate(
|
||||
data.value("sdpMid").toString().toStdString(),
|
||||
data.value("sdpMLineIndex").toInt(),
|
||||
data.value("candidate").toString().toStdString(),
|
||||
&sdpParseError);
|
||||
if (!iceCandidate) {
|
||||
qCWarning(networking_webrtc) << "Error adding WebRTC ICE candidate:"
|
||||
<< QString::fromStdString(sdpParseError.description);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "6. Add ICE candidate";
|
||||
#endif
|
||||
_peerConnection->AddIceCandidate(iceCandidate);
|
||||
}
|
||||
|
||||
void WDCConnection::sendIceCandidate(const IceCandidateInterface* candidate) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCConnection::sendIceCandidate()";
|
||||
#endif
|
||||
|
||||
std::string candidateString;
|
||||
candidate->ToString(&candidateString);
|
||||
QJsonObject jsonCandidate;
|
||||
jsonCandidate.insert("candidate", QString::fromStdString(candidateString));
|
||||
jsonCandidate.insert("sdpMid", QString::fromStdString(candidate->sdp_mid()));
|
||||
jsonCandidate.insert("sdpMLineIndex", candidate->sdp_mline_index());
|
||||
|
||||
QJsonObject jsonWebRTCData;
|
||||
jsonWebRTCData.insert("candidate", jsonCandidate);
|
||||
|
||||
QJsonObject jsonObject;
|
||||
jsonObject.insert("from", QString(_parent->getNodeType()));
|
||||
jsonObject.insert("to", _webSocketID);
|
||||
jsonObject.insert("data", jsonWebRTCData);
|
||||
QJsonDocument jsonDocument = QJsonDocument(jsonObject);
|
||||
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "7. Send ICE candidate to the remote peer";
|
||||
#endif
|
||||
_parent->sendSignalingMessage(jsonObject);
|
||||
}
|
||||
|
||||
void WDCConnection::onPeerConnectionStateChanged(PeerConnectionInterface::PeerConnectionState state) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
const char* STATES[] = {
|
||||
"New",
|
||||
"Connecting",
|
||||
"Connected",
|
||||
"Disconnected",
|
||||
"Failed",
|
||||
"Closed"
|
||||
};
|
||||
qCDebug(networking_webrtc) << "WDCConnection::onPeerConnectionStateChanged() :" << (int)state << STATES[(int)state];
|
||||
#endif
|
||||
}
|
||||
|
||||
void WDCConnection::onDataChannelOpened(rtc::scoped_refptr<DataChannelInterface> dataChannel) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCConnection::onDataChannelOpened() :"
|
||||
<< dataChannel->id()
|
||||
<< QString::fromStdString(dataChannel->label())
|
||||
<< QString::fromStdString(dataChannel->protocol())
|
||||
<< dataChannel->negotiated()
|
||||
<< dataChannel->maxRetransmitTime()
|
||||
<< dataChannel->maxRetransmits()
|
||||
<< dataChannel->maxPacketLifeTime().value_or(-1)
|
||||
<< dataChannel->maxRetransmitsOpt().value_or(-1);
|
||||
#endif
|
||||
|
||||
_dataChannel = dataChannel;
|
||||
_dataChannelID = _parent->getNewDataChannelID(); // Not dataChannel->id() because it's only unique per peer connection.
|
||||
_dataChannel->RegisterObserver(_dataChannelObserver.get());
|
||||
|
||||
_parent->onDataChannelOpened(this, _dataChannelID);
|
||||
}
|
||||
|
||||
void WDCConnection::onDataChannelStateChanged() {
|
||||
auto state = _dataChannel->state();
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCConnection::onDataChannelStateChanged() :" << (int)state
|
||||
<< DataChannelInterface::DataStateString(state);
|
||||
#endif
|
||||
if (state == DataChannelInterface::kClosed) {
|
||||
// Close data channel.
|
||||
_dataChannel->UnregisterObserver();
|
||||
_dataChannelObserver = nullptr;
|
||||
_dataChannel = nullptr;
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "Disposed of data channel";
|
||||
#endif
|
||||
// Close peer connection.
|
||||
_parent->closePeerConnection(this);
|
||||
}
|
||||
}
|
||||
|
||||
void WDCConnection::onDataChannelMessageReceived(const DataBuffer& buffer) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCConnection::onDataChannelMessageReceived()";
|
||||
#endif
|
||||
|
||||
auto byteArray = QByteArray(buffer.data.data<char>(), (int)buffer.data.size());
|
||||
|
||||
// Echo message back to sender.
|
||||
if (byteArray.startsWith("echo:")) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "Echo message back";
|
||||
#endif
|
||||
_parent->sendDataMessage(_dataChannelID, byteArray); // Use parent method to exercise the code stack.
|
||||
return;
|
||||
}
|
||||
|
||||
_parent->emitDataMessage(_dataChannelID, byteArray);
|
||||
}
|
||||
|
||||
bool WDCConnection::sendDataMessage(const DataBuffer& buffer) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCConnection::sendDataMessage()";
|
||||
#endif
|
||||
if (_dataChannel->buffered_amount() + buffer.size() > MAX_WEBRTC_BUFFER_SIZE) {
|
||||
// Don't send, otherwise the data channel will be closed.
|
||||
return false;
|
||||
} else {
|
||||
qCDebug(networking_webrtc) << "WebRTC send buffer overflow";
|
||||
}
|
||||
return _dataChannel->Send(buffer);
|
||||
}
|
||||
|
||||
void WDCConnection::closePeerConnection() {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WDCConnection::closePeerConnection()";
|
||||
#endif
|
||||
_peerConnection->Close();
|
||||
_peerConnection = nullptr;
|
||||
_peerConnectionObserver = nullptr;
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "Disposed of peer connection";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
WebRTCDataChannels::WebRTCDataChannels(NodeType_t nodeType, QObject* parent) :
|
||||
_nodeType(nodeType),
|
||||
_parent(parent)
|
||||
{
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WebRTCDataChannels::WebRTCDataChannels()";
|
||||
#endif
|
||||
|
||||
// Create a peer connection factory.
|
||||
#ifdef WEBRTC_DEBUG
|
||||
// Numbers are per WebRTC's peer_connection_interface.h.
|
||||
qCDebug(networking_webrtc) << "1. Create a new PeerConnectionFactoryInterface";
|
||||
#endif
|
||||
_rtcNetworkThread = rtc::Thread::CreateWithSocketServer();
|
||||
_rtcNetworkThread->Start();
|
||||
_rtcWorkerThread = rtc::Thread::Create();
|
||||
_rtcWorkerThread->Start();
|
||||
_rtcSignalingThread = rtc::Thread::Create();
|
||||
_rtcSignalingThread->Start();
|
||||
PeerConnectionFactoryDependencies dependencies;
|
||||
dependencies.network_thread = _rtcNetworkThread.get();
|
||||
dependencies.worker_thread = _rtcWorkerThread.get();
|
||||
dependencies.signaling_thread = _rtcSignalingThread.get();
|
||||
_peerConnectionFactory = CreateModularPeerConnectionFactory(std::move(dependencies));
|
||||
if (!_peerConnectionFactory) {
|
||||
qCWarning(networking_webrtc) << "Failed to create WebRTC peer connection factory";
|
||||
}
|
||||
|
||||
// Set up mechanism for closing peer connections.
|
||||
connect(this, &WebRTCDataChannels::closePeerConnectionSoon, this, &WebRTCDataChannels::closePeerConnectionNow);
|
||||
}
|
||||
|
||||
WebRTCDataChannels::~WebRTCDataChannels() {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WebRTCDataChannels::~WebRTCDataChannels()";
|
||||
#endif
|
||||
QHashIterator<quint16, WDCConnection*> i(_connectionsByDataChannel);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
delete i.value();
|
||||
}
|
||||
_connectionsByWebSocket.clear();
|
||||
_connectionsByDataChannel.clear();
|
||||
|
||||
_peerConnectionFactory = nullptr;
|
||||
_rtcSignalingThread->Stop();
|
||||
_rtcSignalingThread = nullptr;
|
||||
_rtcWorkerThread->Stop();
|
||||
_rtcWorkerThread = nullptr;
|
||||
_rtcNetworkThread->Stop();
|
||||
_rtcNetworkThread = nullptr;
|
||||
}
|
||||
|
||||
quint16 WebRTCDataChannels::getNewDataChannelID() {
|
||||
static const int QUINT16_LIMIT = std::numeric_limits<uint16_t>::max() + 1;
|
||||
_lastDataChannelID = std::max((_lastDataChannelID + 1) % QUINT16_LIMIT, 1);
|
||||
return _lastDataChannelID;
|
||||
}
|
||||
|
||||
void WebRTCDataChannels::onDataChannelOpened(WDCConnection* connection, quint16 dataChannelID) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WebRTCDataChannels::onDataChannelOpened() :" << dataChannelID;
|
||||
#endif
|
||||
_connectionsByDataChannel.insert(dataChannelID, connection);
|
||||
}
|
||||
|
||||
void WebRTCDataChannels::onSignalingMessage(const QJsonObject& message) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WebRTCDataChannel::onSignalingMessage()" << message;
|
||||
#endif
|
||||
|
||||
// Validate message.
|
||||
const int MAX_DEBUG_DETAIL_LENGTH = 64;
|
||||
auto data = message.value("data").isObject() ? message.value("data").toObject() : QJsonObject();
|
||||
int from = message.value("from").isDouble() ? (quint16)(message.value("from").toInt()) : 0;
|
||||
if (from <= 0 || from > MAXUINT16 || !data.contains("description") && !data.contains("candidate")) {
|
||||
qCWarning(networking_webrtc) << "Unexpected signaling message:"
|
||||
<< QJsonDocument(message).toJson(QJsonDocument::Compact).left(MAX_DEBUG_DETAIL_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find or create a connection.
|
||||
WDCConnection* connection;
|
||||
if (_connectionsByWebSocket.contains(from)) {
|
||||
connection = _connectionsByWebSocket.value(from);
|
||||
} else {
|
||||
connection = new WDCConnection(this, from);
|
||||
_connectionsByWebSocket.insert(from, connection);
|
||||
}
|
||||
|
||||
// Set the remote description and reply with an answer.
|
||||
if (data.contains("description")) {
|
||||
auto description = data.value("description").toObject();
|
||||
if (description.value("type").toString() == "offer") {
|
||||
connection->setRemoteDescription(description);
|
||||
connection->createAnswer();
|
||||
} else {
|
||||
qCWarning(networking_webrtc) << "Unexpected signaling description:"
|
||||
<< QJsonDocument(description).toJson(QJsonDocument::Compact).left(MAX_DEBUG_DETAIL_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
// Add a remote ICE candidate.
|
||||
if (data.contains("candidate")) {
|
||||
connection->addIceCandidate(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void WebRTCDataChannels::sendSignalingMessage(const QJsonObject& message) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WebRTCDataChannels::sendSignalingMessage() :" << QJsonDocument(message).toJson(QJsonDocument::Compact);
|
||||
#endif
|
||||
emit signalingMessage(message);
|
||||
}
|
||||
|
||||
void WebRTCDataChannels::emitDataMessage(int dataChannelID, const QByteArray& byteArray) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WebRTCDataChannels::emitDataMessage() :" << dataChannelID;
|
||||
#endif
|
||||
emit dataMessage(dataChannelID, byteArray);
|
||||
}
|
||||
|
||||
bool WebRTCDataChannels::sendDataMessage(int dataChannelID, const QByteArray& byteArray) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WebRTCDataChannels::sendDataMessage() :" << dataChannelID;
|
||||
#endif
|
||||
|
||||
// Find connection.
|
||||
if (!_connectionsByDataChannel.contains(dataChannelID)) {
|
||||
qCWarning(networking_webrtc) << "Could not find data channel to send message on!";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto connection = _connectionsByDataChannel.value(dataChannelID);
|
||||
DataBuffer buffer(byteArray.toStdString(), true);
|
||||
return connection->sendDataMessage(buffer);
|
||||
}
|
||||
|
||||
rtc::scoped_refptr<PeerConnectionInterface> WebRTCDataChannels::createPeerConnection(
|
||||
const std::shared_ptr<WDCPeerConnectionObserver> peerConnectionObserver) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WebRTCDataChannels::createPeerConnection()";
|
||||
#endif
|
||||
|
||||
PeerConnectionInterface::RTCConfiguration configuration;
|
||||
PeerConnectionInterface::IceServer iceServer;
|
||||
iceServer.uri = ICE_SERVER_URI;
|
||||
configuration.servers.push_back(iceServer);
|
||||
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "2. Create a new peer connection";
|
||||
#endif
|
||||
PeerConnectionDependencies dependencies(peerConnectionObserver.get());
|
||||
auto result = _peerConnectionFactory->CreatePeerConnection(configuration, std::move(dependencies));
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "Created peer connection";
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void WebRTCDataChannels::closePeerConnection(WDCConnection* connection) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WebRTCDataChannels::closePeerConnection()";
|
||||
#endif
|
||||
// Use Qt's signals/slots mechanism to close the peer connection on its own call stack, separate from the DataChannel
|
||||
// callback that initiated the peer connection.
|
||||
// https://bugs.chromium.org/p/webrtc/issues/detail?id=3721
|
||||
emit closePeerConnectionSoon(connection);
|
||||
}
|
||||
|
||||
|
||||
void WebRTCDataChannels::closePeerConnectionNow(WDCConnection* connection) {
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "WebRTCDataChannels::closePeerConnectionNow()";
|
||||
#endif
|
||||
// Close the peer connection.
|
||||
connection->closePeerConnection();
|
||||
|
||||
// Delete the WDCConnection.
|
||||
_connectionsByWebSocket.remove(connection->getWebSocketID());
|
||||
_connectionsByDataChannel.remove(connection->getDataChannelID());
|
||||
delete connection;
|
||||
#ifdef WEBRTC_DEBUG
|
||||
qCDebug(networking_webrtc) << "Disposed of connection";
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // WEBRTC_DATA_CHANNELS
|
328
libraries/networking/src/webrtc/WebRTCDataChannels.h
Normal file
328
libraries/networking/src/webrtc/WebRTCDataChannels.h
Normal file
|
@ -0,0 +1,328 @@
|
|||
//
|
||||
// WebRTCDataChannels.h
|
||||
// libraries/networking/src/webrtc
|
||||
//
|
||||
// Created by David Rowe on 21 May 2021.
|
||||
// Copyright 2021 Vircadia contributors.
|
||||
//
|
||||
|
||||
#ifndef vircadia_WebRTCDataChannels_h
|
||||
#define vircadia_WebRTCDataChannels_h
|
||||
|
||||
#include <shared/WebRTC.h>
|
||||
|
||||
#if defined(WEBRTC_DATA_CHANNELS)
|
||||
|
||||
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
|
||||
#undef emit // Avoid conflict between Qt signals/slots and the WebRTC library's.
|
||||
#include <api/peer_connection_interface.h>
|
||||
#define emit
|
||||
|
||||
#include "../NodeType.h"
|
||||
|
||||
using namespace webrtc;
|
||||
|
||||
class WebRTCDataChannels;
|
||||
class WDCConnection;
|
||||
|
||||
|
||||
/// @addtogroup Networking
|
||||
/// @{
|
||||
|
||||
/// @brief A WebRTC session description observer.
|
||||
class WDCSetSessionDescriptionObserver : public SetSessionDescriptionObserver {
|
||||
public:
|
||||
|
||||
/// @brief The call to SetLocalDescription or SetRemoteDescription succeeded.
|
||||
void OnSuccess() override;
|
||||
|
||||
/// @brief The call to SetLocalDescription or SetRemoteDescription failed.
|
||||
/// @param error Error information.
|
||||
void OnFailure(RTCError error) override;
|
||||
};
|
||||
|
||||
|
||||
/// @brief A WebRTC create session description observer.
|
||||
class WDCCreateSessionDescriptionObserver : public CreateSessionDescriptionObserver {
|
||||
public:
|
||||
|
||||
/// @brief Constructs a session description observer.
|
||||
/// @param parent The parent connection object.
|
||||
WDCCreateSessionDescriptionObserver(WDCConnection* parent);
|
||||
|
||||
/// @brief The call to CreateAnswer succeeded.
|
||||
/// @param The session description.
|
||||
void OnSuccess(SessionDescriptionInterface* desc) override;
|
||||
|
||||
//@ @brief The call to CreateAnswer failed.
|
||||
/// @param error Error information.
|
||||
void OnFailure(RTCError error) override;
|
||||
|
||||
private:
|
||||
WDCConnection* _parent;
|
||||
};
|
||||
|
||||
|
||||
/// @brief A WebRTC peer connection observer.
|
||||
class WDCPeerConnectionObserver : public PeerConnectionObserver {
|
||||
public:
|
||||
|
||||
/// @brief Constructs a peer connection observer.
|
||||
/// @param parent The parent connection object.
|
||||
WDCPeerConnectionObserver(WDCConnection* parent);
|
||||
|
||||
/// @brief Called when the SignalingState changes.
|
||||
/// @param newState The new signaling state.
|
||||
void OnSignalingChange(PeerConnectionInterface::SignalingState newState) override;
|
||||
|
||||
/// @brief Called when renegotiation is needed. For example, an ICE restart has begun.
|
||||
void OnRenegotiationNeeded() override;
|
||||
|
||||
/// @brief Called when the ICE gather state changes.
|
||||
/// @param newState The new ICE gathering state.
|
||||
void OnIceGatheringChange(PeerConnectionInterface::IceGatheringState newState) override;
|
||||
|
||||
/// @brief Called when a new ICE candidate has been gathered.
|
||||
/// @param candidate The new ICE candidate.
|
||||
void OnIceCandidate(const IceCandidateInterface* candidate) override;
|
||||
|
||||
/// @brief Called when a remote peer opens a data channel.
|
||||
/// @param dataChannel The data channel.
|
||||
void OnDataChannel(rtc::scoped_refptr<DataChannelInterface> dataChannel) override;
|
||||
|
||||
/// @brief Called when the peer connection state changes.
|
||||
/// @param newState The new peer connection state.
|
||||
void OnConnectionChange(PeerConnectionInterface::PeerConnectionState newState) override;
|
||||
|
||||
private:
|
||||
WDCConnection* _parent;
|
||||
};
|
||||
|
||||
|
||||
/// @brief A WebRTC data channel observer.
|
||||
class WDCDataChannelObserver : public DataChannelObserver {
|
||||
public:
|
||||
|
||||
/// @brief Constructs a data channel observer.
|
||||
/// @param parent The parent connection object.
|
||||
WDCDataChannelObserver(WDCConnection* parent);
|
||||
|
||||
/// @brief The data channel state changed.
|
||||
void OnStateChange() override;
|
||||
|
||||
/// @brief A data channel message was received.
|
||||
/// @param The message received.
|
||||
void OnMessage(const DataBuffer& buffer) override;
|
||||
|
||||
private:
|
||||
WDCConnection* _parent;
|
||||
};
|
||||
|
||||
|
||||
/// @brief A WebRTC data channel connection.
|
||||
/// @details Opens and manages a WebRTC data channel connection.
|
||||
class WDCConnection {
|
||||
|
||||
public:
|
||||
|
||||
/// @brief Constructs a new WDCConnection and opens a WebRTC data connection.
|
||||
/// @param parent The parent WebRTCDataChannels object.
|
||||
/// @param webSocketID The signaling channel that initiated the opening of the WebRTC data channel.
|
||||
WDCConnection(WebRTCDataChannels* parent, quint16 webSocketID);
|
||||
|
||||
/// @brief Gets the WebSocket ID.
|
||||
/// @return The ID of the WebSocket.
|
||||
quint16 getWebSocketID() { return _webSocketID; }
|
||||
|
||||
/// @brief Gets the WebRTC data channel ID.
|
||||
/// @return The WebRTC data channel ID. `-1` if not open yet.
|
||||
int getDataChannelID() { return _dataChannelID; }
|
||||
|
||||
|
||||
/// @brief Sets the remote session description received from the remote client via the signaling channel.
|
||||
/// @param description The remote session description.
|
||||
void setRemoteDescription(QJsonObject& description);
|
||||
|
||||
/// @brief Creates an answer to an offer received from the remote client via the signaling channel.
|
||||
void createAnswer();
|
||||
|
||||
/// @brief Sends an answer to the remote client via the signaling channel.
|
||||
/// @param description The answer.
|
||||
void sendAnswer(SessionDescriptionInterface* description);
|
||||
|
||||
/// @brief Sets the local session description on the WebRTC data channel being connected.
|
||||
/// @param description The local session description.
|
||||
void setLocalDescription(SessionDescriptionInterface* description);
|
||||
|
||||
/// @brief Adds an ICE candidate received from the remote client via the signaling channel.
|
||||
/// @param data The ICE candidate.
|
||||
void addIceCandidate(QJsonObject& data);
|
||||
|
||||
/// @brief Sends an ICE candidate to the remote vlient via the signaling channel.
|
||||
/// @param candidate The ICE candidate.
|
||||
void sendIceCandidate(const IceCandidateInterface* candidate);
|
||||
|
||||
/// @brief Monitors the peer connection state.
|
||||
/// @param state The new peer connection state.
|
||||
void onPeerConnectionStateChanged(PeerConnectionInterface::PeerConnectionState state);
|
||||
|
||||
/// @brief Handles the WebRTC data channel being opened.
|
||||
/// @param dataChannel The WebRTC data channel.
|
||||
void onDataChannelOpened(rtc::scoped_refptr<DataChannelInterface> dataChannel);
|
||||
|
||||
/// @brief Handles a change in the state of the WebRTC data channel.
|
||||
void onDataChannelStateChanged();
|
||||
|
||||
|
||||
/// @brief Handles a message being received on the WebRTC data channel.
|
||||
/// @param buffer The message received.
|
||||
void onDataChannelMessageReceived(const DataBuffer& buffer);
|
||||
|
||||
/// @brief Sends a message on the WebRTC data channel.
|
||||
/// @param buffer The message to send.
|
||||
/// @return `true` if the message was sent, otherwise `false`.
|
||||
bool sendDataMessage(const DataBuffer& buffer);
|
||||
|
||||
/// @brief Closes the WebRTC peer connection.
|
||||
void closePeerConnection();
|
||||
|
||||
private:
|
||||
WebRTCDataChannels* _parent;
|
||||
quint16 _webSocketID { 0 };
|
||||
int _dataChannelID { -1 };
|
||||
|
||||
rtc::scoped_refptr<WDCSetSessionDescriptionObserver> _setSessionDescriptionObserver { nullptr };
|
||||
rtc::scoped_refptr<WDCCreateSessionDescriptionObserver> _createSessionDescriptionObserver { nullptr };
|
||||
|
||||
std::shared_ptr<WDCDataChannelObserver> _dataChannelObserver { nullptr };
|
||||
rtc::scoped_refptr<DataChannelInterface> _dataChannel { nullptr };
|
||||
|
||||
std::shared_ptr<WDCPeerConnectionObserver> _peerConnectionObserver { nullptr };
|
||||
rtc::scoped_refptr<PeerConnectionInterface> _peerConnection { nullptr };
|
||||
};
|
||||
|
||||
|
||||
/// @brief Manages WebRTC data channels on the domain server or an assignment client that Interface clients can connect to.
|
||||
///
|
||||
/// @details Presents multiple individual WebRTC data channels as a single one-to-many WebRTCDataChannels object. Interface
|
||||
/// clients may use WebRTC data channels for Vircadia protocol network communications instead of UDP.
|
||||
/// A WebRTCSignalingServer is used in the process of setting up a WebRTC data channel between an Interface client and the
|
||||
/// domain server or assignment client.
|
||||
/// The Interface client initiates the connection - including initiating the data channel - and the domain server or assignment
|
||||
/// client responds.
|
||||
///
|
||||
/// Additionally, for debugging purposes, instead of containing a Vircadia protocol payload, a WebRTC message may be an echo
|
||||
/// request. This is bounced back to the client.
|
||||
///
|
||||
class WebRTCDataChannels : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/// @brief Constructs a new WebRTCDataChannels object.
|
||||
/// @param nodeType The type of node that the WebRTCDataChannels object is being used in.
|
||||
/// @param parent The parent Qt object.
|
||||
WebRTCDataChannels(NodeType_t nodeType, QObject* parent);
|
||||
|
||||
/// @brief Destroys a WebRTCDataChannels object.
|
||||
~WebRTCDataChannels();
|
||||
|
||||
/// @brief Returns the type of node that the WebRTCDataChannels object is being used in.
|
||||
/// @return The type of node.
|
||||
NodeType_t getNodeType() {
|
||||
return _nodeType;
|
||||
}
|
||||
|
||||
/// @brief Get a new data channel ID to uniquely identify a WDCConnection.
|
||||
/// @return A new data channel ID.
|
||||
quint16 getNewDataChannelID();
|
||||
|
||||
/// @brief Handles a WebRTC data channel opening.
|
||||
/// @param connection The WebRTC data channel connection.
|
||||
/// @param dataChannelID The WebRTC data channel ID.
|
||||
void onDataChannelOpened(WDCConnection* connection, quint16 dataChannelID);
|
||||
|
||||
/// @brief Emits a signalingMessage to be sent to the Interface client.
|
||||
/// @param message The WebRTC signaling message to send.
|
||||
void sendSignalingMessage(const QJsonObject& message);
|
||||
|
||||
/// @brief Emits a dataMessage received from the Interface client.
|
||||
/// @param dataChannelID The WebRTC data channel the message was received on.
|
||||
/// @param byteArray The data message received.
|
||||
void emitDataMessage(int dataChannelID, const QByteArray& byteArray);
|
||||
|
||||
/// @brief Sends a data message to an Interface client.
|
||||
/// @param dataChannelID The WebRTC channel ID of the Interface client.
|
||||
/// @param message The data message to send.
|
||||
/// @return `true` if the data message was sent, otherwise `false`.
|
||||
bool sendDataMessage(int dataChannelID, const QByteArray& message);
|
||||
|
||||
/// @brief Creates a new WebRTC peer connection for connecting to an Interface client.
|
||||
/// @param peerConnectionObserver An observer to monitor the WebRTC peer connection.
|
||||
/// @return The new WebRTC peer connection.
|
||||
rtc::scoped_refptr<PeerConnectionInterface> createPeerConnection(
|
||||
const std::shared_ptr<WDCPeerConnectionObserver> peerConnectionObserver);
|
||||
|
||||
/// @brief Initiates closing the peer connection for a WebRTC data channel.
|
||||
/// @details Emits a {@link WebRTCDataChannels.closePeerConnectionSoon} signal which is connected to
|
||||
/// {@link WebRTCDataChannels.closePeerConnectionNow} in order to close the peer connection on a new call stack. This is
|
||||
/// necessary to work around a WebRTC library limitation.
|
||||
/// @param connection The WebRTC data channel connection.
|
||||
void closePeerConnection(WDCConnection* connection);
|
||||
|
||||
public slots:
|
||||
|
||||
/// @brief Handles a WebRTC signaling message received from the Interface client.
|
||||
/// @param message The WebRTC signaling message.
|
||||
void onSignalingMessage(const QJsonObject& message);
|
||||
|
||||
/// @brief Closes the peer connection for a WebRTC data channel.
|
||||
/// @details Used by {@link WebRTCDataChannels.closePeerConnection}.
|
||||
/// @param connection The WebRTC data channel connection.
|
||||
void closePeerConnectionNow(WDCConnection* connection);
|
||||
|
||||
signals:
|
||||
|
||||
/// @brief A WebRTC signaling message to be sent to the Interface client.
|
||||
/// @details This message is for the WebRTCSignalingServer to send.
|
||||
/// @param message The WebRTC signaling message to send.
|
||||
void signalingMessage(const QJsonObject& message);
|
||||
|
||||
/// @brief A WebRTC data message received from the Interface client.
|
||||
/// @details This message is for handling at a higher level in the Vircadia protocol.
|
||||
/// @param dataChannelID The WebRTC data channel ID.
|
||||
/// @param byteArray The Vircadia protocol message.
|
||||
void dataMessage(int dataChannelID, const QByteArray& byteArray);
|
||||
|
||||
/// @brief Signals that the peer connection for a WebRTC data channel should be closed.
|
||||
/// @details Used by {@link WebRTCDataChannels.closePeerConnection}.
|
||||
/// @param connection The WebRTC data channel connection.
|
||||
void closePeerConnectionSoon(WDCConnection* connection);
|
||||
|
||||
private:
|
||||
|
||||
QObject* _parent;
|
||||
|
||||
NodeType_t _nodeType;
|
||||
|
||||
std::unique_ptr<rtc::Thread> _rtcNetworkThread { nullptr };
|
||||
std::unique_ptr<rtc::Thread> _rtcWorkerThread { nullptr };
|
||||
std::unique_ptr<rtc::Thread> _rtcSignalingThread { nullptr };
|
||||
|
||||
rtc::scoped_refptr<PeerConnectionFactoryInterface> _peerConnectionFactory { nullptr };
|
||||
|
||||
quint16 _lastDataChannelID { 0 };
|
||||
|
||||
QHash<quint16, WDCConnection*> _connectionsByWebSocket;
|
||||
QHash<quint16, WDCConnection*> _connectionsByDataChannel;
|
||||
};
|
||||
|
||||
|
||||
/// @}
|
||||
|
||||
#endif // WEBRTC_DATA_CHANNELS
|
||||
|
||||
#endif // vircadia_WebRTCDataChannels_h
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include "WebRTCSignalingServer.h"
|
||||
|
||||
#if defined(WEBRTC_DATA_CHANNEL)
|
||||
#if defined(WEBRTC_DATA_CHANNELS)
|
||||
|
||||
#include <QtCore>
|
||||
#include <QWebSocket>
|
||||
|
@ -93,4 +93,4 @@ void WebRTCSignalingServer::newWebSocketConnection() {
|
|||
_webSockets.insert(webSocket->peerPort(), webSocket);
|
||||
}
|
||||
|
||||
#endif // WEBRTC_DATA_CHANNEL
|
||||
#endif // WEBRTC_DATA_CHANNELS
|
||||
|
|
|
@ -2,18 +2,16 @@
|
|||
// 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
|
||||
#ifndef vircadia_WebRTCSignalingServer_h
|
||||
#define vircadia_WebRTCSignalingServer_h
|
||||
|
||||
#include <shared/WebRTC.h>
|
||||
|
||||
#if defined(WEBRTC_DATA_CHANNEL)
|
||||
#if defined(WEBRTC_DATA_CHANNELS)
|
||||
|
||||
#include <QObject>
|
||||
#include <QtCore/QTimer>
|
||||
|
@ -21,8 +19,11 @@
|
|||
|
||||
#include "../HifiSockAddr.h"
|
||||
|
||||
/// @brief WebRTC signaling server that Interface clients can use to initiate WebRTC connections to the domain server and
|
||||
/// assignment clients.
|
||||
/// @addtogroup Networking
|
||||
/// @{
|
||||
|
||||
/// @brief Provides a WebRTC signaling server that Interface clients can use to initiate WebRTC connections to the domain server
|
||||
/// and its 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
|
||||
|
@ -50,14 +51,14 @@
|
|||
/// | `to` | WebSocket port number |
|
||||
/// | `from` | NodeType |
|
||||
/// | [`data`] | WebRTC payload |
|
||||
/// | [`echo`] | Echo request |
|
||||
/// | [`echo`] | Echo response |
|
||||
///
|
||||
class WebRTCSignalingServer : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/// @brief Constructs a new WebRTCSignalingServer.
|
||||
/// @brief Constructs a new WebRTCSignalingServer object.
|
||||
/// @param address The IP address to use for the WebSocket.
|
||||
/// @param port The port to use for the WebSocket.
|
||||
/// @param parent Qt parent object.
|
||||
|
@ -98,7 +99,8 @@ private:
|
|||
QTimer* _isWebSocketServerListeningTimer;
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
||||
#endif // WEBRTC_DATA_CHANNEL
|
||||
#endif // WEBRTC_DATA_CHANNELS
|
||||
|
||||
#endif // vircadia_SignalingServer_h
|
||||
#endif // vircadia_WebRTCSignalingServer_h
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#endif
|
||||
|
||||
// WEBRTC_AUDIO: WebRTC audio features, e.g., echo canceling.
|
||||
// WEBRTC_DATA_CHANNEL: WebRTC client-server connections in parallel with UDP.
|
||||
// WEBRTC_DATA_CHANNELS: WebRTC client-server connections in parallel with UDP.
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
# define WEBRTC_AUDIO 1
|
||||
|
@ -25,7 +25,7 @@
|
|||
# define WEBRTC_LEGACY 1
|
||||
#elif defined(Q_OS_WIN)
|
||||
# define WEBRTC_AUDIO 1
|
||||
# define WEBRTC_DATA_CHANNEL 1
|
||||
# define WEBRTC_DATA_CHANNELS 1
|
||||
# define WEBRTC_WIN 1
|
||||
# define NOMINMAX 1
|
||||
# define WIN32_LEAN_AND_MEAN 1
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit ac1f13a39c702ee54bf2cda8bc35e5d34f7f0756
|
||||
Subproject commit ab6c8b1a54aec359b1894f70722f69cfec7f04f1
|
Loading…
Reference in a new issue