653 lines · 22.5 KB · C++
RawDownload
////  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 // 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 using namespace webrtc;  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    QStringList states {        "New",        "Gathering",        "Complete"    };    qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnIceGatheringChange() :" << newState << states[newState];#endif} void WDCPeerConnectionObserver::OnIceCandidate(const IceCandidateInterface* candidate) {#ifdef WEBRTC_DEBUG    qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnIceCandidate()";#endif    _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()";#endif    _parent->onDataChannelOpened(dataChannel);} void WDCPeerConnectionObserver::OnConnectionChange(PeerConnectionInterface::PeerConnectionState newState) {#ifdef WEBRTC_DEBUG    QStringList states {        "New",        "Connecting",        "Connected",        "Disconnected",        "Failed",        "Closed"    };    qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnConnectionChange() :" << (uint)newState        << states[(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, const QString& dataChannelID) :    _parent(parent),    _dataChannelID(dataChannelID){#ifdef WEBRTC_DEBUG    qCDebug(networking_webrtc) << "WDCConnection::WDCConnection() :" << dataChannelID;#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", _dataChannelID);    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", _dataChannelID);    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    QStringList 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;    _dataChannel->RegisterObserver(_dataChannelObserver.get()); #ifdef WEBRTC_DEBUG    qCDebug(networking_webrtc) << "WDCConnection::onDataChannelOpened() : channel ID:" << _dataChannelID;#endif    _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) {        // Finish with the data channel.        _dataChannel->UnregisterObserver();        // Don't set _dataChannel = nullptr because it is a scoped_refptr.        _dataChannelObserver = nullptr;         // 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        auto addressParts = _dataChannelID.split(":");        if (addressParts.length() != 2) {            qCWarning(networking_webrtc) << "Invalid dataChannelID:" << _dataChannelID;            return;        }        auto address = SockAddr(SocketType::WebRTC, QHostAddress(addressParts[0]), addressParts[1].toInt());        _parent->sendDataMessage(address, byteArray);  // Use parent method to exercise the code stack.        return;    }     _parent->emitDataMessage(_dataChannelID, byteArray);} qint64 WDCConnection::getBufferedAmount() const {#ifdef WEBRTC_DEBUG    qCDebug(networking_webrtc) << "WDCConnection::getBufferedAmount()";#endif    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 || _dataChannel->state() == DataChannelInterface::kClosing        || _dataChannel->state() == DataChannelInterface::kClosed) {        qCDebug(networking_webrtc) << "No data channel to send on";    }#endif    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) {        // Don't send, otherwise the data channel will be closed.        qCDebug(networking_webrtc) << "WebRTC send buffer overflow";        return false;    }    return _dataChannel->Send(buffer);} void WDCConnection::closePeerConnection() {#ifdef WEBRTC_DEBUG    qCDebug(networking_webrtc) << "WDCConnection::closePeerConnection() :" << (int)_peerConnection->peer_connection_state();#endif    _peerConnection->Close();    // Don't set _peerConnection = nullptr because it is a scoped_refptr.    _peerConnectionObserver = nullptr;#ifdef WEBRTC_DEBUG    qCDebug(networking_webrtc) << "Disposed of peer connection";#endif}  WebRTCDataChannels::WebRTCDataChannels(QObject* parent) :    QObject(parent),    _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    reset();    _peerConnectionFactory = nullptr;    _rtcSignalingThread->Stop();    _rtcSignalingThread = nullptr;    _rtcWorkerThread->Stop();    _rtcWorkerThread = nullptr;    _rtcNetworkThread->Stop();    _rtcNetworkThread = nullptr;} void WebRTCDataChannels::reset() {#ifdef WEBRTC_DEBUG    qCDebug(networking_webrtc) << "WebRTCDataChannels::reset() :" << _connectionsByID.count();#endif    QHashIterator<QString, WDCConnection*> i(_connectionsByID);    while (i.hasNext()) {        i.next();        delete i.value();    }    _connectionsByID.clear();} void WebRTCDataChannels::onDataChannelOpened(WDCConnection* connection, const QString& dataChannelID) {#ifdef WEBRTC_DEBUG    qCDebug(networking_webrtc) << "WebRTCDataChannels::onDataChannelOpened() :" << dataChannelID;#endif    _connectionsByID.insert(dataChannelID, connection);} void WebRTCDataChannels::onSignalingMessage(const QJsonObject& message) {

Lines 1–500 of 653.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t