diff --git a/libraries/networking/src/webrtc/WebRTCDataChannels.cpp b/libraries/networking/src/webrtc/WebRTCDataChannels.cpp index 497ecf9a55..fb0cd9cf6e 100644 --- a/libraries/networking/src/webrtc/WebRTCDataChannels.cpp +++ b/libraries/networking/src/webrtc/WebRTCDataChannels.cpp @@ -24,6 +24,8 @@ const std::string ICE_SERVER_URI = "stun://ice.vircadia.com:7337"; #define WEBRTC_DEBUG +using namespace webrtc; + void WDCSetSessionDescriptionObserver::OnSuccess() { #ifdef WEBRTC_DEBUG @@ -308,6 +310,13 @@ void WDCConnection::onDataChannelMessageReceived(const DataBuffer& buffer) { _parent->emitDataMessage(_dataChannelID, byteArray); } +qint64 WDCConnection::getBufferedAmount() const { +#ifdef WEBRTC_DEBUG + qCDebug(networking_webrtc) << "WDCConnection::getBufferedAmount()"; +#endif + return _dataChannel->buffered_amount(); +} + bool WDCConnection::sendDataMessage(const DataBuffer& buffer) { #ifdef WEBRTC_DEBUG qCDebug(networking_webrtc) << "WDCConnection::sendDataMessage()"; @@ -321,12 +330,13 @@ bool WDCConnection::sendDataMessage(const DataBuffer& buffer) { } -WebRTCDataChannels::WebRTCDataChannels(NodeType_t nodeType, QObject* parent) : - _nodeType(nodeType), - _parent(parent) +WebRTCDataChannels::WebRTCDataChannels(QObject* parent, NodeType_t nodeType) : + QObject(parent), + _parent(parent), + _nodeType(nodeType) { #ifdef WEBRTC_DEBUG - qCDebug(networking_webrtc) << "WebRTCDataChannels::WebRTCDataChannels()"; + qCDebug(networking_webrtc) << "WebRTCDataChannels::WebRTCDataChannels()" << nodeType << NodeType::getNodeTypeName(nodeType); #endif // Create a peer connection factory. @@ -354,14 +364,7 @@ WebRTCDataChannels::~WebRTCDataChannels() { #ifdef WEBRTC_DEBUG qCDebug(networking_webrtc) << "WebRTCDataChannels::~WebRTCDataChannels()"; #endif - QHashIterator i(_connectionsByDataChannel); - while (i.hasNext()) { - i.next(); - delete i.value(); - } - _connectionsByWebSocket.clear(); - _connectionsByDataChannel.clear(); - + reset(); _peerConnectionFactory = nullptr; _rtcSignalingThread->Stop(); _rtcSignalingThread = nullptr; @@ -371,6 +374,16 @@ WebRTCDataChannels::~WebRTCDataChannels() { _rtcNetworkThread = nullptr; } +void WebRTCDataChannels::reset() { + QHashIterator i(_connectionsByDataChannel); + while (i.hasNext()) { + i.next(); + delete i.value(); + } + _connectionsByWebSocket.clear(); + _connectionsByDataChannel.clear(); +} + quint16 WebRTCDataChannels::getNewDataChannelID() { static const int QUINT16_LIMIT = std::numeric_limits::max() + 1; _lastDataChannelID = std::max((_lastDataChannelID + 1) % QUINT16_LIMIT, 1); @@ -448,7 +461,7 @@ void WebRTCDataChannels::sendSignalingMessage(const QJsonObject& message) { void WebRTCDataChannels::emitDataMessage(int dataChannelID, const QByteArray& byteArray) { #ifdef WEBRTC_DEBUG - qCDebug(networking_webrtc) << "WebRTCDataChannels::emitDataMessage() :" << dataChannelID; + qCDebug(networking_webrtc) << "WebRTCDataChannels::emitDataMessage() :" << dataChannelID << byteArray; #endif emit dataMessage(dataChannelID, byteArray); } @@ -469,6 +482,14 @@ bool WebRTCDataChannels::sendDataMessage(int dataChannelID, const QByteArray& by return connection->sendDataMessage(buffer); } +/// @brief Gets the number of bytes waiting to be written on a data channel. +/// @param port The data channel ID. +/// @return The number of bytes waiting to be written on the data channel. +qint64 WebRTCDataChannels::getBufferedAmount(int dataChannelID) const { + auto connection = _connectionsByDataChannel.value(dataChannelID); + return connection->getBufferedAmount(); +} + rtc::scoped_refptr WebRTCDataChannels::createPeerConnection( const std::shared_ptr peerConnectionObserver) { #ifdef WEBRTC_DEBUG diff --git a/libraries/networking/src/webrtc/WebRTCDataChannels.h b/libraries/networking/src/webrtc/WebRTCDataChannels.h index d9bb213a1d..21463b1c5f 100644 --- a/libraries/networking/src/webrtc/WebRTCDataChannels.h +++ b/libraries/networking/src/webrtc/WebRTCDataChannels.h @@ -23,8 +23,6 @@ #include "../NodeType.h" -using namespace webrtc; - class WebRTCDataChannels; class WDCConnection; @@ -33,7 +31,7 @@ class WDCConnection; /// @{ /// @brief A WebRTC session description observer. -class WDCSetSessionDescriptionObserver : public SetSessionDescriptionObserver { +class WDCSetSessionDescriptionObserver : public webrtc::SetSessionDescriptionObserver { public: /// @brief The call to SetLocalDescription or SetRemoteDescription succeeded. @@ -41,22 +39,22 @@ public: /// @brief The call to SetLocalDescription or SetRemoteDescription failed. /// @param error Error information. - void OnFailure(RTCError error) override; + void OnFailure(webrtc::RTCError error) override; }; /// @brief A WebRTC create session description observer. -class WDCCreateSessionDescriptionObserver : public CreateSessionDescriptionObserver { +class WDCCreateSessionDescriptionObserver : public webrtc::CreateSessionDescriptionObserver { public: WDCCreateSessionDescriptionObserver(WDCConnection* parent); /// @brief The call to CreateAnswer succeeded. /// @param The session description. - void OnSuccess(SessionDescriptionInterface* desc) override; + void OnSuccess(webrtc::SessionDescriptionInterface* desc) override; //@ @brief The call to CreateAnswer failed. /// @param error Error information. - void OnFailure(RTCError error) override; + void OnFailure(webrtc::RTCError error) override; private: WDCConnection* _parent; @@ -64,32 +62,32 @@ private: /// @brief A WebRTC peer connection observer. -class WDCPeerConnectionObserver : public PeerConnectionObserver { +class WDCPeerConnectionObserver : public webrtc::PeerConnectionObserver { public: WDCPeerConnectionObserver(WDCConnection* parent); /// @brief Called when the SignalingState changes. /// @param newState The new signaling state. - void OnSignalingChange(PeerConnectionInterface::SignalingState newState) override; + void OnSignalingChange(webrtc::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; + void OnIceGatheringChange(webrtc::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; + void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override; /// @brief Called when a remote peer opens a data channel. /// @param dataChannel The data channel. - void OnDataChannel(rtc::scoped_refptr dataChannel) override; + void OnDataChannel(rtc::scoped_refptr dataChannel) override; /// @brief Called when the peer connection state changes. /// @param newState The new peer connection state. - void OnConnectionChange(PeerConnectionInterface::PeerConnectionState newState) override; + void OnConnectionChange(webrtc::PeerConnectionInterface::PeerConnectionState newState) override; private: WDCConnection* _parent; @@ -97,7 +95,7 @@ private: /// @brief A WebRTC data channel observer. -class WDCDataChannelObserver : public DataChannelObserver { +class WDCDataChannelObserver : public webrtc::DataChannelObserver { public: WDCDataChannelObserver(WDCConnection* parent); @@ -106,7 +104,7 @@ public: /// @brief A data channel message was received. /// @param The message received. - void OnMessage(const DataBuffer& buffer) override; + void OnMessage(const webrtc::DataBuffer& buffer) override; private: WDCConnection* _parent; @@ -125,11 +123,11 @@ public: /// @brief Gets the WebSocket ID. /// @return The ID of the WebSocket. - quint16 getWebSocketID() { return _webSocketID; } + quint16 getWebSocketID() const { return _webSocketID; } /// @brief Gets the WebRTC data channel ID. /// @return The WebRTC data channel ID. `-1` if not open yet. - int getDataChannelID() { return _dataChannelID; } + int getDataChannelID() const { return _dataChannelID; } /// @brief Sets the remote session description received from the remote client via the signaling channel. @@ -141,11 +139,11 @@ public: /// @brief Sends an answer to the remote client via the signaling channel. /// @param description The answer. - void sendAnswer(SessionDescriptionInterface* description); + void sendAnswer(webrtc::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); + void setLocalDescription(webrtc::SessionDescriptionInterface* description); /// @brief Adds an ICE candidate received from the remote client via the signaling channel. /// @param data The ICE candidate. @@ -153,11 +151,11 @@ public: /// @brief Sends an ICE candidate to the remote vlient via the signaling channel. /// @param candidate The ICE candidate. - void sendIceCandidate(const IceCandidateInterface* candidate); + void sendIceCandidate(const webrtc::IceCandidateInterface* candidate); /// @brief Handles the WebRTC data channel being opened. /// @param dataChannel The WebRTC data channel. - void onDataChannelOpened(rtc::scoped_refptr dataChannel); + void onDataChannelOpened(rtc::scoped_refptr dataChannel); /// @brief Handles a change in the state of the WebRTC data channel. void onDataChannelStateChanged(); @@ -165,12 +163,17 @@ public: /// @brief Handles a message being received on the WebRTC data channel. /// @param buffer The message received. - void onDataChannelMessageReceived(const DataBuffer& buffer); + void onDataChannelMessageReceived(const webrtc::DataBuffer& buffer); + + /// @brief Gets the number of bytes waiting to be sent on the WebRTC data channel. + /// @return The number of bytes waiting to be sent on the WebRTC data channel. + qint64 getBufferedAmount() const; + /// @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); + bool sendDataMessage(const webrtc::DataBuffer& buffer); private: WebRTCDataChannels* _parent; @@ -181,10 +184,10 @@ private: rtc::scoped_refptr _createSessionDescriptionObserver { nullptr }; std::shared_ptr _dataChannelObserver { nullptr }; - rtc::scoped_refptr _dataChannel { nullptr }; + rtc::scoped_refptr _dataChannel { nullptr }; std::shared_ptr _peerConnectionObserver { nullptr }; - rtc::scoped_refptr _peerConnection { nullptr }; + rtc::scoped_refptr _peerConnection { nullptr }; }; @@ -206,20 +209,25 @@ class WebRTCDataChannels : public QObject { 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); + /// @param nodeType The type of node that the WebRTCDataChannels object is being used in. + WebRTCDataChannels(QObject* parent, NodeType_t nodeType); /// @brief Destroys a WebRTCDataChannels object. ~WebRTCDataChannels(); - /// @brief Returns the type of node that the WebRTCDataChannels object is being used in. + /// @brief Gets the type of node that the WebRTCDataChannels object is being used in. /// @return The type of node. NodeType_t getNodeType() { return _nodeType; } + /// @brief Immediately closes all connections and resets the socket. + void reset(); + /// @brief Get a new data channel ID to uniquely identify a WDCConnection. + /// @details This ID is assigned by WebRTCDataChannels; it is not the WebRTC data channel ID because that is only + /// unique within a peer connection. /// @return A new data channel ID. quint16 getNewDataChannelID(); @@ -248,10 +256,15 @@ public: /// @return `true` if the data message was sent, otherwise `false`. bool sendDataMessage(int dataChannelID, const QByteArray& message); + /// @brief Gets the number of bytes waiting to be sent on a data channel. + /// @param dataChannelID The data channel ID. + /// @return The number of bytes waiting to be sent on the data channel. + qint64 getBufferedAmount(int dataChannelID) const; + /// @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 createPeerConnection( + rtc::scoped_refptr createPeerConnection( const std::shared_ptr peerConnectionObserver); public slots: @@ -283,9 +296,9 @@ private: std::unique_ptr _rtcWorkerThread { nullptr }; std::unique_ptr _rtcSignalingThread { nullptr }; - rtc::scoped_refptr _peerConnectionFactory { nullptr }; + rtc::scoped_refptr _peerConnectionFactory { nullptr }; - quint16 _lastDataChannelID { 0 }; + quint16 _lastDataChannelID { 0 }; // First data channel ID is 1. QHash _connectionsByWebSocket; QHash _connectionsByDataChannel; diff --git a/libraries/networking/src/webrtc/WebRTCSignalingServer.cpp b/libraries/networking/src/webrtc/WebRTCSignalingServer.cpp index 8c661bbf8c..a11d09ea41 100644 --- a/libraries/networking/src/webrtc/WebRTCSignalingServer.cpp +++ b/libraries/networking/src/webrtc/WebRTCSignalingServer.cpp @@ -19,33 +19,33 @@ const int WEBRTC_SOCKET_CHECK_INTERVAL_IN_MS = 30000; -WebRTCSignalingServer::WebRTCSignalingServer(const QHostAddress& address, quint16 port, QObject* parent) : +WebRTCSignalingServer::WebRTCSignalingServer(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); } +bool WebRTCSignalingServer::bind(const QHostAddress& address, quint16 port) { + _address = address; + _port = port; + auto success = _webSocketServer->listen(_address, _port); + if (!success) { + qCWarning(networking_webrtc) << "Failed to open WebSocket for WebRTC signaling."; + } + return success; +} + 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."; + _webSocketServer->listen(_address, _port); } } diff --git a/libraries/networking/src/webrtc/WebRTCSignalingServer.h b/libraries/networking/src/webrtc/WebRTCSignalingServer.h index f2e8594b91..e32133dd17 100644 --- a/libraries/networking/src/webrtc/WebRTCSignalingServer.h +++ b/libraries/networking/src/webrtc/WebRTCSignalingServer.h @@ -59,10 +59,14 @@ class WebRTCSignalingServer : public QObject { public: /// @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. - WebRTCSignalingServer(const QHostAddress& address, quint16 port, QObject* parent = nullptr); + WebRTCSignalingServer(QObject* parent); + + /// @brief Binds the WebRTC signaling server's WebSocket to an address and port. + /// @param address The address to use for the WebSocket. + /// @param port The port to use for the WebSocket. + /// @return true if the WebSocket was successfully bound, false if it wasn't. + bool bind(const QHostAddress& address, quint16 port); public slots: @@ -88,11 +92,10 @@ private slots: private: void checkWebSocketServerIsListening(); - void bindSocket(); QWebSocketServer* _webSocketServer; QHostAddress _address; - const quint16 _port; + quint16 _port { 0 }; QHash _webSockets; // client WebSocket port, client WebSocket object