diff --git a/CMakeLists.txt b/CMakeLists.txt index 1090e1a..f0bfc12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,8 +91,9 @@ set(LIBDATACHANNEL_HEADERS set(TESTS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test/main.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/connectivity.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/test/capi.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/track.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test/capi_connectivity.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test/capi_track.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/websocket.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/benchmark.cpp ) diff --git a/test/capi.cpp b/test/capi_connectivity.cpp similarity index 96% rename from test/capi.cpp rename to test/capi_connectivity.cpp index 715fce8..6082ac4 100644 --- a/test/capi.cpp +++ b/test/capi_connectivity.cpp @@ -37,8 +37,8 @@ typedef struct { bool connected; } Peer; -Peer *peer1 = NULL; -Peer *peer2 = NULL; +static Peer *peer1 = NULL; +static Peer *peer2 = NULL; static void descriptionCallback(const char *sdp, const char *type, void *ptr) { Peer *peer = (Peer *)ptr; @@ -132,7 +132,7 @@ static void deletePeer(Peer *peer) { } } -int test_capi_main() { +int test_capi_connectivity_main() { int attempts; rtcInitLogger(RTC_LOG_DEBUG, nullptr); @@ -170,7 +170,7 @@ int test_capi_main() { rtcSetMessageCallback(peer1->dc, messageCallback); attempts = 10; - while (!peer2->connected && !peer1->connected && attempts--) + while ((!peer2->connected || !peer1->connected) && attempts--) sleep(1); if (peer1->state != RTC_CONNECTED || peer2->state != RTC_CONNECTED) { @@ -213,7 +213,7 @@ error: #include -void test_capi() { - if (test_capi_main()) +void test_capi_connectivity() { + if (test_capi_connectivity_main()) throw std::runtime_error("Connection failed"); } diff --git a/test/capi_track.cpp b/test/capi_track.cpp new file mode 100644 index 0000000..3983a75 --- /dev/null +++ b/test/capi_track.cpp @@ -0,0 +1,198 @@ +/** + * Copyright (c) 2020 Paul-Louis Ageneau + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include +#include + +#ifdef _WIN32 +#include +static void sleep(unsigned int secs) { Sleep(secs * 1000); } +#else +#include // for sleep +#endif + +typedef struct { + rtcState state; + rtcGatheringState gatheringState; + int pc; + int tr; + bool connected; +} Peer; + +static Peer *peer1 = NULL; +static Peer *peer2 = NULL; + +static const char *mediaDescription = "video 9 UDP/TLS/RTP/SAVPF\r\n" + "a=mid:video\r\n"; + +static void descriptionCallback(const char *sdp, const char *type, void *ptr) { + Peer *peer = (Peer *)ptr; + printf("Description %d:\n%s\n", peer == peer1 ? 1 : 2, sdp); + Peer *other = peer == peer1 ? peer2 : peer1; + rtcSetRemoteDescription(other->pc, sdp, type); +} + +static void candidateCallback(const char *cand, const char *mid, void *ptr) { + Peer *peer = (Peer *)ptr; + printf("Candidate %d: %s\n", peer == peer1 ? 1 : 2, cand); + Peer *other = peer == peer1 ? peer2 : peer1; + rtcAddRemoteCandidate(other->pc, cand, mid); +} + +static void stateChangeCallback(rtcState state, void *ptr) { + Peer *peer = (Peer *)ptr; + peer->state = state; + printf("State %d: %d\n", peer == peer1 ? 1 : 2, (int)state); +} + +static void gatheringStateCallback(rtcGatheringState state, void *ptr) { + Peer *peer = (Peer *)ptr; + peer->gatheringState = state; + printf("Gathering state %d: %d\n", peer == peer1 ? 1 : 2, (int)state); +} + +static void openCallback(void *ptr) { + Peer *peer = (Peer *)ptr; + peer->connected = true; + printf("Track %d: Open\n", peer == peer1 ? 1 : 2); +} + +static void closedCallback(void *ptr) { + Peer *peer = (Peer *)ptr; + peer->connected = false; +} + +static void trackCallback(int tr, void *ptr) { + Peer *peer = (Peer *)ptr; + peer->tr = tr; + peer->connected = true; + rtcSetClosedCallback(tr, closedCallback); + + char buffer[1024]; + if (rtcGetTrackDescription(tr, buffer, 1024) >= 0) + printf("Track %d: Received with media description: \n%s\n", peer == peer1 ? 1 : 2, buffer); +} + +static Peer *createPeer(const rtcConfiguration *config) { + Peer *peer = (Peer *)malloc(sizeof(Peer)); + if (!peer) + return nullptr; + memset(peer, 0, sizeof(Peer)); + + // Create peer connection + peer->pc = rtcCreatePeerConnection(config); + rtcSetUserPointer(peer->pc, peer); + rtcSetTrackCallback(peer->pc, trackCallback); + rtcSetLocalDescriptionCallback(peer->pc, descriptionCallback); + rtcSetLocalCandidateCallback(peer->pc, candidateCallback); + rtcSetStateChangeCallback(peer->pc, stateChangeCallback); + rtcSetGatheringStateChangeCallback(peer->pc, gatheringStateCallback); + + return peer; +} + +static void deletePeer(Peer *peer) { + if (peer) { + if (peer->tr) + rtcDeleteTrack(peer->tr); + if (peer->pc) + rtcDeletePeerConnection(peer->pc); + free(peer); + } +} + +int test_capi_track_main() { + int attempts; + + rtcInitLogger(RTC_LOG_DEBUG, nullptr); + + // Create peer 1 + rtcConfiguration config1; + memset(&config1, 0, sizeof(config1)); + // STUN server example + // const char *iceServers[1] = {"stun:stun.l.google.com:19302"}; + // config1.iceServers = iceServers; + // config1.iceServersCount = 1; + + peer1 = createPeer(&config1); + if (!peer1) + goto error; + + // Create peer 2 + rtcConfiguration config2; + memset(&config2, 0, sizeof(config2)); + // STUN server example + // config2.iceServers = iceServers; + // config2.iceServersCount = 1; + // Port range example + config2.portRangeBegin = 5000; + config2.portRangeEnd = 6000; + + peer2 = createPeer(&config2); + if (!peer2) + goto error; + + // Peer 1: Create track + peer1->tr = rtcCreateTrack(peer1->pc, mediaDescription); + rtcSetOpenCallback(peer1->tr, openCallback); + rtcSetClosedCallback(peer1->tr, closedCallback); + + // Initiate the handshake + rtcSetLocalDescription(peer1->pc); + + attempts = 10; + while ((!peer2->connected || !peer1->connected) && attempts--) + sleep(1); + + if (peer1->state != RTC_CONNECTED || peer2->state != RTC_CONNECTED) { + fprintf(stderr, "PeerConnection is not connected\n"); + goto error; + } + + if (!peer1->connected || !peer2->connected) { + fprintf(stderr, "Track is not connected\n"); + goto error; + } + + deletePeer(peer1); + sleep(1); + deletePeer(peer2); + sleep(1); + + // You may call rtcCleanup() when finished to free static resources + rtcCleanup(); + sleep(2); + + printf("Success\n"); + return 0; + +error: + deletePeer(peer1); + deletePeer(peer2); + return -1; +} + +#include + +void test_capi_track() { + if (test_capi_track_main()) + throw std::runtime_error("Connection failed"); +} diff --git a/test/main.cpp b/test/main.cpp index 72142b2..e335840 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -24,8 +24,9 @@ using namespace std; using namespace chrono_literals; void test_connectivity(); -void test_capi(); void test_track(); +void test_capi_connectivity(); +void test_capi_track(); void test_websocket(); size_t benchmark(chrono::milliseconds duration); @@ -50,11 +51,11 @@ int main(int argc, char **argv) { return -1; } try { - cout << endl << "*** Running WebRTC C API test..." << endl; - test_capi(); - cout << "*** Finished WebRTC C API test" << endl; + cout << endl << "*** Running WebRTC C API connectivity test..." << endl; + test_capi_connectivity(); + cout << "*** Finished WebRTC C API connectivity test" << endl; } catch (const exception &e) { - cerr << "WebRTC C API test failed: " << e.what() << endl; + cerr << "WebRTC C API connectivity test failed: " << e.what() << endl; return -1; } #if RTC_ENABLE_MEDIA @@ -66,6 +67,14 @@ int main(int argc, char **argv) { cerr << "WebRTC Track test failed: " << e.what() << endl; return -1; } + try { + cout << endl << "*** Running WebRTC C API track test..." << endl; + test_capi_track(); + cout << "*** Finished WebRTC C API track test" << endl; + } catch (const exception &e) { + cerr << "WebRTC C API track test failed: " << e.what() << endl; + return -1; + } #endif #if RTC_ENABLE_WEBSOCKET try {