From b6a53b2af62a4fd15c80d7e399ab9367e9caf582 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Maheux <35638081+mamaheux@users.noreply.github.com> Date: Wed, 10 Jul 2024 10:02:24 -0400 Subject: [PATCH] Improve stability (#142) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add logs. Fix signaling-server. * Add callAll * Prevent creating a new peer connection after the desctuctor is called. * Use bool and callSync instead of atomic_bool for m_destructorCalled. * Add client connectin failed callback. Set ICE timeout. * Add onClientConnectionFail to the JS API. * Remove invalid changes. * Fix * Add print to debug the deadlock. * Add print to debug the deadlock. * Add print to debug the deadlock. * Add debug print in StreamClientPython.cpp. * Update pybind11. * Remove debug prints. * Update cpp-python-tests.yml * Update VERSION --------- Co-authored-by: Dominic Létourneau --- .github/workflows/cpp-python-tests.yml | 4 +- VERSION | 2 +- examples/cpp-data-channel-client/main.cpp | 17 +++- examples/cpp-stream-client/main.cpp | 24 ++++-- .../python_data_channel_client.py | 8 ++ .../python_stream_client.py | 8 ++ examples/web-data-channel-client/client.js | 4 + examples/web-stream-client/client.js | 4 + .../web-stream-data-channel-client/client.js | 4 + .../3rdParty/pybind11 | 2 +- .../DataChannelPeerConnectionHandler.h | 1 + .../Handlers/PeerConnectionHandler.h | 4 +- .../Handlers/StreamPeerConnectionHandler.h | 1 + .../OpenteraWebrtcNativeClient/WebrtcClient.h | 22 +++++ .../python/src/WebrtcClientPython.cpp | 14 ++++ .../src/DataChannelClient.cpp | 1 + .../DataChannelPeerConnectionHandler.cpp | 4 +- .../src/Handlers/PeerConnectionHandler.cpp | 10 ++- .../Handlers/StreamPeerConnectionHandler.cpp | 4 +- .../src/StreamClient.cpp | 1 + .../src/WebrtcClient.cpp | 82 +++++++++++++++++-- .../src/WebrtcClient.js | 36 +++++++- .../signaling_server/signaling_server.py | 2 +- 23 files changed, 229 insertions(+), 30 deletions(-) diff --git a/.github/workflows/cpp-python-tests.yml b/.github/workflows/cpp-python-tests.yml index f60445fd..dd3cc6aa 100644 --- a/.github/workflows/cpp-python-tests.yml +++ b/.github/workflows/cpp-python-tests.yml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-20.04, ubuntu-22.04, macos-11, macos-12] + os: [ubuntu-20.04, ubuntu-22.04, macos-12] python-version: ["3.8", "3.9", "3.10"] build-type: [Debug, Release] enable-gstreamer: [ON, OFF] @@ -180,7 +180,7 @@ jobs: working-directory: opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test run: | if [ -f requirements.txt ]; then python -m pip install --user -r requirements.txt; fi - python -m pytest -v + python -m pytest -vv -s # With stdout - name: Run Python signaling-server Tests with STDOUT diff --git a/VERSION b/VERSION index 65087b4f..26aaba0e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.4 +1.2.0 diff --git a/examples/cpp-data-channel-client/main.cpp b/examples/cpp-data-channel-client/main.cpp index 90e1ffe2..b1885a05 100644 --- a/examples/cpp-data-channel-client/main.cpp +++ b/examples/cpp-data-channel-client/main.cpp @@ -36,7 +36,7 @@ int main(int argc, char* argv[]) [](const string& error) { // This callback is called from the internal client thread. - cout << "OnSignalingConnectionClosed:" << endl << "\t" << error; + cout << "OnSignalingConnectionError:" << endl << "\t" << error; }); client.setOnRoomClientsChanged( @@ -64,6 +64,13 @@ int main(int argc, char* argv[]) cout << "OnClientDisconnected:" << endl; cout << "\tid=" << client.id() << ", name=" << client.name() << endl; }); + client.setOnClientConnectionFailed( + [](const Client& client) + { + // This callback is called from the internal client thread. + cout << "OnClientConnectionFailed:" << endl; + cout << "\tid=" << client.id() << ", name=" << client.name() << endl; + }); client.setOnError( [](const string& error) @@ -73,6 +80,14 @@ int main(int argc, char* argv[]) cout << "\t" << error << endl; }); + client.setLogger( + [](const string& message) + { + // This callback is called from the internal client thread. + cout << "log:" << endl; + cout << "\t" << message << endl; + }); + client.setOnDataChannelOpened( [](const Client& client) { diff --git a/examples/cpp-stream-client/main.cpp b/examples/cpp-stream-client/main.cpp index f271da45..5c35acb5 100644 --- a/examples/cpp-stream-client/main.cpp +++ b/examples/cpp-stream-client/main.cpp @@ -109,7 +109,7 @@ class SinAudioSource : public AudioSource for (size_t i = 0; i < data.size(); i++) { data[i] = static_cast(SinAudioSourceAmplitude * sin(t)); - t += 2 * M_PI / data.size(); + t += 2 * M_PI / static_cast(data.size()); } while (!m_stopped.load()) @@ -118,8 +118,7 @@ class SinAudioSource : public AudioSource auto start = chrono::steady_clock::now(); this_thread::sleep_for(SinAudioSourceFrameDuration - SinAudioSourceSleepBuffer); - while ((chrono::steady_clock::now() - start) < SinAudioSourceFrameDuration) - ; + while ((chrono::steady_clock::now() - start) < SinAudioSourceFrameDuration); } } }; @@ -164,7 +163,7 @@ int main(int argc, char* argv[]) [](const string& error) { // This callback is called from the internal client thread. - cout << "OnSignalingConnectionClosed:" << endl << "\t" << error; + cout << "OnSignalingConnectionError:" << endl << "\t" << error; }); client.setOnRoomClientsChanged( @@ -194,6 +193,13 @@ int main(int argc, char* argv[]) cout << "\tid=" << client.id() << ", name=" << client.name() << endl; cv::destroyWindow(client.id()); }); + client.setOnClientConnectionFailed( + [](const Client& client) + { + // This callback is called from the internal client thread. + cout << "OnClientConnectionFailed:" << endl; + cout << "\tid=" << client.id() << ", name=" << client.name() << endl; + }); client.setOnError( [](const string& error) @@ -203,6 +209,14 @@ int main(int argc, char* argv[]) cout << "\t" << error << endl; }); + client.setLogger( + [](const string& message) + { + // This callback is called from the internal client thread. + cout << "log:" << endl; + cout << "\t" << message << endl; + }); + client.setOnAddRemoteStream( [](const Client& client) { @@ -221,7 +235,7 @@ int main(int argc, char* argv[]) [](const Client& client, const cv::Mat& bgrImg, uint64_t timestampUs) { // This callback is called from a WebRTC processing thread. - // cout << "OnVideoFrameReceived:" << endl; + cout << "OnVideoFrameReceived:" << endl; cv::imshow(client.id(), bgrImg); cv::waitKey(1); }); diff --git a/examples/python-data-channel-client/python_data_channel_client.py b/examples/python-data-channel-client/python_data_channel_client.py index 8da649ce..6cb6901a 100644 --- a/examples/python-data-channel-client/python_data_channel_client.py +++ b/examples/python-data-channel-client/python_data_channel_client.py @@ -42,6 +42,13 @@ def on_client_disconnected(client): client.id, client.name, client.data)) +def on_client_connection_failed(client): + # This callback is called from the internal client thread. + print('on_client_connection_failed:') + print('\tid={}, name={}, data={}\n'.format( + client.id, client.name, client.data)) + + def on_error(error): # This callback is called from the internal client thread. print('error:') @@ -95,6 +102,7 @@ def on_data_channel_message_string(client, message): client.on_client_connected = on_client_connected client.on_client_disconnected = on_client_disconnected + client.on_client_connection_failed = on_client_connection_failed client.on_error = on_error diff --git a/examples/python-stream-client/python_stream_client.py b/examples/python-stream-client/python_stream_client.py index b3c1cdc2..f6805ae0 100644 --- a/examples/python-stream-client/python_stream_client.py +++ b/examples/python-stream-client/python_stream_client.py @@ -46,6 +46,13 @@ def on_client_disconnected(client): client.id, client.name, client.data)) +def on_client_connection_failed(client): + # This callback is called from the internal client thread. + print('on_client_connection_failed:') + print('\tid={}, name={}, data={}\n'.format( + client.id, client.name, client.data)) + + def on_add_remote_stream(client): # This callback is called from the internal client thread. print('on_add_remote_stream:') @@ -116,6 +123,7 @@ def on_error(error): client.on_client_connected = on_client_connected client.on_client_disconnected = on_client_disconnected + client.on_client_connection_failed = on_client_connection_failed client.on_add_remote_stream = on_add_remote_stream client.on_remove_remote_stream = on_remove_remote_stream diff --git a/examples/web-data-channel-client/client.js b/examples/web-data-channel-client/client.js index 3fc04115..d007e062 100644 --- a/examples/web-data-channel-client/client.js +++ b/examples/web-data-channel-client/client.js @@ -60,6 +60,10 @@ alert('The call is rejected (' + name + ')'); }; + dataChannelClient.onClientConnectionFail = (id, name, clientData) => { + console.log('The connect with the client ' + name + '(' + id + ') failed.'); + } + dataChannelClient.onDataChannelOpen = (id, name, clientData) => { sendButton.disabled = false; callAllButton.disabled = true; diff --git a/examples/web-stream-client/client.js b/examples/web-stream-client/client.js index a1dad547..65d7cc18 100644 --- a/examples/web-stream-client/client.js +++ b/examples/web-stream-client/client.js @@ -62,6 +62,10 @@ }); }; + streamClient.onClientConnectionFail = (id, name, clientData) => { + console.log('The connect with the client ' + name + '(' + id + ') failed.'); + } + streamClient.onAddRemoteStream = (id, name, clientData, stream) => { callAllButton.disabled = true; hangUpAllButton.disabled = false; diff --git a/examples/web-stream-data-channel-client/client.js b/examples/web-stream-data-channel-client/client.js index a61b1f29..136e588a 100644 --- a/examples/web-stream-data-channel-client/client.js +++ b/examples/web-stream-data-channel-client/client.js @@ -66,6 +66,10 @@ }); }; + streamDataChannelClient.onClientConnectionFail = (id, name, clientData) => { + console.log('The connect with the client ' + name + '(' + id + ') failed.'); + } + streamDataChannelClient.onAddRemoteStream = (id, name, clientData, stream) => { sendButton.disabled = false; callAllButton.disabled = true; diff --git a/opentera-webrtc-native-client/3rdParty/pybind11 b/opentera-webrtc-native-client/3rdParty/pybind11 index 1a917f18..941f45bc 160000 --- a/opentera-webrtc-native-client/3rdParty/pybind11 +++ b/opentera-webrtc-native-client/3rdParty/pybind11 @@ -1 +1 @@ -Subproject commit 1a917f1852eb7819b671fc3fa862840f4c491a07 +Subproject commit 941f45bcb51457884fa1afd6e24a67377d70f75c diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/DataChannelPeerConnectionHandler.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/DataChannelPeerConnectionHandler.h index 0c0215d1..769b79f7 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/DataChannelPeerConnectionHandler.h +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/DataChannelPeerConnectionHandler.h @@ -33,6 +33,7 @@ namespace opentera std::function onError, std::function onClientConnected, std::function onClientDisconnected, + std::function onClientConnectionFailed, DataChannelConfiguration dataChannelConfiguration, std::function onDataChannelOpen, std::function onDataChannelClosed, diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/PeerConnectionHandler.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/PeerConnectionHandler.h index 5d5e0eeb..2b3637a6 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/PeerConnectionHandler.h +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/PeerConnectionHandler.h @@ -42,6 +42,7 @@ namespace opentera std::function m_onError; std::function m_onClientConnected; std::function m_onClientDisconnected; + std::function m_onClientConnectionFailed; rtc::scoped_refptr m_peerConnection; @@ -55,7 +56,8 @@ namespace opentera SignalingClient& m_signalingClient, std::function&& onError, std::function&& onClientConnected, - std::function&& onClientDisconnected); + std::function&& onClientDisconnected, + std::function&& onClientConnectionFailed); ~PeerConnectionHandler() override; virtual void setPeerConnection(const rtc::scoped_refptr& peerConnection); diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/StreamPeerConnectionHandler.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/StreamPeerConnectionHandler.h index 7139a259..60b04d92 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/StreamPeerConnectionHandler.h +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/StreamPeerConnectionHandler.h @@ -55,6 +55,7 @@ namespace opentera std::function onError, std::function onClientConnected, std::function onClientDisconnected, + std::function onClientConnectionFailed, rtc::scoped_refptr videoTrack, rtc::scoped_refptr audioTrack, std::function onAddRemoteStream, diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/WebrtcClient.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/WebrtcClient.h index d5e83e22..be27c726 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/WebrtcClient.h +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/WebrtcClient.h @@ -45,6 +45,7 @@ namespace opentera std::function m_onClientConnected; std::function m_onClientDisconnected; + std::function m_onClientConnectionFailed; std::function m_onError; @@ -54,6 +55,8 @@ namespace opentera std::unique_ptr m_workerThread; std::unique_ptr m_signalingThread; + bool m_destructorCalled; + protected: std::unique_ptr m_signalingClient; @@ -105,6 +108,7 @@ namespace opentera void setOnClientConnected(const std::function& callback); void setOnClientDisconnected(const std::function& callback); + void setOnClientConnectionFailed(const std::function& callback); void setOnError(const std::function& callback); @@ -122,6 +126,7 @@ namespace opentera std::function getOnErrorFunction(); std::function getOnClientConnectedFunction(); std::function getOnClientDisconnectedFunction(); + std::function getOnClientConnectionFailedFunction(); rtc::Thread* getInternalClientThread(); @@ -332,6 +337,23 @@ namespace opentera callSync(m_internalClientThread.get(), [this, &callback]() { m_onClientDisconnected = callback; }); } + /** + * @brief Sets the callback that is called when a client peer connection fails. + * + * The callback is called from the internal client thread. The callback should not block. + * + * @parblock + * Callback parameters: + * - client: The client that has a connection failure + * @endparblock + * + * @param callback The callback + */ + inline void WebrtcClient::setOnClientConnectionFailed(const std::function& callback) + { + callSync(m_internalClientThread.get(), [this, &callback]() { m_onClientConnectionFailed = callback; }); + } + /** * @brief Sets the callback that is called when an error occurs. * diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/WebrtcClientPython.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/WebrtcClientPython.cpp index 19a5095b..6f5d300c 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/WebrtcClientPython.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/WebrtcClientPython.cpp @@ -186,6 +186,20 @@ void opentera::initWebrtcClientPython(pybind11::module& m) " - client: The client that is disconnected\n" "\n" ":param callback: The callback") + .def_property( + "on_client_connection_failed", + nullptr, + GilScopedRelease::guard(&WebrtcClient::setOnClientConnectionFailed), + "Sets the callback that is called when a client peer " + "connection fails.\n" + "\n" + "The callback is called from the internal client thread. " + "The callback should not block.\n" + "\n" + "Callback parameters:\n" + " - client: The client that has a connection failure\n" + "\n" + ":param callback: The callback") .def_property( "on_error", diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/DataChannelClient.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/DataChannelClient.cpp index b771eb9d..b35eb674 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/DataChannelClient.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/DataChannelClient.cpp @@ -87,6 +87,7 @@ unique_ptr getOnErrorFunction(), getOnClientConnectedFunction(), getOnClientDisconnectedFunction(), + getOnClientConnectionFailedFunction(), m_dataChannelConfiguration, onDataChannelOpen, onDataChannelClosed, diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/DataChannelPeerConnectionHandler.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/DataChannelPeerConnectionHandler.cpp index 980c52b8..f08bdbf7 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/DataChannelPeerConnectionHandler.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/DataChannelPeerConnectionHandler.cpp @@ -11,6 +11,7 @@ DataChannelPeerConnectionHandler::DataChannelPeerConnectionHandler( function onError, function onClientConnected, function onClientDisconnected, + function onClientConnectionFailed, DataChannelConfiguration dataChannelConfiguration, function onDataChannelOpen, function onDataChannelClosed, @@ -24,7 +25,8 @@ DataChannelPeerConnectionHandler::DataChannelPeerConnectionHandler( m_signalingClient, move(onError), move(onClientConnected), - move(onClientDisconnected)), + move(onClientDisconnected), + move(onClientConnectionFailed)), m_dataChannelConfiguration(move(dataChannelConfiguration)), m_onDataChannelOpen(move(onDataChannelOpen)), m_onDataChannelClosed(move(onDataChannelClosed)), diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/PeerConnectionHandler.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/PeerConnectionHandler.cpp index d07ab049..3cfca346 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/PeerConnectionHandler.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/PeerConnectionHandler.cpp @@ -49,7 +49,8 @@ PeerConnectionHandler::PeerConnectionHandler( SignalingClient& m_signalingClient, function&& onError, function&& onClientConnected, - function&& onClientDisconnected) + function&& onClientDisconnected, + function&& onClientConnectionFailed) : m_id(move(id)), m_peerClient(move(peerClient)), m_isCaller(isCaller), @@ -57,6 +58,7 @@ PeerConnectionHandler::PeerConnectionHandler( m_onError(move(onError)), m_onClientConnected(move(onClientConnected)), m_onClientDisconnected(move(onClientDisconnected)), + m_onClientConnectionFailed(move(onClientConnectionFailed)), m_onClientDisconnectedCalled(true) { } @@ -139,14 +141,14 @@ void PeerConnectionHandler::OnConnectionChange(webrtc::PeerConnectionInterface:: m_onClientConnected(m_peerClient); m_onClientDisconnectedCalled = false; break; - - case webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected: case webrtc::PeerConnectionInterface::PeerConnectionState::kFailed: + m_onClientConnectionFailed(m_peerClient); + break; + case webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected: case webrtc::PeerConnectionInterface::PeerConnectionState::kClosed: m_onClientDisconnected(m_peerClient); m_onClientDisconnectedCalled = true; break; - default: break; } diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/StreamPeerConnectionHandler.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/StreamPeerConnectionHandler.cpp index 1c93bc33..8ad408aa 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/StreamPeerConnectionHandler.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/StreamPeerConnectionHandler.cpp @@ -18,6 +18,7 @@ StreamPeerConnectionHandler::StreamPeerConnectionHandler( function onError, function onClientConnected, function onClientDisconnected, + function onClientConnectionFailed, webrtc::scoped_refptr videoTrack, webrtc::scoped_refptr audioTrack, function onAddRemoteStream, @@ -32,7 +33,8 @@ StreamPeerConnectionHandler::StreamPeerConnectionHandler( m_signalingClient, move(onError), move(onClientConnected), - move(onClientDisconnected)), + move(onClientDisconnected), + move(onClientConnectionFailed)), m_offerToReceiveAudio(hasOnMixedAudioFrameReceivedCallback || onAudioFrameReceived), m_offerToReceiveVideo(static_cast(onVideoFrameReceived)), m_videoTrack(move(videoTrack)), diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/StreamClient.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/StreamClient.cpp index 0c59d4aa..b327757f 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/StreamClient.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/StreamClient.cpp @@ -208,6 +208,7 @@ unique_ptr getOnErrorFunction(), getOnClientConnectedFunction(), getOnClientDisconnectedFunction(), + getOnClientConnectionFailedFunction(), videoTrack, audioTrack, onAddRemoteStream, diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/WebrtcClient.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/WebrtcClient.cpp index 75df6094..3fa75682 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/WebrtcClient.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/WebrtcClient.cpp @@ -13,7 +13,8 @@ WebrtcClient::WebrtcClient( SignalingServerConfiguration&& signalingServerConfiguration, WebrtcConfiguration&& webrtcConfiguration, VideoStreamConfiguration&& videoStreamConfiguration) - : m_webrtcConfiguration(move(webrtcConfiguration)) + : m_webrtcConfiguration(move(webrtcConfiguration)), + m_destructorCalled(false) { m_signalingClient = make_unique(signalingServerConfiguration); connectSignalingClientCallbacks(); @@ -53,7 +54,11 @@ WebrtcClient::WebrtcClient( } } -WebrtcClient::~WebrtcClient() {} +WebrtcClient::~WebrtcClient() +{ + callSync(m_internalClientThread.get(), [this]() { m_destructorCalled = true; }); + closeSync(); +} /** * Enable or disable the TLS verification. By default, the TLS verification is @@ -234,6 +239,20 @@ function WebrtcClient::getOnClientDisconnectedFunction() }; } +function WebrtcClient::getOnClientConnectionFailedFunction() +{ + return [this](const Client& client) + { + callAsync( + m_internalClientThread.get(), + [this, client]() + { + removeConnection(client.id()); + invokeIfCallable(m_onClientConnectionFailed, client); + }); + }; +} + void setOnRoomClientsChanged(const function&)>& callback); void WebrtcClient::connectSignalingClientCallbacks() @@ -246,6 +265,11 @@ void WebrtcClient::connectSignalingClientCallbacks() m_signalingClient->setOnRoomClientsChanged( [this](const vector& clients) { + if (m_destructorCalled) + { + return; + } + callAsync( m_internalClientThread.get(), [this, clients]() @@ -259,18 +283,55 @@ void WebrtcClient::connectSignalingClientCallbacks() }); }); - m_signalingClient->setMakePeerCall([this](const string& id) { makePeerCall(id); }); - m_signalingClient->setReceivePeerCall([this](const string& fromId, const string& sdp) - { receivePeerCall(fromId, sdp); }); - m_signalingClient->setReceivePeerCallAnswer([this](const string& fromId, const string& sdp) - { receivePeerCallAnswer(fromId, sdp); }); + m_signalingClient->setMakePeerCall( + [this](const string& id) + { + if (m_destructorCalled) + { + return; + } + + makePeerCall(id); + }); + m_signalingClient->setReceivePeerCall( + [this](const string& fromId, const string& sdp) + { + if (m_destructorCalled) + { + return; + } + + receivePeerCall(fromId, sdp); + }); + m_signalingClient->setReceivePeerCallAnswer( + [this](const string& fromId, const string& sdp) + { + if (m_destructorCalled) + { + return; + } + + receivePeerCallAnswer(fromId, sdp); + }); m_signalingClient->setReceiveIceCandidate( [this](const string& fromId, const string& sdpMid, int sdpMLineIndex, const string& sdp) - { receiveIceCandidate(fromId, sdpMid, sdpMLineIndex, sdp); }); + { + if (m_destructorCalled) + { + return; + } + + receiveIceCandidate(fromId, sdpMid, sdpMLineIndex, sdp); + }); m_signalingClient->setOnCallRejected( [this](const string& fromId) { + if (m_destructorCalled) + { + return; + } + callAsync( m_internalClientThread.get(), [this, fromId]() @@ -284,6 +345,11 @@ void WebrtcClient::connectSignalingClientCallbacks() m_signalingClient->setCloseAllPeerConnections( [this]() { + if (m_destructorCalled) + { + return; + } + log("onCloseAllPeerConnectionsRequestReceivedEvent"); hangUpAll(); }); diff --git a/opentera-webrtc-web-client/src/WebrtcClient.js b/opentera-webrtc-web-client/src/WebrtcClient.js index 196e228c..67432029 100644 --- a/opentera-webrtc-web-client/src/WebrtcClient.js +++ b/opentera-webrtc-web-client/src/WebrtcClient.js @@ -59,6 +59,7 @@ class WebrtcClient { this._onClientConnect = () => {}; this._onClientDisconnect = () => {}; + this._onClientConnectionFail = () => {}; this._offerOptions = {}; @@ -205,8 +206,14 @@ class WebrtcClient { this._onClientConnect(id, this.getClientName(id), this.getClientData(id)); break; - case 'disconnected': case 'failed': + this._logger('RtcPeerConnection failed event id=', id); + this._removeConnection(id, false); + this._onClientConnectionFail(id, this.getClientName(id), this.getClientData(id)); + this.updateRoomClients(); + break; + + case 'disconnected': case 'closed': this._logger('RtcPeerConnection disconnected, failed or closed event, id=', id); @@ -222,13 +229,18 @@ class WebrtcClient { rtcPeerConnection.onconnectionstatechange = () => {}; } - _removeConnection(id) { + _removeConnection(id, callOnClientDisconnect) { + callOnClientDisconnect = typeof callOnClientDisconnect !== 'undefined' ? callOnClientDisconnect : true; + if (id in this._rtcPeerConnections) { this._rtcPeerConnections[id].close(); this._disconnectRtcPeerConnectionEvents(this._rtcPeerConnections[id]); delete this._rtcPeerConnections[id]; this._alreadyAcceptedCalls = this._alreadyAcceptedCalls.filter(x => x != id); - this._onClientDisconnect(id, this.getClientName(id), this.getClientData(id)); + + if (callOnClientDisconnect) { + this._onClientDisconnect(id, this.getClientName(id), this.getClientData(id)); + } } } @@ -498,7 +510,7 @@ class WebrtcClient { } /** - * @brief Sets the callback that is called when an error occurs. + * @brief Sets the callback that is called when a client peer connection closes. * * @parblock * Callback parameters: @@ -512,6 +524,22 @@ class WebrtcClient { set onClientDisconnect(onClientDisconnect) { this._onClientDisconnect = onClientDisconnect; } + + /** + * @brief Sets the callback that is called when a client peer connection fails. + * + * @parblock + * Callback parameters: + * - clientId: The client id + * - clientName: The client name + * - clientData: The client data + * @endparblock + * + * @param {CallableFunction} onClientConnectionFail The callback + */ + set onClientConnectionFail(onClientConnectionFail) { + this._onClientConnectionFail = onClientConnectionFail; + } } export default WebrtcClient; diff --git a/signaling-server/opentera_webrtc/signaling_server/signaling_server.py b/signaling-server/opentera_webrtc/signaling_server/signaling_server.py index ad6066be..08a0ad14 100755 --- a/signaling-server/opentera_webrtc/signaling_server/signaling_server.py +++ b/signaling-server/opentera_webrtc/signaling_server/signaling_server.py @@ -61,8 +61,8 @@ async def disconnect_inactive_user(id): async def web_socket_ping_task(ws): while not ws.closed: - await asyncio.sleep(PING_INTERVAL_S) await ws.ping() + await asyncio.sleep(PING_INTERVAL_S) def event_to_message(event, data=None):