From 8b5cefe134c15e20bb8578fa53cc6e0376b6a8a3 Mon Sep 17 00:00:00 2001 From: mamaheux <35638081+mamaheux@users.noreply.github.com> Date: Mon, 8 Jan 2024 11:46:03 -0500 Subject: [PATCH] Sio to websocket (#135) * Extract signaling client from webrtc clients. * Extract signaling client from webrtc clients. * Fix SignalingClient.js * Use WebSocket instead of sio, C++ not done. * Replace sio::message by nlohmann::json (Not working yet). * Migrate from sio to ws. * Fix python tests. * Fix python tests. --- .gitmodules | 9 +- VERSION | 2 +- .../CMakeLists.txt | 4 +- .../main.cpp | 16 +- .../cpp-data-channel-client/CMakeLists.txt | 4 +- examples/cpp-data-channel-client/main.cpp | 2 +- examples/cpp-stream-client/CMakeLists.txt | 4 +- examples/cpp-stream-client/main.cpp | 2 +- .../python_data_channel_client.py | 4 +- .../python_stream_client.py | 4 +- examples/web-data-channel-client/client.js | 4 +- examples/web-stream-client/client.js | 2 +- .../web-stream-data-channel-client/client.js | 2 +- .../3rdParty/CMakeLists.txt | 16 +- .../3rdParty/IXWebSocket | 1 + .../3rdParty/cpp-httplib | 2 +- .../3rdParty/cpp-subprocess | 2 +- .../3rdParty/googletest | 2 +- opentera-webrtc-native-client/3rdParty/json | 1 + .../3rdParty/pybind11 | 2 +- .../3rdParty/socket.io-client-cpp | 1 - .../OpenteraWebrtcNativeClient/CMakeLists.txt | 6 +- .../SignalingServerConfiguration.h | 28 +- .../DataChannelClient.h | 9 +- .../DataChannelPeerConnectionHandler.h | 4 +- .../Handlers/PeerConnectionHandler.h | 7 +- .../Handlers/StreamPeerConnectionHandler.h | 2 +- .../Signaling/SignalingClient.h | 167 +++++ .../Signaling/WebSocketSignalingClient.h | 64 ++ .../OpenteraWebrtcNativeClient/StreamClient.h | 4 +- .../OpenteraWebrtcNativeClient/Utils/Client.h | 53 +- .../{SignalingClient.h => WebrtcClient.h} | 83 +- .../OpenteraWebrtcNativeClientPython/Json.h | 14 + .../SignalingClientPython.h | 11 - .../SioMessage.h | 14 - .../WebrtcClientPython.h | 11 + .../SignalingServerConfigurationPython.cpp | 24 +- .../python/src/DataChannelClientPython.cpp | 2 +- .../python/src/Json.cpp | 113 +++ .../python/src/SioMessage.cpp | 104 --- .../python/src/StreamClientPython.cpp | 2 +- .../python/src/Utils/ClientPython.cpp | 10 +- ...lientPython.cpp => WebrtcClientPython.cpp} | 56 +- .../src/opentera_webrtc_native_client.cpp | 4 +- .../signaling_server_configuration_test.py | 25 +- .../python/test/data_channel_client_test.py | 12 +- .../python/test/requirements.txt | 2 +- .../test/socketio_inactive_client_test.py | 37 - .../python/test/stream_client_test.py | 14 +- .../test/websocket_inactive_client_test.py | 46 ++ .../SignalingServerConfiguration.cpp | 2 +- .../VideoStreamConfiguration.cpp | 2 +- .../src/DataChannelClient.cpp | 8 +- .../DataChannelPeerConnectionHandler.cpp | 10 +- .../src/Handlers/PeerConnectionHandler.cpp | 35 +- .../Handlers/StreamPeerConnectionHandler.cpp | 7 +- .../src/Signaling/SignalingClient.cpp | 8 + .../Signaling/WebSocketSignalingClient.cpp | 422 +++++++++++ .../src/SignalingClient.cpp | 709 ------------------ .../src/StreamClient.cpp | 10 +- .../src/Utils/Client.cpp | 99 +-- .../src/Utils/IceServer.cpp | 36 +- .../src/WebrtcClient.cpp | 491 ++++++++++++ .../src/Codecs/VideoCodecFactoriesTests.cpp | 14 +- .../SignalingServerConfigurationTests.cpp | 22 +- .../VideoStreamConfigurationTests.cpp | 8 +- .../test/src/DataChannelClientTests.cpp | 145 ++-- .../test/src/StreamClientTests.cpp | 32 +- .../test/src/Utils/ClientTests.cpp | 149 ++-- .../src/Pipeline/GStreamerEncoderPipeline.cpp | 10 +- .../disconnectedDataChannelClient.spec.js | 4 +- .../rightPasswordDataChannelClient.spec.js | 6 +- .../wrongPasswordDataChannelClient.spec.js | 2 +- .../src/DataChannelClient.js | 6 +- .../src/Signaling/SignalingClient.js | 106 +++ .../src/Signaling/WebSocketSignalingClient.js | 146 ++++ .../src/StreamClient.js | 4 +- .../src/StreamDataChannelClient.js | 6 +- .../{SignalingClient.js => WebrtcClient.js} | 166 ++-- .../signaling_server/room_manager.py | 30 +- .../signaling_server/signaling_server.py | 123 ++- .../web_socket_client_manager.py | 65 ++ .../opentera_webrtc/tests/__init__.py | 14 + .../tests/test_room_manager.py | 136 ++-- .../tests/test_web_socket_client_manager.py | 72 ++ signaling-server/requirements.txt | 1 - 86 files changed, 2383 insertions(+), 1737 deletions(-) create mode 160000 opentera-webrtc-native-client/3rdParty/IXWebSocket create mode 160000 opentera-webrtc-native-client/3rdParty/json delete mode 160000 opentera-webrtc-native-client/3rdParty/socket.io-client-cpp create mode 100644 opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Signaling/SignalingClient.h create mode 100644 opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Signaling/WebSocketSignalingClient.h rename opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/{SignalingClient.h => WebrtcClient.h} (80%) create mode 100644 opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Json.h delete mode 100644 opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/SignalingClientPython.h delete mode 100644 opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/SioMessage.h create mode 100644 opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/WebrtcClientPython.h create mode 100644 opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Json.cpp delete mode 100644 opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/SioMessage.cpp rename opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/{SignalingClientPython.cpp => WebrtcClientPython.cpp} (75%) delete mode 100644 opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/socketio_inactive_client_test.py create mode 100644 opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/websocket_inactive_client_test.py create mode 100644 opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Signaling/SignalingClient.cpp create mode 100644 opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Signaling/WebSocketSignalingClient.cpp delete mode 100644 opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/SignalingClient.cpp create mode 100644 opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/WebrtcClient.cpp create mode 100644 opentera-webrtc-web-client/src/Signaling/SignalingClient.js create mode 100644 opentera-webrtc-web-client/src/Signaling/WebSocketSignalingClient.js rename opentera-webrtc-web-client/src/{SignalingClient.js => WebrtcClient.js} (76%) create mode 100644 signaling-server/opentera_webrtc/signaling_server/web_socket_client_manager.py create mode 100644 signaling-server/opentera_webrtc/tests/test_web_socket_client_manager.py diff --git a/.gitmodules b/.gitmodules index 4f10de86..7e5b5cbf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "opentera-webrtc-native-client/3rdParty/googletest"] path = opentera-webrtc-native-client/3rdParty/googletest url = https://github.com/google/googletest.git -[submodule "opentera-webrtc-native-client/3rdParty/socket.io-client-cpp"] - path = opentera-webrtc-native-client/3rdParty/socket.io-client-cpp - url = https://github.com/introlab/socket.io-client-cpp.git [submodule "opentera-webrtc-native-client/3rdParty/cpp-subprocess"] path = opentera-webrtc-native-client/3rdParty/cpp-subprocess url = https://github.com/arun11299/cpp-subprocess.git @@ -16,3 +13,9 @@ [submodule "opentera-webrtc-native-client/3rdParty/opencv"] path = opentera-webrtc-native-client/3rdParty/opencv url = https://github.com/opencv/opencv.git +[submodule "opentera-webrtc-native-client/3rdParty/json"] + path = opentera-webrtc-native-client/3rdParty/json + url = https://github.com/nlohmann/json +[submodule "opentera-webrtc-native-client/3rdParty/IXWebSocket"] + path = opentera-webrtc-native-client/3rdParty/IXWebSocket + url = https://github.com/machinezone/IXWebSocket.git diff --git a/VERSION b/VERSION index 2228cad4..3eefcb9d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.6.7 +1.0.0 diff --git a/examples/cpp-data-channel-client-reliability-tests/CMakeLists.txt b/examples/cpp-data-channel-client-reliability-tests/CMakeLists.txt index ad5e9258..6583530b 100644 --- a/examples/cpp-data-channel-client-reliability-tests/CMakeLists.txt +++ b/examples/cpp-data-channel-client-reliability-tests/CMakeLists.txt @@ -8,8 +8,8 @@ set(LIBRARY_OUTPUT_PATH bin/${CMAKE_BUILD_TYPE}) include_directories(${OpenCV_INCLUDE_DIRS}) include_directories(BEFORE SYSTEM ${webrtc_native_INCLUDE}) -include_directories(../../opentera-webrtc-native-client/3rdParty/socket.io-client-cpp/src) -include_directories(../../opentera-webrtc-native-client/3rdParty/socket.io-client-cpp/lib/rapidjson/include) +include_directories(../../opentera-webrtc-native-client/3rdParty/json/include) +include_directories(../../opentera-webrtc-native-client/3rdParty/IXWebSocket) include_directories(../../opentera-webrtc-native-client/3rdParty/cpp-httplib) include_directories(../../opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include) diff --git a/examples/cpp-data-channel-client-reliability-tests/main.cpp b/examples/cpp-data-channel-client-reliability-tests/main.cpp index 987f0e2c..9313d974 100644 --- a/examples/cpp-data-channel-client-reliability-tests/main.cpp +++ b/examples/cpp-data-channel-client-reliability-tests/main.cpp @@ -31,7 +31,7 @@ bool waitFor(F f) { this_thread::sleep_for(SLEEP_TIME); - if (std::chrono::duration_cast(chrono::steady_clock::now() - start) > TIMEOUT) + if (chrono::duration_cast(chrono::steady_clock::now() - start) > TIMEOUT) { return false; } @@ -80,6 +80,20 @@ int main(int argc, char* argv[]) } cout << endl; + string wsUrl; + if (baseUrl.find("http://") == 0) + { + wsUrl = "ws://" + baseUrl.substr(7) + "/signaling"; + } + else if (baseUrl.find("https://") == 0) + { + wsUrl = "wss://" + baseUrl.substr(8) + "/signaling"; + } + else + { + cout << "Invalid base URL (" << baseUrl << ")" << endl; + return -1; + } auto signalingServerConfiguration = SignalingServerConfiguration::create(baseUrl, name, "reliability", password); auto webrtcConfiguration = WebrtcConfiguration::create(iceServers); diff --git a/examples/cpp-data-channel-client/CMakeLists.txt b/examples/cpp-data-channel-client/CMakeLists.txt index a387ded5..b7e87b19 100644 --- a/examples/cpp-data-channel-client/CMakeLists.txt +++ b/examples/cpp-data-channel-client/CMakeLists.txt @@ -8,8 +8,8 @@ set(LIBRARY_OUTPUT_PATH bin/${CMAKE_BUILD_TYPE}) include_directories(${OpenCV_INCLUDE_DIRS}) include_directories(BEFORE SYSTEM ${webrtc_native_INCLUDE}) -include_directories(../../opentera-webrtc-native-client/3rdParty/socket.io-client-cpp/src) -include_directories(../../opentera-webrtc-native-client/3rdParty/socket.io-client-cpp/lib/rapidjson/include) +include_directories(../../opentera-webrtc-native-client/3rdParty/json/include) +include_directories(../../opentera-webrtc-native-client/3rdParty/IXWebSocket) include_directories(../../opentera-webrtc-native-client/3rdParty/cpp-httplib) include_directories(../../opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include) diff --git a/examples/cpp-data-channel-client/main.cpp b/examples/cpp-data-channel-client/main.cpp index 70939cda..90e1ffe2 100644 --- a/examples/cpp-data-channel-client/main.cpp +++ b/examples/cpp-data-channel-client/main.cpp @@ -15,7 +15,7 @@ int main(int argc, char* argv[]) } auto signalingServerConfiguration = - SignalingServerConfiguration::create("http://localhost:8080", "C++", "chat", "abc"); + SignalingServerConfiguration::create("ws://localhost:8080/signaling", "C++", "chat", "abc"); auto webrtcConfiguration = WebrtcConfiguration::create(iceServers); auto dataChannelConfiguration = DataChannelConfiguration::create(); DataChannelClient client(signalingServerConfiguration, webrtcConfiguration, dataChannelConfiguration); diff --git a/examples/cpp-stream-client/CMakeLists.txt b/examples/cpp-stream-client/CMakeLists.txt index b0d6e20c..5a1de138 100644 --- a/examples/cpp-stream-client/CMakeLists.txt +++ b/examples/cpp-stream-client/CMakeLists.txt @@ -8,8 +8,8 @@ set(LIBRARY_OUTPUT_PATH bin/${CMAKE_BUILD_TYPE}) include_directories(${OpenCV_INCLUDE_DIRS}) include_directories(BEFORE SYSTEM ${webrtc_native_INCLUDE}) -include_directories(../../opentera-webrtc-native-client/3rdParty/socket.io-client-cpp/src) -include_directories(../../opentera-webrtc-native-client/3rdParty/socket.io-client-cpp/lib/rapidjson/include) +include_directories(../../opentera-webrtc-native-client/3rdParty/json/include) +include_directories(../../opentera-webrtc-native-client/3rdParty/IXWebSocket) include_directories(../../opentera-webrtc-native-client/3rdParty/cpp-httplib) include_directories(../../opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include) diff --git a/examples/cpp-stream-client/main.cpp b/examples/cpp-stream-client/main.cpp index 59cbbb52..f271da45 100644 --- a/examples/cpp-stream-client/main.cpp +++ b/examples/cpp-stream-client/main.cpp @@ -140,7 +140,7 @@ int main(int argc, char* argv[]) } auto signalingServerConfiguration = - SignalingServerConfiguration::create("http://localhost:8080", "C++", "chat", "abc"); + SignalingServerConfiguration::create("ws://localhost:8080/signaling", "C++", "chat", "abc"); auto webrtcConfiguration = WebrtcConfiguration::create(iceServers); auto videoStreamConfiguration = VideoStreamConfiguration::create(); auto videoSource = make_shared(argv[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 c4ae521a..8da649ce 100644 --- a/examples/python-data-channel-client/python_data_channel_client.py +++ b/examples/python-data-channel-client/python_data_channel_client.py @@ -77,8 +77,8 @@ def on_data_channel_message_string(client, message): if __name__ == '__main__': - signaling_server_configuration = webrtc.SignalingServerConfiguration.create( - 'http://localhost:8080', 'Python', None, 'chat', 'abc') + signaling_server_configuration = webrtc.SignalingServerConfiguration.create_with_data( + 'ws://localhost:8080/signaling', 'Python', None, 'chat', 'abc') ice_servers = webrtc.IceServer.fetch_from_server( 'http://localhost:8080/iceservers', 'abc') webrtc_configuration = webrtc.WebrtcConfiguration.create(ice_servers) diff --git a/examples/python-stream-client/python_stream_client.py b/examples/python-stream-client/python_stream_client.py index f7c8d70e..b3c1cdc2 100644 --- a/examples/python-stream-client/python_stream_client.py +++ b/examples/python-stream-client/python_stream_client.py @@ -92,8 +92,8 @@ def on_error(error): frame = cv2.imread(os.path.join(os.path.dirname( os.path.realpath(__file__)), 'frame.png')) - signaling_server_configuration = webrtc.SignalingServerConfiguration.create( - 'http://localhost:8080', 'Python', None, 'chat', 'abc') + signaling_server_configuration = webrtc.SignalingServerConfiguration.create_with_data( + 'ws://localhost:8080/signaling', 'Python', None, 'chat', 'abc') ice_servers = webrtc.IceServer.fetch_from_server( 'http://localhost:8080/iceservers', 'abc') webrtc_configuration = webrtc.WebrtcConfiguration.create(ice_servers) diff --git a/examples/web-data-channel-client/client.js b/examples/web-data-channel-client/client.js index 47e51359..3fc04115 100644 --- a/examples/web-data-channel-client/client.js +++ b/examples/web-data-channel-client/client.js @@ -21,7 +21,7 @@ sendButton.disabled = true; chatTextArea.value = ''; - let dataChannelClient = null; + let dataChannelClient = null; function connectDataChannelClientEvents() { dataChannelClient.onSignalingConnectionOpen = () => { @@ -84,7 +84,7 @@ connectButton.onclick = async () => { const SignalingServerConfiguration = { - url: 'http://localhost:8080', + url: 'ws://localhost:8080/signaling', name: nameInput.value, data: {}, // Client custom data room: 'chat', diff --git a/examples/web-stream-client/client.js b/examples/web-stream-client/client.js index a2fb5816..a1dad547 100644 --- a/examples/web-stream-client/client.js +++ b/examples/web-stream-client/client.js @@ -116,7 +116,7 @@ }; connectButton.onclick = async () => { const SignalingServerConfiguration = { - url: 'http://localhost:8080', + url: 'ws://localhost:8080/signaling', name: nameInput.value, data: {}, // Client custom data room: 'chat', diff --git a/examples/web-stream-data-channel-client/client.js b/examples/web-stream-data-channel-client/client.js index 5c9c6eb0..a61b1f29 100644 --- a/examples/web-stream-data-channel-client/client.js +++ b/examples/web-stream-data-channel-client/client.js @@ -143,7 +143,7 @@ }; connectButton.onclick = async () => { const SignalingServerConfiguration = { - url: 'http://localhost:8080', + url: 'ws://localhost:8080/signaling', name: nameInput.value, data: {}, // Client custom data room: 'chat', diff --git a/opentera-webrtc-native-client/3rdParty/CMakeLists.txt b/opentera-webrtc-native-client/3rdParty/CMakeLists.txt index 4ebcd087..9c0f8c06 100644 --- a/opentera-webrtc-native-client/3rdParty/CMakeLists.txt +++ b/opentera-webrtc-native-client/3rdParty/CMakeLists.txt @@ -8,11 +8,16 @@ set (BUILD_SHARED_LIBS OFF) add_subdirectory(webrtc_native) add_subdirectory(pybind11) -add_subdirectory(socket.io-client-cpp) +add_subdirectory(json) -if(WIN32) - target_compile_definitions(sioclient PRIVATE WIN32_LEAN_AND_MEAN) -endif() +set(USE_ZLIB OFF) +set(USE_TLS ON) +set(OPENSSL_FOUND TRUE) +set(OPENSSL_DEFINITIONS "") +set(OPENSSL_INCLUDE_DIR ${boringssl_INCLUDE}) +set(OPENSSL_LIBRARIES ${boringssl_LIBRARY}) +add_subdirectory(IXWebSocket) +set_property(TARGET ixwebsocket PROPERTY CXX_STANDARD 17) if (OPENTERA_WEBRTC_ENABLE_TESTS) add_subdirectory(googletest) @@ -54,5 +59,4 @@ if(NOT OPENTERA_WEBRTC_USE_SYSTEM_OPENCV) endif() -install(DIRECTORY socket.io-client-cpp/lib/rapidjson/include/rapidjson DESTINATION include - FILES_MATCHING PATTERN "*.h") +install(DIRECTORY json/include DESTINATION include FILES_MATCHING PATTERN "*.hpp") diff --git a/opentera-webrtc-native-client/3rdParty/IXWebSocket b/opentera-webrtc-native-client/3rdParty/IXWebSocket new file mode 160000 index 00000000..688af997 --- /dev/null +++ b/opentera-webrtc-native-client/3rdParty/IXWebSocket @@ -0,0 +1 @@ +Subproject commit 688af99747bc109d3476cb3a6703c5e7d37b10d9 diff --git a/opentera-webrtc-native-client/3rdParty/cpp-httplib b/opentera-webrtc-native-client/3rdParty/cpp-httplib index 4e6ded1f..f14accb7 160000 --- a/opentera-webrtc-native-client/3rdParty/cpp-httplib +++ b/opentera-webrtc-native-client/3rdParty/cpp-httplib @@ -1 +1 @@ -Subproject commit 4e6ded1f36ec24d6428ab560f8c0ddfb653651e6 +Subproject commit f14accb7b6ff4499321e14c61497bc7e4b28e49b diff --git a/opentera-webrtc-native-client/3rdParty/cpp-subprocess b/opentera-webrtc-native-client/3rdParty/cpp-subprocess index 1392c47c..40cd59c0 160000 --- a/opentera-webrtc-native-client/3rdParty/cpp-subprocess +++ b/opentera-webrtc-native-client/3rdParty/cpp-subprocess @@ -1 +1 @@ -Subproject commit 1392c47cbbf519bd02ddafb5871526c16b7f2dd1 +Subproject commit 40cd59c0970960a0ef41365ae9d96c6a72ee6922 diff --git a/opentera-webrtc-native-client/3rdParty/googletest b/opentera-webrtc-native-client/3rdParty/googletest index b796f7d4..f8d7d77c 160000 --- a/opentera-webrtc-native-client/3rdParty/googletest +++ b/opentera-webrtc-native-client/3rdParty/googletest @@ -1 +1 @@ -Subproject commit b796f7d44681514f58a683a3a71ff17c94edb0c1 +Subproject commit f8d7d77c06936315286eb55f8de22cd23c188571 diff --git a/opentera-webrtc-native-client/3rdParty/json b/opentera-webrtc-native-client/3rdParty/json new file mode 160000 index 00000000..9cca280a --- /dev/null +++ b/opentera-webrtc-native-client/3rdParty/json @@ -0,0 +1 @@ +Subproject commit 9cca280a4d0ccf0c08f47a99aa71d1b0e52f8d03 diff --git a/opentera-webrtc-native-client/3rdParty/pybind11 b/opentera-webrtc-native-client/3rdParty/pybind11 index 0bd8896a..1a917f18 160000 --- a/opentera-webrtc-native-client/3rdParty/pybind11 +++ b/opentera-webrtc-native-client/3rdParty/pybind11 @@ -1 +1 @@ -Subproject commit 0bd8896a4010f2d91b2340570c24fa08606ec406 +Subproject commit 1a917f1852eb7819b671fc3fa862840f4c491a07 diff --git a/opentera-webrtc-native-client/3rdParty/socket.io-client-cpp b/opentera-webrtc-native-client/3rdParty/socket.io-client-cpp deleted file mode 160000 index 46d3a89c..00000000 --- a/opentera-webrtc-native-client/3rdParty/socket.io-client-cpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 46d3a89cc8b5c3693b09a55543f7dd83441456ee diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/CMakeLists.txt b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/CMakeLists.txt index eee268ee..5d553b28 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/CMakeLists.txt +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/CMakeLists.txt @@ -33,8 +33,8 @@ include_directories(${OpenCV_INCLUDE_DIRS}) include_directories(BEFORE SYSTEM ${webrtc_native_INCLUDE}) include_directories(BEFORE SYSTEM ${boringssl_INCLUDE}) include_directories(BEFORE SYSTEM ${libyuv_INCLUDE}) -include_directories(../3rdParty/socket.io-client-cpp/src) -include_directories(../3rdParty/socket.io-client-cpp/lib/rapidjson/include) +include_directories(../3rdParty/json/include) +include_directories(../3rdParty/IXWebSocket) include_directories(../3rdParty/cpp-httplib) include_directories(include) @@ -50,7 +50,7 @@ add_library(OpenteraWebrtcNativeClient ${source_files}) target_link_libraries(OpenteraWebrtcNativeClient - sioclient + ixwebsocket ${webrtc_native_LIBRARY} ${boringssl_LIBRARY} ${libyuv_LIBRARY} diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Configurations/SignalingServerConfiguration.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Configurations/SignalingServerConfiguration.h index 634e89ff..4d5174f7 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Configurations/SignalingServerConfiguration.h +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Configurations/SignalingServerConfiguration.h @@ -1,7 +1,7 @@ #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_CONFIGURATIONS_SIGNALING_SERVER_CONFIGURATION_H #define OPENTERA_WEBRTC_NATIVE_CLIENT_CONFIGURATIONS_SIGNALING_SERVER_CONFIGURATION_H -#include +#include #include @@ -14,14 +14,14 @@ namespace opentera { std::string m_url; std::string m_clientName; - sio::message::ptr m_clientData; + nlohmann::json m_clientData; std::string m_room; std::string m_password; SignalingServerConfiguration( std::string&& url, std::string&& clientName, - sio::message::ptr&& clientData, + nlohmann::json&& clientData, std::string&& room, std::string&& password); @@ -32,19 +32,19 @@ namespace opentera static SignalingServerConfiguration create(std::string url, std::string clientName, std::string room); static SignalingServerConfiguration - create(std::string url, std::string clientName, sio::message::ptr clientData, std::string room); + createWithData(std::string url, std::string clientName, nlohmann::json clientData, std::string room); static SignalingServerConfiguration create(std::string url, std::string clientName, std::string room, std::string password); - static SignalingServerConfiguration create( + static SignalingServerConfiguration createWithData( std::string url, std::string clientName, - sio::message::ptr clientData, + nlohmann::json clientData, std::string room, std::string password); [[nodiscard]] const std::string& url() const; [[nodiscard]] const std::string& clientName() const; - [[nodiscard]] sio::message::ptr clientData() const; + [[nodiscard]] const nlohmann::json& clientData() const; [[nodiscard]] const std::string& room() const; [[nodiscard]] const std::string& password() const; @@ -63,7 +63,7 @@ namespace opentera inline SignalingServerConfiguration SignalingServerConfiguration::create(std::string url, std::string clientName, std::string room) { - return {std::move(url), std::move(clientName), sio::null_message::create(), std::move(room), ""}; + return {std::move(url), std::move(clientName), nlohmann::json{}, std::move(room), ""}; } /** @@ -75,10 +75,10 @@ namespace opentera * @param room The room name * @return A signaling server configuration with the specified values */ - inline SignalingServerConfiguration SignalingServerConfiguration::create( + inline SignalingServerConfiguration SignalingServerConfiguration::createWithData( std::string url, std::string clientName, - sio::message::ptr clientData, + nlohmann::json clientData, std::string room) { return {std::move(url), std::move(clientName), std::move(clientData), std::move(room), ""}; @@ -102,7 +102,7 @@ namespace opentera return { std::move(url), std::move(clientName), - sio::null_message::create(), + nlohmann::json{}, std::move(room), std::move(password)}; } @@ -117,10 +117,10 @@ namespace opentera * @param password The signaling server password * @return A signaling server configuration with the specified values */ - inline SignalingServerConfiguration SignalingServerConfiguration::create( + inline SignalingServerConfiguration SignalingServerConfiguration::createWithData( std::string url, std::string clientName, - sio::message::ptr clientData, + nlohmann::json clientData, std::string room, std::string password) { @@ -143,7 +143,7 @@ namespace opentera * @brief Returns the client data. * @return The client data */ - inline sio::message::ptr SignalingServerConfiguration::clientData() const { return m_clientData; } + inline const nlohmann::json& SignalingServerConfiguration::clientData() const { return m_clientData; } /** * @brief Returns the room name. diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/DataChannelClient.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/DataChannelClient.h index 20578d7d..3c0489f1 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/DataChannelClient.h +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/DataChannelClient.h @@ -1,7 +1,7 @@ #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_DATA_CHANNEL_CLIENT_H #define OPENTERA_WEBRTC_NATIVE_CLIENT_DATA_CHANNEL_CLIENT_H -#include +#include #include #include @@ -12,7 +12,7 @@ namespace opentera /** * @brief Represents a client for data channel communication. */ - class DataChannelClient : public SignalingClient + class DataChannelClient : public WebrtcClient { DataChannelConfiguration m_dataChannelConfiguration; @@ -91,7 +91,10 @@ namespace opentera * * @param message The string message */ - inline bool DataChannelClient::sendToAll(const std::string& message) { return sendToAll(webrtc::DataBuffer(message)); } + inline bool DataChannelClient::sendToAll(const std::string& message) + { + return sendToAll(webrtc::DataBuffer(message)); + } /** * @brief Sets the callback that is called when a data channel opens. 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 04eee513..0c0215d1 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/DataChannelPeerConnectionHandler.h +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/DataChannelPeerConnectionHandler.h @@ -12,7 +12,6 @@ namespace opentera { class DataChannelPeerConnectionHandler : public PeerConnectionHandler, public webrtc::DataChannelObserver { - std::string m_room; DataChannelConfiguration m_dataChannelConfiguration; std::function m_onDataChannelOpen; @@ -30,11 +29,10 @@ namespace opentera std::string id, Client peerClient, bool isCaller, - std::function sendEvent, + SignalingClient& m_signalingClient, std::function onError, std::function onClientConnected, std::function onClientDisconnected, - std::string room, 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 73f50d52..5d5e0eeb 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/PeerConnectionHandler.h +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/PeerConnectionHandler.h @@ -1,10 +1,9 @@ #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_FUNCTIONAL_PEER_CONNECTION_OBSERVER_H #define OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_FUNCTIONAL_PEER_CONNECTION_OBSERVER_H +#include #include -#include - #include #include @@ -39,7 +38,7 @@ namespace opentera std::string m_id; Client m_peerClient; bool m_isCaller; - std::function m_sendEvent; + SignalingClient& m_signalingClient; std::function m_onError; std::function m_onClientConnected; std::function m_onClientDisconnected; @@ -53,7 +52,7 @@ namespace opentera std::string&& id, Client&& peerClient, bool isCaller, - std::function&& sendEvent, + SignalingClient& m_signalingClient, std::function&& onError, std::function&& onClientConnected, std::function&& onClientDisconnected); 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 a294ec02..7139a259 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/StreamPeerConnectionHandler.h +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Handlers/StreamPeerConnectionHandler.h @@ -51,7 +51,7 @@ namespace opentera Client peerClient, bool isCaller, bool hasOnMixedAudioFrameReceivedCallback, - std::function sendEvent, + SignalingClient& m_signalingClient, std::function onError, std::function onClientConnected, std::function onClientDisconnected, diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Signaling/SignalingClient.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Signaling/SignalingClient.h new file mode 100644 index 00000000..6c866be3 --- /dev/null +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Signaling/SignalingClient.h @@ -0,0 +1,167 @@ +#ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_SIGNALING_SIGNALING_CLIENT_H +#define OPENTERA_WEBRTC_NATIVE_CLIENT_SIGNALING_SIGNALING_CLIENT_H + +#include +#include +#include + +#include +#include +#include +#include + +namespace opentera +{ + class SignalingClient + { + protected: + SignalingServerConfiguration m_configuration; + + std::function m_onSignalingConnectionOpened; + std::function m_onSignalingConnectionClosed; + std::function m_onSignalingConnectionError; + + std::function&)> m_onRoomClientsChanged; + + std::function m_makePeerCall; + std::function m_receivePeerCall; + std::function m_receivePeerCallAnswer; + std::function< + void(const std::string& fromId, const std::string& sdpMid, int sdpMLineIndex, const std::string& sdp)> + m_receiveIceCandidate; + + std::function m_onCallRejected; + std::function m_closeAllPeerConnections; + + std::function m_onError; + + public: + SignalingClient(SignalingServerConfiguration configuration); + virtual ~SignalingClient(); + + DECLARE_NOT_COPYABLE(SignalingClient); + DECLARE_NOT_MOVABLE(SignalingClient); + + const std::string& room(); + + virtual void setTlsVerificationEnabled(bool isEnabled) = 0; + + virtual bool isConnected() = 0; + virtual std::string sessionId() = 0; + + virtual void connect() = 0; + virtual void close() = 0; + virtual void closeSync() = 0; + + virtual void callAll() = 0; + virtual void callIds(const std::vector& ids) = 0; + virtual void closeAllRoomPeerConnections() = 0; + + virtual void callPeer(const std::string& toId, const std::string& sdp) = 0; + virtual void makePeerCallAnswer(const std::string& toId, const std::string& sdp) = 0; + virtual void rejectCall(const std::string& toId) = 0; + virtual void sendIceCandidate( + const std::string& sdpMid, + int sdpMLineIndex, + const std::string& candidate, + const std::string& toId) = 0; + + void setOnSignalingConnectionOpened(const std::function& callback); + void setOnSignalingConnectionClosed(const std::function& callback); + void setOnSignalingConnectionError(const std::function& callback); + + void setOnRoomClientsChanged(const std::function&)>& callback); + + void setMakePeerCall(const std::function& callback); + void setReceivePeerCall(const std::function& callback); + void setReceivePeerCallAnswer( + const std::function& callback); + void setReceiveIceCandidate( + const std::function< + void(const std::string& fromId, const std::string& sdpMid, int sdpMLineIndex, const std::string& sdp)>& + callback); + + void setOnCallRejected(const std::function& callback); + void setCloseAllPeerConnections(const std::function& callback); + + void setOnError(const std::function& callback); + + protected: + template + void invokeIfCallable(const std::function& f, Types... args); + }; + + inline const std::string& SignalingClient::room() { return m_configuration.room(); } + + inline void SignalingClient::setOnSignalingConnectionOpened(const std::function& callback) + { + m_onSignalingConnectionOpened = callback; + } + + inline void SignalingClient::setOnSignalingConnectionClosed(const std::function& callback) + { + m_onSignalingConnectionClosed = callback; + } + + inline void SignalingClient::setOnSignalingConnectionError(const std::function& callback) + { + m_onSignalingConnectionError = callback; + } + + inline void + SignalingClient::setOnRoomClientsChanged(const std::function&)>& callback) + { + m_onRoomClientsChanged = callback; + } + + inline void SignalingClient::setMakePeerCall(const std::function& callback) + { + m_makePeerCall = callback; + } + + inline void SignalingClient::setReceivePeerCall( + const std::function& callback) + { + m_receivePeerCall = callback; + } + + inline void SignalingClient::setReceivePeerCallAnswer( + const std::function& callback) + { + m_receivePeerCallAnswer = callback; + } + + inline void SignalingClient::setReceiveIceCandidate( + const std::function< + void(const std::string& fromId, const std::string& sdpMid, int sdpMLineIndex, const std::string& sdp)>& + callback) + { + m_receiveIceCandidate = callback; + } + + inline void SignalingClient::setOnCallRejected(const std::function& callback) + { + m_onCallRejected = callback; + } + + inline void SignalingClient::setCloseAllPeerConnections(const std::function& callback) + { + m_closeAllPeerConnections = callback; + } + + inline void SignalingClient::setOnError(const std::function& callback) + { + m_onError = callback; + } + + template + inline void SignalingClient::invokeIfCallable(const std::function& f, Types... args) + { + if (f) + { + f(args...); + } + } +} + +#endif diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Signaling/WebSocketSignalingClient.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Signaling/WebSocketSignalingClient.h new file mode 100644 index 00000000..ea57186b --- /dev/null +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Signaling/WebSocketSignalingClient.h @@ -0,0 +1,64 @@ +#ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_SIGNALING_SIO_SIGNALING_CLIENT_H +#define OPENTERA_WEBRTC_NATIVE_CLIENT_SIGNALING_SIO_SIGNALING_CLIENT_H + +#include + +#include + +namespace opentera +{ + class WebSocketSignalingClient : public SignalingClient + { + ix::WebSocket m_ws; + std::string m_sessionId; + + public: + WebSocketSignalingClient(SignalingServerConfiguration configuration); + ~WebSocketSignalingClient() override; + + DECLARE_NOT_COPYABLE(WebSocketSignalingClient); + DECLARE_NOT_MOVABLE(WebSocketSignalingClient); + + void setTlsVerificationEnabled(bool isEnabled) override; + + bool isConnected() override; + std::string sessionId() override; + + void connect() override; + void close() override; + void closeSync() override; + + void callAll() override; + void callIds(const std::vector& ids) override; + void closeAllRoomPeerConnections() override; + + void callPeer(const std::string& toId, const std::string& sdp) override; + void makePeerCallAnswer(const std::string& toId, const std::string& sdp) override; + void rejectCall(const std::string& toId) override; + void sendIceCandidate( + const std::string& sdpMid, + int sdpMLineIndex, + const std::string& candidate, + const std::string& toId) override; + + private: + void connectWsEvents(); + + void onWsOpenEvent(); + void onWsCloseEvent(); + void onWsErrorEvent(const std::string& error); + void onWsMessage(const std::string& message); + + void onJoinRoomAnswerEvent(const nlohmann::json& data); + + void onRoomClientsEvent(const nlohmann::json& data); + + void onMakePeerCallEvent(const nlohmann::json& data); + void onPeerCallReceivedEvent(const nlohmann::json& data); + void onPeerCallAnswerReceivedEvent(const nlohmann::json& data); + void onCloseAllPeerConnectionsRequestReceivedEvent(); + void onIceCandidateReceivedEvent(const nlohmann::json& data); + }; +} + +#endif diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/StreamClient.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/StreamClient.h index 159e1031..7f34f819 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/StreamClient.h +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/StreamClient.h @@ -5,7 +5,7 @@ #include #include -#include +#include #include @@ -14,7 +14,7 @@ namespace opentera /** * @brief A signaling client to join a WebRTC room and stream a video source. */ - class StreamClient : public SignalingClient + class StreamClient : public WebrtcClient { std::shared_ptr m_videoSource; std::shared_ptr m_audioSource; diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Utils/Client.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Utils/Client.h index f13d8e52..f9c9820d 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Utils/Client.h +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/Utils/Client.h @@ -1,15 +1,12 @@ #ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_CLIENT_H #define OPENTERA_WEBRTC_NATIVE_CLIENT_UTILS_CLIENT_H -#include +#include #include namespace opentera { - bool operator==(const sio::message& m1, const sio::message& m2); - bool operator!=(const sio::message& m1, const sio::message& m2); - /** * @brief Represents a peer client. */ @@ -17,21 +14,21 @@ namespace opentera { std::string m_id; std::string m_name; - sio::message::ptr m_data; + nlohmann::json m_data; public: Client() = default; - Client(std::string id, std::string name, sio::message::ptr data); - explicit Client(const sio::message::ptr& message); + Client(std::string id, std::string name, nlohmann::json data); + explicit Client(const nlohmann::json& message); Client(const Client& other) = default; Client(Client&& other) = default; virtual ~Client() = default; [[nodiscard]] const std::string& id() const; [[nodiscard]] const std::string& name() const; - [[nodiscard]] const sio::message::ptr& data() const; + [[nodiscard]] const nlohmann::json& data() const; - static bool isValid(const sio::message::ptr& message); + static bool isValid(const nlohmann::json& message); Client& operator=(const Client& other) = default; Client& operator=(Client&& other) = default; @@ -55,22 +52,11 @@ namespace opentera * @brief Returns the client data. * @return The client data */ - inline const sio::message::ptr& Client::data() const { return m_data; } + inline const nlohmann::json& Client::data() const { return m_data; } inline bool operator==(const Client& c1, const Client& c2) { - if (c1.m_data != nullptr && c2.m_data != nullptr) - { - return c1.m_id == c2.m_id && c1.m_name == c2.m_name && *c1.m_data == *c2.m_data; - } - else if (c1.m_data == nullptr && c2.m_data == nullptr) - { - return c1.m_id == c2.m_id && c1.m_name == c2.m_name; - } - else - { - return false; - } + return c1.m_id == c2.m_id && c1.m_name == c2.m_name && c1.m_data == c2.m_data; } inline bool operator!=(const Client& c1, const Client& c2) { return !(c1 == c2); } @@ -82,12 +68,12 @@ namespace opentera { std::string m_id; std::string m_name; - sio::message::ptr m_data; + nlohmann::json m_data; bool m_isConnected; public: RoomClient(); - RoomClient(std::string id, std::string name, sio::message::ptr data, bool isConnected); + RoomClient(std::string id, std::string name, nlohmann::json data, bool isConnected); RoomClient(const Client& client, bool isConnected); RoomClient(const RoomClient& other) = default; RoomClient(RoomClient&& other) = default; @@ -95,7 +81,7 @@ namespace opentera [[nodiscard]] const std::string& id() const; [[nodiscard]] const std::string& name() const; - [[nodiscard]] const sio::message::ptr& data() const; + [[nodiscard]] const nlohmann::json& data() const; [[nodiscard]] bool isConnected() const; explicit operator Client() const; @@ -122,7 +108,7 @@ namespace opentera * @brief Returns the client data. * @return The client data */ - inline const sio::message::ptr& RoomClient::data() const { return m_data; } + inline const nlohmann::json& RoomClient::data() const { return m_data; } /** * @brief Indicates if the client is connected (RTCPeerConnection). @@ -134,19 +120,8 @@ namespace opentera inline bool operator==(const RoomClient& c1, const RoomClient& c2) { - if (c1.m_data != nullptr && c2.m_data != nullptr) - { - return c1.m_id == c2.m_id && c1.m_name == c2.m_name && *c1.m_data == *c2.m_data && - c1.m_isConnected == c2.m_isConnected; - } - else if (c1.m_data == nullptr && c2.m_data == nullptr) - { - return c1.m_id == c2.m_id && c1.m_name == c2.m_name && c1.m_isConnected == c2.m_isConnected; - } - else - { - return false; - } + return c1.m_id == c2.m_id && c1.m_name == c2.m_name && c1.m_data == c2.m_data && + c1.m_isConnected == c2.m_isConnected; } inline bool operator!=(const RoomClient& c1, const RoomClient& c2) { return !(c1 == c2); } diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/SignalingClient.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/WebrtcClient.h similarity index 80% rename from opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/SignalingClient.h rename to opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/WebrtcClient.h index 8aa3f2a0..d5e83e22 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/SignalingClient.h +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/include/OpenteraWebrtcNativeClient/WebrtcClient.h @@ -1,9 +1,9 @@ -#ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_SIGNALING_CLIENT_H -#define OPENTERA_WEBRTC_NATIVE_CLIENT_SIGNALING_CLIENT_H +#ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_WEBRTC_CLIENT_H +#define OPENTERA_WEBRTC_NATIVE_CLIENT_WEBRTC_CLIENT_H -#include #include #include +#include #include #include #include @@ -11,8 +11,6 @@ #include #include -#include - #include #include @@ -27,15 +25,12 @@ namespace opentera /** * @brief Represents the base class of DataChannelClient and StreamClient. */ - class SignalingClient + class WebrtcClient { std::unique_ptr m_internalClientThread; WebrtcConfiguration m_webrtcConfiguration; - sio::client m_sio; - bool m_hasClosePending; - std::map m_roomClientsById; std::vector m_alreadyAcceptedCalls; @@ -60,7 +55,7 @@ namespace opentera std::unique_ptr m_signalingThread; protected: - SignalingServerConfiguration m_signalingServerConfiguration; + std::unique_ptr m_signalingClient; rtc::scoped_refptr m_peerConnectionFactory; std::map> m_peerConnectionHandlersById; @@ -69,14 +64,14 @@ namespace opentera rtc::scoped_refptr m_audioProcessing; public: - SignalingClient( + WebrtcClient( SignalingServerConfiguration&& signalingServerConfiguration, WebrtcConfiguration&& webrtcConfiguration, VideoStreamConfiguration&& videoStreamConfiguration); - virtual ~SignalingClient(); + virtual ~WebrtcClient(); - DECLARE_NOT_COPYABLE(SignalingClient); - DECLARE_NOT_MOVABLE(SignalingClient); + DECLARE_NOT_COPYABLE(WebrtcClient); + DECLARE_NOT_MOVABLE(WebrtcClient); void setTlsVerificationEnabled(bool isEnabled); @@ -124,7 +119,6 @@ namespace opentera virtual std::unique_ptr createPeerConnectionHandler(const std::string& id, const Client& peerClient, bool isCaller) = 0; - std::function getSendEventFunction(); std::function getOnErrorFunction(); std::function getOnClientConnectedFunction(); std::function getOnClientDisconnectedFunction(); @@ -132,28 +126,11 @@ namespace opentera rtc::Thread* getInternalClientThread(); private: - void connectSioEvents(); - - void onSioConnectEvent(); - void onSioErrorEvent(); - void onSioDisconnectEvent(const sio::client::close_reason& reason); + void connectSignalingClientCallbacks(); - void onJoinRoomCallback(const sio::message::list& message); - - void onRoomClientsEvent(sio::event& event); - - void onMakePeerCallEvent(sio::event& event); void makePeerCall(const std::string& id); - - void onPeerCallReceivedEvent(sio::event& event); void receivePeerCall(const std::string& fromId, const std::string& sdp); - - void onPeerCallAnswerReceivedEvent(sio::event& event); void receivePeerCallAnswer(const std::string& fromId, const std::string& sdp); - - void onCloseAllPeerConnectionsRequestReceivedEvent(sio::event& event); - - void onIceCandidateReceivedEvent(sio::event& event); void receiveIceCandidate( const std::string& fromId, const std::string& sdpMid, @@ -173,16 +150,16 @@ namespace opentera * @brief Indicates if the client is connected to the signaling server. * @return true if the client is connected to the signaling server */ - inline bool SignalingClient::isConnected() + inline bool WebrtcClient::isConnected() { - return callSync(m_internalClientThread.get(), [this]() { return m_sio.opened(); }); + return callSync(m_internalClientThread.get(), [this]() { return m_signalingClient->isConnected(); }); } /** * @brief Indicates if the client is connected to at least one client (RTCPeerConnection). * @return true if the client is connected to at least one client (RTCPeerConnection) */ - inline bool SignalingClient::isRtcConnected() + inline bool WebrtcClient::isRtcConnected() { return callSync(m_internalClientThread.get(), [this]() { return !m_peerConnectionHandlersById.empty(); }); } @@ -191,11 +168,9 @@ namespace opentera * @brief Returns the client id. * @return The client id */ - inline std::string SignalingClient::id() + inline std::string WebrtcClient::id() { - return callSync( - m_internalClientThread.get(), - [this]() { return m_hasClosePending ? "" : m_sio.get_sessionid(); }); + return callSync(m_internalClientThread.get(), [this]() { return m_signalingClient->sessionId(); }); } /** @@ -205,7 +180,7 @@ namespace opentera * @param id The room client id * @return The room client that matches with the specified id */ - inline RoomClient SignalingClient::getRoomClient(const std::string& id) + inline RoomClient WebrtcClient::getRoomClient(const std::string& id) { return callSync( m_internalClientThread.get(), @@ -234,7 +209,7 @@ namespace opentera * * @param callback The callback */ - inline void SignalingClient::setOnSignalingConnectionOpened(const std::function& callback) + inline void WebrtcClient::setOnSignalingConnectionOpened(const std::function& callback) { callSync(m_internalClientThread.get(), [this, &callback]() { m_onSignalingConnectionOpened = callback; }); } @@ -246,7 +221,7 @@ namespace opentera * * @param callback The callback */ - inline void SignalingClient::setOnSignalingConnectionClosed(const std::function& callback) + inline void WebrtcClient::setOnSignalingConnectionClosed(const std::function& callback) { callSync(m_internalClientThread.get(), [this, &callback]() { m_onSignalingConnectionClosed = callback; }); } @@ -263,7 +238,7 @@ namespace opentera * * @param callback The callback */ - inline void SignalingClient::setOnSignalingConnectionError(const std::function& callback) + inline void WebrtcClient::setOnSignalingConnectionError(const std::function& callback) { callSync(m_internalClientThread.get(), [this, &callback]() { m_onSignalingConnectionError = callback; }); } @@ -281,7 +256,7 @@ namespace opentera * @param callback The callback */ inline void - SignalingClient::setOnRoomClientsChanged(const std::function&)>& callback) + WebrtcClient::setOnRoomClientsChanged(const std::function&)>& callback) { callSync(m_internalClientThread.get(), [this, &callback]() { m_onRoomClientsChanged = callback; }); } @@ -301,7 +276,7 @@ namespace opentera * * @param callback The callback */ - inline void SignalingClient::setCallAcceptor(const std::function& callback) + inline void WebrtcClient::setCallAcceptor(const std::function& callback) { callSync(m_internalClientThread.get(), [this, &callback]() { m_callAcceptor = callback; }); } @@ -318,7 +293,7 @@ namespace opentera * * @param callback The callback */ - inline void SignalingClient::setOnCallRejected(const std::function& callback) + inline void WebrtcClient::setOnCallRejected(const std::function& callback) { callSync(m_internalClientThread.get(), [this, &callback]() { m_onCallRejected = callback; }); } @@ -335,7 +310,7 @@ namespace opentera * * @param callback The callback */ - inline void SignalingClient::setOnClientConnected(const std::function& callback) + inline void WebrtcClient::setOnClientConnected(const std::function& callback) { callSync(m_internalClientThread.get(), [this, &callback]() { m_onClientConnected = callback; }); } @@ -352,7 +327,7 @@ namespace opentera * * @param callback The callback */ - inline void SignalingClient::setOnClientDisconnected(const std::function& callback) + inline void WebrtcClient::setOnClientDisconnected(const std::function& callback) { callSync(m_internalClientThread.get(), [this, &callback]() { m_onClientDisconnected = callback; }); } @@ -369,7 +344,7 @@ namespace opentera * * @param callback The callback */ - inline void SignalingClient::setOnError(const std::function& callback) + inline void WebrtcClient::setOnError(const std::function& callback) { callSync(m_internalClientThread.get(), [this, &callback]() { m_onError = callback; }); } @@ -386,13 +361,13 @@ namespace opentera * * @param callback The callback */ - inline void SignalingClient::setLogger(const std::function& callback) + inline void WebrtcClient::setLogger(const std::function& callback) { callSync(m_internalClientThread.get(), [this, &callback]() { m_logger = callback; }); } template - void SignalingClient::invokeIfCallable(const std::function& f, Types... args) + void WebrtcClient::invokeIfCallable(const std::function& f, Types... args) { callAsync( m_internalClientThread.get(), @@ -405,7 +380,7 @@ namespace opentera }); } - inline void SignalingClient::log(const std::string& message) + inline void WebrtcClient::log(const std::string& message) { callAsync( m_internalClientThread.get(), @@ -418,7 +393,7 @@ namespace opentera }); } - inline rtc::Thread* SignalingClient::getInternalClientThread() { return m_internalClientThread.get(); } + inline rtc::Thread* WebrtcClient::getInternalClientThread() { return m_internalClientThread.get(); } } #endif diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Json.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Json.h new file mode 100644 index 00000000..92482b18 --- /dev/null +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/Json.h @@ -0,0 +1,14 @@ +#ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_SIO_MESSAGE_H +#define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_SIO_MESSAGE_H + +#include + +#include + +namespace opentera +{ + PYBIND11_EXPORT nlohmann::json pyObjectToJson(const pybind11::object& message); + PYBIND11_EXPORT pybind11::object jsonToPyObject(const nlohmann::json& json); +} + +#endif diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/SignalingClientPython.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/SignalingClientPython.h deleted file mode 100644 index ec9afee1..00000000 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/SignalingClientPython.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_SIGNALING_CLIENT_PYTHON_H -#define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_SIGNALING_CLIENT_PYTHON_H - -#include - -namespace opentera -{ - PYBIND11_EXPORT void initSignalingClientPython(pybind11::module& m); -} - -#endif diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/SioMessage.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/SioMessage.h deleted file mode 100644 index 692b539c..00000000 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/SioMessage.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_SIO_MESSAGE_H -#define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_SIO_MESSAGE_H - -#include - -#include - -namespace opentera -{ - PYBIND11_EXPORT sio::message::ptr pyObjectToSioMessage(const pybind11::object& message); - PYBIND11_EXPORT pybind11::object sioMessageToPyObject(sio::message::ptr message); -} - -#endif diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/WebrtcClientPython.h b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/WebrtcClientPython.h new file mode 100644 index 00000000..072aa29d --- /dev/null +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/include/OpenteraWebrtcNativeClientPython/WebrtcClientPython.h @@ -0,0 +1,11 @@ +#ifndef OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_WEBRTC_CLIENT_PYTHON_H +#define OPENTERA_WEBRTC_NATIVE_CLIENT_PYTHON_WEBRTC_CLIENT_PYTHON_H + +#include + +namespace opentera +{ + PYBIND11_EXPORT void initWebrtcClientPython(pybind11::module& m); +} + +#endif diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Configurations/SignalingServerConfigurationPython.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Configurations/SignalingServerConfigurationPython.cpp index 8eaf8455..c00ed366 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Configurations/SignalingServerConfigurationPython.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Configurations/SignalingServerConfigurationPython.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include @@ -9,22 +9,22 @@ using namespace opentera; using namespace std; namespace py = pybind11; -SignalingServerConfiguration create(string url, string clientName, const py::object& clientData, string room) +SignalingServerConfiguration createWithData(string url, string clientName, const py::object& clientData, string room) { - return SignalingServerConfiguration::create( + return SignalingServerConfiguration::createWithData( move(url), move(clientName), - pyObjectToSioMessage(clientData), + pyObjectToJson(clientData), move(room)); } SignalingServerConfiguration - create(string url, string clientName, const py::object& clientData, string room, string password) + createWithData(string url, string clientName, const py::object& clientData, string room, string password) { - return SignalingServerConfiguration::create( + return SignalingServerConfiguration::createWithData( move(url), move(clientName), - pyObjectToSioMessage(clientData), + pyObjectToJson(clientData), move(room), move(password)); } @@ -50,8 +50,8 @@ void opentera::initSignalingServerConfigurationPython(pybind11::module& m) py::arg("client_name"), py::arg("room")) .def_static( - "create", - py::overload_cast(&create), + "create_with_data", + py::overload_cast(&createWithData), "Creates an signaling server configuration with the specified " "values.\n" "\n" @@ -82,8 +82,8 @@ void opentera::initSignalingServerConfigurationPython(pybind11::module& m) py::arg("room"), py::arg("password")) .def_static( - "create", - py::overload_cast(&create), + "create_with_data", + py::overload_cast(&createWithData), "Creates an signaling server configuration with the specified " "values.\n" "\n" @@ -114,7 +114,7 @@ void opentera::initSignalingServerConfigurationPython(pybind11::module& m) ":return: The client name") .def_property_readonly( "client_data", - [](const SignalingServerConfiguration& self) { return sioMessageToPyObject(self.clientData()); }, + [](const SignalingServerConfiguration& self) { return jsonToPyObject(self.clientData()); }, "Returns the client data.\n" "\n" ":return: The client data") diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/DataChannelClientPython.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/DataChannelClientPython.cpp index 716391e3..310cfdce 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/DataChannelClientPython.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/DataChannelClientPython.cpp @@ -25,7 +25,7 @@ void setOnDataChannelMessageBinary( void opentera::initDataChannelClientPython(pybind11::module& m) { - py::class_( + py::class_( m, "DataChannelClient", "Represents a client for data channel communication.") diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Json.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Json.cpp new file mode 100644 index 00000000..1d190351 --- /dev/null +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Json.cpp @@ -0,0 +1,113 @@ +#include + +#include + +using namespace opentera; +using namespace std; +namespace py = pybind11; + +nlohmann::json opentera::pyObjectToJson(const py::object& object) +{ + if (py::isinstance(object)) + { + return py::bool_(object).cast(); + } + else if (py::isinstance(object)) + { + return py::int_(object).cast(); + } + else if (py::isinstance(object)) + { + return py::float_(object).cast(); + } + else if (py::isinstance(object)) + { + auto dataStr = py::bytes(object).cast(); + vector data; + copy(dataStr.begin(), dataStr.end(), back_inserter(data)); + return nlohmann::json::binary(data); + } + else if (py::isinstance(object)) + { + return py::str(object).cast(); + } + else if (py::isinstance(object)) + { + auto json = nlohmann::json::array(); + for (const auto x : py::list(object)) + { + json.emplace_back(pyObjectToJson(x.cast())); + } + return json; + } + else if (py::isinstance(object)) + { + auto json = nlohmann::json::object(); + for (const auto x : py::dict(object)) + { + if (py::isinstance(x.first)) + { + json.emplace(py::str(x.first).cast(), pyObjectToJson(x.second.cast())); + } + else + { + py::pybind11_fail("pyObjectToSioMessage: The dict must have str keys."); + } + } + return json; + } + + return {}; +} + +py::object opentera::jsonToPyObject(const nlohmann::json& json) +{ + switch (json.type()) + { + case nlohmann::detail::value_t::number_integer: + return py::int_(static_cast(json)); + + case nlohmann::detail::value_t::number_unsigned: + return py::int_(static_cast(json)); + + case nlohmann::detail::value_t::number_float: + return py::float_(static_cast(json)); + + case nlohmann::detail::value_t::string: + return py::str(json); + + case nlohmann::detail::value_t::binary: + { + nlohmann::json::binary_t data = json; + return py::bytes(string(data.begin(), data.end())); + } + + case nlohmann::detail::value_t::boolean: + return py::bool_(json); + + case nlohmann::detail::value_t::null: + return py::none(); + + case nlohmann::detail::value_t::array: + { + py::list list; + for (const auto& x : json) + { + list.append(jsonToPyObject(x)); + } + return list; + } + + case nlohmann::detail::value_t::object: + { + py::dict dict; + for (const auto& pair : json.items()) + { + dict[pair.key().c_str()] = jsonToPyObject(pair.value()); + } + return dict; + } + } + + return py::none(); +} diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/SioMessage.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/SioMessage.cpp deleted file mode 100644 index c17ab2ba..00000000 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/SioMessage.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include - -#include - -using namespace opentera; -using namespace std; -namespace py = pybind11; - -sio::message::ptr opentera::pyObjectToSioMessage(const py::object& object) -{ - if (py::isinstance(object)) - { - return sio::bool_message::create(py::bool_(object).cast()); - } - else if (py::isinstance(object)) - { - return sio::int_message::create(py::int_(object).cast()); - } - else if (py::isinstance(object)) - { - return sio::double_message::create(py::float_(object).cast()); - } - else if (py::isinstance(object)) - { - return sio::binary_message::create(make_shared(py::bytes(object).cast())); - } - else if (py::isinstance(object)) - { - return sio::string_message::create(py::str(object).cast()); - } - else if (py::isinstance(object)) - { - auto message = sio::array_message::create(); - for (const auto x : py::list(object)) - { - message->get_vector().push_back(pyObjectToSioMessage(x.cast())); - } - return message; - } - else if (py::isinstance(object)) - { - auto message = sio::object_message::create(); - for (const auto x : py::dict(object)) - { - if (py::isinstance(x.first)) - { - message->get_map()[py::str(x.first).cast()] = pyObjectToSioMessage(x.second.cast()); - } - else - { - py::pybind11_fail("pyObjectToSioMessage: The dict must have str keys."); - } - } - return message; - } - - return sio::null_message::create(); -} - -py::object opentera::sioMessageToPyObject(sio::message::ptr message) -{ - switch (message->get_flag()) - { - case sio::message::flag_integer: - return py::int_(message->get_int()); - - case sio::message::flag_double: - return py::float_(message->get_double()); - - case sio::message::flag_string: - return py::str(message->get_string()); - - case sio::message::flag_binary: - return py::bytes(*message->get_binary()); - - case sio::message::flag_boolean: - return py::bool_(message->get_bool()); - - case sio::message::flag_null: - return py::none(); - - case sio::message::flag_array: - { - py::list list; - for (const auto& x : message->get_vector()) - { - list.append(sioMessageToPyObject(x)); - } - return list; - } - - case sio::message::flag_object: - { - py::dict dict; - for (const auto& pair : message->get_map()) - { - dict[pair.first.c_str()] = sioMessageToPyObject(pair.second); - } - return dict; - } - } - - return py::none(); -} diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/StreamClientPython.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/StreamClientPython.cpp index 32283115..2a791f38 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/StreamClientPython.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/StreamClientPython.cpp @@ -153,7 +153,7 @@ void opentera::initStreamClientPython(pybind11::module& m) .value("H264", VideoCodecType::H264) .value("MULTIPLEX", VideoCodecType::Multiplex); - py::class_( + py::class_( m, "StreamClient", "A signaling client to join a WebRTC room and stream a video source.") diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Utils/ClientPython.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Utils/ClientPython.cpp index 12bd1af6..c661eee2 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Utils/ClientPython.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/Utils/ClientPython.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -9,12 +9,12 @@ namespace py = pybind11; Client clientConstructor(string id, string name, const py::object& data) { - return Client(move(id), move(name), pyObjectToSioMessage(data)); + return Client(move(id), move(name), pyObjectToJson(data)); } RoomClient roomClientConstructor(string id, string name, const py::object& data, bool isConnected) { - return RoomClient(move(id), move(name), pyObjectToSioMessage(data), isConnected); + return RoomClient(move(id), move(name), pyObjectToJson(data), isConnected); } void opentera::initClientPython(pybind11::module& m) @@ -46,7 +46,7 @@ void opentera::initClientPython(pybind11::module& m) ":return: The client name") .def_property_readonly( "data", - [](const Client& self) { return sioMessageToPyObject(self.data()); }, + [](const Client& self) { return jsonToPyObject(self.data()); }, "Returns the client data.\n" "\n" ":return: The client data"); @@ -90,7 +90,7 @@ void opentera::initClientPython(pybind11::module& m) ":return: The client name") .def_property_readonly( "data", - [](const RoomClient& self) { return sioMessageToPyObject(self.data()); }, + [](const RoomClient& self) { return jsonToPyObject(self.data()); }, "Returns the client data.\n" "\n" ":return: The client data") diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/SignalingClientPython.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/WebrtcClientPython.cpp similarity index 75% rename from opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/SignalingClientPython.cpp rename to opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/WebrtcClientPython.cpp index b7b2cca0..19a5095b 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/SignalingClientPython.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/WebrtcClientPython.cpp @@ -1,7 +1,7 @@ #include -#include +#include -#include +#include #include #include @@ -10,35 +10,35 @@ using namespace opentera; using namespace std; namespace py = pybind11; -void opentera::initSignalingClientPython(pybind11::module& m) +void opentera::initWebrtcClientPython(pybind11::module& m) { - py::class_(m, "SignalingClient") - .def("connect", &SignalingClient::connect, "Connects the client the signaling server.") - .def("close", &SignalingClient::close, "Closes all client connections (asynchronous).") + py::class_(m, "WebrtcClient") + .def("connect", &WebrtcClient::connect, "Connects the client the signaling server.") + .def("close", &WebrtcClient::close, "Closes all client connections (asynchronous).") .def( "close_sync", - &SignalingClient::closeSync, + &WebrtcClient::closeSync, py::call_guard(), "Closes all client connections (synchronous).") - .def("call_all", &SignalingClient::callAll, "Calls all room clients.") - .def("call_ids", &SignalingClient::callIds, "Calls the specified clients.", py::arg("ids")) + .def("call_all", &WebrtcClient::callAll, "Calls all room clients.") + .def("call_ids", &WebrtcClient::callIds, "Calls the specified clients.", py::arg("ids")) - .def("hang_up_all", &SignalingClient::hangUpAll, "Hangs up all clients.") + .def("hang_up_all", &WebrtcClient::hangUpAll, "Hangs up all clients.") .def( "close_all_room_peer_connections", - &SignalingClient::closeAllRoomPeerConnections, + &WebrtcClient::closeAllRoomPeerConnections, "Closes all room peer connections.") .def_property_readonly( "is_connected", - GilScopedRelease::guard(&SignalingClient::isConnected), + GilScopedRelease::guard(&WebrtcClient::isConnected), "Indicates if the client is connected to the signaling server.\n" "\n" ":return: True if the client is connected to the signaling server") .def_property_readonly( "is_rtc_connected", - GilScopedRelease::guard(&SignalingClient::isRtcConnected), + GilScopedRelease::guard(&WebrtcClient::isRtcConnected), "Indicates if the client is connected to a least " "one client (RTCPeerConnection).\n" "\n" @@ -46,21 +46,21 @@ void opentera::initSignalingClientPython(pybind11::module& m) "least one client (RTCPeerConnection)") .def_property_readonly( "id", - GilScopedRelease::guard(&SignalingClient::id), + GilScopedRelease::guard(&WebrtcClient::id), "Returns the client id.\n" "\n" ":return: The client id") .def_property_readonly( "connected_room_client_ids", - GilScopedRelease::guard(&SignalingClient::getConnectedRoomClientIds), + GilScopedRelease::guard(&WebrtcClient::getConnectedRoomClientIds), "Returns the connected room client ids.\n" "\n" ":return: The connected room client ids") .def( "get_room_client", - &SignalingClient::getRoomClient, + &WebrtcClient::getRoomClient, py::call_guard(), "Returns the room client that matches with the specified id.\n" "If no room client matches with the id, a default room client is " @@ -72,7 +72,7 @@ void opentera::initSignalingClientPython(pybind11::module& m) py::arg("id")) .def_property_readonly( "room_clients", - GilScopedRelease::guard(&SignalingClient::getRoomClients), + GilScopedRelease::guard(&WebrtcClient::getRoomClients), "Returns the room clients\n" "\n" ":return: The room clients") @@ -80,7 +80,7 @@ void opentera::initSignalingClientPython(pybind11::module& m) .def_property( "on_signaling_connection_opened", nullptr, - GilScopedRelease::guard(&SignalingClient::setOnSignalingConnectionOpened), + GilScopedRelease::guard(&WebrtcClient::setOnSignalingConnectionOpened), "Sets the callback that is called when the signaling " "connection opens.\n" "\n" @@ -91,7 +91,7 @@ void opentera::initSignalingClientPython(pybind11::module& m) .def_property( "on_signaling_connection_closed", nullptr, - GilScopedRelease::guard(&SignalingClient::setOnSignalingConnectionClosed), + GilScopedRelease::guard(&WebrtcClient::setOnSignalingConnectionClosed), "Sets the callback that is called when the signaling " "connection closes.\n" "\n" @@ -102,7 +102,7 @@ void opentera::initSignalingClientPython(pybind11::module& m) .def_property( "on_signaling_connection_error", nullptr, - GilScopedRelease::guard(&SignalingClient::setOnSignalingConnectionError), + GilScopedRelease::guard(&WebrtcClient::setOnSignalingConnectionError), "Sets the callback that is called when a signaling " "connection error occurs.\n" "\n" @@ -117,7 +117,7 @@ void opentera::initSignalingClientPython(pybind11::module& m) .def_property( "on_room_clients_changed", nullptr, - GilScopedRelease::guard(&SignalingClient::setOnRoomClientsChanged), + GilScopedRelease::guard(&WebrtcClient::setOnRoomClientsChanged), "Sets the callback that is called when the room client changes.\n" "\n" "The callback is called from the internal client thread. The " @@ -131,7 +131,7 @@ void opentera::initSignalingClientPython(pybind11::module& m) .def_property( "call_acceptor", nullptr, - GilScopedRelease::guard(&SignalingClient::setCallAcceptor), + GilScopedRelease::guard(&WebrtcClient::setCallAcceptor), "Sets the callback that is used to accept or reject a call.\n" "\n" "The callback is called from the internal client thread. The " @@ -147,7 +147,7 @@ void opentera::initSignalingClientPython(pybind11::module& m) .def_property( "on_call_rejected", nullptr, - GilScopedRelease::guard(&SignalingClient::setOnCallRejected), + GilScopedRelease::guard(&WebrtcClient::setOnCallRejected), "Sets the callback that is called when a call is rejected.\n" "\n" "The callback is called from the internal client thread. The " @@ -161,7 +161,7 @@ void opentera::initSignalingClientPython(pybind11::module& m) .def_property( "on_client_connected", nullptr, - GilScopedRelease::guard(&SignalingClient::setOnClientConnected), + GilScopedRelease::guard(&WebrtcClient::setOnClientConnected), "Sets the callback that is called when a client peer " "connection opens.\n" "\n" @@ -175,7 +175,7 @@ void opentera::initSignalingClientPython(pybind11::module& m) .def_property( "on_client_disconnected", nullptr, - GilScopedRelease::guard(&SignalingClient::setOnClientDisconnected), + GilScopedRelease::guard(&WebrtcClient::setOnClientDisconnected), "Sets the callback that is called when a client peer " "connection closes.\n" "\n" @@ -190,7 +190,7 @@ void opentera::initSignalingClientPython(pybind11::module& m) .def_property( "on_error", nullptr, - GilScopedRelease::guard(&SignalingClient::setOnError), + GilScopedRelease::guard(&WebrtcClient::setOnError), "Sets the callback that is called when an error occurs.\n" "\n" "The callback is called from the internal client thread. " @@ -204,7 +204,7 @@ void opentera::initSignalingClientPython(pybind11::module& m) .def_property( "logger", nullptr, - GilScopedRelease::guard(&SignalingClient::setLogger), + GilScopedRelease::guard(&WebrtcClient::setLogger), "Sets the callback that is used to log information.\n" "\n" "The callback is called from the internal client thread. The " @@ -218,7 +218,7 @@ void opentera::initSignalingClientPython(pybind11::module& m) .def_property( "tls_verification_enabled", nullptr, - &SignalingClient::setTlsVerificationEnabled, + &WebrtcClient::setTlsVerificationEnabled, "Enable or disable the TLS verification. By default, the " "TLS verification is enabled.\n" "\n" diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/opentera_webrtc_native_client.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/opentera_webrtc_native_client.cpp index 79c4b2d5..5eb882b5 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/opentera_webrtc_native_client.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/src/opentera_webrtc_native_client.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include using namespace opentera; @@ -33,7 +33,7 @@ PYBIND11_MODULE(_opentera_webrtc_native_client, m) initAudioSourcePython(m); initVideoSourcePython(m); - initSignalingClientPython(m); + initWebrtcClientPython(m); initDataChannelClientPython(m); initStreamClientPython(m); diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/configurations/signaling_server_configuration_test.py b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/configurations/signaling_server_configuration_test.py index 7f35d854..e4735f78 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/configurations/signaling_server_configuration_test.py +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/configurations/signaling_server_configuration_test.py @@ -14,7 +14,7 @@ def test_create__url_client_name_room__should_set_the_attributes(self): self.assertEqual(testee.password, '') def test_create__url_client_name_client_data_room__should_set_the_attributes(self): - testee = webrtc.SignalingServerConfiguration.create('url', 'name', {'data': 10}, 'room') + testee = webrtc.SignalingServerConfiguration.create_with_data('url', 'name', {'data': 10}, 'room') self.assertEqual(testee.url, 'url') self.assertEqual(testee.client_name, 'name') @@ -23,7 +23,7 @@ def test_create__url_client_name_client_data_room__should_set_the_attributes(sel self.assertEqual(testee.password, '') def test_create__url_client_name_room_password__should_set_the_attributes(self): - testee = webrtc.SignalingServerConfiguration.create('url', 'name', room='room', password='password') + testee = webrtc.SignalingServerConfiguration.create('url', 'name', 'room', 'password') self.assertEqual(testee.url, 'url') self.assertEqual(testee.client_name, 'name') @@ -32,10 +32,29 @@ def test_create__url_client_name_room_password__should_set_the_attributes(self): self.assertEqual(testee.password, 'password') def test_create__url_client_name_client_data_room_password__should_set_the_attributes(self): - testee = webrtc.SignalingServerConfiguration.create('url', 'name', {'data': 10}, 'room', 'password') + testee = webrtc.SignalingServerConfiguration.create_with_data('url', 'name', {'data': 10}, 'room', 'password') self.assertEqual(testee.url, 'url') self.assertEqual(testee.client_name, 'name') self.assertEqual(testee.client_data, {'data': 10}) self.assertEqual(testee.room, 'room') self.assertEqual(testee.password, 'password') + + def test_create__all_data_types__should_set_the_attributes(self): + testee1 = webrtc.SignalingServerConfiguration.create_with_data('url', 'name', 10, 'room', 'password') + testee2 = webrtc.SignalingServerConfiguration.create_with_data('url', 'name', 1.5, 'room', 'password') + testee3 = webrtc.SignalingServerConfiguration.create_with_data('url', 'name', 'data', 'room', 'password') + testee4 = webrtc.SignalingServerConfiguration.create_with_data('url', 'name', b'data', 'room', 'password') + testee5 = webrtc.SignalingServerConfiguration.create_with_data('url', 'name', True, 'room', 'password') + testee6 = webrtc.SignalingServerConfiguration.create_with_data('url', 'name', None, 'room', 'password') + testee7 = webrtc.SignalingServerConfiguration.create_with_data('url', 'name', [1, 2], 'room', 'password') + testee8 = webrtc.SignalingServerConfiguration.create_with_data('url', 'name', {'data': 10}, 'room', 'password') + + self.assertEqual(testee1.client_data, 10) + self.assertEqual(testee2.client_data, 1.5) + self.assertEqual(testee3.client_data, 'data') + self.assertEqual(testee4.client_data, b'data') + self.assertEqual(testee5.client_data, True) + self.assertEqual(testee6.client_data, None) + self.assertEqual(testee7.client_data, [1, 2]) + self.assertEqual(testee8.client_data, {'data': 10}) diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/data_channel_client_test.py b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/data_channel_client_test.py index 7e2be1d5..6ad39f37 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/data_channel_client_test.py +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/data_channel_client_test.py @@ -13,7 +13,7 @@ class DisconnectedDataChannelClientTestCase(FailureTestCase): def setUp(self): super(DisconnectedDataChannelClientTestCase, self).setUp() self._client1 = webrtc.DataChannelClient( - webrtc.SignalingServerConfiguration.create('http://localhost:8080', 'c1', 'cd1', 'chat', ""), + webrtc.SignalingServerConfiguration.create_with_data('ws://localhost:8080/signaling', 'c1', 'cd1', 'chat', ""), DEFAULT_WEBRTC_CONFIGURATION, webrtc.DataChannelConfiguration.create()) @@ -51,7 +51,7 @@ def tearDownClass(cls): def setUp(self): super(WrongPasswordDataChannelClientTestCase, self).setUp() self._client1 = webrtc.DataChannelClient( - webrtc.SignalingServerConfiguration.create('http://localhost:8080', 'c1', 'cd1', 'chat', ''), + webrtc.SignalingServerConfiguration.create_with_data('ws://localhost:8080/signaling', 'c1', 'cd1', 'chat', ''), DEFAULT_WEBRTC_CONFIGURATION, webrtc.DataChannelConfiguration.create()) @@ -102,7 +102,7 @@ def tearDownClass(cls): def setUp(self): super(SingleDataChannelClientTestCase, self).setUp() self._client1 = webrtc.DataChannelClient( - webrtc.SignalingServerConfiguration.create('http://localhost:8080', 'c1', 'cd1', 'chat', 'abc'), + webrtc.SignalingServerConfiguration.create_with_data('ws://localhost:8080/signaling', 'c1', 'cd1', 'chat', 'abc'), DEFAULT_WEBRTC_CONFIGURATION, webrtc.DataChannelConfiguration.create()) @@ -152,17 +152,17 @@ def on_signaling_connection_opened(): awaiter.done() self._client1 = webrtc.DataChannelClient( - webrtc.SignalingServerConfiguration.create('http://localhost:8080', 'c1', 'cd1', 'chat', 'abc'), + webrtc.SignalingServerConfiguration.create_with_data('ws://localhost:8080/signaling', 'c1', 'cd1', 'chat', 'abc'), DEFAULT_WEBRTC_CONFIGURATION, webrtc.DataChannelConfiguration.create()) self._client2 = webrtc.DataChannelClient( - webrtc.SignalingServerConfiguration.create('http://localhost:8080', 'c2', 'cd2', 'chat', 'abc'), + webrtc.SignalingServerConfiguration.create_with_data('ws://localhost:8080/signaling', 'c2', 'cd2', 'chat', 'abc'), DEFAULT_WEBRTC_CONFIGURATION, webrtc.DataChannelConfiguration.create()) self._client3 = webrtc.DataChannelClient( - webrtc.SignalingServerConfiguration.create('http://localhost:8080', 'c3', 'cd3', 'chat', 'abc'), + webrtc.SignalingServerConfiguration.create_with_data('ws://localhost:8080/signaling', 'c3', 'cd3', 'chat', 'abc'), DEFAULT_WEBRTC_CONFIGURATION, webrtc.DataChannelConfiguration.create()) diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/requirements.txt b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/requirements.txt index 07172ff5..09bbd2c7 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/requirements.txt +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/requirements.txt @@ -1,3 +1,3 @@ numpy -python-socketio==5.0.4 +websocket-client==1.7.0 requests diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/socketio_inactive_client_test.py b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/socketio_inactive_client_test.py deleted file mode 100644 index 9a818752..00000000 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/socketio_inactive_client_test.py +++ /dev/null @@ -1,37 +0,0 @@ -from callback_awaiter import CallbackAwaiter -from failure_test_case import FailureTestCase -from signaling_server_runner import SignalingServerRunner -import socketio - - -class SocketIOInactiveClientTestCase(FailureTestCase): - @classmethod - def setUpClass(cls): - super(SocketIOInactiveClientTestCase, cls).setUpClass() - cls._signaling_server_runner = SignalingServerRunner() - - @classmethod - def tearDownClass(cls): - cls._signaling_server_runner.close() - super(SocketIOInactiveClientTestCase, cls).tearDownClass() - - def test_socketio_inactive_is_disconnected_after_timeout(self): - awaiter = CallbackAwaiter(2, 15) - sio = socketio.Client() - - @sio.event - def connect(): - awaiter.done() - - @sio.event - def connect_error(): - awaiter.done() - awaiter.done() - self.add_failure('sio.connect_error') - - @sio.event - def disconnect(): - awaiter.done() - - sio.connect('http://localhost:8080') - awaiter.wait() diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/stream_client_test.py b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/stream_client_test.py index 183c6c37..80f6315d 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/stream_client_test.py +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/stream_client_test.py @@ -23,9 +23,9 @@ def test_video_stream__should_be_sent_and_received(self): # Initialize the clients setup_awaiter = CallbackAwaiter(2, 15) - frame1 = np.zeros((480, 640, 3), dtype=np.int8) + frame1 = np.zeros((480, 640, 3), dtype=np.uint8) frame1[:, :, 2] = 255 - frame2 = np.zeros((480, 640, 3), dtype=np.int8) + frame2 = np.zeros((480, 640, 3), dtype=np.uint8) frame2[:, :, 0] = 255 video_source1 = webrtc.VideoSource(webrtc.VideoSourceConfiguration.create(False, True)) @@ -35,13 +35,13 @@ def on_signaling_connection_opened(): setup_awaiter.done() client1 = webrtc.StreamClient( - webrtc.SignalingServerConfiguration.create('http://localhost:8080', 'c1', 'cd1', 'chat', 'abc'), + webrtc.SignalingServerConfiguration.create_with_data('ws://localhost:8080/signaling', 'c1', 'cd1', 'chat', 'abc'), webrtc.WebrtcConfiguration.create(), webrtc.VideoStreamConfiguration.create(), video_source1) client2 = webrtc.StreamClient( - webrtc.SignalingServerConfiguration.create('http://localhost:8080', 'c2', 'cd2', 'chat', 'abc'), + webrtc.SignalingServerConfiguration.create_with_data('ws://localhost:8080/signaling', 'c2', 'cd2', 'chat', 'abc'), webrtc.WebrtcConfiguration.create(), webrtc.VideoStreamConfiguration.create(), video_source2) @@ -62,8 +62,8 @@ def on_signaling_connection_opened(): self._on_add_remote_stream_client_name1 = None self._on_add_remote_stream_client_name2 = None - self._mean_color_1 = np.array([0, 0, 0], dtype=np.int8) - self._mean_color_2 = np.array([0, 0, 0], dtype=np.int8) + self._mean_color_1 = np.array([0, 0, 0], dtype=np.uint8) + self._mean_color_2 = np.array([0, 0, 0], dtype=np.uint8) def on_add_remote_stream1(client): self._on_add_remote_stream_client_name1 = client.name @@ -129,7 +129,7 @@ def on_audio_frame_received(client, data, sample_rate, number_of_channels, numbe def test_mute_methods__should_set_the_flag_accordingly(self): client = webrtc.StreamClient( - webrtc.SignalingServerConfiguration.create('http://localhost:8080', 'c1', 'cd1', 'chat', 'abc'), + webrtc.SignalingServerConfiguration.create_with_data('ws://localhost:8080/signaling', 'c1', 'cd1', 'chat', 'abc'), webrtc.WebrtcConfiguration.create(), webrtc.VideoStreamConfiguration.create()) diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/websocket_inactive_client_test.py b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/websocket_inactive_client_test.py new file mode 100644 index 00000000..2230d386 --- /dev/null +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/python/test/websocket_inactive_client_test.py @@ -0,0 +1,46 @@ +import threading + +import websocket + +from callback_awaiter import CallbackAwaiter +from failure_test_case import FailureTestCase +from signaling_server_runner import SignalingServerRunner + + +class WebSocketInactiveClientTestCase(FailureTestCase): + @classmethod + def setUpClass(cls): + super(WebSocketInactiveClientTestCase, cls).setUpClass() + cls._signaling_server_runner = SignalingServerRunner() + + @classmethod + def tearDownClass(cls): + cls._signaling_server_runner.close() + super(WebSocketInactiveClientTestCase, cls).tearDownClass() + + def test_socketio_inactive_is_disconnected_after_timeout(self): + awaiter = CallbackAwaiter(2, 15) + + def on_open(ws): + awaiter.done() + + def on_message(ws, message): + pass + + def on_error(ws, error): + awaiter.done() + awaiter.done() + self.add_failure(error) + + def on_close(ws, close_status_code, close_msg): + awaiter.done() + + websocket.enableTrace(True) + ws = websocket.WebSocketApp('ws://localhost:8080/signaling', + on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close) + + thread = threading.Thread(target=ws.run_forever) + thread.start() + + awaiter.wait() + ws.close() diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Configurations/SignalingServerConfiguration.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Configurations/SignalingServerConfiguration.cpp index 1bc58a83..3d16f9ca 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Configurations/SignalingServerConfiguration.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Configurations/SignalingServerConfiguration.cpp @@ -6,7 +6,7 @@ using namespace std; SignalingServerConfiguration::SignalingServerConfiguration( string&& url, string&& clientName, - sio::message::ptr&& clientData, + nlohmann::json&& clientData, string&& room, string&& password) : m_url(move(url)), diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Configurations/VideoStreamConfiguration.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Configurations/VideoStreamConfiguration.cpp index f3ec2ef7..76495dfd 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Configurations/VideoStreamConfiguration.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Configurations/VideoStreamConfiguration.cpp @@ -3,7 +3,7 @@ using namespace opentera; using namespace std; -absl::optional opentera::stringToVideoStreamCodec(std::string_view value) +absl::optional opentera::stringToVideoStreamCodec(string_view value) { if (value == "VP8" || value == "vp8" || value == "vP8" || value == "Vp8") { diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/DataChannelClient.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/DataChannelClient.cpp index 1ba2f55d..b771eb9d 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/DataChannelClient.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/DataChannelClient.cpp @@ -15,10 +15,7 @@ DataChannelClient::DataChannelClient( SignalingServerConfiguration signalingServerConfiguration, WebrtcConfiguration webrtcConfiguration, DataChannelConfiguration dataChannelConfiguration) - : SignalingClient( - move(signalingServerConfiguration), - move(webrtcConfiguration), - VideoStreamConfiguration::create()), + : WebrtcClient(move(signalingServerConfiguration), move(webrtcConfiguration), VideoStreamConfiguration::create()), m_dataChannelConfiguration(move(dataChannelConfiguration)) { } @@ -86,11 +83,10 @@ unique_ptr id, peerClient, isCaller, - getSendEventFunction(), + *m_signalingClient, getOnErrorFunction(), getOnClientConnectedFunction(), getOnClientDisconnectedFunction(), - m_signalingServerConfiguration.room(), 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 35c4ba80..980c52b8 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/DataChannelPeerConnectionHandler.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/DataChannelPeerConnectionHandler.cpp @@ -7,11 +7,10 @@ DataChannelPeerConnectionHandler::DataChannelPeerConnectionHandler( string id, Client peerClient, bool isCaller, - function sendEvent, + SignalingClient& m_signalingClient, function onError, function onClientConnected, function onClientDisconnected, - string room, DataChannelConfiguration dataChannelConfiguration, function onDataChannelOpen, function onDataChannelClosed, @@ -22,11 +21,10 @@ DataChannelPeerConnectionHandler::DataChannelPeerConnectionHandler( move(id), move(peerClient), isCaller, - move(sendEvent), + m_signalingClient, move(onError), move(onClientConnected), move(onClientDisconnected)), - m_room(move(room)), m_dataChannelConfiguration(move(dataChannelConfiguration)), m_onDataChannelOpen(move(onDataChannelOpen)), m_onDataChannelClosed(move(onDataChannelClosed)), @@ -59,7 +57,7 @@ void DataChannelPeerConnectionHandler::setPeerConnection( if (m_isCaller) { auto configuration = static_cast(m_dataChannelConfiguration); - auto dataChannelOrError = m_peerConnection->CreateDataChannelOrError(m_room, &configuration); + auto dataChannelOrError = m_peerConnection->CreateDataChannelOrError(m_signalingClient.room(), &configuration); if (dataChannelOrError.ok()) { m_dataChannel = dataChannelOrError.MoveValue(); @@ -67,7 +65,7 @@ void DataChannelPeerConnectionHandler::setPeerConnection( } else { - m_onError(std::string("CreateDataChannel failed: ") + dataChannelOrError.error().message()); + m_onError(string("CreateDataChannel failed: ") + dataChannelOrError.error().message()); } } } diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/PeerConnectionHandler.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/PeerConnectionHandler.cpp index be2b6f87..d07ab049 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/PeerConnectionHandler.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/PeerConnectionHandler.cpp @@ -19,10 +19,7 @@ class OnlyFailureSetSessionDescriptionObserver : public webrtc::SetSessionDescri void OnSuccess() override {} - void OnFailure(webrtc::RTCError error) override - { - m_onError(error.message()); - } + void OnFailure(webrtc::RTCError error) override { m_onError(error.message()); } }; void CreateSessionDescriptionObserverHelper::OnSuccess(webrtc::SessionDescriptionInterface* desc) @@ -49,14 +46,14 @@ PeerConnectionHandler::PeerConnectionHandler( string&& id, Client&& peerClient, bool isCaller, - function&& sendEvent, + SignalingClient& m_signalingClient, function&& onError, function&& onClientConnected, function&& onClientDisconnected) : m_id(move(id)), m_peerClient(move(peerClient)), m_isCaller(isCaller), - m_sendEvent(move(sendEvent)), + m_signalingClient(m_signalingClient), m_onError(move(onError)), m_onClientConnected(move(onClientConnected)), m_onClientDisconnected(move(onClientDisconnected)), @@ -68,7 +65,6 @@ PeerConnectionHandler::~PeerConnectionHandler() { if (m_peerConnection) { - m_sendEvent = [](const string&, const sio::message::ptr&) {}; m_onError = [](const string&) {}; m_onClientConnected = [](const Client&) {}; m_onClientDisconnected = [](const Client&) {}; @@ -161,16 +157,7 @@ void PeerConnectionHandler::OnIceCandidate(const webrtc::IceCandidateInterface* string sdp; candidate->ToString(&sdp); - auto candidateMessage = sio::object_message::create(); - candidateMessage->get_map()["sdpMid"] = sio::string_message::create(candidate->sdp_mid()); - candidateMessage->get_map()["sdpMLineIndex"] = sio::int_message::create(candidate->sdp_mline_index()); - candidateMessage->get_map()["candidate"] = sio::string_message::create(sdp); - - auto data = sio::object_message::create(); - data->get_map()["toId"] = sio::string_message::create(m_peerClient.id()); - data->get_map()["candidate"] = candidateMessage; - - m_sendEvent("send-ice-candidate", data); + m_signalingClient.sendIceCandidate(candidate->sdp_mid(), candidate->sdp_mline_index(), sdp, m_peerClient.id()); } void PeerConnectionHandler::OnDataChannel(rtc::scoped_refptr dataChannel) {} @@ -190,23 +177,13 @@ void PeerConnectionHandler::OnCreateSessionDescriptionObserverSuccess(webrtc::Se string sdp; desc->ToString(&sdp); - auto offer = sio::object_message::create(); - offer->get_map()["sdp"] = sio::string_message::create(sdp); - - auto data = sio::object_message::create(); - data->get_map()["toId"] = sio::string_message::create(m_peerClient.id()); - if (m_isCaller) { - offer->get_map()["type"] = sio::string_message::create("offer"); - data->get_map()["offer"] = offer; - m_sendEvent("call-peer", data); + m_signalingClient.callPeer(m_peerClient.id(), sdp); } else { - offer->get_map()["type"] = sio::string_message::create("answer"); - data->get_map()["answer"] = offer; - m_sendEvent("make-peer-call-answer", data); + m_signalingClient.makePeerCallAnswer(m_peerClient.id(), sdp); } } diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/StreamPeerConnectionHandler.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/StreamPeerConnectionHandler.cpp index f63d3832..90f80e91 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/StreamPeerConnectionHandler.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Handlers/StreamPeerConnectionHandler.cpp @@ -9,15 +9,12 @@ using namespace rtc; using namespace webrtc; using namespace std; -static constexpr bool OfferToReceiveVideo = true; -static constexpr bool OfferToReceiveAudio = true; - StreamPeerConnectionHandler::StreamPeerConnectionHandler( string id, Client peerClient, bool isCaller, bool hasOnMixedAudioFrameReceivedCallback, - function sendEvent, + SignalingClient& m_signalingClient, function onError, function onClientConnected, function onClientDisconnected, @@ -32,7 +29,7 @@ StreamPeerConnectionHandler::StreamPeerConnectionHandler( move(id), move(peerClient), isCaller, - move(sendEvent), + m_signalingClient, move(onError), move(onClientConnected), move(onClientDisconnected)), diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Signaling/SignalingClient.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Signaling/SignalingClient.cpp new file mode 100644 index 00000000..ecf0f057 --- /dev/null +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Signaling/SignalingClient.cpp @@ -0,0 +1,8 @@ +#include + +using namespace opentera; +using namespace std; + +SignalingClient::SignalingClient(SignalingServerConfiguration configuration) : m_configuration(move(configuration)) {} + +SignalingClient::~SignalingClient() {} diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Signaling/WebSocketSignalingClient.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Signaling/WebSocketSignalingClient.cpp new file mode 100644 index 00000000..71fae25b --- /dev/null +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Signaling/WebSocketSignalingClient.cpp @@ -0,0 +1,422 @@ +#include + +#include + +#include + +using namespace opentera; +using namespace std; + +constexpr int SignalingProtocolVersion = 1; + +#define JSON_CHECK_RETURN(condition, message) \ + if ((condition)) \ + { \ + invokeIfCallable(m_onError, (message)); \ + return; \ + } \ + do \ + { \ + } while (false) + +#define JSON_CHECK_CONTINUE(condition, message) \ + if ((condition)) \ + { \ + invokeIfCallable(m_onError, (message)); \ + continue; \ + } \ + do \ + { \ + } while (false) + +string eventToMessage(const char* event) +{ + nlohmann::json message { + {"event", event} + }; + + return message.dump(); +} + +string eventToMessage(const char* event, const nlohmann::json& data) +{ + nlohmann::json message { + {"event", event}, + {"data", data} + }; + + return message.dump(); +} + + +once_flag initNetSystemOnceFlag; + +WebSocketSignalingClient::WebSocketSignalingClient(SignalingServerConfiguration configuration) + : SignalingClient(move(configuration)) +{ + constexpr int PingIntervalSecs = 10; + m_ws.setPingInterval(PingIntervalSecs); + + call_once(initNetSystemOnceFlag, []() { ix::initNetSystem(); } ); +} + +WebSocketSignalingClient::~WebSocketSignalingClient() +{ + m_ws.stop(); +} + +void WebSocketSignalingClient::setTlsVerificationEnabled(bool isEnabled) +{ + // TODO + ix::SocketTLSOptions options; + if (isEnabled) + { + options.disable_hostname_validation = false; + options.caFile = "SYSTEM"; + } + else + { + options.disable_hostname_validation = true; + options.caFile = "NONE"; + } + m_ws.setTLSOptions(options); +} + +bool WebSocketSignalingClient::isConnected() +{ + return !m_sessionId.empty(); +} + +string WebSocketSignalingClient::sessionId() +{ + return m_sessionId; +} + +void WebSocketSignalingClient::connect() +{ + m_sessionId = ""; + m_ws.stop(); + m_ws.setUrl(m_configuration.url()); + connectWsEvents(); + m_ws.start(); +} + +void WebSocketSignalingClient::close() +{ + m_ws.close(); + m_sessionId = ""; +} + +void WebSocketSignalingClient::closeSync() +{ + m_ws.stop(); + m_sessionId = ""; +} + +void WebSocketSignalingClient::callAll() +{ + m_ws.send(eventToMessage("call-all")); +} + +void WebSocketSignalingClient::callIds(const vector& ids) +{ + m_ws.send(eventToMessage("call-ids", ids)); +} + +void WebSocketSignalingClient::closeAllRoomPeerConnections() +{ + m_ws.send(eventToMessage("close-all-room-peer-connections")); +} + +void WebSocketSignalingClient::callPeer(const string& toId, const string& sdp) +{ + nlohmann::json offer { + {"sdp", sdp}, + {"type", "offer"} + }; + nlohmann::json data { + {"toId", toId}, + {"offer", offer} + }; + m_ws.send(eventToMessage("call-peer", data)); +} + +void WebSocketSignalingClient::makePeerCallAnswer(const string& toId, const string& sdp) +{ + nlohmann::json offer { + {"sdp", sdp}, + {"type", "answer"}, + }; + nlohmann::json data { + {"toId", toId}, + {"answer", offer} + }; + m_ws.send(eventToMessage("make-peer-call-answer", data)); +} + +void WebSocketSignalingClient::rejectCall(const string& toId) +{ + nlohmann::json data { + {"toId", toId} + }; + m_ws.send(eventToMessage("make-peer-call-answer", data)); +} + +void WebSocketSignalingClient::sendIceCandidate( + const string& sdpMid, + int sdpMLineIndex, + const string& candidate, + const string& toId) +{ + nlohmann::json candidateJson { + {"sdpMid", sdpMid}, + {"sdpMLineIndex", sdpMLineIndex}, + {"candidate", candidate}, + }; + nlohmann::json data { + {"toId", toId}, + {"candidate", candidateJson} + }; + m_ws.send(eventToMessage("send-ice-candidate", data)); +} + +void WebSocketSignalingClient::connectWsEvents() +{ + m_ws.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) + { + switch (msg->type) + { + case ix::WebSocketMessageType::Open: + onWsOpenEvent(); + break; + case ix::WebSocketMessageType::Close: + onWsCloseEvent(); + break; + case ix::WebSocketMessageType::Error: + onWsErrorEvent(msg->errorInfo.reason); + break; + case ix::WebSocketMessageType::Message: + onWsMessage(msg->str); + break; + default: + break; + } + }); +} + +void WebSocketSignalingClient::onWsOpenEvent() +{ + nlohmann::json data { + {"name", m_configuration.clientName()}, + {"data", m_configuration.clientData()}, + {"room", m_configuration.room()}, + {"password", m_configuration.password()}, + {"protocolVersion", SignalingProtocolVersion} + }; + m_ws.send(eventToMessage("join-room", data)); +} + +void WebSocketSignalingClient::onWsCloseEvent() +{ + invokeIfCallable(m_onSignalingConnectionClosed); +} + +void WebSocketSignalingClient::onWsErrorEvent(const string& error) +{ + invokeIfCallable(m_onSignalingConnectionError, error); +} + +void WebSocketSignalingClient::onWsMessage(const string& message) +{ + nlohmann::json parsedMesssage = nlohmann::json::parse(message, nullptr, false); + + if (parsedMesssage.is_discarded() || !parsedMesssage.is_object() || !parsedMesssage.contains("event")) + { + return; + } + + string event = parsedMesssage["event"]; + nlohmann::json data; + if (parsedMesssage.contains("data")) + { + data = parsedMesssage["data"]; + } + + if (event == "join-room-answer") + { + onJoinRoomAnswerEvent(data); + } + else if (event == "room-clients") + { + onRoomClientsEvent(data); + } + else if (event == "make-peer-call") + { + onMakePeerCallEvent(data); + } + else if (event == "peer-call-received") + { + onPeerCallReceivedEvent(data); + } + else if (event == "peer-call-answer-received") + { + onPeerCallAnswerReceivedEvent(data); + } + else if (event == "close-all-peer-connections-request-received") + { + onCloseAllPeerConnectionsRequestReceivedEvent(); + } + else if (event == "ice-candidate-received") + { + onIceCandidateReceivedEvent(data); + } +} + +void WebSocketSignalingClient::onJoinRoomAnswerEvent(const nlohmann::json& data) +{ + if (data.is_string()) + { + if (data != nlohmann::json("")) + { + m_sessionId = data; + invokeIfCallable(m_onSignalingConnectionOpened); + } + else + { + close(); + invokeIfCallable(m_onSignalingConnectionError, "Invalid password or invalid protocol version"); + } + } + else + { + close(); + invokeIfCallable(m_onSignalingConnectionError, "Invalid join-room response"); + } +} + +void WebSocketSignalingClient::onRoomClientsEvent(const nlohmann::json& data) +{ + vector clients; + if (!data.is_array()) + { + invokeIfCallable(m_onError, "Invalid room clients data"); + invokeIfCallable(m_onRoomClientsChanged, clients); + return; + } + + for (const auto& roomClient : data) + { + if (Client::isValid(roomClient)) + { + clients.emplace_back(roomClient); + } + } + invokeIfCallable(m_onRoomClientsChanged, clients); +} + +void WebSocketSignalingClient::onMakePeerCallEvent(const nlohmann::json& data) +{ + JSON_CHECK_RETURN(!data.is_array(), "Invalid onMakePeerCallEvent data (global type)"); + + for (const auto& id : data) + { + JSON_CHECK_CONTINUE(!id.is_string(), "Invalid onMakePeerCallEvent peer id"); + invokeIfCallable(m_makePeerCall, id); + } +} + +void WebSocketSignalingClient::onPeerCallReceivedEvent(const nlohmann::json& data) +{ + JSON_CHECK_RETURN(!data.is_object(), "Invalid onPeerCallReceivedEvent data (global type)"); + + JSON_CHECK_RETURN( + !data.contains("fromId") || !data.contains("offer"), + "Invalid onPeerCallReceivedEvent data (fromId or offer are missing)"); + + auto fromId = data["fromId"]; + auto offer = data["offer"]; + JSON_CHECK_RETURN( + !fromId.is_string() || !offer.is_object(), + "Invalid onPeerCallReceivedEvent data (fromId or offer types)"); + + JSON_CHECK_RETURN( + !offer.contains("sdp") || !offer.contains("type"), + "Invalid onPeerCallReceivedEvent message (sdp or type are missing)"); + + auto sdp = offer["sdp"]; + auto type = offer["type"]; + JSON_CHECK_RETURN( + !sdp.is_string() || !type.is_string(), + "Invalid onPeerCallReceivedEvent message (sdp or type wrong types)"); + + JSON_CHECK_RETURN(type != "offer", "Invalid onPeerCallReceivedEvent message (invalid offer type)"); + invokeIfCallable(m_receivePeerCall, fromId, sdp); +} + +void WebSocketSignalingClient::onPeerCallAnswerReceivedEvent(const nlohmann::json& data) +{ + JSON_CHECK_RETURN(!data.is_object(), "Invalid onPeerCallAnswerReceivedEvent message (global type)"); + + auto fromIdIt = data.find("fromId"); + auto answerIt = data.find("answer"); + + JSON_CHECK_RETURN( + fromIdIt == data.end() || !fromIdIt->is_string(), + "Invalid onPeerCallAnswerReceivedEvent message (fromId type)"); + auto fromId = *fromIdIt; + + if (answerIt == data.end() || !answerIt->is_object()) + { + invokeIfCallable(m_onCallRejected, fromId); + return; + } + + auto answer = *answerIt; + JSON_CHECK_RETURN( + !answer.contains("sdp") || !answer.contains("type"), + "Invalid onPeerCallAnswerReceivedEvent message (sdp or type are missing)"); + + auto sdp = answer["sdp"]; + auto type = answer["type"]; + JSON_CHECK_RETURN( + !sdp.is_string() || !type.is_string(), + "Invalid onPeerCallAnswerReceivedEvent message (sdp or type types)"); + + JSON_CHECK_RETURN(type != "answer", "Invalid onPeerCallAnswerReceivedEvent message (invalid answer type)"); + invokeIfCallable(m_receivePeerCallAnswer, fromId, sdp); +} + +void WebSocketSignalingClient::onCloseAllPeerConnectionsRequestReceivedEvent() +{ + invokeIfCallable(m_closeAllPeerConnections); +} + +void WebSocketSignalingClient::onIceCandidateReceivedEvent(const nlohmann::json& data) +{ + JSON_CHECK_RETURN(!data.is_object(), "Invalid onIceCandidateReceivedEvent message (global type)"); + JSON_CHECK_RETURN( + !data.contains("fromId") || !data.contains("candidate"), + "Invalid onIceCandidateReceivedEvent message (fromId or candidate are missing)"); + + auto fromId = data["fromId"]; + auto candidate = data["candidate"]; + if (candidate.is_null()) + { + return; + } + JSON_CHECK_RETURN( + !fromId.is_string() || !candidate.is_object(), + "Invalid onIceCandidateReceivedEvent message (fromId or candidate wrong types)"); + JSON_CHECK_RETURN( + !candidate.contains("sdpMid") || !candidate.contains("sdpMLineIndex") || !candidate.contains("candidate"), + "Invalid onIceCandidateReceivedEvent message (sdpMid, sdpMLineIndex or candidate are missing)"); + + auto sdpMid = candidate["sdpMid"]; + auto sdpMLineIndex = candidate["sdpMLineIndex"]; + auto sdp = candidate["candidate"]; + JSON_CHECK_RETURN( + !sdpMid.is_string() || !sdpMLineIndex.is_number_integer() || !sdp.is_string(), + "Invalid onIceCandidateReceivedEvent message (sdpMid, sdpMLineIndex or candidate wrong types)"); + + invokeIfCallable(m_receiveIceCandidate, fromId, sdpMid, static_cast(sdpMLineIndex), sdp); +} diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/SignalingClient.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/SignalingClient.cpp deleted file mode 100644 index 9ceabb15..00000000 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/SignalingClient.cpp +++ /dev/null @@ -1,709 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include - -using namespace opentera; -using namespace std; - -#define SIO_MESSAGE_CHECK_RETURN(condition, message) \ - if ((condition)) \ - { \ - invokeIfCallable(m_onError, (message)); \ - return; \ - } \ - do \ - { \ - } while (false) - -#define SIO_MESSAGE_CHECK_CONTINUE(condition, message) \ - if ((condition)) \ - { \ - invokeIfCallable(m_onError, (message)); \ - continue; \ - } \ - do \ - { \ - } while (false) - -constexpr int SignalingProtocolVersion = 1; - -SignalingClient::SignalingClient( - SignalingServerConfiguration&& signalingServerConfiguration, - WebrtcConfiguration&& webrtcConfiguration, - VideoStreamConfiguration&& videoStreamConfiguration) - : m_signalingServerConfiguration(move(signalingServerConfiguration)), - m_webrtcConfiguration(move(webrtcConfiguration)), - m_hasClosePending(false) -{ - constexpr int ReconnectAttempts = 10; - m_sio.set_reconnect_attempts(ReconnectAttempts); - - m_internalClientThread = move(rtc::Thread::Create()); - m_internalClientThread->SetName(m_signalingServerConfiguration.clientName() + " - internal client", nullptr); - m_internalClientThread->Start(); - - m_networkThread = move(rtc::Thread::CreateWithSocketServer()); - m_networkThread->SetName(m_signalingServerConfiguration.clientName() + " - network", nullptr); - m_networkThread->Start(); - m_workerThread = move(rtc::Thread::Create()); - m_workerThread->SetName(m_signalingServerConfiguration.clientName() + " - worker", nullptr); - m_workerThread->Start(); - m_signalingThread = move(rtc::Thread::Create()); - m_signalingThread->SetName(m_signalingServerConfiguration.clientName() + " - signaling", nullptr); - m_signalingThread->Start(); - - m_audioDeviceModule = - rtc::scoped_refptr(new rtc::RefCountedObject); - m_audioProcessing = webrtc::AudioProcessingBuilder().Create(); - m_peerConnectionFactory = webrtc::CreatePeerConnectionFactory( - m_networkThread.get(), - m_workerThread.get(), - m_signalingThread.get(), - m_audioDeviceModule, - webrtc::CreateBuiltinAudioEncoderFactory(), - webrtc::CreateBuiltinAudioDecoderFactory(), - createVideoEncoderFactory(videoStreamConfiguration), - createVideoDecoderFactory(videoStreamConfiguration), - nullptr, // Audio mixer, - m_audioProcessing); - - if (!m_peerConnectionFactory) - { - throw runtime_error("CreatePeerConnectionFactory failed"); - } -} - -SignalingClient::~SignalingClient() -{ - closeSync(); -} - -/** - * Enable or disable the TLS verification. By default, the TLS verification is - * enabled. - * @param isEnabled - */ -void SignalingClient::setTlsVerificationEnabled(bool isEnabled) -{ - callAsync(m_internalClientThread.get(), [this, isEnabled]() { m_sio.set_is_tls_verification_enabled(isEnabled); }); -} - -/** - * @brief Connects the client the signaling server. - */ -void SignalingClient::connect() -{ - callAsync( - m_internalClientThread.get(), - [this]() - { - closeAllConnections(); - m_hasClosePending = false; - connectSioEvents(); - m_sio.connect(m_signalingServerConfiguration.url()); - }); -} - -/** - * @brief Closes all client connections (asynchronous). - */ -void SignalingClient::close() -{ - callAsync( - m_internalClientThread.get(), - [this]() - { - closeAllConnections(); - m_sio.close(); - m_hasClosePending = true; - }); -} - -/** - * @brief Closes all client connections (synchronous). - */ -void SignalingClient::closeSync() -{ - callSync( - m_internalClientThread.get(), - [this]() - { - closeAllConnections(); - m_sio.sync_close(); - m_hasClosePending = true; - }); -} - -/** - * @brief Calls all room clients. - */ -void SignalingClient::callAll() -{ - callAsync( - m_internalClientThread.get(), - [this]() - { - m_alreadyAcceptedCalls.clear(); - for (const auto& pair : m_roomClientsById) - { - m_alreadyAcceptedCalls.emplace_back(pair.first); - } - - m_sio.socket()->emit("call-all"); - }); -} - -/** - * @brief Calls the specified clients. - * @param ids The client ids to call - */ -void SignalingClient::callIds(const vector& ids) -{ - callAsync( - m_internalClientThread.get(), - [this, ids]() - { - m_alreadyAcceptedCalls = ids; - - auto data = sio::array_message::create(); - for (const auto& id : ids) - { - data->get_vector().emplace_back(sio::string_message::create(id)); - } - m_sio.socket()->emit("call-ids", data); - }); -} - -/** - * @brief Hangs up all clients. - */ -void SignalingClient::hangUpAll() -{ - callAsync( - m_internalClientThread.get(), - [this]() - { - closeAllConnections(); - invokeIfCallable(m_onRoomClientsChanged, getRoomClients()); - }); -} - -/** - * @brief Closes all room peer connections. - */ -void SignalingClient::closeAllRoomPeerConnections() -{ - callAsync(m_internalClientThread.get(), [this]() { m_sio.socket()->emit("close-all-room-peer-connections"); }); -} - -/** - * @brief Returns the connected room client ids. - * @return The connected room client ids - */ -vector SignalingClient::getConnectedRoomClientIds() -{ - return callSync( - m_internalClientThread.get(), - [this]() - { - vector ids; - ids.reserve(m_peerConnectionHandlersById.size()); - for (const auto& pair : m_peerConnectionHandlersById) - { - ids.emplace_back(pair.first); - } - return ids; - }); -} - -/** - * @brief Returns the room clients - * @return The room clients - */ -vector SignalingClient::getRoomClients() -{ - return callSync( - m_internalClientThread.get(), - [this]() - { - vector roomClients; - roomClients.reserve(m_roomClientsById.size()); - for (const auto& pair : m_roomClientsById) - { - auto client = pair.second; - bool isConnected = - m_peerConnectionHandlersById.find(client.id()) != m_peerConnectionHandlersById.end() || - client.id() == id(); - roomClients.emplace_back(client, isConnected); - } - - return roomClients; - }); -} - -function SignalingClient::getSendEventFunction() -{ - return [this](const string& event, const sio::message::ptr& message) - { callAsync(m_internalClientThread.get(), [this, event, message]() { m_sio.socket()->emit(event, message); }); }; -} - -function SignalingClient::getOnErrorFunction() -{ - return [this](const string& message) { invokeIfCallable(m_onError, message); }; -} - -function SignalingClient::getOnClientConnectedFunction() -{ - return [this](const Client& client) { invokeIfCallable(m_onClientConnected, client); }; -} - -function SignalingClient::getOnClientDisconnectedFunction() -{ - return [this](const Client& client) - { - callAsync( - m_internalClientThread.get(), - [this, client]() - { - removeConnection(client.id()); - invokeIfCallable(m_onClientDisconnected, client); - }); - }; -} - -void SignalingClient::connectSioEvents() -{ - m_sio.set_open_listener([this] { onSioConnectEvent(); }); - m_sio.set_fail_listener([this] { onSioErrorEvent(); }); - m_sio.set_close_listener([this](const sio::client::close_reason& reason) { onSioDisconnectEvent(reason); }); - - m_sio.on("room-clients", [this](sio::event& event) { onRoomClientsEvent(event); }); - - m_sio.on("make-peer-call", [this](sio::event& event) { onMakePeerCallEvent(event); }); - m_sio.on("peer-call-received", [this](sio::event& event) { onPeerCallReceivedEvent(event); }); - m_sio.on("peer-call-answer-received", [this](sio::event& event) { onPeerCallAnswerReceivedEvent(event); }); - m_sio.on( - "close-all-peer-connections-request-received", - [this](sio::event& event) { onCloseAllPeerConnectionsRequestReceivedEvent(event); }); - - m_sio.on("ice-candidate-received", [this](sio::event& event) { onIceCandidateReceivedEvent(event); }); -} - -void SignalingClient::onSioConnectEvent() -{ - auto data = sio::object_message::create(); - data->get_map()["name"] = sio::string_message::create(m_signalingServerConfiguration.clientName()); - data->get_map()["data"] = m_signalingServerConfiguration.clientData(); - data->get_map()["room"] = sio::string_message::create(m_signalingServerConfiguration.room()); - data->get_map()["password"] = sio::string_message::create(m_signalingServerConfiguration.password()); - data->get_map()["protocolVersion"] = sio::int_message::create(SignalingProtocolVersion); - - m_sio.socket()->emit("join-room", data, [this](const sio::message::list& msg) { onJoinRoomCallback(msg); }); -} - -void SignalingClient::onSioErrorEvent() -{ - invokeIfCallable(m_onSignalingConnectionError, ""); -} - -void SignalingClient::onSioDisconnectEvent(const sio::client::close_reason& reason) -{ - invokeIfCallable(m_onSignalingConnectionClosed); -} - -void SignalingClient::onJoinRoomCallback(const sio::message::list& message) -{ - if (message.size() == 1 && message[0]->get_flag() == sio::message::flag_boolean) - { - if (message[0]->get_bool()) - { - invokeIfCallable(m_onSignalingConnectionOpened); - } - else - { - close(); - invokeIfCallable(m_onSignalingConnectionError, "Invalid password or invalid protocol version"); - } - } - else - { - close(); - invokeIfCallable(m_onSignalingConnectionError, "Invalid join-room response"); - } -} - -void SignalingClient::onRoomClientsEvent(sio::event& event) -{ - callAsync( - m_internalClientThread.get(), - [this, event]() - { - m_roomClientsById.clear(); - for (const auto& roomClient : event.get_message()->get_vector()) - { - if (Client::isValid(roomClient)) - { - Client decodedClient(roomClient); - m_roomClientsById[decodedClient.id()] = decodedClient; - } - } - invokeIfCallable(m_onRoomClientsChanged, getRoomClients()); - }); -} - -void SignalingClient::onMakePeerCallEvent(sio::event& event) -{ - SIO_MESSAGE_CHECK_RETURN( - event.get_message()->get_flag() != sio::message::flag_array, - "Invalid onMakePeerCallEvent message (global type)"); - - for (const auto& idMessage : event.get_message()->get_vector()) - { - SIO_MESSAGE_CHECK_CONTINUE( - idMessage->get_flag() != sio::message::flag_string, - "Invalid onMakePeerCallEvent peer id"); - makePeerCall(idMessage->get_string()); - } -} - -void SignalingClient::makePeerCall(const string& id) -{ - callAsync( - m_internalClientThread.get(), - [this, id]() - { - log("makePeerCall (to_id=" + id + ")"); - auto clientIt = m_roomClientsById.find(id); - if (clientIt == m_roomClientsById.end()) - { - log("makePeerCall failed because " + id + " is not in the room."); - return; - } - if (m_peerConnectionHandlersById.find(id) != m_peerConnectionHandlersById.end()) - { - log("makePeerCall failed because " + id + " is already connected."); - return; - } - - if (!getCallAcceptance(id)) - { - invokeIfCallable(m_onCallRejected, clientIt->second); - return; - } - - m_peerConnectionHandlersById[id] = createConnection(id, clientIt->second, true); - m_peerConnectionHandlersById[id]->makePeerCall(); - }); -} - -void SignalingClient::onPeerCallReceivedEvent(sio::event& event) -{ - SIO_MESSAGE_CHECK_RETURN( - event.get_message()->get_flag() != sio::message::flag_object, - "Invalid onPeerCallReceivedEvent message (global type)"); - auto data = event.get_message()->get_map(); - auto fromIdIt = data.find("fromId"); - auto offerIt = data.find("offer"); - - SIO_MESSAGE_CHECK_RETURN( - fromIdIt == data.end() || offerIt == data.end(), - "Invalid onPeerCallReceivedEvent message (fromId or offer are missing)"); - SIO_MESSAGE_CHECK_RETURN( - fromIdIt->second->get_flag() != sio::message::flag_string || - offerIt->second->get_flag() != sio::message::flag_object, - "Invalid onPeerCallReceivedEvent message (fromId or offer types)"); - auto fromId = fromIdIt->second->get_string(); - auto offer = offerIt->second->get_map(); - auto sdpIt = offer.find("sdp"); - auto typeIt = offer.find("type"); - - SIO_MESSAGE_CHECK_RETURN( - sdpIt == offer.end() || typeIt == offer.end(), - "Invalid onPeerCallReceivedEvent message (sdp or type are missing)"); - SIO_MESSAGE_CHECK_RETURN( - sdpIt->second->get_flag() != sio::message::flag_string || - typeIt->second->get_flag() != sio::message::flag_string, - "Invalid onPeerCallReceivedEvent message (sdp or type wrong types)"); - auto sdp = sdpIt->second->get_string(); - auto type = typeIt->second->get_string(); - - SIO_MESSAGE_CHECK_RETURN(type != "offer", "Invalid onPeerCallReceivedEvent message (invalid offer type)"); - receivePeerCall(fromId, sdp); -} - -void SignalingClient::receivePeerCall(const string& fromId, const string& sdp) -{ - callAsync( - m_internalClientThread.get(), - [this, fromId, sdp]() - { - log("receivePeerCall (from_id=" + fromId + ")"); - auto fromClientIt = m_roomClientsById.find(fromId); - if (fromClientIt == m_roomClientsById.end()) - { - return; - } - - if (m_peerConnectionHandlersById.find(fromId) != m_peerConnectionHandlersById.end()) - { - log("receivePeerCall failed because " + fromId + " is already connected."); - return; - } - if (!getCallAcceptance(fromId)) - { - auto data = sio::object_message::create(); - data->get_map()["toId"] = sio::string_message::create(fromId); - m_sio.socket()->emit("make-peer-call-answer", data); - return; - } - - m_peerConnectionHandlersById[fromId] = createConnection(fromId, fromClientIt->second, false); - m_peerConnectionHandlersById[fromId]->receivePeerCall(sdp); - }); -} - -void SignalingClient::onPeerCallAnswerReceivedEvent(sio::event& event) -{ - SIO_MESSAGE_CHECK_RETURN( - event.get_message()->get_flag() != sio::message::flag_object, - "Invalid onPeerCallAnswerReceivedEvent message (global type)"); - auto data = event.get_message()->get_map(); - auto fromIdIt = data.find("fromId"); - auto answerIt = data.find("answer"); - - SIO_MESSAGE_CHECK_RETURN( - fromIdIt == data.end() || fromIdIt->second->get_flag() != sio::message::flag_string, - "Invalid onPeerCallAnswerReceivedEvent message (fromId type)"); - auto fromId = fromIdIt->second->get_string(); - - if (answerIt == data.end() || answerIt->second->get_flag() != sio::message::flag_object) - { - callAsync( - m_internalClientThread.get(), - [this, fromId]() - { - removeConnection(fromId); - auto clientIt = m_roomClientsById.find(fromId); - invokeIfCallable(m_onCallRejected, clientIt->second); - }); - return; - } - auto answer = answerIt->second->get_map(); - auto sdpIt = answer.find("sdp"); - auto typeIt = answer.find("type"); - - SIO_MESSAGE_CHECK_RETURN( - sdpIt == answer.end() || typeIt == answer.end(), - "Invalid onPeerCallAnswerReceivedEvent message (sdp " - "or type are missing)"); - SIO_MESSAGE_CHECK_RETURN( - sdpIt->second->get_flag() != sio::message::flag_string || - typeIt->second->get_flag() != sio::message::flag_string, - "Invalid onPeerCallAnswerReceivedEvent message (sdp or type types)"); - auto sdp = sdpIt->second->get_string(); - auto type = typeIt->second->get_string(); - - SIO_MESSAGE_CHECK_RETURN(type != "answer", "Invalid onPeerCallAnswerReceivedEvent message (invalid answer type)"); - receivePeerCallAnswer(fromId, sdp); -} - -void SignalingClient::receivePeerCallAnswer(const string& fromId, const string& sdp) -{ - callAsync( - m_internalClientThread.get(), - [this, fromId, sdp]() - { - log("receivePeerCallAnswer (from_id=" + fromId + ")"); - auto peerConnectionsHandlerIt = m_peerConnectionHandlersById.find(fromId); - if (peerConnectionsHandlerIt == m_peerConnectionHandlersById.end()) - { - log("receivePeerCallAnswer failed because " + fromId + " is not found."); - return; - } - - peerConnectionsHandlerIt->second->receivePeerCallAnswer(sdp); - }); -} - -void SignalingClient::onCloseAllPeerConnectionsRequestReceivedEvent(sio::event& event) -{ - log("onCloseAllPeerConnectionsRequestReceivedEvent"); - hangUpAll(); -} - -void SignalingClient::onIceCandidateReceivedEvent(sio::event& event) -{ - SIO_MESSAGE_CHECK_RETURN( - event.get_message()->get_flag() != sio::message::flag_object, - "Invalid onIceCandidateReceivedEvent message (global type)"); - auto data = event.get_message()->get_map(); - auto fromIdIt = data.find("fromId"); - auto candidateIt = data.find("candidate"); - - SIO_MESSAGE_CHECK_RETURN( - fromIdIt == data.end() || candidateIt == data.end(), - "Invalid onIceCandidateReceivedEvent message " - "(fromId or candidate are missing)"); - - if (candidateIt->second->get_flag() == sio::message::flag_null) - { - return; - } - SIO_MESSAGE_CHECK_RETURN( - fromIdIt->second->get_flag() != sio::message::flag_string || - candidateIt->second->get_flag() != sio::message::flag_object, - "Invalid onIceCandidateReceivedEvent message (fromId or candidate wrong " - "types)"); - auto fromId = fromIdIt->second->get_string(); - auto candidate = candidateIt->second->get_map(); - auto sdpMidIt = candidate.find("sdpMid"); - auto sdpMLineIndexIt = candidate.find("sdpMLineIndex"); - auto sdpIt = candidate.find("candidate"); - - SIO_MESSAGE_CHECK_RETURN( - sdpMidIt == candidate.end() || sdpMLineIndexIt == candidate.end() || sdpIt == candidate.end(), - "Invalid onIceCandidateReceivedEvent message " - "(sdpMid, sdpMLineIndex or candidate are missing)"); - SIO_MESSAGE_CHECK_RETURN( - sdpMidIt->second->get_flag() != sio::message::flag_string || - sdpMLineIndexIt->second->get_flag() != sio::message::flag_integer || - sdpIt->second->get_flag() != sio::message::flag_string, - "Invalid onIceCandidateReceivedEvent message (sdpMid, sdpMLineIndex or " - "candidate wrong types)"); - auto sdpMid = sdpMidIt->second->get_string(); - auto sdpMLineIndex = sdpMLineIndexIt->second->get_int(); - auto sdp = sdpIt->second->get_string(); - - receiveIceCandidate(fromId, sdpMid, static_cast(sdpMLineIndex), sdp); -} - -void SignalingClient::receiveIceCandidate( - const string& fromId, - const string& sdpMid, - int sdpMLineIndex, - const string& sdp) -{ - callAsync( - m_internalClientThread.get(), - [this, fromId, sdpMid, sdpMLineIndex, sdp]() - { - log("receiveIceCandidate (from_id=" + fromId + ")"); - auto peerConnectionsHandlerIt = m_peerConnectionHandlersById.find(fromId); - if (peerConnectionsHandlerIt == m_peerConnectionHandlersById.end()) - { - log("receivePeerCallAnswer failed because " + fromId + " is already connected."); - return; - } - - peerConnectionsHandlerIt->second->receiveIceCandidate(sdpMid, sdpMLineIndex, sdp); - }); -} - -void SignalingClient::closeAllConnections() -{ - callSync( - m_internalClientThread.get(), - [this]() - { - vector ids(m_peerConnectionHandlersById.size()); - for (const auto& pair : m_peerConnectionHandlersById) - { - ids.emplace_back(pair.first); - } - - for (const auto& id : ids) - { - removeConnection(id); - } - }); -} - -bool SignalingClient::getCallAcceptance(const string& id) -{ - return callSync( - m_internalClientThread.get(), - [this, id]() - { - if (find(m_alreadyAcceptedCalls.begin(), m_alreadyAcceptedCalls.end(), id) != m_alreadyAcceptedCalls.end()) - { - log("The call is already accepted (id=" + id + ")."); - return true; - } - - auto clientIt = m_roomClientsById.find(id); - if (clientIt == m_roomClientsById.end()) - { - log("The call is rejected because " + id + " is not in the room."); - return false; - } - else if (!m_callAcceptor) - { - log("The call is accepted by default (id=" + id + ")."); - return true; - } - else if (m_callAcceptor(clientIt->second)) - { - log("The call is accepted by the user (id=" + id + ")."); - return true; - } - else - { - log("The call is rejected by the user (id=" + id + ")."); - return false; - } - }); -} - -unique_ptr - SignalingClient::createConnection(const string& peerId, const Client& peerClient, bool isCaller) -{ - return callSync( - m_internalClientThread.get(), - [&, this]() - { - auto configuration = static_cast(m_webrtcConfiguration); - unique_ptr handler = createPeerConnectionHandler(id(), peerClient, isCaller); - auto peerConnection = m_peerConnectionFactory->CreatePeerConnectionOrError( - configuration, - webrtc::PeerConnectionDependencies(handler.get())); - if (peerConnection.ok()) - { - handler->setPeerConnection(peerConnection.MoveValue()); - } - else - { - throw std::runtime_error( - std::string("Failed to create peer connection: ") + peerConnection.error().message()); - } - return handler; - }); -} - -void SignalingClient::removeConnection(const string& id) -{ - callSync( - m_internalClientThread.get(), - [this, &id]() - { - log("removeConnection (" + id + ")"); - - auto it = find(m_alreadyAcceptedCalls.begin(), m_alreadyAcceptedCalls.end(), id); - if (it != m_alreadyAcceptedCalls.end()) - { - m_alreadyAcceptedCalls.erase(it); - } - - auto peerConnectionIt = m_peerConnectionHandlersById.find(id); - if (peerConnectionIt != m_peerConnectionHandlersById.end()) - { - unique_ptr peerConnectionHandler; - peerConnectionHandler = move(peerConnectionIt->second); - m_peerConnectionHandlersById.erase(peerConnectionIt); - } - }); -} diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/StreamClient.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/StreamClient.cpp index 0094f868..0c59d4aa 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/StreamClient.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/StreamClient.cpp @@ -15,7 +15,7 @@ StreamClient::StreamClient( SignalingServerConfiguration signalingServerConfiguration, WebrtcConfiguration webrtcConfiguration, VideoStreamConfiguration videoStreamConfiguration) - : SignalingClient(move(signalingServerConfiguration), move(webrtcConfiguration), move(videoStreamConfiguration)), + : WebrtcClient(move(signalingServerConfiguration), move(webrtcConfiguration), move(videoStreamConfiguration)), m_hasOnMixedAudioFrameReceivedCallback(false), m_isLocalAudioMuted(false), m_isRemoteAudioMuted(false), @@ -37,7 +37,7 @@ StreamClient::StreamClient( WebrtcConfiguration webrtcConfiguration, VideoStreamConfiguration videoStreamConfiguration, shared_ptr videoSource) - : SignalingClient(move(signalingServerConfiguration), move(webrtcConfiguration), move(videoStreamConfiguration)), + : WebrtcClient(move(signalingServerConfiguration), move(webrtcConfiguration), move(videoStreamConfiguration)), m_videoSource(move(videoSource)), m_hasOnMixedAudioFrameReceivedCallback(false), m_isLocalAudioMuted(false), @@ -60,7 +60,7 @@ StreamClient::StreamClient( WebrtcConfiguration webrtcConfiguration, VideoStreamConfiguration videoStreamConfiguration, shared_ptr audioSource) - : SignalingClient(move(signalingServerConfiguration), move(webrtcConfiguration), move(videoStreamConfiguration)), + : WebrtcClient(move(signalingServerConfiguration), move(webrtcConfiguration), move(videoStreamConfiguration)), m_audioSource(move(audioSource)), m_hasOnMixedAudioFrameReceivedCallback(false), m_isLocalAudioMuted(false), @@ -90,7 +90,7 @@ StreamClient::StreamClient( VideoStreamConfiguration videoStreamConfiguration, shared_ptr videoSource, shared_ptr audioSource) - : SignalingClient(move(signalingServerConfiguration), move(webrtcConfiguration), move(videoStreamConfiguration)), + : WebrtcClient(move(signalingServerConfiguration), move(webrtcConfiguration), move(videoStreamConfiguration)), m_videoSource(move(videoSource)), m_audioSource(move(audioSource)), m_hasOnMixedAudioFrameReceivedCallback(false), @@ -204,7 +204,7 @@ unique_ptr peerClient, isCaller, m_hasOnMixedAudioFrameReceivedCallback, - getSendEventFunction(), + *m_signalingClient, getOnErrorFunction(), getOnClientConnectedFunction(), getOnClientDisconnectedFunction(), diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Utils/Client.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Utils/Client.cpp index 4afc8dca..a8b74a68 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Utils/Client.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Utils/Client.cpp @@ -3,77 +3,6 @@ using namespace opentera; using namespace std; -bool opentera::operator==(const sio::message& m1, const sio::message& m2) -{ - if (m1.get_flag() != m2.get_flag()) - { - return false; - } - - switch (m1.get_flag()) - { - case sio::message::flag_integer: - return m1.get_int() == m2.get_int(); - - case sio::message::flag_double: - return m1.get_double() == m2.get_double(); - - case sio::message::flag_string: - return m1.get_string() == m2.get_string(); - - case sio::message::flag_binary: - if (m1.get_binary() == m2.get_binary()) - { - return true; - } - if (m1.get_binary() && m2.get_binary()) - { - return *m1.get_binary() == *m2.get_binary(); - } - else - { - return false; - } - - case sio::message::flag_boolean: - return m1.get_bool() == m2.get_bool(); - - case sio::message::flag_null: - return true; - - case sio::message::flag_array: - if (m1.get_vector().size() != m2.get_vector().size()) - { - return false; - } - for (size_t i = 0; i < m1.get_vector().size(); i++) - { - if (*m1.get_vector()[i] != *m2.get_vector()[i]) - { - return false; - } - } - return true; - - case sio::message::flag_object: - for (const auto& m1Pair : m1.get_map()) - { - if (m2.get_map().find(m1Pair.first) == m2.get_map().end() || - *m1Pair.second != *m2.get_map().at(m1Pair.first)) - { - return false; - } - } - return true; - } - return true; -} - -bool opentera::operator!=(const sio::message& m1, const sio::message& m2) -{ - return !(m1 == m2); -} - /** * @brief Creates a client with the specified values. * @@ -81,40 +10,32 @@ bool opentera::operator!=(const sio::message& m1, const sio::message& m2) * @param name The client name * @param data The client data */ -Client::Client(string id, string name, sio::message::ptr data) : m_id(move(id)), m_name(move(name)), m_data(move(data)) +Client::Client(string id, string name, nlohmann::json data) : m_id(move(id)), m_name(move(name)), m_data(move(data)) { } -Client::Client(const sio::message::ptr& message) +Client::Client(const nlohmann::json& message) { if (isValid(message)) { - auto id = message->get_map()["id"]; - auto name = message->get_map()["name"]; - auto data = message->get_map()["data"]; - - m_id = id->get_string(); - m_name = name->get_string(); - m_data = data; + m_id = message["id"]; + m_name = message["name"]; + m_data = message["data"]; } } -bool Client::isValid(const sio::message::ptr& message) +bool Client::isValid(const nlohmann::json& message) { - if (message->get_flag() != sio::message::flag_object) + if (!message.is_object()) { return false; } - if (message->get_map().find("id") == message->get_map().end() || - message->get_map().find("name") == message->get_map().end() || - message->get_map().find("data") == message->get_map().end()) + if (!message.contains("id") || !message.contains("name") || !message.contains("data")) { return false; } - auto id = message->get_map()["id"]; - auto name = message->get_map()["name"]; - return id->get_flag() == sio::message::flag_string && name->get_flag() == sio::message::flag_string; + return message["id"].is_string() && message["name"].is_string(); } /** @@ -130,7 +51,7 @@ RoomClient::RoomClient() : m_isConnected(false) {} * @param data The client data * @param isConnected Indicates if the client is connected (RTCPeerConnection) */ -RoomClient::RoomClient(string id, string name, sio::message::ptr data, bool isConnected) +RoomClient::RoomClient(string id, string name, nlohmann::json data, bool isConnected) : m_id(move(id)), m_name(move(name)), m_data(move(data)), diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Utils/IceServer.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Utils/IceServer.cpp index 38b1a1c0..6ee95db6 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Utils/IceServer.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/Utils/IceServer.cpp @@ -2,10 +2,9 @@ #include -#include +#include using namespace opentera; -using namespace rapidjson; using namespace std; /** @@ -74,28 +73,28 @@ bool IceServer::fetchFromServer( return fromJson(response, iceServers); } -bool parseIceServerJson(GenericValue>& iceServerJson, vector& iceServers) +bool parseIceServerJson(const nlohmann::json& iceServerJson, vector& iceServers) { - if (!iceServerJson.IsObject() || !iceServerJson.HasMember("urls")) + if (!iceServerJson.is_object() || !iceServerJson.contains("urls")) { return false; } vector urls; auto& urlsJson = iceServerJson["urls"]; - if (urlsJson.IsString()) + if (urlsJson.is_string()) { - urls.emplace_back(urlsJson.GetString()); + urls.emplace_back(urlsJson); } - else if (urlsJson.IsArray()) + else if (urlsJson.is_array()) { - for (auto it = urlsJson.Begin(); it != urlsJson.End(); ++it) + for (auto& it : urlsJson) { - if (!it->IsString()) + if (!it.is_string()) { return false; } - urls.emplace_back(it->GetString()); + urls.emplace_back(it); } } else @@ -103,17 +102,17 @@ bool parseIceServerJson(GenericValue>& iceServerJson, vector& return false; } - if (iceServerJson.HasMember("username") && iceServerJson.HasMember("credential")) + if (iceServerJson.contains("username") && iceServerJson.contains("credential")) { auto& usernameJson = iceServerJson["username"]; auto& credentialJson = iceServerJson["credential"]; - if (!usernameJson.IsString() || !credentialJson.IsString()) + if (!usernameJson.is_string() || !credentialJson.is_string()) { return false; } - iceServers.emplace_back(IceServer(urls, usernameJson.GetString(), credentialJson.GetString())); + iceServers.emplace_back(IceServer(urls, usernameJson, credentialJson)); } - else if (!iceServerJson.HasMember("username") && !iceServerJson.HasMember("credential")) + else if (!iceServerJson.contains("username") && !iceServerJson.contains("credential")) { iceServers.emplace_back(IceServer(urls)); } @@ -133,17 +132,16 @@ bool parseIceServerJson(GenericValue>& iceServerJson, vector& */ bool IceServer::fromJson(const string& json, vector& iceServers) { - Document jsonDocument; - jsonDocument.Parse(json.data()); + nlohmann::json parsedJson = nlohmann::json::parse(json, nullptr, false); - if (!jsonDocument.IsArray()) + if (parsedJson.is_discarded() || !parsedJson.is_array()) { return false; } - for (auto it = jsonDocument.Begin(); it != jsonDocument.End(); ++it) + for (auto& it : parsedJson) { - if (!parseIceServerJson(*it, iceServers)) + if (!parseIceServerJson(it, iceServers)) { return false; } diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/WebrtcClient.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/WebrtcClient.cpp new file mode 100644 index 00000000..7c521586 --- /dev/null +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/src/WebrtcClient.cpp @@ -0,0 +1,491 @@ +#include +#include +#include + +#include +#include +#include + +using namespace opentera; +using namespace std; + +WebrtcClient::WebrtcClient( + SignalingServerConfiguration&& signalingServerConfiguration, + WebrtcConfiguration&& webrtcConfiguration, + VideoStreamConfiguration&& videoStreamConfiguration) + : m_webrtcConfiguration(move(webrtcConfiguration)) +{ + m_signalingClient = make_unique(signalingServerConfiguration); + connectSignalingClientCallbacks(); + + m_internalClientThread = move(rtc::Thread::Create()); + m_internalClientThread->SetName(signalingServerConfiguration.clientName() + " - internal client", nullptr); + m_internalClientThread->Start(); + + m_networkThread = move(rtc::Thread::CreateWithSocketServer()); + m_networkThread->SetName(signalingServerConfiguration.clientName() + " - network", nullptr); + m_networkThread->Start(); + m_workerThread = move(rtc::Thread::Create()); + m_workerThread->SetName(signalingServerConfiguration.clientName() + " - worker", nullptr); + m_workerThread->Start(); + m_signalingThread = move(rtc::Thread::Create()); + m_signalingThread->SetName(signalingServerConfiguration.clientName() + " - signaling", nullptr); + m_signalingThread->Start(); + + m_audioDeviceModule = + rtc::scoped_refptr(new rtc::RefCountedObject); + m_audioProcessing = webrtc::AudioProcessingBuilder().Create(); + m_peerConnectionFactory = webrtc::CreatePeerConnectionFactory( + m_networkThread.get(), + m_workerThread.get(), + m_signalingThread.get(), + m_audioDeviceModule, + webrtc::CreateBuiltinAudioEncoderFactory(), + webrtc::CreateBuiltinAudioDecoderFactory(), + createVideoEncoderFactory(videoStreamConfiguration), + createVideoDecoderFactory(videoStreamConfiguration), + nullptr, // Audio mixer, + m_audioProcessing); + + if (!m_peerConnectionFactory) + { + throw runtime_error("CreatePeerConnectionFactory failed"); + } +} + +WebrtcClient::~WebrtcClient() {} + +/** + * Enable or disable the TLS verification. By default, the TLS verification is + * enabled. + * @param isEnabled + */ +void WebrtcClient::setTlsVerificationEnabled(bool isEnabled) +{ + callAsync( + m_internalClientThread.get(), + [this, isEnabled]() { m_signalingClient->setTlsVerificationEnabled(isEnabled); }); +} + +/** + * @brief Connects the client the signaling server. + */ +void WebrtcClient::connect() +{ + callAsync( + m_internalClientThread.get(), + [this]() + { + closeAllConnections(); + m_signalingClient->connect(); + }); +} + +/** + * @brief Closes all client connections (asynchronous). + */ +void WebrtcClient::close() +{ + callAsync( + m_internalClientThread.get(), + [this]() + { + closeAllConnections(); + m_signalingClient->close(); + }); +} + +/** + * @brief Closes all client connections (synchronous). + */ +void WebrtcClient::closeSync() +{ + callSync( + m_internalClientThread.get(), + [this]() + { + closeAllConnections(); + m_signalingClient->closeSync(); + }); +} + +/** + * @brief Calls all room clients. + */ +void WebrtcClient::callAll() +{ + callAsync( + m_internalClientThread.get(), + [this]() + { + m_alreadyAcceptedCalls.clear(); + for (const auto& pair : m_roomClientsById) + { + m_alreadyAcceptedCalls.emplace_back(pair.first); + } + + m_signalingClient->callAll(); + }); +} + +/** + * @brief Calls the specified clients. + * @param ids The client ids to call + */ +void WebrtcClient::callIds(const vector& ids) +{ + callAsync( + m_internalClientThread.get(), + [this, ids]() + { + m_alreadyAcceptedCalls = ids; + m_signalingClient->callIds(ids); + }); +} + +/** + * @brief Hangs up all clients. + */ +void WebrtcClient::hangUpAll() +{ + callAsync( + m_internalClientThread.get(), + [this]() + { + closeAllConnections(); + invokeIfCallable(m_onRoomClientsChanged, getRoomClients()); + }); +} + +/** + * @brief Closes all room peer connections. + */ +void WebrtcClient::closeAllRoomPeerConnections() +{ + callAsync(m_internalClientThread.get(), [this]() { m_signalingClient->closeAllRoomPeerConnections(); }); +} + +/** + * @brief Returns the connected room client ids. + * @return The connected room client ids + */ +vector WebrtcClient::getConnectedRoomClientIds() +{ + return callSync( + m_internalClientThread.get(), + [this]() + { + vector ids; + ids.reserve(m_peerConnectionHandlersById.size()); + for (const auto& pair : m_peerConnectionHandlersById) + { + ids.emplace_back(pair.first); + } + return ids; + }); +} + +/** + * @brief Returns the room clients + * @return The room clients + */ +vector WebrtcClient::getRoomClients() +{ + return callSync( + m_internalClientThread.get(), + [this]() + { + vector roomClients; + roomClients.reserve(m_roomClientsById.size()); + for (const auto& pair : m_roomClientsById) + { + auto client = pair.second; + bool isConnected = + m_peerConnectionHandlersById.find(client.id()) != m_peerConnectionHandlersById.end() || + client.id() == id(); + roomClients.emplace_back(client, isConnected); + } + + return roomClients; + }); +} + +function WebrtcClient::getOnErrorFunction() +{ + return [this](const string& message) { invokeIfCallable(m_onError, message); }; +} + +function WebrtcClient::getOnClientConnectedFunction() +{ + return [this](const Client& client) { invokeIfCallable(m_onClientConnected, client); }; +} + +function WebrtcClient::getOnClientDisconnectedFunction() +{ + return [this](const Client& client) + { + callAsync( + m_internalClientThread.get(), + [this, client]() + { + removeConnection(client.id()); + invokeIfCallable(m_onClientDisconnected, client); + }); + }; +} + +void setOnRoomClientsChanged(const function&)>& callback); + +void WebrtcClient::connectSignalingClientCallbacks() +{ + m_signalingClient->setOnSignalingConnectionOpened([this]() { invokeIfCallable(m_onSignalingConnectionOpened); }); + m_signalingClient->setOnSignalingConnectionClosed([this]() { invokeIfCallable(m_onSignalingConnectionClosed); }); + m_signalingClient->setOnSignalingConnectionError([this](const string& error) + { invokeIfCallable(m_onSignalingConnectionError, error); }); + + m_signalingClient->setOnRoomClientsChanged( + [this](const vector& clients) + { + callAsync( + m_internalClientThread.get(), + [this, clients]() + { + m_roomClientsById.clear(); + for (auto& client : clients) + { + m_roomClientsById[client.id()] = client; + } + invokeIfCallable(m_onRoomClientsChanged, getRoomClients()); + }); + }); + + 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->setReceiveIceCandidate( + [this](const string& fromId, const string& sdpMid, int sdpMLineIndex, const string& sdp) + { receiveIceCandidate(fromId, sdpMid, sdpMLineIndex, sdp); }); + + m_signalingClient->setOnCallRejected( + [this](const string& fromId) + { + callAsync( + m_internalClientThread.get(), + [this, fromId]() + { + removeConnection(fromId); + auto clientIt = m_roomClientsById.find(fromId); + invokeIfCallable(m_onCallRejected, clientIt->second); + }); + }); + + m_signalingClient->setCloseAllPeerConnections( + [this]() + { + log("onCloseAllPeerConnectionsRequestReceivedEvent"); + hangUpAll(); + }); + + m_signalingClient->setOnError([this](const string& error) { invokeIfCallable(m_onError, error); }); +} + +void WebrtcClient::makePeerCall(const string& id) +{ + callAsync( + m_internalClientThread.get(), + [this, id]() + { + log("makePeerCall (to_id=" + id + ")"); + auto clientIt = m_roomClientsById.find(id); + if (clientIt == m_roomClientsById.end()) + { + log("makePeerCall failed because " + id + " is not in the room."); + return; + } + if (m_peerConnectionHandlersById.find(id) != m_peerConnectionHandlersById.end()) + { + log("makePeerCall failed because " + id + " is already connected."); + return; + } + + if (!getCallAcceptance(id)) + { + invokeIfCallable(m_onCallRejected, clientIt->second); + return; + } + + m_peerConnectionHandlersById[id] = createConnection(id, clientIt->second, true); + m_peerConnectionHandlersById[id]->makePeerCall(); + }); +} + +void WebrtcClient::receivePeerCall(const string& fromId, const string& sdp) +{ + callAsync( + m_internalClientThread.get(), + [this, fromId, sdp]() + { + log("receivePeerCall (from_id=" + fromId + ")"); + auto fromClientIt = m_roomClientsById.find(fromId); + if (fromClientIt == m_roomClientsById.end()) + { + return; + } + + if (m_peerConnectionHandlersById.find(fromId) != m_peerConnectionHandlersById.end()) + { + log("receivePeerCall failed because " + fromId + " is already connected."); + return; + } + if (!getCallAcceptance(fromId)) + { + m_signalingClient->rejectCall(fromId); + return; + } + + m_peerConnectionHandlersById[fromId] = createConnection(fromId, fromClientIt->second, false); + m_peerConnectionHandlersById[fromId]->receivePeerCall(sdp); + }); +} + +void WebrtcClient::receivePeerCallAnswer(const string& fromId, const string& sdp) +{ + callAsync( + m_internalClientThread.get(), + [this, fromId, sdp]() + { + log("receivePeerCallAnswer (from_id=" + fromId + ")"); + auto peerConnectionsHandlerIt = m_peerConnectionHandlersById.find(fromId); + if (peerConnectionsHandlerIt == m_peerConnectionHandlersById.end()) + { + log("receivePeerCallAnswer failed because " + fromId + " is not found."); + return; + } + + peerConnectionsHandlerIt->second->receivePeerCallAnswer(sdp); + }); +} + +void WebrtcClient::receiveIceCandidate(const string& fromId, const string& sdpMid, int sdpMLineIndex, const string& sdp) +{ + callAsync( + m_internalClientThread.get(), + [this, fromId, sdpMid, sdpMLineIndex, sdp]() + { + log("receiveIceCandidate (from_id=" + fromId + ")"); + auto peerConnectionsHandlerIt = m_peerConnectionHandlersById.find(fromId); + if (peerConnectionsHandlerIt == m_peerConnectionHandlersById.end()) + { + log("receivePeerCallAnswer failed because " + fromId + " is already connected."); + return; + } + + peerConnectionsHandlerIt->second->receiveIceCandidate(sdpMid, sdpMLineIndex, sdp); + }); +} + +void WebrtcClient::closeAllConnections() +{ + callSync( + m_internalClientThread.get(), + [this]() + { + vector ids(m_peerConnectionHandlersById.size()); + for (const auto& pair : m_peerConnectionHandlersById) + { + ids.emplace_back(pair.first); + } + + for (const auto& id : ids) + { + removeConnection(id); + } + }); +} + +bool WebrtcClient::getCallAcceptance(const string& id) +{ + return callSync( + m_internalClientThread.get(), + [this, id]() + { + if (find(m_alreadyAcceptedCalls.begin(), m_alreadyAcceptedCalls.end(), id) != m_alreadyAcceptedCalls.end()) + { + log("The call is already accepted (id=" + id + ")."); + return true; + } + + auto clientIt = m_roomClientsById.find(id); + if (clientIt == m_roomClientsById.end()) + { + log("The call is rejected because " + id + " is not in the room."); + return false; + } + else if (!m_callAcceptor) + { + log("The call is accepted by default (id=" + id + ")."); + return true; + } + else if (m_callAcceptor(clientIt->second)) + { + log("The call is accepted by the user (id=" + id + ")."); + return true; + } + else + { + log("The call is rejected by the user (id=" + id + ")."); + return false; + } + }); +} + +unique_ptr + WebrtcClient::createConnection(const string& peerId, const Client& peerClient, bool isCaller) +{ + return callSync( + m_internalClientThread.get(), + [&, this]() + { + auto configuration = static_cast(m_webrtcConfiguration); + unique_ptr handler = createPeerConnectionHandler(id(), peerClient, isCaller); + auto peerConnection = m_peerConnectionFactory->CreatePeerConnectionOrError( + configuration, + webrtc::PeerConnectionDependencies(handler.get())); + if (peerConnection.ok()) + { + handler->setPeerConnection(peerConnection.MoveValue()); + } + else + { + throw runtime_error( + string("Failed to create peer connection: ") + peerConnection.error().message()); + } + return handler; + }); +} + +void WebrtcClient::removeConnection(const string& id) +{ + callSync( + m_internalClientThread.get(), + [this, &id]() + { + log("removeConnection (" + id + ")"); + + auto it = find(m_alreadyAcceptedCalls.begin(), m_alreadyAcceptedCalls.end(), id); + if (it != m_alreadyAcceptedCalls.end()) + { + m_alreadyAcceptedCalls.erase(it); + } + + auto peerConnectionIt = m_peerConnectionHandlersById.find(id); + if (peerConnectionIt != m_peerConnectionHandlersById.end()) + { + unique_ptr peerConnectionHandler; + peerConnectionHandler = move(peerConnectionIt->second); + m_peerConnectionHandlersById.erase(peerConnectionIt); + } + }); +} diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Codecs/VideoCodecFactoriesTests.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Codecs/VideoCodecFactoriesTests.cpp index fdfea420..c42883c2 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Codecs/VideoCodecFactoriesTests.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Codecs/VideoCodecFactoriesTests.cpp @@ -108,7 +108,7 @@ class DummyVideoEncoderFactory : public webrtc::VideoEncoderFactory [[nodiscard]] CodecSupport QueryCodecSupport( const webrtc::SdpVideoFormat& format, - absl::optional scalabilityMode) const override + absl::optional scalabilityMode) const override { CodecSupport codec_support; codec_support.is_supported = !scalabilityMode.has_value(); @@ -126,7 +126,7 @@ class DummyVideoEncoderFactory : public webrtc::VideoEncoderFactory TEST(VideoCodecFactoriesTests, GetSupportedFormats_emptyForcedCodecs_shouldReturnAllFormats) { - std::unordered_set forcedCodecs; + unordered_set forcedCodecs; ForcedCodecVideoDecoderFactory decoderFactory(make_unique(), forcedCodecs); ForcedCodecVideoEncoderFactory encoderFactory(make_unique(), forcedCodecs); @@ -149,7 +149,7 @@ TEST(VideoCodecFactoriesTests, GetSupportedFormats_emptyForcedCodecs_shouldRetur TEST(VideoCodecFactoriesTests, GetSupportedFormats_h264Vp8ForcedCodecs_shouldReturnAllFormats) { - std::unordered_set forcedCodecs{VideoStreamCodec::H264, VideoStreamCodec::VP8}; + unordered_set forcedCodecs{VideoStreamCodec::H264, VideoStreamCodec::VP8}; ForcedCodecVideoDecoderFactory decoderFactory(make_unique(), forcedCodecs); ForcedCodecVideoEncoderFactory encoderFactory(make_unique(), forcedCodecs); @@ -168,7 +168,7 @@ TEST(VideoCodecFactoriesTests, GetSupportedFormats_h264Vp8ForcedCodecs_shouldRet TEST(VideoCodecFactoriesTests, QueryCodecSupport_scaling_shouldReturnNotSupported) { - std::unordered_set forcedCodecs; + unordered_set forcedCodecs; ForcedCodecVideoDecoderFactory decoderFactory(make_unique(), forcedCodecs); ForcedCodecVideoEncoderFactory encoderFactory(make_unique(), forcedCodecs); @@ -185,7 +185,7 @@ TEST(VideoCodecFactoriesTests, QueryCodecSupport_scaling_shouldReturnNotSupporte TEST(VideoCodecFactoriesTests, QueryCodecSupport_emptyForcedCodecs_shouldReturnSupported) { - std::unordered_set forcedCodecs; + unordered_set forcedCodecs; ForcedCodecVideoDecoderFactory decoderFactory(make_unique(), forcedCodecs); ForcedCodecVideoEncoderFactory encoderFactory(make_unique(), forcedCodecs); @@ -203,7 +203,7 @@ TEST(VideoCodecFactoriesTests, QueryCodecSupport_emptyForcedCodecs_shouldReturnS TEST(VideoCodecFactoriesTests, QueryCodecSupport_vp8ForcedCodecs_shouldReturnSupportedIfVp8) { - std::unordered_set forcedCodecs{VideoStreamCodec::VP8, VideoStreamCodec::VP9}; + unordered_set forcedCodecs{VideoStreamCodec::VP8, VideoStreamCodec::VP9}; ForcedCodecVideoDecoderFactory decoderFactory(make_unique(), forcedCodecs); ForcedCodecVideoEncoderFactory encoderFactory(make_unique(), forcedCodecs); @@ -229,7 +229,7 @@ TEST(VideoCodecFactoriesTests, QueryCodecSupport_vp8ForcedCodecs_shouldReturnSup TEST(VideoCodecFactoriesTests, CreateVideoDecoder_shouldCallDummyFactory) { - std::unordered_set forcedCodecs; + unordered_set forcedCodecs; ForcedCodecVideoDecoderFactory decoderFactory(make_unique(), forcedCodecs); ForcedCodecVideoEncoderFactory encoderFactory(make_unique(), forcedCodecs); diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Configurations/SignalingServerConfigurationTests.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Configurations/SignalingServerConfigurationTests.cpp index f9b7d588..562eb98b 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Configurations/SignalingServerConfigurationTests.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Configurations/SignalingServerConfigurationTests.cpp @@ -8,46 +8,44 @@ using namespace std; TEST(SignalingServerConfigurationTests, create_urlClientNameRoom_shouldSetTheAttributes) { - SignalingServerConfiguration testee = SignalingServerConfiguration::create("url", "name", "room"); + auto testee = SignalingServerConfiguration::create("url", "name", "room"); EXPECT_EQ(testee.url(), "url"); EXPECT_EQ(testee.clientName(), "name"); - EXPECT_TRUE(*testee.clientData() == *sio::null_message::create()); + EXPECT_EQ(testee.clientData(), nlohmann::json{}); EXPECT_EQ(testee.room(), "room"); EXPECT_EQ(testee.password(), ""); } -TEST(SignalingServerConfigurationTests, create_urlClientNameClientDataRoom__shouldSetTheAttributes) +TEST(SignalingServerConfigurationTests, createWithData_urlClientNameClientDataRoom__shouldSetTheAttributes) { - SignalingServerConfiguration testee = - SignalingServerConfiguration::create("url", "name", sio::int_message::create(10), "room"); + auto testee = SignalingServerConfiguration::createWithData("url", "name", 10, "room"); EXPECT_EQ(testee.url(), "url"); EXPECT_EQ(testee.clientName(), "name"); - EXPECT_TRUE(*testee.clientData() == *sio::int_message::create(10)); + EXPECT_EQ(testee.clientData(), 10); EXPECT_EQ(testee.room(), "room"); EXPECT_EQ(testee.password(), ""); } TEST(SignalingServerConfigurationTests, create_urlClientNameRoomPassword_shouldSetTheAttributes) { - SignalingServerConfiguration testee = SignalingServerConfiguration::create("url", "name", "room", "password"); + auto testee = SignalingServerConfiguration::create("url", "name", "room", "password"); EXPECT_EQ(testee.url(), "url"); EXPECT_EQ(testee.clientName(), "name"); - EXPECT_TRUE(*testee.clientData() == *sio::null_message::create()); + EXPECT_EQ(testee.clientData(), nlohmann::json{}); EXPECT_EQ(testee.room(), "room"); EXPECT_EQ(testee.password(), "password"); } -TEST(SignalingServerConfigurationTests, create_urlClientNameClientDataRoomPassword_shouldSetTheAttributes) +TEST(SignalingServerConfigurationTests, createWithData_urlClientNameClientDataRoomPassword_shouldSetTheAttributes) { - SignalingServerConfiguration testee = - SignalingServerConfiguration::create("url", "name", sio::int_message::create(10), "room", "password"); + auto testee = SignalingServerConfiguration::createWithData("url", "name", 10, "room", "password"); EXPECT_EQ(testee.url(), "url"); EXPECT_EQ(testee.clientName(), "name"); - EXPECT_TRUE(*testee.clientData() == *sio::int_message::create(10)); + EXPECT_EQ(testee.clientData(), 10); EXPECT_EQ(testee.room(), "room"); EXPECT_EQ(testee.password(), "password"); } diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Configurations/VideoStreamConfigurationTests.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Configurations/VideoStreamConfigurationTests.cpp index f2862a60..8e47d7f4 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Configurations/VideoStreamConfigurationTests.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Configurations/VideoStreamConfigurationTests.cpp @@ -26,7 +26,7 @@ TEST(VideoStreamConfigurationTests, create_shouldSetTheAttributes) { VideoStreamConfiguration testee = VideoStreamConfiguration::create(); - EXPECT_EQ(testee.forcedCodecs(), std::unordered_set({})); + EXPECT_EQ(testee.forcedCodecs(), unordered_set({})); EXPECT_EQ(testee.forceGStreamerHardwareAcceleration(), false); EXPECT_EQ(testee.useGStreamerSoftwareEncoderDecoder(), false); } @@ -35,7 +35,7 @@ TEST(VideoStreamConfigurationTests, create_forcedCodecs_shouldSetTheAttributes) { VideoStreamConfiguration testee = VideoStreamConfiguration::create({VideoStreamCodec::VP8}); - EXPECT_EQ(testee.forcedCodecs(), std::unordered_set({VideoStreamCodec::VP8})); + EXPECT_EQ(testee.forcedCodecs(), unordered_set({VideoStreamCodec::VP8})); EXPECT_EQ(testee.forceGStreamerHardwareAcceleration(), false); EXPECT_EQ(testee.useGStreamerSoftwareEncoderDecoder(), false); } @@ -44,7 +44,7 @@ TEST(VideoStreamConfigurationTests, create_all_shouldSetTheAttributes) { VideoStreamConfiguration testee1 = VideoStreamConfiguration::create({VideoStreamCodec::VP9}, false, true); - EXPECT_EQ(testee1.forcedCodecs(), std::unordered_set({VideoStreamCodec::VP9})); + EXPECT_EQ(testee1.forcedCodecs(), unordered_set({VideoStreamCodec::VP9})); EXPECT_EQ(testee1.forceGStreamerHardwareAcceleration(), false); EXPECT_EQ(testee1.useGStreamerSoftwareEncoderDecoder(), true); @@ -54,7 +54,7 @@ TEST(VideoStreamConfigurationTests, create_all_shouldSetTheAttributes) EXPECT_EQ( testee2.forcedCodecs(), - std::unordered_set({VideoStreamCodec::VP8, VideoStreamCodec::H264})); + unordered_set({VideoStreamCodec::VP8, VideoStreamCodec::H264})); EXPECT_EQ(testee2.forceGStreamerHardwareAcceleration(), true); EXPECT_EQ(testee2.useGStreamerSoftwareEncoderDecoder(), false); } diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/DataChannelClientTests.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/DataChannelClientTests.cpp index ddedcec8..61b17bba 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/DataChannelClientTests.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/DataChannelClientTests.cpp @@ -67,11 +67,11 @@ class DataChannelClientTests : public ::testing::TestWithParam if (tlsTestEnable) { - m_baseUrl = "https://localhost:8081"; + m_baseUrl = "wss://localhost:8081/signaling"; } else { - m_baseUrl = "http://localhost:8080"; + m_baseUrl = "ws://localhost:8080/signaling"; } } }; @@ -91,10 +91,10 @@ class DisconnectedDataChannelClientTests : public ::testing::TestWithParam if (tlsTestEnable) { m_client1 = make_unique( - SignalingServerConfiguration::create( - "https://localhost:8081", + SignalingServerConfiguration::createWithData( + "wss://localhost:8081/signaling", "c1", - sio::string_message::create("cd1"), + "cd1", "chat", ""), DefaultWebrtcConfiguration, @@ -103,10 +103,10 @@ class DisconnectedDataChannelClientTests : public ::testing::TestWithParam else { m_client1 = make_unique( - SignalingServerConfiguration::create( - "http://localhost:8080", + SignalingServerConfiguration::createWithData( + "ws://localhost:8080/signaling", "c1", - sio::string_message::create("cd1"), + "cd1", "chat", ""), DefaultWebrtcConfiguration, @@ -130,7 +130,7 @@ class WrongPasswordDataChannelClientTests : public DataChannelClientTests DataChannelClientTests::SetUp(); m_client1 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c1", sio::string_message::create("cd1"), "chat", ""), + SignalingServerConfiguration::createWithData(m_baseUrl, "c1", "cd1", "chat", ""), DefaultWebrtcConfiguration, DataChannelConfiguration::create()); @@ -156,7 +156,7 @@ class SingleDataChannelClientTests : public DataChannelClientTests DataChannelClientTests::SetUp(); m_client1 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c1", sio::string_message::create("cd1"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c1", "cd1", "chat", "abc"), DefaultWebrtcConfiguration, DataChannelConfiguration::create()); @@ -189,15 +189,15 @@ class RightPasswordDataChannelClientTests : public DataChannelClientTests CallbackAwaiter setupAwaiter(3, 15s); m_client1 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c1", sio::string_message::create("cd1"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c1", "cd1", "chat", "abc"), DefaultWebrtcConfiguration, DataChannelConfiguration::create()); m_client2 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c2", sio::string_message::create("cd2"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c2", "cd2", "chat", "abc"), DefaultWebrtcConfiguration, DataChannelConfiguration::create()); m_client3 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c3", sio::string_message::create("cd3"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c3", "cd3", "chat", "abc"), DefaultWebrtcConfiguration, DataChannelConfiguration::create()); @@ -306,7 +306,7 @@ TEST_P(SingleDataChannelClientTests, onRoomClientsChanged_shouldBeCallAfterTheCo count( roomClients.begin(), roomClients.end(), - RoomClient(m_client1->id(), "c1", sio::string_message::create("cd1"), true)), + RoomClient(m_client1->id(), "c1", "cd1", true)), 1); awaiter.done(); }); @@ -350,13 +350,13 @@ TEST_P(RightPasswordDataChannelClientTests, getRoomClient_shouldReturnTheSpecifi { EXPECT_EQ( m_client1->getRoomClient(m_client1->id()), - RoomClient(m_client1->id(), "c1", sio::string_message::create("cd1"), true)); + RoomClient(m_client1->id(), "c1", "cd1", true)); EXPECT_EQ( m_client1->getRoomClient(m_client2->id()), - RoomClient(m_client2->id(), "c2", sio::string_message::create("cd2"), false)); + RoomClient(m_client2->id(), "c2", "cd2", false)); EXPECT_EQ( m_client1->getRoomClient(m_client3->id()), - RoomClient(m_client3->id(), "c3", sio::string_message::create("cd3"), false)); + RoomClient(m_client3->id(), "c3", "cd3", false)); EXPECT_EQ(m_client1->getRoomClient(""), RoomClient()); } @@ -369,19 +369,19 @@ TEST_P(RightPasswordDataChannelClientTests, getRoomClients_shouldReturnAllClient count( roomClients1.begin(), roomClients1.end(), - RoomClient(m_client1->id(), "c1", sio::string_message::create("cd1"), true)), + RoomClient(m_client1->id(), "c1", "cd1", true)), 1); EXPECT_EQ( count( roomClients1.begin(), roomClients1.end(), - RoomClient(m_client2->id(), "c2", sio::string_message::create("cd2"), false)), + RoomClient(m_client2->id(), "c2", "cd2", false)), 1); EXPECT_EQ( count( roomClients1.begin(), roomClients1.end(), - RoomClient(m_client3->id(), "c3", sio::string_message::create("cd3"), false)), + RoomClient(m_client3->id(), "c3", "cd3", false)), 1); auto roomClients2 = m_client2->getRoomClients(); @@ -390,19 +390,19 @@ TEST_P(RightPasswordDataChannelClientTests, getRoomClients_shouldReturnAllClient count( roomClients2.begin(), roomClients2.end(), - RoomClient(m_client1->id(), "c1", sio::string_message::create("cd1"), false)), + RoomClient(m_client1->id(), "c1", "cd1", false)), 1); EXPECT_EQ( count( roomClients2.begin(), roomClients2.end(), - RoomClient(m_client2->id(), "c2", sio::string_message::create("cd2"), true)), + RoomClient(m_client2->id(), "c2", "cd2", true)), 1); EXPECT_EQ( count( roomClients2.begin(), roomClients2.end(), - RoomClient(m_client3->id(), "c3", sio::string_message::create("cd3"), false)), + RoomClient(m_client3->id(), "c3", "cd3", false)), 1); auto roomClients3 = m_client3->getRoomClients(); @@ -411,19 +411,19 @@ TEST_P(RightPasswordDataChannelClientTests, getRoomClients_shouldReturnAllClient count( roomClients3.begin(), roomClients3.end(), - RoomClient(m_client1->id(), "c1", sio::string_message::create("cd1"), false)), + RoomClient(m_client1->id(), "c1", "cd1", false)), 1); EXPECT_EQ( count( roomClients3.begin(), roomClients3.end(), - RoomClient(m_client2->id(), "c2", sio::string_message::create("cd2"), false)), + RoomClient(m_client2->id(), "c2", "cd2", false)), 1); EXPECT_EQ( count( roomClients3.begin(), roomClients3.end(), - RoomClient(m_client3->id(), "c3", sio::string_message::create("cd3"), true)), + RoomClient(m_client3->id(), "c3", "cd3", true)), 1); } @@ -490,8 +490,7 @@ TEST_P(RightPasswordDataChannelClientTests, callIds_shouldCallTheSpecifiedClient EXPECT_EQ(client.id(), m_clientId2); EXPECT_EQ(client.name(), "c2"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd2"); + EXPECT_EQ(client.data(), "cd2"); }); m_client2->setOnDataChannelOpened( [this, &awaiter](const Client& client) @@ -500,8 +499,7 @@ TEST_P(RightPasswordDataChannelClientTests, callIds_shouldCallTheSpecifiedClient EXPECT_EQ(client.id(), m_clientId1); EXPECT_EQ(client.name(), "c1"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd1"); + EXPECT_EQ(client.data(), "cd1"); }); m_client3->setOnDataChannelOpened([](const Client& client) { ADD_FAILURE(); }); @@ -523,8 +521,7 @@ TEST_P(RightPasswordDataChannelClientTests, onClientConnected_shouldBeCalledAfte EXPECT_EQ(client.id(), m_clientId2); EXPECT_EQ(client.name(), "c2"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd2"); + EXPECT_EQ(client.data(), "cd2"); }); m_client2->setOnClientConnected( [this, &awaiter](const Client& client) @@ -533,8 +530,7 @@ TEST_P(RightPasswordDataChannelClientTests, onClientConnected_shouldBeCalledAfte EXPECT_EQ(client.id(), m_clientId1); EXPECT_EQ(client.name(), "c1"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd1"); + EXPECT_EQ(client.data(), "cd1"); }); m_client3->setOnClientConnected([](const Client& client) { ADD_FAILURE(); }); @@ -557,8 +553,7 @@ TEST_P(RightPasswordDataChannelClientTests, onClientDisconnected_shouldBeCalledA EXPECT_EQ(client.id(), m_clientId2); EXPECT_EQ(client.name(), "c2"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd2"); + EXPECT_EQ(client.data(), "cd2"); }); m_client2->setOnClientDisconnected( [this, &awaiter](const Client& client) @@ -567,8 +562,7 @@ TEST_P(RightPasswordDataChannelClientTests, onClientDisconnected_shouldBeCalledA EXPECT_EQ(client.id(), m_clientId1); EXPECT_EQ(client.name(), "c1"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd1"); + EXPECT_EQ(client.data(), "cd1"); }); m_client3->setOnClientDisconnected([](const Client& client) { ADD_FAILURE(); }); @@ -607,8 +601,7 @@ TEST_P(RightPasswordDataChannelClientTests, callAcceptor_shouldBeAbleToRejectACa { EXPECT_EQ(client.id(), m_clientId2); EXPECT_EQ(client.name(), "c2"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd2"); + EXPECT_EQ(client.data(), "cd2"); onFinish(); }); @@ -617,8 +610,7 @@ TEST_P(RightPasswordDataChannelClientTests, callAcceptor_shouldBeAbleToRejectACa { EXPECT_EQ(client.id(), m_clientId1); EXPECT_EQ(client.name(), "c1"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd1"); + EXPECT_EQ(client.data(), "cd1"); onFinish(); }); @@ -636,14 +628,12 @@ TEST_P(RightPasswordDataChannelClientTests, callAcceptor_shouldBeAbleToRejectACa if (client.id() == m_clientId1) { EXPECT_EQ(client.name(), "c1"); - EXPECT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd1"); + EXPECT_EQ(client.data(), "cd1"); } else if (client.id() == m_clientId3) { EXPECT_EQ(client.name(), "c3"); - EXPECT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd3"); + EXPECT_EQ(client.data(), "cd3"); } else { @@ -657,8 +647,7 @@ TEST_P(RightPasswordDataChannelClientTests, callAcceptor_shouldBeAbleToRejectACa if (client.id() == m_clientId1) { EXPECT_EQ(client.name(), "c1"); - EXPECT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd1"); + EXPECT_EQ(client.data(), "cd1"); } else { @@ -672,8 +661,7 @@ TEST_P(RightPasswordDataChannelClientTests, callAcceptor_shouldBeAbleToRejectACa { EXPECT_EQ(client.id(), m_clientId3); EXPECT_EQ(client.name(), "c3"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd3"); + EXPECT_EQ(client.data(), "cd3"); onFinish(); }); @@ -682,8 +670,7 @@ TEST_P(RightPasswordDataChannelClientTests, callAcceptor_shouldBeAbleToRejectACa { EXPECT_EQ(client.id(), m_clientId3); EXPECT_EQ(client.name(), "c3"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd3"); + EXPECT_EQ(client.data(), "cd3"); onFinish(); }); @@ -814,8 +801,7 @@ TEST_P(RightPasswordDataChannelClientTests, sendTo_binary_shouldSendTheDataToThe EXPECT_EQ(client.id(), m_clientId3); EXPECT_EQ(client.name(), "c3"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd3"); + EXPECT_EQ(client.data(), "cd3"); ASSERT_EQ(size, 1); EXPECT_EQ(data[0], 103); }); @@ -826,8 +812,7 @@ TEST_P(RightPasswordDataChannelClientTests, sendTo_binary_shouldSendTheDataToThe EXPECT_EQ(client.id(), m_clientId1); EXPECT_EQ(client.name(), "c1"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd1"); + EXPECT_EQ(client.data(), "cd1"); ASSERT_EQ(size, 1); EXPECT_EQ(data[0], 101); }); @@ -838,8 +823,7 @@ TEST_P(RightPasswordDataChannelClientTests, sendTo_binary_shouldSendTheDataToThe EXPECT_EQ(client.id(), m_clientId2); EXPECT_EQ(client.name(), "c2"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd2"); + EXPECT_EQ(client.data(), "cd2"); ASSERT_EQ(size, 1); EXPECT_EQ(data[0], 102); }); @@ -883,8 +867,7 @@ TEST_P(RightPasswordDataChannelClientTests, sendTo_string_shouldSendTheDataToThe EXPECT_EQ(client.id(), m_clientId3); EXPECT_EQ(client.name(), "c3"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd3"); + EXPECT_EQ(client.data(), "cd3"); EXPECT_EQ(data, "data3"); }); m_client2->setOnDataChannelMessageString( @@ -894,8 +877,7 @@ TEST_P(RightPasswordDataChannelClientTests, sendTo_string_shouldSendTheDataToThe EXPECT_EQ(client.id(), m_clientId1); EXPECT_EQ(client.name(), "c1"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd1"); + EXPECT_EQ(client.data(), "cd1"); EXPECT_EQ(data, "data1"); }); m_client3->setOnDataChannelMessageString( @@ -905,8 +887,7 @@ TEST_P(RightPasswordDataChannelClientTests, sendTo_string_shouldSendTheDataToThe EXPECT_EQ(client.id(), m_clientId2); EXPECT_EQ(client.name(), "c2"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd2"); + EXPECT_EQ(client.data(), "cd2"); EXPECT_EQ(data, "data2"); }); @@ -954,16 +935,14 @@ TEST_P(RightPasswordDataChannelClientTests, sendToAll_binary_shouldSendTheDataTo if (client.id() == m_clientId2) { EXPECT_EQ(client.name(), "c2"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd2"); + EXPECT_EQ(client.data(), "cd2"); EXPECT_EQ(size, 1); EXPECT_EQ(data[0], 102); } else if (client.id() == m_clientId3) { EXPECT_EQ(client.name(), "c3"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd3"); + EXPECT_EQ(client.data(), "cd3"); ASSERT_EQ(size, 1); EXPECT_EQ(data[0], 103); } @@ -980,16 +959,14 @@ TEST_P(RightPasswordDataChannelClientTests, sendToAll_binary_shouldSendTheDataTo if (client.id() == m_clientId1) { EXPECT_EQ(client.name(), "c1"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd1"); + EXPECT_EQ(client.data(), "cd1"); ASSERT_EQ(size, 1); EXPECT_EQ(data[0], 101); } else if (client.id() == m_clientId3) { EXPECT_EQ(client.name(), "c3"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd3"); + EXPECT_EQ(client.data(), "cd3"); ASSERT_EQ(size, 1); EXPECT_EQ(data[0], 103); } @@ -1006,16 +983,14 @@ TEST_P(RightPasswordDataChannelClientTests, sendToAll_binary_shouldSendTheDataTo if (client.id() == m_clientId1) { EXPECT_EQ(client.name(), "c1"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd1"); + EXPECT_EQ(client.data(), "cd1"); ASSERT_EQ(size, 1); EXPECT_EQ(data[0], 101); } else if (client.id() == m_clientId2) { EXPECT_EQ(client.name(), "c2"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd2"); + EXPECT_EQ(client.data(), "cd2"); ASSERT_EQ(size, 1); EXPECT_EQ(data[0], 102); } @@ -1065,15 +1040,13 @@ TEST_P(RightPasswordDataChannelClientTests, sendToAll_string_shouldSendTheDataTo if (client.id() == m_clientId2) { EXPECT_EQ(client.name(), "c2"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd2"); + EXPECT_EQ(client.data(), "cd2"); EXPECT_EQ(data, "data2"); } else if (client.id() == m_clientId3) { EXPECT_EQ(client.name(), "c3"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd3"); + EXPECT_EQ(client.data(), "cd3"); EXPECT_EQ(data, "data3"); } else @@ -1089,15 +1062,13 @@ TEST_P(RightPasswordDataChannelClientTests, sendToAll_string_shouldSendTheDataTo if (client.id() == m_clientId1) { EXPECT_EQ(client.name(), "c1"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd1"); + EXPECT_EQ(client.data(), "cd1"); EXPECT_EQ(data, "data1"); } else if (client.id() == m_clientId3) { EXPECT_EQ(client.name(), "c3"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd3"); + EXPECT_EQ(client.data(), "cd3"); EXPECT_EQ(data, "data3"); } else @@ -1113,15 +1084,13 @@ TEST_P(RightPasswordDataChannelClientTests, sendToAll_string_shouldSendTheDataTo if (client.id() == m_clientId1) { EXPECT_EQ(client.name(), "c1"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd1"); + EXPECT_EQ(client.data(), "cd1"); EXPECT_EQ(data, "data1"); } else if (client.id() == m_clientId2) { EXPECT_EQ(client.name(), "c2"); - ASSERT_EQ(client.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(client.data()->get_string(), "cd2"); + EXPECT_EQ(client.data(), "cd2"); EXPECT_EQ(data, "data2"); } else diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/StreamClientTests.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/StreamClientTests.cpp index 2f18dc0a..e9cf4e59 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/StreamClientTests.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/StreamClientTests.cpp @@ -114,7 +114,7 @@ struct StreamClientTestsParameters bool useGStreamerSoftwareEncoderDecoder; }; -void PrintTo(const StreamClientTestsParameters& parameters, std::ostream* os) +void PrintTo(const StreamClientTestsParameters& parameters, ostream* os) { *os << "tlsTestEnable=" << parameters.tlsTestEnable; *os << ", useGStreamerSoftwareEncoderDecoder=" << parameters.useGStreamerSoftwareEncoderDecoder; @@ -173,11 +173,11 @@ class StreamClientTests : public ::testing::TestWithParam StreamClientTests::m_signalingServerProcessTLS = n TEST_P(StreamClientTests, muteMethods_shouldSetTheFlagAccordingly) { unique_ptr client = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c1", sio::string_message::create("cd1"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c1", "cd1", "chat", "abc"), DefaultWebrtcConfiguration, m_videoStreamConfiguration); @@ -249,12 +249,12 @@ TEST_P(StreamClientTests, videoStream_bidirectional_shouldBeSentAndReceived) CallbackAwaiter setupAwaiter(2, 15s); unique_ptr client1 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c1", sio::string_message::create("cd1"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c1", "cd1", "chat", "abc"), DefaultWebrtcConfiguration, m_videoStreamConfiguration, videoSource1); unique_ptr client2 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c2", sio::string_message::create("cd2"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c2", "cd2", "chat", "abc"), DefaultWebrtcConfiguration, m_videoStreamConfiguration, videoSource2); @@ -358,12 +358,12 @@ TEST_P(StreamClientTests, videoStream_muted_shouldBeSentAndReceived) CallbackAwaiter setupAwaiter(2, 15s); unique_ptr client1 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c1", sio::string_message::create("cd1"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c1", "cd1", "chat", "abc"), DefaultWebrtcConfiguration, m_videoStreamConfiguration, videoSource1); unique_ptr client2 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c2", sio::string_message::create("cd2"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c2", "cd2", "chat", "abc"), DefaultWebrtcConfiguration, m_videoStreamConfiguration, videoSource2); @@ -450,12 +450,12 @@ TEST_P(StreamClientTests, videoStream_unidirectional_shouldBeSentAndReceived) CallbackAwaiter setupAwaiter(2, 15s); unique_ptr client1 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c1", sio::string_message::create("cd1"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c1", "cd1", "chat", "abc"), DefaultWebrtcConfiguration, m_videoStreamConfiguration, videoSource); unique_ptr client2 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c2", sio::string_message::create("cd2"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c2", "cd2", "chat", "abc"), DefaultWebrtcConfiguration, m_videoStreamConfiguration); @@ -554,12 +554,12 @@ TEST_P(StreamClientTests, audioStream_bidirectional_shouldBeSentAndReceived) CallbackAwaiter setupAwaiter(2, 15s); unique_ptr client1 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c1", sio::string_message::create("cd1"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c1", "cd1", "chat", "abc"), DefaultWebrtcConfiguration, m_videoStreamConfiguration, audioSource1); unique_ptr client2 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c2", sio::string_message::create("cd2"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c2", "cd2", "chat", "abc"), DefaultWebrtcConfiguration, m_videoStreamConfiguration, audioSource2); @@ -702,12 +702,12 @@ TEST_P(StreamClientTests, audioStream_muted_shouldBeSentAndReceived) CallbackAwaiter setupAwaiter(2, 15s); unique_ptr client1 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c1", sio::string_message::create("cd1"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c1", "cd1", "chat", "abc"), DefaultWebrtcConfiguration, m_videoStreamConfiguration, audioSource1); unique_ptr client2 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c2", sio::string_message::create("cd2"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c2", "cd2", "chat", "abc"), DefaultWebrtcConfiguration, m_videoStreamConfiguration, audioSource2); @@ -848,12 +848,12 @@ TEST_P(StreamClientTests, audioStream_unidirectional_shouldBeSentAndReceived) CallbackAwaiter setupAwaiter(2, 15s); unique_ptr client1 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c1", sio::string_message::create("cd1"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c1", "cd1", "chat", "abc"), DefaultWebrtcConfiguration, m_videoStreamConfiguration, audioSource); unique_ptr client2 = make_unique( - SignalingServerConfiguration::create(m_baseUrl, "c2", sio::string_message::create("cd2"), "chat", "abc"), + SignalingServerConfiguration::createWithData(m_baseUrl, "c2", "cd2", "chat", "abc"), DefaultWebrtcConfiguration, m_videoStreamConfiguration); diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Utils/ClientTests.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Utils/ClientTests.cpp index c3221118..6f9aab19 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Utils/ClientTests.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeClient/test/src/Utils/ClientTests.cpp @@ -7,149 +7,130 @@ using namespace std; TEST(ClientTests, constructor_Client_shouldSetTheAttributes) { - Client testee1("id1", "name1", sio::string_message::create("data1")); + Client testee1("id1", "name1", "data1"); EXPECT_EQ(testee1.id(), "id1"); EXPECT_EQ(testee1.name(), "name1"); - ASSERT_EQ(testee1.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(testee1.data()->get_string(), "data1"); - - auto message = sio::object_message::create(); - message->get_map()["id"] = sio::string_message::create("id2"); - message->get_map()["name"] = sio::string_message::create("name2"); - message->get_map()["data"] = sio::string_message::create("data2"); + ASSERT_TRUE(testee1.data().is_string()); + EXPECT_EQ(testee1.data(), "data1"); + + nlohmann::json message { + {"id", "id2"}, + {"name", "name2"}, + {"data", "data2"} + }; Client testee2(message); EXPECT_EQ(testee2.id(), "id2"); EXPECT_EQ(testee2.name(), "name2"); - ASSERT_EQ(testee2.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(testee2.data()->get_string(), "data2"); + ASSERT_TRUE(testee2.data().is_string()); + EXPECT_EQ(testee2.data(), "data2"); } TEST(ClientTests, isValid_shouldReturnTrueOnlyIfTheMessageIsValid) { - EXPECT_FALSE(Client::isValid(sio::string_message::create("data1"))); + EXPECT_FALSE(Client::isValid("data1")); - auto message = sio::object_message::create(); + nlohmann::json message; EXPECT_FALSE(Client::isValid(message)); - message->get_map()["id"] = sio::null_message::create(); + message.emplace("id", nlohmann::json{}); EXPECT_FALSE(Client::isValid(message)); - message->get_map()["name"] = sio::null_message::create(); + message.emplace("name", nlohmann::json{}); EXPECT_FALSE(Client::isValid(message)); - message->get_map()["data"] = sio::null_message::create(); + message.emplace("data", nlohmann::json{}); EXPECT_FALSE(Client::isValid(message)); - message->get_map()["id"] = sio::string_message::create("id"); + message["id"] = "id"; EXPECT_FALSE(Client::isValid(message)); - message->get_map()["name"] = sio::string_message::create("name"); + message["name"] = "name"; EXPECT_TRUE(Client::isValid(message)); } TEST(ClientTests, equalityOperator_Client_shouldReturnFalseIfOperandsAreNotEqual) { - EXPECT_FALSE( - Client("c1", "n1", sio::string_message::create("d")) == Client("c2", "n1", sio::string_message::create("d"))); - EXPECT_FALSE( - Client("c1", "n1", sio::string_message::create("d")) == Client("c1", "n2", sio::string_message::create("d"))); - EXPECT_FALSE( - Client("c1", "n1", sio::string_message::create("d")) == Client("c1", "n1", sio::string_message::create("e"))); - EXPECT_FALSE( - Client("c1", "n1", sio::string_message::create("d")) == Client("c1", "n1", sio::int_message::create(10))); - EXPECT_FALSE(Client("c1", "n1", sio::string_message::create("d")) == Client("c1", "n1", nullptr)); - EXPECT_FALSE(Client("c1", "n1", nullptr) == Client("c1", "n1", sio::int_message::create(10))); - - auto array1 = sio::array_message::create(); - array1->get_vector().emplace_back(sio::string_message::create("a")); - auto array2 = sio::array_message::create(); + EXPECT_FALSE(Client("c1", "n1", "d") == Client("c2", "n1", "d")); + EXPECT_FALSE(Client("c1", "n1", "d") == Client("c1", "n2", "d")); + EXPECT_FALSE(Client("c1", "n1", "d") == Client("c1", "n1", "e")); + EXPECT_FALSE(Client("c1", "n1", "d") == Client("c1", "n1", 10)); + EXPECT_FALSE(Client("c1", "n1", "d") == Client("c1", "n1", nullptr)); + EXPECT_FALSE(Client("c1", "n1", nullptr) == Client("c1", "n1", 10)); + + auto array1 = nlohmann::json::array({"a"}); + auto array2 = nlohmann::json::array(); EXPECT_FALSE(Client("c1", "n1", array1) == Client("c1", "n1", array2)); - array2->get_vector().emplace_back(sio::string_message::create("b")); + array2.emplace_back("b"); EXPECT_FALSE(Client("c1", "n1", array1) == Client("c1", "n1", array2)); - auto object1 = sio::object_message::create(); - object1->get_map()["x"] = sio::null_message::create(); - object1->get_map()["bob"] = sio::string_message::create("d"); - auto object2 = sio::object_message::create(); - object2->get_map()["x"] = sio::string_message::create("d"); + nlohmann::json object1 = { + {"x", nlohmann::json{}}, + {"bob", "d"} + }; + nlohmann::json object2 { + {"x", "d"} + }; EXPECT_FALSE(Client("c1", "n1", object1) == Client("c1", "n1", object2)); } TEST(ClientTests, equalityOperator_Client_shouldReturnTrueIfOperandsAreEqual) { - EXPECT_TRUE(Client("c", "n", sio::int_message::create(10)) == Client("c", "n", sio::int_message::create(10))); - EXPECT_TRUE( - Client("c", "n", sio::double_message::create(0.0)) == Client("c", "n", sio::double_message::create(0.0))); - EXPECT_TRUE( - Client("c", "n", sio::binary_message::create(nullptr)) == - Client("c", "n", sio::binary_message::create(nullptr))); - EXPECT_TRUE( - Client("c", "n", sio::bool_message::create(false)) == Client("c", "n", sio::bool_message::create(false))); - EXPECT_TRUE(Client("c", "n", sio::null_message::create()) == Client("c", "n", sio::null_message::create())); + EXPECT_TRUE(Client("c", "n", 10) == Client("c", "n", 10)); + EXPECT_TRUE(Client("c", "n", 0.0) == Client("c", "n", 0.0)); EXPECT_TRUE(Client("c", "n", nullptr) == Client("c", "n", nullptr)); + EXPECT_TRUE(Client("c", "n", false) == Client("c", "n", false)); + EXPECT_TRUE(Client("c", "n", nlohmann::json{}) == Client("c", "n", nlohmann::json{})); - auto array1 = sio::array_message::create(); - array1->get_vector().emplace_back(sio::string_message::create("a")); - auto array2 = sio::array_message::create(); - array2->get_vector().emplace_back(sio::string_message::create("a")); + auto array1 = nlohmann::json::array({"a"}); + auto array2 = nlohmann::json::array({"a"}); EXPECT_TRUE(Client("c1", "n1", array1) == Client("c1", "n1", array2)); - auto object1 = sio::object_message::create(); - object1->get_map()["x"] = sio::null_message::create(); - object1->get_map()["bob"] = sio::string_message::create("d"); - auto object2 = sio::object_message::create(); - object2->get_map()["x"] = sio::null_message::create(); - object2->get_map()["bob"] = sio::string_message::create("d"); + nlohmann::json object1 = { + {"x", nlohmann::json{}}, + {"bob", "d"} + }; + nlohmann::json object2 { + {"x", nlohmann::json{}}, + {"bob", "d"} + }; EXPECT_TRUE(Client("c1", "n1", object1) == Client("c1", "n1", object2)); } TEST(ClientTests, constructor_RoomClient_shouldSetTheAttributes) { - RoomClient testee1("id1", "name1", sio::string_message::create("data1"), false); + RoomClient testee1("id1", "name1", "data1", false); EXPECT_EQ(testee1.id(), "id1"); EXPECT_EQ(testee1.name(), "name1"); - EXPECT_EQ(testee1.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(testee1.data()->get_string(), "data1"); + ASSERT_TRUE(testee1.data().is_string()); + EXPECT_EQ(testee1.data(), "data1"); EXPECT_EQ(testee1.isConnected(), false); - RoomClient testee2(Client("id2", "name2", sio::string_message::create("data2")), true); + RoomClient testee2(Client("id2", "name2", "data2"), true); EXPECT_EQ(testee2.id(), "id2"); EXPECT_EQ(testee2.name(), "name2"); - EXPECT_EQ(testee2.data()->get_flag(), sio::message::flag_string); - EXPECT_EQ(testee2.data()->get_string(), "data2"); + ASSERT_TRUE(testee2.data().is_string()); + EXPECT_EQ(testee2.data(), "data2"); EXPECT_EQ(testee2.isConnected(), true); } TEST(ClientTests, equalityOperator_RoomClient_shouldReturnFalseIfOperandsAreNotEqual) { - EXPECT_FALSE( - RoomClient("c1", "n1", sio::string_message::create("d"), true) == - RoomClient("c2", "n1", sio::string_message::create("d"), true)); - EXPECT_FALSE( - RoomClient("c1", "n1", sio::string_message::create("d"), false) == - RoomClient("c1", "n2", sio::string_message::create("d"), false)); - EXPECT_FALSE( - RoomClient("c1", "n1", sio::string_message::create("d"), false) == - RoomClient("c1", "n1", sio::string_message::create("e"), false)); - EXPECT_FALSE( - RoomClient("c1", "n1", sio::string_message::create("d"), true) == - RoomClient("c1", "n1", sio::string_message::create("d"), false)); - EXPECT_FALSE( - RoomClient("c1", "n1", sio::string_message::create("d"), true) == RoomClient("c1", "n1", nullptr, false)); - EXPECT_FALSE( - RoomClient("c1", "n1", nullptr, true) == RoomClient("c1", "n1", sio::string_message::create("d"), false)); - - EXPECT_FALSE(RoomClient("c1", "n1", sio::string_message::create("d"), true) == RoomClient()); - EXPECT_FALSE(RoomClient() == RoomClient("c1", "n1", sio::string_message::create("d"), true)); + EXPECT_FALSE(RoomClient("c1", "n1", "d", true) == RoomClient("c2", "n1", "d", true)); + EXPECT_FALSE(RoomClient("c1", "n1", "d", false) == RoomClient("c1", "n2", "d", false)); + EXPECT_FALSE(RoomClient("c1", "n1", "d", false) == RoomClient("c1", "n1", "e", false)); + EXPECT_FALSE(RoomClient("c1", "n1", "d", true) == RoomClient("c1", "n1", "d", false)); + EXPECT_FALSE(RoomClient("c1", "n1", "d", true) == RoomClient("c1", "n1", nullptr, false)); + EXPECT_FALSE(RoomClient("c1", "n1", nullptr, true) == RoomClient("c1", "n1", "d", false)); + + EXPECT_FALSE(RoomClient("c1", "n1", "d", true) == RoomClient()); + EXPECT_FALSE(RoomClient() == RoomClient("c1", "n1", "d", true)); } TEST(ClientTests, equalityOperator_RoomClient_shouldReturnTrueIfOperandsAreEqual) { - EXPECT_TRUE( - RoomClient("c", "n", sio::int_message::create(10), false) == - RoomClient("c", "n", sio::int_message::create(10), false)); + EXPECT_TRUE(RoomClient("c", "n", 10, false) == RoomClient("c", "n", 10, false)); EXPECT_TRUE(RoomClient("c", "n", nullptr, false) == RoomClient("c", "n", nullptr, false)); EXPECT_TRUE(RoomClient() == RoomClient()); } diff --git a/opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/src/Pipeline/GStreamerEncoderPipeline.cpp b/opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/src/Pipeline/GStreamerEncoderPipeline.cpp index c8d637b4..f860c51b 100644 --- a/opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/src/Pipeline/GStreamerEncoderPipeline.cpp +++ b/opentera-webrtc-native-client/OpenteraWebrtcNativeGStreamer/src/Pipeline/GStreamerEncoderPipeline.cpp @@ -178,20 +178,20 @@ int32_t GStreamerEncoderPipeline::initialize( return WEBRTC_VIDEO_CODEC_OK; } -void GStreamerEncoderPipeline::setEncoderProperty(const std::string& name, guint value) +void GStreamerEncoderPipeline::setEncoderProperty(const string& name, guint value) { auto dotPosition = name.find('.'); - auto valueString = std::to_string(value); + auto valueString = to_string(value); - if (dotPosition == std::string::npos) + if (dotPosition == string::npos) { GST_INFO("Set encoder property - %s=%s", name.c_str(), valueString.c_str()); g_object_set(m_encoder.get(), name.c_str(), value, nullptr); } else { - std::string parentName = name.substr(0, dotPosition); - std::string childName = name.substr(dotPosition + 1); + string parentName = name.substr(0, dotPosition); + string childName = name.substr(dotPosition + 1); GST_INFO("Set encoder property - %s.%s=%s", parentName.c_str(), childName.c_str(), valueString.c_str()); GstStructure* structureRaw; diff --git a/opentera-webrtc-web-client/browser-tests/DataChannelClient/disconnectedDataChannelClient.spec.js b/opentera-webrtc-web-client/browser-tests/DataChannelClient/disconnectedDataChannelClient.spec.js index 8bb84eba..e2255f90 100644 --- a/opentera-webrtc-web-client/browser-tests/DataChannelClient/disconnectedDataChannelClient.spec.js +++ b/opentera-webrtc-web-client/browser-tests/DataChannelClient/disconnectedDataChannelClient.spec.js @@ -1,5 +1,5 @@ const SignalingServerConfiguration = { - url: 'http://localhost:8080', + url: 'ws://localhost:8080/signaling', name: '', room: 'chat', password: '' @@ -12,7 +12,7 @@ let dataChannelClient; describe('Disconnected DataChannelClient', () => { beforeEach(() => dataChannelClient = new window.openteraWebrtcWebClient.DataChannelClient(SignalingServerConfiguration, DataChannelConfiguration, RtcConfiguration)); - + it('isConnected should return false', () => { expect(dataChannelClient.isConnected).to.eql(false); }); diff --git a/opentera-webrtc-web-client/browser-tests/DataChannelClient/rightPasswordDataChannelClient.spec.js b/opentera-webrtc-web-client/browser-tests/DataChannelClient/rightPasswordDataChannelClient.spec.js index f256eab0..245a26cf 100644 --- a/opentera-webrtc-web-client/browser-tests/DataChannelClient/rightPasswordDataChannelClient.spec.js +++ b/opentera-webrtc-web-client/browser-tests/DataChannelClient/rightPasswordDataChannelClient.spec.js @@ -6,21 +6,21 @@ describe('Right password DataChannelClient', done => { const BEFORE_AFTER_TIMEOUT_MS = 100; const TEST_TIMEOUT_MS = 15000; const SignalingServerConfiguration1 = { - url: 'http://localhost:8080', + url: 'ws://localhost:8080/signaling', name: 'c1', data:'cd1', room: 'chat', password: 'abc' }; const SignalingServerConfiguration2 = { - url: 'http://localhost:8080/socket.io', + url: 'ws://localhost:8080/signaling', name: 'c2', data:'cd2', room: 'chat', password: 'abc' }; const SignalingServerConfiguration3 = { - url: 'http://localhost:8080/socket.io/', + url: 'ws://localhost:8080/signaling', name: 'c3', data:'cd3', room: 'chat', diff --git a/opentera-webrtc-web-client/browser-tests/DataChannelClient/wrongPasswordDataChannelClient.spec.js b/opentera-webrtc-web-client/browser-tests/DataChannelClient/wrongPasswordDataChannelClient.spec.js index 1a3bab2c..0bd0c426 100644 --- a/opentera-webrtc-web-client/browser-tests/DataChannelClient/wrongPasswordDataChannelClient.spec.js +++ b/opentera-webrtc-web-client/browser-tests/DataChannelClient/wrongPasswordDataChannelClient.spec.js @@ -1,6 +1,6 @@ describe('Wrong password DataChannelClient', () => { const SignalingServerConfiguration = { - url: 'http://localhost:8080/', + url: 'ws://localhost:8080/signaling', name: '', room: 'chat', password: '' diff --git a/opentera-webrtc-web-client/src/DataChannelClient.js b/opentera-webrtc-web-client/src/DataChannelClient.js index a42d5594..7183244f 100644 --- a/opentera-webrtc-web-client/src/DataChannelClient.js +++ b/opentera-webrtc-web-client/src/DataChannelClient.js @@ -1,9 +1,9 @@ -import SignalingClient from './SignalingClient'; +import WebrtcClient from './WebrtcClient'; /** * @brief Represents a client for data channel communication. */ -class DataChannelClient extends SignalingClient { +class DataChannelClient extends WebrtcClient { /** * @brief Creates a data channel client with the specified configurations. * @@ -58,7 +58,7 @@ class DataChannelClient extends SignalingClient { let rtcPeerConnection = new window.RTCPeerConnection(this._rtcConfiguration); if (isCaller) { - let dataChannel = rtcPeerConnection.createDataChannel(this._signalingServerConfiguration.room, + let dataChannel = rtcPeerConnection.createDataChannel(this._signalingClient.room, this._dataChannelConfiguration); this._dataChannels[id] = dataChannel; this._connectDataChannelEvents(id, dataChannel); diff --git a/opentera-webrtc-web-client/src/Signaling/SignalingClient.js b/opentera-webrtc-web-client/src/Signaling/SignalingClient.js new file mode 100644 index 00000000..877a88bf --- /dev/null +++ b/opentera-webrtc-web-client/src/Signaling/SignalingClient.js @@ -0,0 +1,106 @@ +class SignalingClient { + constructor(signalingServerConfiguration, logger) { + if (this.constructor === SignalingClient) { + throw new TypeError('Abstract class "SignalingClient" cannot be instantiated directly.'); + } + + this._signalingServerConfiguration = signalingServerConfiguration; + this._logger = logger; + + this._onSignalingConnectionOpen = () => {}; + this._onSignalingConnectionClose = () => {}; + this._onSignalingConnectionError = () => {}; + + this._onRoomClientsChange = () => {}; + + this._makePeerCall = () => {}; + this._peerCallReceived = () => {}; + this._peerCallAnswerReceived = () => {}; + this._iceCandidateReceived = () => {}; + + this._closeAllPeerConnections = () => {}; + } + + get room() { + return this._signalingServerConfiguration.room; + } + + set onSignalingConnectionOpen(onSignalingConnectionOpen) { + this._onSignalingConnectionOpen = onSignalingConnectionOpen; + } + + set onSignalingConnectionClose(onSignalingConnectionClose) { + this._onSignalingConnectionClose = onSignalingConnectionClose; + } + + set onSignalingConnectionError(onSignalingConnectionError) { + this._onSignalingConnectionError = onSignalingConnectionError; + } + + set onRoomClientsChange(onRoomClientsChange) { + this._onRoomClientsChange = onRoomClientsChange; + } + + set makePeerCall(makePeerCall) { + this._makePeerCall = makePeerCall; + } + + set peerCallReceived(peerCallReceived) { + this._peerCallReceived = peerCallReceived; + } + + set peerCallAnswerReceived(peerCallAnswerReceived) { + this._peerCallAnswerReceived = peerCallAnswerReceived; + } + + set iceCandidateReceived(iceCandidateReceived) { + this._iceCandidateReceived = iceCandidateReceived; + } + + set closeAllPeerConnections(closeAllPeerConnections) { + this._closeAllPeerConnections = closeAllPeerConnections; + } + + async connect() { + throw new TypeError('The method "connect" is not overrided.'); + } + + disconnect() { + throw new TypeError('The method "disconnect" is not overrided.'); + } + + callAll() { + throw new TypeError('The method "callAll" is not overrided.'); + } + + // eslint-disable-next-line no-unused-vars + callIds(ids) { + throw new TypeError('The method "callIds" is not overrided.'); + } + + closeAllRoomPeerConnections() { + throw new TypeError('The method "closeAllRoomPeerConnections" is not overrided.'); + } + + // eslint-disable-next-line no-unused-vars + callPeer(toId, offer) { + throw new TypeError('The method "callPeer" is not overrided.'); + } + + // eslint-disable-next-line no-unused-vars + makePeerCallAnswer(toId, answer) { + throw new TypeError('The method "makePeerCallAnswer" is not overrided.'); + } + + // eslint-disable-next-line no-unused-vars + rejectCall(toId) { + throw new TypeError('The method "rejectCall" is not overrided.'); + } + + // eslint-disable-next-line no-unused-vars + sendIceCandidate(toId, candidate) { + throw new TypeError('The method "sendIceCandidate" is not overrided.'); + } +} + +export default SignalingClient; diff --git a/opentera-webrtc-web-client/src/Signaling/WebSocketSignalingClient.js b/opentera-webrtc-web-client/src/Signaling/WebSocketSignalingClient.js new file mode 100644 index 00000000..2901438a --- /dev/null +++ b/opentera-webrtc-web-client/src/Signaling/WebSocketSignalingClient.js @@ -0,0 +1,146 @@ +import SignalingClient from './SignalingClient'; + +const SignalingProtocolVersion = 1; + +function _eventToMessage(event, data) { + if (data === undefined) { + return JSON.stringify({event: event}); + } else { + return JSON.stringify({event: event, data: data}); + } +} + +class WebSocketSignalingClient extends SignalingClient { + constructor(signalingServerConfiguration, logger) { + super(signalingServerConfiguration, logger); + this._ws = null; + this._id = null; + } + + get isConnected() { + return this._id !== null; + } + + get sessionId() { + return this._id; + } + + async connect() { + this._ws = new WebSocket(this._signalingServerConfiguration.url); + this._connectEvents(); + } + + _connectEvents() { + this._ws.onopen = () => { + this._logger('SignalingServer connect event'); + let data = { + name: this._signalingServerConfiguration.name, + data: this._signalingServerConfiguration.data, + room: this._signalingServerConfiguration.room, + password: this._signalingServerConfiguration.password, + protocolVersion: SignalingProtocolVersion + }; + this._ws.send(_eventToMessage('join-room', data)); + }; + this._ws.onclose = event => { + this._logger('SignalingServer disconnect event: ', event); + this._onSignalingConnectionClose(); + }; + this._ws.onerror = event => { + this._logger('SignalingServer error event: ', event); + this._onSignalingConnectionError(event); + }; + + this._ws.onmessage = async event => { + try { + let data = JSON.parse(event.data); + let eventName = data.event; + data = data.data; + + switch (eventName) + { + case 'join-room-answer': + this._handle_join_room_answer(data); + break; + case 'room-clients': + this._onRoomClientsChange(data); + break; + case 'make-peer-call': + await this._makePeerCall(data); + break; + case 'peer-call-received': + await this._peerCallReceived(data); + break; + case 'peer-call-answer-received': + await this._peerCallAnswerReceived(data); + break; + case 'close-all-peer-connections-request-received': + this._closeAllPeerConnections(); + break; + case 'ice-candidate-received': + this._iceCandidateReceived(data); + break; + } + } catch(error) { + this._logger('Message error: ', error); + } + }; + } + + _handle_join_room_answer(id){ + if (id === '') { + this._onSignalingConnectionError('Invalid password or invalid protocol version'); + } else { + this._id = id; + this._onSignalingConnectionOpen(); + } + } + + disconnect() { + this._disconnectEvents(); + this._id = null; + this._ws.close(); + this._ws = null; + } + + _disconnectEvents() { + this._ws.onopen = () => {}; + this._ws.onclose = () => {}; + this._ws.onerror = () => {}; + this._ws.onmessage = () => {}; + } + + callAll() { + this._ws.send(_eventToMessage('call-all')); + } + + callIds(ids) { + this._ws.send(_eventToMessage('call-ids', ids)); + } + + closeAllRoomPeerConnections() { + this._ws.send(_eventToMessage('close-all-room-peer-connections')); + } + + callPeer(toId, offer) { + let data = { toId: toId, offer: offer }; + this._ws.send(_eventToMessage('call-peer', data)); + } + + makePeerCallAnswer(toId, answer) { + let data = { toId: toId, answer: answer }; + this._ws.send(_eventToMessage('make-peer-call-answer', data)); + } + + rejectCall(toId) { + let data = { toId: toId }; + this._ws.send(_eventToMessage('make-peer-call-answer', data)); + } + + sendIceCandidate(toId, candidate) { + let data = { toId: toId, candidate: candidate }; + this._ws.send(_eventToMessage('send-ice-candidate', data)); + } +} + +export default WebSocketSignalingClient; diff --git a/opentera-webrtc-web-client/src/StreamClient.js b/opentera-webrtc-web-client/src/StreamClient.js index ecb5626b..2ae1115e 100644 --- a/opentera-webrtc-web-client/src/StreamClient.js +++ b/opentera-webrtc-web-client/src/StreamClient.js @@ -1,9 +1,9 @@ -import SignalingClient from './SignalingClient'; +import WebrtcClient from './WebrtcClient'; /** * @brief A signaling client to join a WebRTC room and stream a video source. */ -class StreamClient extends SignalingClient { +class StreamClient extends WebrtcClient { /** * @brief Creates a stream client * diff --git a/opentera-webrtc-web-client/src/StreamDataChannelClient.js b/opentera-webrtc-web-client/src/StreamDataChannelClient.js index bf5bb7d4..56b85e67 100644 --- a/opentera-webrtc-web-client/src/StreamDataChannelClient.js +++ b/opentera-webrtc-web-client/src/StreamDataChannelClient.js @@ -1,9 +1,9 @@ -import SignalingClient from './SignalingClient'; +import WebrtcClient from './WebrtcClient'; /** * @brief A signaling client to join a WebRTC room, stream a video source and send data channel communication. */ -class StreamDataChannelClient extends SignalingClient { +class StreamDataChannelClient extends WebrtcClient { /** * @brief Creates a stream data channel client * @@ -85,7 +85,7 @@ class StreamDataChannelClient extends SignalingClient { let rtcPeerConnection = new window.RTCPeerConnection(this._rtcConfiguration); if (isCaller) { - let dataChannel = rtcPeerConnection.createDataChannel(this._signalingServerConfiguration.room, + let dataChannel = rtcPeerConnection.createDataChannel(this._signalingClient.room, this._dataChannelConfiguration); this._dataChannels[id] = dataChannel; this._connectDataChannelEvents(id, dataChannel); diff --git a/opentera-webrtc-web-client/src/SignalingClient.js b/opentera-webrtc-web-client/src/WebrtcClient.js similarity index 76% rename from opentera-webrtc-web-client/src/SignalingClient.js rename to opentera-webrtc-web-client/src/WebrtcClient.js index 2fc977eb..196e228c 100644 --- a/opentera-webrtc-web-client/src/SignalingClient.js +++ b/opentera-webrtc-web-client/src/WebrtcClient.js @@ -1,6 +1,4 @@ -import io from 'socket.io-client'; - -const SignalingProtocolVersion = 1; +import WebSocketSignalingClient from './Signaling/WebSocketSignalingClient'; function isPromise(obj) { return obj && typeof obj.then === 'function' && Object.prototype.toString.call(obj) === '[object Promise]'; @@ -9,7 +7,7 @@ function isPromise(obj) { /** * @brief Represents the base class of DataChannelClient, StreamClient and StreamDataChannelClient. */ -class SignalingClient { +class WebrtcClient { /** * @brief Creates a signaling client with the specified configurations. * @@ -27,8 +25,8 @@ class SignalingClient { * @param {CallableFunction} logger An optional logger callback */ constructor(signalingServerConfiguration, logger) { - if (this.constructor === SignalingClient) { - throw new TypeError('Abstract class "SignalingClient" cannot be instantiated directly.'); + if (this.constructor === WebrtcClient) { + throw new TypeError('Abstract class "WebrtcClient" cannot be instantiated directly.'); } if (this._createRtcPeerConnection === undefined) { throw new TypeError('_createRtcPeerConnection is missing.'); @@ -41,10 +39,8 @@ class SignalingClient { logger = () => {}; } - this._signalingServerConfiguration = signalingServerConfiguration; this._logger = logger; - this._socket = null; this._rtcPeerConnections = {}; this._clients = []; @@ -65,110 +61,53 @@ class SignalingClient { this._onClientDisconnect = () => {}; this._offerOptions = {}; - } - - /** - * @brief Connects the client the signaling server. - * @returns {Promise} - */ - async connect() { - this._logger('SignalingClient.connect method call'); - - let url = new URL(this._signalingServerConfiguration.url); - let path = url.pathname; - url = url.protocol + '//' + url.hostname + ':' + url.port; - if (path === '/') { - path = '/socket.io'; - } - - this._socket = io(url, {path: path}); - this._connectEvents(); - - await new Promise((resolve, reject) => { - this._socket.on('connect', () => { - this._logger('SignalingServer connect event'); - resolve(); - }); - this._socket.on('connect_error', error => { - this._logger('SignalingServer connect_error event'); - - reject(error); - }); - this._socket.on('connect_timeout', error => { - this._logger('SignalingServer connect_timeout event'); - - reject(error); - }); - }); - - let data = { - name: this._signalingServerConfiguration.name, - data: this._signalingServerConfiguration.data, - room: this._signalingServerConfiguration.room, - password: this._signalingServerConfiguration.password, - protocolVersion: SignalingProtocolVersion - }; - this._socket.emit('join-room', data, isJoined => { - this._logger('SignalingServer join-room event, isJoined=', isJoined); - if (isJoined) { - this._onSignalingConnectionOpen(); - } - else { - this.close(); - this._onSignalingConnectionError('Invalid password or invalid protocol version'); - } - }); + this._signalingClient = new WebSocketSignalingClient(signalingServerConfiguration, logger); + this._connectSignalingClientCallbacks(); } - _connectEvents() { - this._socket.on('disconnect', () => { - this._logger('SignalingServer disconnect event'); - - this._disconnect(); - }); + _connectSignalingClientCallbacks() { + this._signalingClient.onSignalingConnectionOpen = () => { this._onSignalingConnectionOpen(); }; + this._signalingClient.onSignalingConnectionClose = () => { this.close(); }; + this._signalingClient.onSignalingConnectionError = error => { + this.close(); + this._onSignalingConnectionError(error); + }; - this._socket.on('room-clients', clients => { + this._signalingClient.onRoomClientsChange = (clients) => { this._logger('SignalingServer room-clients event, clients=', clients); this._clients = clients; this._updateClientNamesById(clients); this._updateClientDatumById(clients); this._onRoomClientsChange(this._addConnectionStateToClients(this._clients)); - }); + }; - this._socket.on('make-peer-call', async ids => await this._makePeerCall(ids)); - this._socket.on('peer-call-received', async data => await this._peerCallReceived(data)); - this._socket.on('peer-call-answer-received', async data => await this._peerCallAnswerReceived(data)); - this._socket.on('close-all-peer-connections-request-received', () => { - this._logger('SignalingServer close-all-peer-connections-request-received event'); + this._signalingClient.makePeerCall = ids => { this._makePeerCall(ids); }; + this._signalingClient.peerCallReceived = data => { this._peerCallReceived(data); }; + this._signalingClient.peerCallAnswerReceived = data => { this._peerCallAnswerReceived(data); }; + this._signalingClient.iceCandidateReceived = data => { this._addIceCandidate(data); }; + this._signalingClient.closeAllPeerConnections = () => { + this._logger('SignalingServer close-all-peer-connections-request-received event'); this.hangUpAll(); - }); - - this._socket.on('ice-candidate-received', async data => await this._addIceCandidate(data)); + }; } - _disconnectEvents() { - this._socket.off('connect'); - this._socket.off('connect_error'); - this._socket.off('connect_timeout'); - this._socket.off('disconnect'); - - this._socket.off('room-clients'); + /** + * @brief Connects the client the signaling server. + * @returns {Promise} + */ + async connect() { + this._logger('WebrtcClient.connect method call'); + await this._signalingClient.connect(); + } - this._socket.off('make-peer-call'); - this._socket.off('peer-call-received'); - this._socket.off('peer-call-answer-received'); + _disconnect() { + this._signalingClient.disconnect(); this._getAllRtcPeerConnection().forEach(c => this._disconnectRtcPeerConnectionEvents(c)); - this._socket.off('ice-candidate'); - } - _disconnect() { - this._disconnectEvents(); - this._socket.close(); - this._socket = null; this._clients = []; this._alreadyAcceptedCalls = []; this.close(); @@ -188,12 +127,10 @@ class SignalingClient { let answer = await rtcPeerConnection.createAnswer(); await rtcPeerConnection.setLocalDescription(new window.RTCSessionDescription(answer)); - data = { toId: data.fromId, answer: answer }; - this._socket.emit('make-peer-call-answer', data); + this._signalingClient.makePeerCallAnswer(data.fromId, answer); } else { - data = { toId: data.fromId }; - this._socket.emit('make-peer-call-answer', data); + this._signalingClient.rejectCall(data.fromId); } } @@ -221,7 +158,7 @@ class SignalingClient { async _makePeerCall(ids) { this._logger('SignalingServer make-peer-call event, ids=', ids); - ids = ids.filter(id => id != this._socket.id); + ids = ids.filter(id => id != this.id); ids.forEach(async id => { if (this._hasRtcPeerConnection(id)) { return; @@ -235,8 +172,7 @@ class SignalingClient { let offer = await rtcPeerConnection.createOffer(this._offerOptions); await rtcPeerConnection.setLocalDescription(new RTCSessionDescription(offer)); - let data = { toId: id, offer: offer }; - this._socket.emit('call-peer', data); + this._signalingClient.callPeer(id, offer); } else { this._onCallReject(id, this.getClientName(id), this.getClientData(id)); @@ -258,8 +194,7 @@ class SignalingClient { _connectRtcPeerConnectionEvents(id, rtcPeerConnection) { rtcPeerConnection.onicecandidate = event => { - let data = { toId: id, candidate: event.candidate }; - this._socket.emit('send-ice-candidate', data); + this._signalingClient.sendIceCandidate(id, event.candidate); }; rtcPeerConnection.onconnectionstatechange = () => { @@ -351,7 +286,7 @@ class SignalingClient { * @brief Closes all client connections */ close() { - if (this._socket !== null) { + if (this._signalingClient.isConnected) { this._disconnect(); } // The RTC peer connections need to close after the socket because of socket can create a RTC connection after @@ -363,10 +298,10 @@ class SignalingClient { * @brief Calls all room clients. */ callAll() { - this._logger('SignalingClient.callAll method call'); + this._logger('WebrtcClient.callAll method call'); this._alreadyAcceptedCalls = this._clients.map(client => client.id); - this._socket.emit('call-all'); + this._signalingClient.callAll(); } /** @@ -374,17 +309,17 @@ class SignalingClient { * @param {Array} ids The client ids to call */ callIds(ids) { - this._logger('SignalingClient.callIds method call, ids=', ids); + this._logger('WebrtcClient.callIds method call, ids=', ids); this._alreadyAcceptedCalls = ids; - this._socket.emit('call-ids', ids); + this._signalingClient.callIds(ids); } /** * @brief Hangs up all clients. */ hangUpAll() { - this._logger('SignalingClient.hangUpAll method call'); + this._logger('WebrtcClient.hangUpAll method call'); this._closeAllRtcPeerConnections(); this.updateRoomClients(); @@ -394,9 +329,9 @@ class SignalingClient { * @brief Closes all room peer connections. */ closeAllRoomPeerConnections() { - this._logger('SignalingClient.closeAllRoomPeerConnections method call'); + this._logger('WebrtcClient.closeAllRoomPeerConnections method call'); - this._socket.emit('close-all-room-peer-connections'); + this._signalingClient.closeAllRoomPeerConnections(); } /** @@ -422,7 +357,7 @@ class SignalingClient { * @return {Boolean} true if the client is connected to the signaling server */ get isConnected() { - return this._socket !== null; + return this._signalingClient.isConnected; } /** @@ -438,12 +373,7 @@ class SignalingClient { * @return {String} The client id */ get id() { - if (this._socket !== null) { - return this._socket.id; - } - else { - return null; - } + return this._signalingClient.sessionId; } /** @@ -584,4 +514,4 @@ class SignalingClient { } } -export default SignalingClient; +export default WebrtcClient; diff --git a/signaling-server/opentera_webrtc/signaling_server/room_manager.py b/signaling-server/opentera_webrtc/signaling_server/room_manager.py index 0b938094..042555ff 100644 --- a/signaling-server/opentera_webrtc/signaling_server/room_manager.py +++ b/signaling-server/opentera_webrtc/signaling_server/room_manager.py @@ -2,16 +2,17 @@ class RoomManager: - def __init__(self, sio): - self._sio = sio + def __init__(self, web_socket_client_manager): + self._web_socket_client_manager = web_socket_client_manager self._room_by_id = {} self._ids_by_room = {} self._client_name_by_id = {} self._client_datum_by_id = {} - self._lock = asyncio.Lock() + self._lock = None async def add_client(self, id, client_name, client_data, room): + self._create_lock_if_none() async with self._lock: if id in self._room_by_id: return @@ -28,6 +29,7 @@ async def add_client(self, id, client_name, client_data, room): self._client_datum_by_id[id] = client_data async def remove_client(self, id): + self._create_lock_if_none() async with self._lock: if id in self._room_by_id: room = self._room_by_id[id] @@ -45,6 +47,7 @@ async def remove_client(self, id): del self._client_datum_by_id[id] async def get_room(self, id): + self._create_lock_if_none() async with self._lock: if id in self._room_by_id: return self._room_by_id[id] @@ -52,6 +55,7 @@ async def get_room(self, id): return None async def list_clients(self, room): + self._create_lock_if_none() async with self._lock: if room in self._ids_by_room: clients = [] @@ -66,24 +70,22 @@ async def list_clients(self, room): else: return [] - async def send_to_all(self, event, data=None, room=None, skip_id=None): + async def send_to_all(self, message, room=None, skip_id=None): if room == None: - await self._sio.emit(event, data) + await self._web_socket_client_manager.send_to_all(message) else: - tasks = [] clients = await self.list_clients(room) - - for client in clients: - if client['id'] != skip_id: - tasks.append(asyncio.create_task(self._sio.emit(event, data, to=client['id']))) - - if tasks == []: - return - await asyncio.wait(tasks) + ids = [c['id'] for c in clients if c['id'] != skip_id] + await self._web_socket_client_manager.send_to(message, ids) async def get_client_name(self, id): + self._create_lock_if_none() async with self._lock: if id in self._client_name_by_id: return self._client_name_by_id[id] else: return None + + def _create_lock_if_none(self): + if self._lock is None: + self._lock = asyncio.Lock() diff --git a/signaling-server/opentera_webrtc/signaling_server/signaling_server.py b/signaling-server/opentera_webrtc/signaling_server/signaling_server.py index 38100a27..c3f0fc20 100755 --- a/signaling-server/opentera_webrtc/signaling_server/signaling_server.py +++ b/signaling-server/opentera_webrtc/signaling_server/signaling_server.py @@ -10,13 +10,13 @@ from pathlib import Path from typing import Union -from aiohttp import web +from aiohttp import web, WSMsgType from aiohttp_index import IndexMiddleware -import socketio import ssl from opentera_webrtc.signaling_server.room_manager import RoomManager +from opentera_webrtc.signaling_server.web_socket_client_manager import WebSocketClientManager PROTOCOL_VERSION = 1 DISCONNECT_DELAY_S = 1 @@ -35,10 +35,10 @@ async def cors_middleware(request, handler): logging.basicConfig(format='[%(asctime)s] -- %(message)s') logger = logging.getLogger('signaling_server') -sio = socketio.AsyncServer(async_mode='aiohttp', logger=False, engineio_logger=False, cors_allowed_origins='*') app = web.Application(middlewares=[IndexMiddleware(), cors_middleware]) -room_manager = RoomManager(sio) +web_socket_client_manager = WebSocketClientManager() +room_manager = RoomManager(web_socket_client_manager) password = None ice_servers = [] @@ -46,7 +46,7 @@ async def cors_middleware(request, handler): async def disconnect_delayed(id): await asyncio.sleep(DISCONNECT_DELAY_S) - await sio.disconnect(id) + await web_socket_client_manager.close(id) async def disconnect_inactive_user(id): @@ -55,51 +55,98 @@ async def disconnect_inactive_user(id): room = await room_manager.get_room(id) if room is None: logger.info('inactive: %s', id) - await sio.disconnect(id) + await web_socket_client_manager.close(id) -@sio.on('connect') -async def connect(id, env): +def event_to_message(event, data=None): + if data is None: + message = {'event': event} + else: + message = {'event': event, 'data': data} + + return json.dumps(message) + + +async def web_socket_handler(request): + ws = web.WebSocketResponse() + await ws.prepare(request) + + id = await web_socket_client_manager.add_ws(ws) logger.info('connect %s', id) - # Launch task to verify if client joins a room (active), otherwise disconnect client. asyncio.create_task(disconnect_inactive_user(id)) + async for msg in ws: + if msg.type == WSMsgType.TEXT: + try: + data = json.loads(msg.data) + await handle_web_socket_message(id, data) + except Exception as e: + logger.error('Message error (%s): %s', id, str(e)) -@sio.on('disconnect') -async def disconnect(id): logger.info('disconnect %s (%s)', id, await room_manager.get_client_name(id)) + await web_socket_client_manager.close(id) room = await room_manager.get_room(id) await room_manager.remove_client(id) if room is not None: clients = await room_manager.list_clients(room) - await room_manager.send_to_all('room-clients', data=clients, room=room) + await room_manager.send_to_all(event_to_message('room-clients', clients), room=room) + return ws -@sio.on('join-room') -async def join_room(id, data): + +async def handle_web_socket_message(id, data): + if 'event' not in data: + logger.error('Invalid message (%s): %s', id, str(data)) + return + + event = data['event'] + if 'data' not in data: + data = {} + else: + data = data['data'] + + if event == 'join-room': + await handle_join_room(id, data) + elif event == 'send-ice-candidate': + await handle_ice_candidate(id, data) + elif event == 'call-peer': + await handle_call_peer(id, data) + elif event == 'make-peer-call-answer': + await handle_make_call_answer(id, data) + elif event == 'call-all': + await handle_call_all(id) + elif event == 'call-ids': + await handle_call_ids(id, data) + elif event == 'close-all-room-peer-connections': + await handle_close_all_peer_connections(id) + else: + logger.error('Not handled message (%s): %s: %s', id, event, str(data)) + + +async def handle_join_room(id, data): logger.info('join_room %s (%s)', id, data) if not _isAuthorized(data['password'] if 'password' in data else ''): asyncio.create_task(disconnect_delayed(id)) - return False + await web_socket_client_manager.send_to(event_to_message('join-room-answer', ''), id) + return if (data['protocolVersion'] if 'protocolVersion' in data else 0) != PROTOCOL_VERSION: asyncio.create_task(disconnect_delayed(id)) - return False + await web_socket_client_manager.send_to(event_to_message('join-room-answer', ''), id) + return if 'data' not in data: data['data'] = {} - await room_manager.add_client(id, data['name'], data['data'], data['room']) + await web_socket_client_manager.send_to(event_to_message('join-room-answer', id), id) + await room_manager.add_client(id, data['name'], data['data'], data['room']) clients = await room_manager.list_clients(data['room']) - await room_manager.send_to_all('room-clients', data=clients, room=data['room']) - - return True + await room_manager.send_to_all(event_to_message('room-clients', clients), room=data['room']) -@sio.on('send-ice-candidate') -async def ice_candidate(from_id, data): +async def handle_ice_candidate(from_id, data): from_name = await room_manager.get_client_name(from_id) to_name = await room_manager.get_client_name(data['toId']) logger.info('send-ice-candidate %s (%s) to %s (%s)', from_id, from_name, data['toId'], to_name) @@ -108,11 +155,10 @@ async def ice_candidate(from_id, data): if room1 is not None and room1 == room2: data['fromId'] = from_id - await sio.emit('ice-candidate-received', data, to=data['toId']) + await web_socket_client_manager.send_to(event_to_message('ice-candidate-received', data), data['toId']) -@sio.on('call-peer') -async def call_peer(from_id, data): +async def handle_call_peer(from_id, data): from_name = await room_manager.get_client_name(from_id) to_name = await room_manager.get_client_name(data['toId']) logger.info('call %s (%s) to %s (%s)', from_id, from_name, data['toId'], to_name) @@ -121,11 +167,10 @@ async def call_peer(from_id, data): if room1 is not None and room1 == room2: data['fromId'] = from_id - await sio.emit('peer-call-received', data, to=data['toId']) + await web_socket_client_manager.send_to(event_to_message('peer-call-received', data), data['toId']) -@sio.on('make-peer-call-answer') -async def make_call_answer(from_id, data): +async def handle_make_call_answer(from_id, data): from_name = await room_manager.get_client_name(from_id) to_name = await room_manager.get_client_name(data['toId']) logger.info('make-peer-call-answer %s (%s) to %s (%s)', from_id, from_name, data['toId'], to_name) @@ -134,11 +179,10 @@ async def make_call_answer(from_id, data): if room1 is not None and room1 == room2: data['fromId'] = from_id - await sio.emit('peer-call-answer-received', data, to=data['toId']) + await web_socket_client_manager.send_to(event_to_message('peer-call-answer-received', data), data['toId']) -@sio.on('call-all') -async def call_all(from_id): +async def handle_call_all(from_id): logger.info('call-all %s (%s)', from_id, await room_manager.get_client_name(from_id)) room = await room_manager.get_room(from_id) @@ -148,8 +192,7 @@ async def call_all(from_id): await _make_peer_calls(ids) -@sio.on('call-ids') -async def call_ids(from_id, ids): +async def handle_call_ids(from_id, ids): names = [(id, await room_manager.get_client_name(id)) for id in ids] logger.info('call-ids %s (%s) %s', from_id, await room_manager.get_client_name(from_id), names) room = await room_manager.get_room(from_id) @@ -168,17 +211,16 @@ async def _make_peer_calls(ids): tasks = [] for id in ids: ids_to_call = [c[1] for c in combinations if c[0] == id] - tasks.append(sio.emit('make-peer-call', ids_to_call, to=id)) + tasks.append(web_socket_client_manager.send_to(event_to_message('make-peer-call', ids_to_call), id)) await asyncio.gather(*tasks) -@sio.on('close-all-room-peer-connections') -async def close_all_peer_connections(from_id): +async def handle_close_all_peer_connections(from_id): logger.info('close-all-room-peer-connections %s (%s)', from_id, await room_manager.get_client_name(from_id)) room = await room_manager.get_room(from_id) if room is not None: - await room_manager.send_to_all('close-all-peer-connections-request-received', room=room) + await room_manager.send_to_all(event_to_message('close-all-peer-connections-request-received'), room=room) async def get_ice_servers(request: web.Request): @@ -196,6 +238,7 @@ class ExpandUserPath: def __new__(cls, path: Union[str, Path]) -> Path: return Path(path).expanduser().resolve() + class Args: port: int password: str @@ -248,11 +291,9 @@ def main(): global ice_servers ice_servers = json.load(file) - # Make sure websocket path is defined - sio.attach(app, socketio_path=args.socketio_path) - # Create route to get iceservers - app.add_routes([web.get('/iceservers', get_ice_servers)]) + app.add_routes([web.get('/iceservers', get_ice_servers), + web.get('/signaling', web_socket_handler)]) # Create static route if required if args.static_folder is not None: diff --git a/signaling-server/opentera_webrtc/signaling_server/web_socket_client_manager.py b/signaling-server/opentera_webrtc/signaling_server/web_socket_client_manager.py new file mode 100644 index 00000000..eb78fd55 --- /dev/null +++ b/signaling-server/opentera_webrtc/signaling_server/web_socket_client_manager.py @@ -0,0 +1,65 @@ +import uuid + +import asyncio + + +class WebSocketClientManager: + def __init__(self): + self._ws_by_id = {} + + self._lock = None + + async def add_ws(self, ws): + self._create_lock_if_none() + async with self._lock: + id = self._generate_id() + self._ws_by_id[id] = ws + return id + + async def close(self, id): + self._create_lock_if_none() + async with self._lock: + if id in self._ws_by_id: + await self._ws_by_id[id].close() + del self._ws_by_id[id] + + async def send_to(self, message, ids): + if isinstance(ids, str): + ids = [ids] + + self._create_lock_if_none() + async with self._lock: + tasks = [] + + for id in ids: + if id in self._ws_by_id and not self._ws_by_id[id].closed: + tasks.append(asyncio.create_task(self._ws_by_id[id].send_str(message))) + + if len(tasks) == 0: + return + await asyncio.wait(tasks) + + async def send_to_all(self, message): + self._create_lock_if_none() + async with self._lock: + tasks = [] + + for ws in self._ws_by_id.values(): + if not ws.closed: + tasks.append(asyncio.create_task(ws.send_str(message))) + + if len(tasks) == 0: + return + await asyncio.wait(tasks) + + async def list_ids(self): + self._create_lock_if_none() + async with self._lock: + return list(self._ws_by_id.keys()) + + def _generate_id(self): + return str(uuid.uuid4()) + + def _create_lock_if_none(self): + if self._lock is None: + self._lock = asyncio.Lock() diff --git a/signaling-server/opentera_webrtc/tests/__init__.py b/signaling-server/opentera_webrtc/tests/__init__.py index e69de29b..737291d4 100644 --- a/signaling-server/opentera_webrtc/tests/__init__.py +++ b/signaling-server/opentera_webrtc/tests/__init__.py @@ -0,0 +1,14 @@ +import asyncio + +from typing import Optional + + +class AsyncRunner: + def __init__(self, event_loop: Optional[asyncio.BaseEventLoop] = None) -> None: + self.loop = event_loop or asyncio.new_event_loop() + + def run_async(self, coroutine): + return self.loop.run_until_complete(coroutine) + + def __del__(self): + self.loop.close() diff --git a/signaling-server/opentera_webrtc/tests/test_room_manager.py b/signaling-server/opentera_webrtc/tests/test_room_manager.py index f7b375ce..b1996bd3 100644 --- a/signaling-server/opentera_webrtc/tests/test_room_manager.py +++ b/signaling-server/opentera_webrtc/tests/test_room_manager.py @@ -1,25 +1,37 @@ -import asyncio import unittest -from typing import Optional - from signaling_server.room_manager import RoomManager +from tests import AsyncRunner -class AsyncRunner: - def __init__(self, event_loop: Optional[asyncio.BaseEventLoop] = None) -> None: - self.loop = event_loop or asyncio.new_event_loop() +class WebSocketClientManagerMock: + def __init__(self): + self.messages = [] - def run_async(self, coroutine): - return self.loop.run_until_complete(coroutine) + async def add_ws(self, ws): + raise NotImplementedError() - def __del__(self): - self.loop.close() + async def close(self, id): + raise NotImplementedError() + async def send_to(self, message, ids): + if isinstance(ids, str): + ids = [ids] -class SioMock: - def __init__(self): - self.messages = [] + for id in ids: + self.messages.append({ + 'message': message, + 'to': id + }) + + async def send_to_all(self, message): + self.messages.append({ + 'message': message, + 'to': None + }) + + async def list_ids(self): + raise NotImplementedError() async def emit(self, event, data, to=None): self.messages.append({ @@ -34,96 +46,68 @@ def _run_async(self, coroutine): return self.sync_runner.run_async(coroutine) def setUp(self): - self._sio_mock = SioMock() - self._room_manager = RoomManager(self._sio_mock) + self._web_socket_client_manager_mock = WebSocketClientManagerMock() + self._room_manager = RoomManager(self._web_socket_client_manager_mock) self.sync_runner = AsyncRunner() def test_get_room(self): - self._run_async(self._room_manager.add_client( - 'id1', 'name1', 'data1', 'room1')) - self._run_async(self._room_manager.add_client( - 'id2', 'name2', 'data2', 'room2')) + self._run_async(self._room_manager.add_client('id1', 'name1', 'data1', 'room1')) + self._run_async(self._room_manager.add_client('id2', 'name2', 'data2', 'room2')) - self.assertEqual(self._run_async( - self._room_manager.get_room('id1')), 'room1') - self.assertEqual(self._run_async( - self._room_manager.get_room('id2')), 'room2') + self.assertEqual(self._run_async(self._room_manager.get_room('id1')), 'room1') + self.assertEqual(self._run_async(self._room_manager.get_room('id2')), 'room2') self.assertEqual(self._run_async( self._room_manager.get_room('id3')), None) def test_list_clients(self): - self._run_async(self._room_manager.add_client( - 'id1', 'name1', 'data1', 'room1')) - self._run_async(self._room_manager.add_client( - 'id2', 'name2', 'data2', 'room1')) + self._run_async(self._room_manager.add_client('id1', 'name1', 'data1', 'room1')) + self._run_async(self._room_manager.add_client('id2', 'name2', 'data2', 'room1')) clients = self._run_async(self._room_manager.list_clients('room1')) self.assertEqual(len(clients), 2) - self.assertEqual( - clients[0], {'id': 'id1', 'name': 'name1', 'data': 'data1'}) - self.assertEqual( - clients[1], {'id': 'id2', 'name': 'name2', 'data': 'data2'}) + self.assertEqual(clients[0], {'id': 'id1', 'name': 'name1', 'data': 'data1'}) + self.assertEqual(clients[1], {'id': 'id2', 'name': 'name2', 'data': 'data2'}) def test_remove_client(self): - self._run_async(self._room_manager.add_client( - 'id1', 'name1', 'data1', 'room1')) + self._run_async(self._room_manager.add_client('id1', 'name1', 'data1', 'room1')) - self.assertEqual(self._run_async( - self._room_manager.get_room('id1')), 'room1') + self.assertEqual(self._run_async(self._room_manager.get_room('id1')), 'room1') clients = self._run_async(self._room_manager.list_clients('room1')) self.assertEqual(len(clients), 1) - self.assertEqual( - clients[0], {'id': 'id1', 'name': 'name1', 'data': 'data1'}) + self.assertEqual(clients[0], {'id': 'id1', 'name': 'name1', 'data': 'data1'}) self._run_async(self._room_manager.remove_client('id1')) - self.assertEqual(self._run_async( - self._room_manager.get_room('id1')), None) + self.assertEqual(self._run_async(self._room_manager.get_room('id1')), None) clients = self._run_async(self._room_manager.list_clients('room1')) self.assertEqual(len(clients), 0) def test_send_to_all(self): - self._run_async(self._room_manager.add_client( - 'id1', 'name1', 'data1', 'room1')) - self._run_async(self._room_manager.add_client( - 'id2', 'name2', 'data2', 'room1')) - self._run_async(self._room_manager.add_client( - 'id3', 'name3', 'data3', 'room2')) - - self._run_async(self._room_manager.send_to_all('event1', 'data1')) - self._run_async(self._room_manager.send_to_all( - 'event2', 'data2', room='room1')) - self._run_async(self._room_manager.send_to_all( - 'event3', 'data3', room='room1', skip_id='id1')) - - self.assertEqual(len(self._sio_mock.messages), 4) - self.assertTrue({'event': 'event1', 'data': 'data1', - 'to': None} in self._sio_mock.messages) - self.assertTrue({'event': 'event2', 'data': 'data2', - 'to': 'id1'} in self._sio_mock.messages) - self.assertTrue({'event': 'event2', 'data': 'data2', - 'to': 'id2'} in self._sio_mock.messages) - self.assertTrue({'event': 'event3', 'data': 'data3', - 'to': 'id2'} in self._sio_mock.messages) + self._run_async(self._room_manager.add_client('id1', 'name1', 'data1', 'room1')) + self._run_async(self._room_manager.add_client('id2', 'name2', 'data2', 'room1')) + self._run_async(self._room_manager.add_client('id3', 'name3', 'data3', 'room2')) - def test_get_client_name(self): - self._run_async(self._room_manager.add_client( - 'id1', 'name1', 'data1', 'room1')) - self._run_async(self._room_manager.add_client( - 'id2', 'name2', 'data2', 'room1')) - self._run_async(self._room_manager.add_client( - 'id3', 'name3', 'data3', 'room2')) + self._run_async(self._room_manager.send_to_all('message1')) + self._run_async(self._room_manager.send_to_all('message2', room='room1')) + self._run_async(self._room_manager.send_to_all('message3', room='room1', skip_id='id1')) - self.assertEqual(self._run_async( - self._room_manager.get_client_name('id1')), 'name1') - self.assertEqual(self._run_async( - self._room_manager.get_client_name('id2')), 'name2') - self.assertEqual(self._run_async( - self._room_manager.get_client_name('id3')), 'name3') - self.assertEqual(self._run_async( - self._room_manager.get_client_name('id4')), None) + self.assertEqual(len(self._web_socket_client_manager_mock.messages), 4) + self.assertTrue({'message': 'message1', 'to': None} in self._web_socket_client_manager_mock.messages) + self.assertTrue({'message': 'message2', 'to': 'id1'} in self._web_socket_client_manager_mock.messages) + self.assertTrue({'message': 'message2', 'to': 'id2'} in self._web_socket_client_manager_mock.messages) + self.assertTrue({'message': 'message3', 'to': 'id2'} in self._web_socket_client_manager_mock.messages) + + def test_get_client_name(self): + self._run_async(self._room_manager.add_client('id1', 'name1', 'data1', 'room1')) + self._run_async(self._room_manager.add_client('id2', 'name2', 'data2', 'room1')) + self._run_async(self._room_manager.add_client('id3', 'name3', 'data3', 'room2')) + + self.assertEqual(self._run_async(self._room_manager.get_client_name('id1')), 'name1') + self.assertEqual(self._run_async(self._room_manager.get_client_name('id2')), 'name2') + self.assertEqual(self._run_async(self._room_manager.get_client_name('id3')), 'name3') + self.assertEqual(self._run_async(self._room_manager.get_client_name('id4')), None) if __name__ == '__main__': diff --git a/signaling-server/opentera_webrtc/tests/test_web_socket_client_manager.py b/signaling-server/opentera_webrtc/tests/test_web_socket_client_manager.py new file mode 100644 index 00000000..6c234e91 --- /dev/null +++ b/signaling-server/opentera_webrtc/tests/test_web_socket_client_manager.py @@ -0,0 +1,72 @@ +import unittest + +from signaling_server.web_socket_client_manager import WebSocketClientManager +from tests import AsyncRunner + + +class WsMock: + def __init__(self): + self._closed = False + self.messages = [] + + async def send_str(self, message): + self.messages.append(message) + + async def close(self): + self._closed = True + + @property + def closed(self): + return self._closed + + +class TestRoomManager(unittest.TestCase): + def _run_async(self, coroutine): + return self.sync_runner.run_async(coroutine) + + def setUp(self): + self._ws_manager = WebSocketClientManager() + self.sync_runner = AsyncRunner() + + def test_add_ws(self): + id1 = self._run_async(self._ws_manager.add_ws(WsMock())) + id2 = self._run_async(self._ws_manager.add_ws(WsMock())) + + self.assertNotEqual(id1, id2) + + ids = self._run_async(self._ws_manager.list_ids()) + self.assertEqual(len(ids), 2) + self.assertIn(id1, ids) + self.assertIn(id2, ids) + + def test_close(self): + ws = WsMock() + id = self._run_async(self._ws_manager.add_ws(ws)) + self.assertIn(id, self._run_async(self._ws_manager.list_ids())) + self.assertFalse(ws.closed) + + self._run_async(self._ws_manager.close(id)) + self.assertNotIn(id, self._run_async(self._ws_manager.list_ids())) + self.assertTrue(ws.closed) + + def test_send_to_send_to_all(self): + ws1 = WsMock() + ws2 = WsMock() + ws3 = WsMock() + ws4 = WsMock() + self._run_async(ws4.close()) + + id1 = self._run_async(self._ws_manager.add_ws(ws1)) + id2 = self._run_async(self._ws_manager.add_ws(ws2)) + id3 = self._run_async(self._ws_manager.add_ws(ws3)) + id4 = self._run_async(self._ws_manager.add_ws(ws4)) + + self._run_async(self._ws_manager.send_to('message1', [id1, id2])) + self._run_async(self._ws_manager.send_to('message2', id3)) + self._run_async(self._ws_manager.send_to('message3', id4)) + self._run_async(self._ws_manager.send_to_all('message4')) + + self.assertEqual(ws1.messages, ['message1', 'message4']) + self.assertEqual(ws2.messages, ['message1', 'message4']) + self.assertEqual(ws3.messages, ['message2', 'message4']) + self.assertEqual(ws4.messages, []) diff --git a/signaling-server/requirements.txt b/signaling-server/requirements.txt index f5076980..3aafc386 100644 --- a/signaling-server/requirements.txt +++ b/signaling-server/requirements.txt @@ -1,3 +1,2 @@ -python-socketio==5.7.2 aiohttp==3.8.5 aiohttp_index==0.1