Merge branch 'webapp' into dev/webrtc-packet

# Conflicts:
#	libraries/networking/src/webrtc/WebRTCDataChannels.h
This commit is contained in:
David Rowe 2021-07-08 14:54:21 +12:00
commit ed13cbd01b
3 changed files with 118 additions and 33 deletions

View file

@ -11,7 +11,7 @@ endif ()
if (WIN32) if (WIN32)
# we need ws2_32.lib on windows, but it's static so we don't bubble it up # we need ws2_32.lib on windows, but it's static so we don't bubble it up
# Libraries needed for WebRTC: security.log winmm.lib # Libraries needed for WebRTC: security.lib winmm.lib
target_link_libraries(${TARGET_NAME} ws2_32.lib security.lib winmm.lib) target_link_libraries(${TARGET_NAME} ws2_32.lib security.lib winmm.lib)
elseif(APPLE) elseif(APPLE)
# IOKit is needed for getting machine fingerprint # IOKit is needed for getting machine fingerprint

View file

@ -21,8 +21,9 @@
// - https://webrtc.googlesource.com/src/+/master/api/peer_connection_interface.h // - https://webrtc.googlesource.com/src/+/master/api/peer_connection_interface.h
const std::string ICE_SERVER_URI = "stun://ice.vircadia.com:7337"; const std::string ICE_SERVER_URI = "stun://ice.vircadia.com:7337";
const int MAX_WEBRTC_BUFFER_SIZE = 16777216; // 16MB
#define WEBRTC_DEBUG // #define WEBRTC_DEBUG
using namespace webrtc; using namespace webrtc;
@ -104,6 +105,10 @@ void WDCPeerConnectionObserver::OnDataChannel(rtc::scoped_refptr<DataChannelInte
} }
void WDCPeerConnectionObserver::OnConnectionChange(PeerConnectionInterface::PeerConnectionState newState) { void WDCPeerConnectionObserver::OnConnectionChange(PeerConnectionInterface::PeerConnectionState newState) {
#ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "WDCPeerConnectionObserver::OnConnectionChange()" << (uint)newState;
#endif
_parent->onPeerConnectionStateChanged(newState);
} }
@ -126,9 +131,9 @@ void WDCDataChannelObserver::OnMessage(const DataBuffer& buffer) {
} }
WDCConnection::WDCConnection(quint16 webSocketID, WebRTCDataChannels* parent) : WDCConnection::WDCConnection(WebRTCDataChannels* parent, quint16 webSocketID) :
_webSocketID(webSocketID), _parent(parent),
_parent(parent) _webSocketID(webSocketID)
{ {
#ifdef WEBRTC_DEBUG #ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "WDCConnection::WDCConnection() :" << webSocketID; qCDebug(networking_webrtc) << "WDCConnection::WDCConnection() :" << webSocketID;
@ -255,6 +260,20 @@ void WDCConnection::sendIceCandidate(const IceCandidateInterface* candidate) {
_parent->sendSignalingMessage(jsonObject); _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) { void WDCConnection::onDataChannelOpened(rtc::scoped_refptr<DataChannelInterface> dataChannel) {
#ifdef WEBRTC_DEBUG #ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "WDCConnection::onDataChannelOpened() :" qCDebug(networking_webrtc) << "WDCConnection::onDataChannelOpened() :"
@ -278,16 +297,19 @@ void WDCConnection::onDataChannelOpened(rtc::scoped_refptr<DataChannelInterface>
void WDCConnection::onDataChannelStateChanged() { void WDCConnection::onDataChannelStateChanged() {
auto state = _dataChannel->state(); auto state = _dataChannel->state();
#ifdef WEBRTC_DEBUG #ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "WDCConnection::dataChannelStateChanged() :" << (int)state qCDebug(networking_webrtc) << "WDCConnection::onDataChannelStateChanged() :" << (int)state
<< DataChannelInterface::DataStateString(state); << DataChannelInterface::DataStateString(state);
#endif #endif
if (state == DataChannelInterface::kClosed) { if (state == DataChannelInterface::kClosed) {
_dataChannel->Close(); // Close data channel.
_dataChannel->UnregisterObserver();
_dataChannelObserver = nullptr;
_dataChannel = nullptr; _dataChannel = nullptr;
// WEBRTC FIXME: The following line causes the _peerConnectionFactory to fail. #ifdef WEBRTC_DEBUG
//_peerConnection->Close(); qCDebug(networking_webrtc) << "Disposed of data channel";
//_peerConnection = nullptr; #endif
_parent->onDataChannelClosed(this, _dataChannelID); // Close peer connection.
_parent->closePeerConnection(this);
} }
} }
@ -321,14 +343,27 @@ bool WDCConnection::sendDataMessage(const DataBuffer& buffer) {
#ifdef WEBRTC_DEBUG #ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "WDCConnection::sendDataMessage()"; qCDebug(networking_webrtc) << "WDCConnection::sendDataMessage()";
#endif #endif
const int MAX_WEBRTC_BUFFER_SIZE = 16 * 1024 * 1024; // 16MB
if (_dataChannel->buffered_amount() + buffer.size() > MAX_WEBRTC_BUFFER_SIZE) { if (_dataChannel->buffered_amount() + buffer.size() > MAX_WEBRTC_BUFFER_SIZE) {
// Don't send, otherwise the data channel will be closed. // Don't send, otherwise the data channel will be closed.
return false; return false;
} else {
qCDebug(networking_webrtc) << "WebRTC send buffer overflow";
} }
return _dataChannel->Send(buffer); 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(QObject* parent, NodeType_t nodeType) : WebRTCDataChannels::WebRTCDataChannels(QObject* parent, NodeType_t nodeType) :
QObject(parent), QObject(parent),
@ -358,6 +393,9 @@ WebRTCDataChannels::WebRTCDataChannels(QObject* parent, NodeType_t nodeType) :
if (!_peerConnectionFactory) { if (!_peerConnectionFactory) {
qCWarning(networking_webrtc) << "Failed to create WebRTC peer connection factory"; 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() { WebRTCDataChannels::~WebRTCDataChannels() {
@ -397,18 +435,6 @@ void WebRTCDataChannels::onDataChannelOpened(WDCConnection* connection, quint16
_connectionsByDataChannel.insert(dataChannelID, connection); _connectionsByDataChannel.insert(dataChannelID, connection);
} }
void WebRTCDataChannels::onDataChannelClosed(WDCConnection* connection, quint16 dataChannelID) {
#ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "WebRTCDataChannels::onDataChannelClosed() :" << dataChannelID;
#endif
// Delete WDCConnection.
_connectionsByWebSocket.remove(connection->getWebSocketID());
_connectionsByDataChannel.remove(dataChannelID);
// WEBRTC FIXME: The following line causes the _peerConnectionFactory to fail.
//delete connection;
}
void WebRTCDataChannels::onSignalingMessage(const QJsonObject& message) { void WebRTCDataChannels::onSignalingMessage(const QJsonObject& message) {
#ifdef WEBRTC_DEBUG #ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "WebRTCDataChannel::onSignalingMessage()" << message; qCDebug(networking_webrtc) << "WebRTCDataChannel::onSignalingMessage()" << message;
@ -429,7 +455,7 @@ void WebRTCDataChannels::onSignalingMessage(const QJsonObject& message) {
if (_connectionsByWebSocket.contains(from)) { if (_connectionsByWebSocket.contains(from)) {
connection = _connectionsByWebSocket.value(from); connection = _connectionsByWebSocket.value(from);
} else { } else {
connection = new WDCConnection(from, this); connection = new WDCConnection(this, from);
_connectionsByWebSocket.insert(from, connection); _connectionsByWebSocket.insert(from, connection);
} }
@ -502,12 +528,42 @@ rtc::scoped_refptr<PeerConnectionInterface> WebRTCDataChannels::createPeerConnec
configuration.servers.push_back(iceServer); configuration.servers.push_back(iceServer);
#ifdef WEBRTC_DEBUG #ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "2. Create a new PeerConnection"; qCDebug(networking_webrtc) << "2. Create a new peer connection";
#endif #endif
PeerConnectionDependencies dependencies(peerConnectionObserver.get()); PeerConnectionDependencies dependencies(peerConnectionObserver.get());
auto result = _peerConnectionFactory->CreatePeerConnection(configuration, std::move(dependencies)); auto result = _peerConnectionFactory->CreatePeerConnection(configuration, std::move(dependencies));
#ifdef WEBRTC_DEBUG
qCDebug(networking_webrtc) << "Created peer connection";
#endif
return result; 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 #endif // WEBRTC_DATA_CHANNELS

View file

@ -46,6 +46,9 @@ public:
/// @brief A WebRTC create session description observer. /// @brief A WebRTC create session description observer.
class WDCCreateSessionDescriptionObserver : public webrtc::CreateSessionDescriptionObserver { class WDCCreateSessionDescriptionObserver : public webrtc::CreateSessionDescriptionObserver {
public: public:
/// @brief Constructs a session description observer.
/// @param parent The parent connection object.
WDCCreateSessionDescriptionObserver(WDCConnection* parent); WDCCreateSessionDescriptionObserver(WDCConnection* parent);
/// @brief The call to CreateAnswer succeeded. /// @brief The call to CreateAnswer succeeded.
@ -64,6 +67,9 @@ private:
/// @brief A WebRTC peer connection observer. /// @brief A WebRTC peer connection observer.
class WDCPeerConnectionObserver : public webrtc::PeerConnectionObserver { class WDCPeerConnectionObserver : public webrtc::PeerConnectionObserver {
public: public:
/// @brief Constructs a peer connection observer.
/// @param parent The parent connection object.
WDCPeerConnectionObserver(WDCConnection* parent); WDCPeerConnectionObserver(WDCConnection* parent);
/// @brief Called when the SignalingState changes. /// @brief Called when the SignalingState changes.
@ -97,6 +103,9 @@ private:
/// @brief A WebRTC data channel observer. /// @brief A WebRTC data channel observer.
class WDCDataChannelObserver : public webrtc::DataChannelObserver { class WDCDataChannelObserver : public webrtc::DataChannelObserver {
public: public:
/// @brief Constructs a data channel observer.
/// @param parent The parent connection object.
WDCDataChannelObserver(WDCConnection* parent); WDCDataChannelObserver(WDCConnection* parent);
/// @brief The data channel state changed. /// @brief The data channel state changed.
@ -116,10 +125,11 @@ private:
class WDCConnection { class WDCConnection {
public: public:
/// @brief Constructs a new WDCConnection and opens a WebRTC data connection. /// @brief Constructs a new WDCConnection and opens a WebRTC data connection.
/// @param webSocketID The signaling channel that initiated the opening of the WebRTC data channel.
/// @param parent The parent WebRTCDataChannels object. /// @param parent The parent WebRTCDataChannels object.
WDCConnection(quint16 webSocketID, WebRTCDataChannels* parent); /// @param webSocketID The signaling channel that initiated the opening of the WebRTC data channel.
WDCConnection(WebRTCDataChannels* parent, quint16 webSocketID);
/// @brief Gets the WebSocket ID. /// @brief Gets the WebSocket ID.
/// @return The ID of the WebSocket. /// @return The ID of the WebSocket.
@ -153,6 +163,10 @@ public:
/// @param candidate The ICE candidate. /// @param candidate The ICE candidate.
void sendIceCandidate(const webrtc::IceCandidateInterface* candidate); void sendIceCandidate(const webrtc::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. /// @brief Handles the WebRTC data channel being opened.
/// @param dataChannel The WebRTC data channel. /// @param dataChannel The WebRTC data channel.
void onDataChannelOpened(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel); void onDataChannelOpened(rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel);
@ -174,6 +188,9 @@ public:
/// @param buffer The message to send. /// @param buffer The message to send.
/// @return `true` if the message was sent, otherwise `false`. /// @return `true` if the message was sent, otherwise `false`.
bool sendDataMessage(const webrtc::DataBuffer& buffer); bool sendDataMessage(const webrtc::DataBuffer& buffer);
/// @brief Closes the WebRTC peer connection.
void closePeerConnection();
private: private:
WebRTCDataChannels* _parent; WebRTCDataChannels* _parent;
@ -236,11 +253,6 @@ public:
/// @param dataChannelID The WebRTC data channel ID. /// @param dataChannelID The WebRTC data channel ID.
void onDataChannelOpened(WDCConnection* connection, quint16 dataChannelID); void onDataChannelOpened(WDCConnection* connection, quint16 dataChannelID);
/// @brief Handles a WebRTC data channel closing.
/// @param connection The WebRTC data channel connection.
/// @param dataChannelID The WebRTC data channel ID.
void onDataChannelClosed(WDCConnection* connection, quint16 dataChannelID);
/// @brief Emits a signalingMessage to be sent to the Interface client. /// @brief Emits a signalingMessage to be sent to the Interface client.
/// @param message The WebRTC signaling message to send. /// @param message The WebRTC signaling message to send.
void sendSignalingMessage(const QJsonObject& message); void sendSignalingMessage(const QJsonObject& message);
@ -267,12 +279,24 @@ public:
rtc::scoped_refptr<webrtc::PeerConnectionInterface> createPeerConnection( rtc::scoped_refptr<webrtc::PeerConnectionInterface> createPeerConnection(
const std::shared_ptr<WDCPeerConnectionObserver> peerConnectionObserver); 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: public slots:
/// @brief Handles a WebRTC signaling message received from the Interface client. /// @brief Handles a WebRTC signaling message received from the Interface client.
/// @param message The WebRTC signaling message. /// @param message The WebRTC signaling message.
void onSignalingMessage(const QJsonObject& 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: signals:
/// @brief A WebRTC signaling message to be sent to the Interface client. /// @brief A WebRTC signaling message to be sent to the Interface client.
@ -286,6 +310,11 @@ signals:
/// @param byteArray The Vircadia protocol message. /// @param byteArray The Vircadia protocol message.
void dataMessage(int dataChannelID, const QByteArray& byteArray); 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: private:
QObject* _parent; QObject* _parent;