mirror of
https://github.com/mii443/libdatachannel.git
synced 2025-08-31 11:29:28 +00:00
Added tests for C API
This commit is contained in:
@ -39,6 +39,7 @@ set(LIBDATACHANNEL_SOURCES
|
|||||||
set(TESTS_SOURCES
|
set(TESTS_SOURCES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/main.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test/main.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/connectivity.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/test/connectivity.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test/capi.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(TESTS_OFFERER_SOURCES
|
set(TESTS_OFFERER_SOURCES
|
||||||
|
9
Makefile
9
Makefile
@ -6,7 +6,7 @@ AR=$(CROSS)ar
|
|||||||
RM=rm -f
|
RM=rm -f
|
||||||
CXXFLAGS=-std=c++17
|
CXXFLAGS=-std=c++17
|
||||||
CPPFLAGS=-O2 -pthread -fPIC -Wall -Wno-address-of-packed-member
|
CPPFLAGS=-O2 -pthread -fPIC -Wall -Wno-address-of-packed-member
|
||||||
LDFLAGS=-pthread
|
LDFLAGS=-pthread -g
|
||||||
LIBS=
|
LIBS=
|
||||||
LOCALLIBS=libusrsctp.a
|
LOCALLIBS=libusrsctp.a
|
||||||
USRSCTP_DIR=deps/usrsctp
|
USRSCTP_DIR=deps/usrsctp
|
||||||
@ -44,6 +44,9 @@ LDLIBS+=$(LOCALLIBS) $(shell pkg-config --libs $(LIBS))
|
|||||||
SRCS=$(shell printf "%s " src/*.cpp)
|
SRCS=$(shell printf "%s " src/*.cpp)
|
||||||
OBJS=$(subst .cpp,.o,$(SRCS))
|
OBJS=$(subst .cpp,.o,$(SRCS))
|
||||||
|
|
||||||
|
TEST_SRCS=$(shell printf "%s " test/*.cpp)
|
||||||
|
TEST_OBJS=$(subst .cpp,.o,$(TEST_SRCS))
|
||||||
|
|
||||||
all: $(NAME).a $(NAME).so tests
|
all: $(NAME).a $(NAME).so tests
|
||||||
|
|
||||||
src/%.o: src/%.cpp
|
src/%.o: src/%.cpp
|
||||||
@ -60,8 +63,8 @@ $(NAME).a: $(OBJS)
|
|||||||
$(NAME).so: $(LOCALLIBS) $(OBJS)
|
$(NAME).so: $(LOCALLIBS) $(OBJS)
|
||||||
$(CXX) $(LDFLAGS) -shared -o $@ $(OBJS) $(LDLIBS)
|
$(CXX) $(LDFLAGS) -shared -o $@ $(OBJS) $(LDLIBS)
|
||||||
|
|
||||||
tests: $(NAME).a test/main.o
|
tests: $(NAME).a $(TEST_OBJS)
|
||||||
$(CXX) $(LDFLAGS) -o $@ test/main.o $(NAME).a $(LDLIBS)
|
$(CXX) $(LDFLAGS) -o $@ $(TEST_OBJS) $(NAME).a $(LDLIBS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-$(RM) include/rtc/*.d *.d
|
-$(RM) include/rtc/*.d *.d
|
||||||
|
@ -64,6 +64,7 @@ template <class... Ts> overloaded(Ts...)->overloaded<Ts...>;
|
|||||||
template <typename... P> class synchronized_callback {
|
template <typename... P> class synchronized_callback {
|
||||||
public:
|
public:
|
||||||
synchronized_callback() = default;
|
synchronized_callback() = default;
|
||||||
|
synchronized_callback(std::function<void(P...)> func) { *this = std::move(func); };
|
||||||
~synchronized_callback() { *this = nullptr; }
|
~synchronized_callback() { *this = nullptr; }
|
||||||
|
|
||||||
synchronized_callback &operator=(std::function<void(P...)> func) {
|
synchronized_callback &operator=(std::function<void(P...)> func) {
|
||||||
|
@ -52,12 +52,18 @@ typedef enum {
|
|||||||
RTC_LOG_VERBOSE = 6
|
RTC_LOG_VERBOSE = 6
|
||||||
} rtcLogLevel;
|
} rtcLogLevel;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char **iceServers;
|
||||||
|
int iceServersCount;
|
||||||
|
} rtcConfiguration;
|
||||||
|
|
||||||
typedef void (*dataChannelCallbackFunc)(int dc, void *ptr);
|
typedef void (*dataChannelCallbackFunc)(int dc, void *ptr);
|
||||||
typedef void (*descriptionCallbackFunc)(const char *sdp, const char *type, void *ptr);
|
typedef void (*descriptionCallbackFunc)(const char *sdp, const char *type, void *ptr);
|
||||||
typedef void (*candidateCallbackFunc)(const char *cand, const char *mid, void *ptr);
|
typedef void (*candidateCallbackFunc)(const char *cand, const char *mid, void *ptr);
|
||||||
typedef void (*stateChangeCallbackFunc)(rtcState state, void *ptr);
|
typedef void (*stateChangeCallbackFunc)(rtcState state, void *ptr);
|
||||||
typedef void (*gatheringStateCallbackFunc)(rtcGatheringState state, void *ptr);
|
typedef void (*gatheringStateCallbackFunc)(rtcGatheringState state, void *ptr);
|
||||||
typedef void (*openCallbackFunc)(void *ptr);
|
typedef void (*openCallbackFunc)(void *ptr);
|
||||||
|
typedef void (*closedCallbackFunc)(void *ptr);
|
||||||
typedef void (*errorCallbackFunc)(const char *error, void *ptr);
|
typedef void (*errorCallbackFunc)(const char *error, void *ptr);
|
||||||
typedef void (*messageCallbackFunc)(const char *message, int size, void *ptr);
|
typedef void (*messageCallbackFunc)(const char *message, int size, void *ptr);
|
||||||
typedef void (*bufferedAmountLowCallbackFunc)(void *ptr);
|
typedef void (*bufferedAmountLowCallbackFunc)(void *ptr);
|
||||||
@ -70,7 +76,7 @@ void rtcInitLogger(rtcLogLevel level);
|
|||||||
void rtcSetUserPointer(int i, void *ptr);
|
void rtcSetUserPointer(int i, void *ptr);
|
||||||
|
|
||||||
// PeerConnection
|
// PeerConnection
|
||||||
int rtcCreatePeerConnection(const char **iceServers, int iceServersCount);
|
int rtcCreatePeerConnection(const rtcConfiguration *config);
|
||||||
int rtcDeletePeerConnection(int pc);
|
int rtcDeletePeerConnection(int pc);
|
||||||
|
|
||||||
int rtcSetDataChannelCallback(int pc, dataChannelCallbackFunc cb);
|
int rtcSetDataChannelCallback(int pc, dataChannelCallbackFunc cb);
|
||||||
@ -88,6 +94,7 @@ int rtcDeleteDataChannel(int dc);
|
|||||||
|
|
||||||
int rtcGetDataChannelLabel(int dc, char *buffer, int size);
|
int rtcGetDataChannelLabel(int dc, char *buffer, int size);
|
||||||
int rtcSetOpenCallback(int dc, openCallbackFunc cb);
|
int rtcSetOpenCallback(int dc, openCallbackFunc cb);
|
||||||
|
int rtcSetClosedCallback(int dc, closedCallbackFunc cb);
|
||||||
int rtcSetErrorCallback(int dc, errorCallbackFunc cb);
|
int rtcSetErrorCallback(int dc, errorCallbackFunc cb);
|
||||||
int rtcSetMessageCallback(int dc, messageCallbackFunc cb);
|
int rtcSetMessageCallback(int dc, messageCallbackFunc cb);
|
||||||
int rtcSendMessage(int dc, const char *data, int size);
|
int rtcSendMessage(int dc, const char *data, int size);
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
#include "channel.hpp"
|
#include "channel.hpp"
|
||||||
|
|
||||||
namespace {}
|
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
|
|
||||||
size_t Channel::maxMessageSize() const { return DEFAULT_MAX_MESSAGE_SIZE; }
|
size_t Channel::maxMessageSize() const { return DEFAULT_MAX_MESSAGE_SIZE; }
|
||||||
|
91
src/rtc.cpp
91
src/rtc.cpp
@ -106,15 +106,28 @@ void rtcSetUserPointer(int i, void *ptr) {
|
|||||||
userPointerMap.erase(i);
|
userPointerMap.erase(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtcCreatePeerConnection(const char **iceServers, int iceServersCount) {
|
int rtcCreatePeerConnection(const rtcConfiguration *config) {
|
||||||
Configuration config;
|
Configuration c;
|
||||||
for (int i = 0; i < iceServersCount; ++i)
|
for (int i = 0; i < config->iceServersCount; ++i)
|
||||||
config.iceServers.emplace_back(IceServer(string(iceServers[i])));
|
c.iceServers.emplace_back(string(config->iceServers[i]));
|
||||||
|
|
||||||
return emplacePeerConnection(std::make_shared<PeerConnection>(config));
|
return emplacePeerConnection(std::make_shared<PeerConnection>(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtcDeletePeerConnection(int pc) { return erasePeerConnection(pc) ? 0 : -1; }
|
int rtcDeletePeerConnection(int pc) {
|
||||||
|
auto peerConnection = getPeerConnection(pc);
|
||||||
|
if (!peerConnection)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
peerConnection->onDataChannel(nullptr);
|
||||||
|
peerConnection->onLocalDescription(nullptr);
|
||||||
|
peerConnection->onLocalCandidate(nullptr);
|
||||||
|
peerConnection->onStateChange(nullptr);
|
||||||
|
peerConnection->onGatheringStateChange(nullptr);
|
||||||
|
|
||||||
|
erasePeerConnection(pc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int rtcCreateDataChannel(int pc, const char *label) {
|
int rtcCreateDataChannel(int pc, const char *label) {
|
||||||
auto peerConnection = getPeerConnection(pc);
|
auto peerConnection = getPeerConnection(pc);
|
||||||
@ -127,19 +140,36 @@ int rtcCreateDataChannel(int pc, const char *label) {
|
|||||||
return dc;
|
return dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtcDeleteDataChannel(int dc) { return eraseDataChannel(dc) ? 0 : -1; }
|
int rtcDeleteDataChannel(int dc) {
|
||||||
|
auto dataChannel = getDataChannel(dc);
|
||||||
|
if (!dataChannel)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
dataChannel->onOpen(nullptr);
|
||||||
|
dataChannel->onClosed(nullptr);
|
||||||
|
dataChannel->onError(nullptr);
|
||||||
|
dataChannel->onMessage(nullptr);
|
||||||
|
dataChannel->onBufferedAmountLow(nullptr);
|
||||||
|
dataChannel->onAvailable(nullptr);
|
||||||
|
|
||||||
|
eraseDataChannel(dc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int rtcSetDataChannelCallback(int pc, dataChannelCallbackFunc cb) {
|
int rtcSetDataChannelCallback(int pc, dataChannelCallbackFunc cb) {
|
||||||
auto peerConnection = getPeerConnection(pc);
|
auto peerConnection = getPeerConnection(pc);
|
||||||
if (!peerConnection)
|
if (!peerConnection)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (cb)
|
||||||
peerConnection->onDataChannel([pc, cb](std::shared_ptr<DataChannel> dataChannel) {
|
peerConnection->onDataChannel([pc, cb](std::shared_ptr<DataChannel> dataChannel) {
|
||||||
int dc = emplaceDataChannel(dataChannel);
|
int dc = emplaceDataChannel(dataChannel);
|
||||||
void *ptr = getUserPointer(pc);
|
void *ptr = getUserPointer(pc);
|
||||||
rtcSetUserPointer(dc, ptr);
|
rtcSetUserPointer(dc, ptr);
|
||||||
cb(dc, ptr);
|
cb(dc, ptr);
|
||||||
});
|
});
|
||||||
|
else
|
||||||
|
peerConnection->onDataChannel(nullptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,9 +178,12 @@ int rtcSetLocalDescriptionCallback(int pc, descriptionCallbackFunc cb) {
|
|||||||
if (!peerConnection)
|
if (!peerConnection)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (cb)
|
||||||
peerConnection->onLocalDescription([pc, cb](const Description &desc) {
|
peerConnection->onLocalDescription([pc, cb](const Description &desc) {
|
||||||
cb(string(desc).c_str(), desc.typeString().c_str(), getUserPointer(pc));
|
cb(string(desc).c_str(), desc.typeString().c_str(), getUserPointer(pc));
|
||||||
});
|
});
|
||||||
|
else
|
||||||
|
peerConnection->onLocalDescription(nullptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,9 +192,12 @@ int rtcSetLocalCandidateCallback(int pc, candidateCallbackFunc cb) {
|
|||||||
if (!peerConnection)
|
if (!peerConnection)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (cb)
|
||||||
peerConnection->onLocalCandidate([pc, cb](const Candidate &cand) {
|
peerConnection->onLocalCandidate([pc, cb](const Candidate &cand) {
|
||||||
cb(cand.candidate().c_str(), cand.mid().c_str(), getUserPointer(pc));
|
cb(cand.candidate().c_str(), cand.mid().c_str(), getUserPointer(pc));
|
||||||
});
|
});
|
||||||
|
else
|
||||||
|
peerConnection->onLocalCandidate(nullptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,9 +206,12 @@ int rtcSetStateChangeCallback(int pc, stateChangeCallbackFunc cb) {
|
|||||||
if (!peerConnection)
|
if (!peerConnection)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (cb)
|
||||||
peerConnection->onStateChange([pc, cb](PeerConnection::State state) {
|
peerConnection->onStateChange([pc, cb](PeerConnection::State state) {
|
||||||
cb(static_cast<rtcState>(state), getUserPointer(pc));
|
cb(static_cast<rtcState>(state), getUserPointer(pc));
|
||||||
});
|
});
|
||||||
|
else
|
||||||
|
peerConnection->onStateChange(nullptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,9 +220,12 @@ int rtcSetGatheringStateChangeCallback(int pc, gatheringStateCallbackFunc cb) {
|
|||||||
if (!peerConnection)
|
if (!peerConnection)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (cb)
|
||||||
peerConnection->onGatheringStateChange([pc, cb](PeerConnection::GatheringState state) {
|
peerConnection->onGatheringStateChange([pc, cb](PeerConnection::GatheringState state) {
|
||||||
cb(static_cast<rtcGatheringState>(state), getUserPointer(pc));
|
cb(static_cast<rtcGatheringState>(state), getUserPointer(pc));
|
||||||
});
|
});
|
||||||
|
else
|
||||||
|
peerConnection->onGatheringStateChange(nullptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +267,22 @@ int rtcSetOpenCallback(int dc, openCallbackFunc cb) {
|
|||||||
if (!dataChannel)
|
if (!dataChannel)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (cb)
|
||||||
dataChannel->onOpen([dc, cb]() { cb(getUserPointer(dc)); });
|
dataChannel->onOpen([dc, cb]() { cb(getUserPointer(dc)); });
|
||||||
|
else
|
||||||
|
dataChannel->onOpen(nullptr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtcSetClosedCallback(int dc, closedCallbackFunc cb) {
|
||||||
|
auto dataChannel = getDataChannel(dc);
|
||||||
|
if (!dataChannel)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (cb)
|
||||||
|
dataChannel->onClosed([dc, cb]() { cb(getUserPointer(dc)); });
|
||||||
|
else
|
||||||
|
dataChannel->onClosed(nullptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,7 +291,11 @@ int rtcSetErrorCallback(int dc, errorCallbackFunc cb) {
|
|||||||
if (!dataChannel)
|
if (!dataChannel)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
dataChannel->onError([dc, cb](const string &error) { cb(error.c_str(), getUserPointer(dc)); });
|
if (cb)
|
||||||
|
dataChannel->onError(
|
||||||
|
[dc, cb](const string &error) { cb(error.c_str(), getUserPointer(dc)); });
|
||||||
|
else
|
||||||
|
dataChannel->onError(nullptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,11 +304,15 @@ int rtcSetMessageCallback(int dc, messageCallbackFunc cb) {
|
|||||||
if (!dataChannel)
|
if (!dataChannel)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (cb)
|
||||||
dataChannel->onMessage(
|
dataChannel->onMessage(
|
||||||
[dc, cb](const binary &b) {
|
[dc, cb](const binary &b) {
|
||||||
cb(reinterpret_cast<const char *>(b.data()), b.size(), getUserPointer(dc));
|
cb(reinterpret_cast<const char *>(b.data()), b.size(), getUserPointer(dc));
|
||||||
},
|
},
|
||||||
[dc, cb](const string &s) { cb(s.c_str(), -1, getUserPointer(dc)); });
|
[dc, cb](const string &s) { cb(s.c_str(), -1, getUserPointer(dc)); });
|
||||||
|
else
|
||||||
|
dataChannel->onMessage(nullptr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +354,10 @@ int rtcSetBufferedAmountLowCallback(int dc, bufferedAmountLowCallbackFunc cb) {
|
|||||||
if (!dataChannel)
|
if (!dataChannel)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
dataChannel->onOpen([dc, cb]() { cb(getUserPointer(dc)); });
|
if (cb)
|
||||||
|
dataChannel->onBufferedAmountLow([dc, cb]() { cb(getUserPointer(dc)); });
|
||||||
|
else
|
||||||
|
dataChannel->onBufferedAmountLow(nullptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,7 +374,10 @@ int rtcSetAvailableCallback(int dc, availableCallbackFunc cb) {
|
|||||||
if (!dataChannel)
|
if (!dataChannel)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (cb)
|
||||||
dataChannel->onOpen([dc, cb]() { cb(getUserPointer(dc)); });
|
dataChannel->onOpen([dc, cb]() { cb(getUserPointer(dc)); });
|
||||||
|
else
|
||||||
|
dataChannel->onOpen(nullptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,11 +404,11 @@ int rtcReceiveMessage(int dc, char *buffer, int *size) {
|
|||||||
},
|
},
|
||||||
[&](const string &s) {
|
[&](const string &s) {
|
||||||
int len = std::min(*size - 1, int(s.size()));
|
int len = std::min(*size - 1, int(s.size()));
|
||||||
*size = -1;
|
|
||||||
if (len >= 0) {
|
if (len >= 0) {
|
||||||
std::copy(s.data(), s.data() + len, buffer);
|
std::copy(s.data(), s.data() + len, buffer);
|
||||||
buffer[len] = '\0';
|
buffer[len] = '\0';
|
||||||
}
|
}
|
||||||
|
*size = -(len + 1);
|
||||||
return len + 1;
|
return len + 1;
|
||||||
}},
|
}},
|
||||||
*message);
|
*message);
|
||||||
|
178
test/capi.cpp
Normal file
178
test/capi.cpp
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
/**
|
||||||
|
* 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 <rtc/rtc.h>
|
||||||
|
|
||||||
|
#include <cstdbool>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <unistd.h> // for sleep
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
rtcState state;
|
||||||
|
rtcGatheringState gatheringState;
|
||||||
|
int pc;
|
||||||
|
int dc;
|
||||||
|
bool connected;
|
||||||
|
} Peer;
|
||||||
|
|
||||||
|
Peer *peer1 = NULL;
|
||||||
|
Peer *peer2 = NULL;
|
||||||
|
|
||||||
|
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("DataChannel %d: Open\n", peer == peer1 ? 1 : 2);
|
||||||
|
|
||||||
|
const char *message = peer == peer1 ? "Hello from 1" : "Hello from 2";
|
||||||
|
rtcSendMessage(peer->dc, message, -1); // negative size indicates a null-terminated string
|
||||||
|
}
|
||||||
|
|
||||||
|
static void closedCallback(void *ptr) {
|
||||||
|
Peer *peer = (Peer *)ptr;
|
||||||
|
peer->connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void messageCallback(const char *message, int size, void *ptr) {
|
||||||
|
Peer *peer = (Peer *)ptr;
|
||||||
|
if (size < 0) { // negative size indicates a null-terminated string
|
||||||
|
printf("Message %d: %s\n", peer == peer1 ? 1 : 2, message);
|
||||||
|
} else {
|
||||||
|
printf("Message %d: [binary of size %d]\n", peer == peer1 ? 1 : 2, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dataChannelCallback(int dc, void *ptr) {
|
||||||
|
Peer *peer = (Peer *)ptr;
|
||||||
|
peer->dc = dc;
|
||||||
|
peer->connected = true;
|
||||||
|
rtcSetClosedCallback(dc, closedCallback);
|
||||||
|
rtcSetMessageCallback(dc, messageCallback);
|
||||||
|
|
||||||
|
char buffer[256];
|
||||||
|
if (rtcGetDataChannelLabel(dc, buffer, 256) >= 0)
|
||||||
|
printf("DataChannel %d: Received with label \"%s\"\n", peer == peer1 ? 1 : 2, buffer);
|
||||||
|
|
||||||
|
const char *message = peer == peer1 ? "Hello from 1" : "Hello from 2";
|
||||||
|
rtcSendMessage(peer->dc, message, -1); // negative size indicates a null-terminated string
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
rtcSetDataChannelCallback(peer->pc, dataChannelCallback);
|
||||||
|
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->dc)
|
||||||
|
rtcDeleteDataChannel(peer->dc);
|
||||||
|
if (peer->pc)
|
||||||
|
rtcDeletePeerConnection(peer->pc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_capi_main() {
|
||||||
|
rtcInitLogger(RTC_LOG_DEBUG);
|
||||||
|
|
||||||
|
rtcConfiguration config;
|
||||||
|
memset(&config, 0, sizeof(config));
|
||||||
|
// const char *iceServers[1] = {"stun:stun.l.google.com:19302"};
|
||||||
|
// config.iceServers = iceServers;
|
||||||
|
// config.iceServersCount = 1;
|
||||||
|
|
||||||
|
// Create peer 1
|
||||||
|
peer1 = createPeer(&config);
|
||||||
|
if (!peer1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// Create peer 2
|
||||||
|
peer2 = createPeer(&config);
|
||||||
|
if (!peer2)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// Peer 1: Create data channel
|
||||||
|
peer1->dc = rtcCreateDataChannel(peer1->pc, "test");
|
||||||
|
rtcSetOpenCallback(peer1->dc, openCallback);
|
||||||
|
rtcSetClosedCallback(peer1->dc, closedCallback);
|
||||||
|
rtcSetMessageCallback(peer1->dc, messageCallback);
|
||||||
|
|
||||||
|
sleep(3);
|
||||||
|
|
||||||
|
if (peer1->connected && peer2->connected) {
|
||||||
|
deletePeer(peer1);
|
||||||
|
deletePeer(peer2);
|
||||||
|
sleep(1);
|
||||||
|
printf("Success\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
error:
|
||||||
|
deletePeer(peer1);
|
||||||
|
deletePeer(peer2);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
void test_capi() {
|
||||||
|
if (test_capi_main())
|
||||||
|
throw std::runtime_error("C API test failed");
|
||||||
|
}
|
@ -33,10 +33,9 @@ void test_connectivity() {
|
|||||||
|
|
||||||
Configuration config;
|
Configuration config;
|
||||||
// config.iceServers.emplace_back("stun:stun.l.google.com:19302");
|
// config.iceServers.emplace_back("stun:stun.l.google.com:19302");
|
||||||
// config.iceServers.emplace_back("turn:USER@PASSWORD:turn.example.net:3478?transport=udp"); //
|
|
||||||
// libnice only config.enableIceTcp = true; // libnice only
|
|
||||||
|
|
||||||
auto pc1 = std::make_shared<PeerConnection>(config);
|
auto pc1 = std::make_shared<PeerConnection>(config);
|
||||||
|
|
||||||
auto pc2 = std::make_shared<PeerConnection>(config);
|
auto pc2 = std::make_shared<PeerConnection>(config);
|
||||||
|
|
||||||
pc1->onLocalDescription([wpc2 = make_weak_ptr(pc2)](const Description &sdp) {
|
pc1->onLocalDescription([wpc2 = make_weak_ptr(pc2)](const Description &sdp) {
|
||||||
@ -83,11 +82,11 @@ void test_connectivity() {
|
|||||||
|
|
||||||
shared_ptr<DataChannel> dc2;
|
shared_ptr<DataChannel> dc2;
|
||||||
pc2->onDataChannel([&dc2](shared_ptr<DataChannel> dc) {
|
pc2->onDataChannel([&dc2](shared_ptr<DataChannel> dc) {
|
||||||
cout << "Got a DataChannel with label: " << dc->label() << endl;
|
cout << "DataChannel 2: Received with label \"" << dc->label() << "\"" << endl;
|
||||||
dc2 = dc;
|
dc2 = dc;
|
||||||
dc2->onMessage([](const variant<binary, string> &message) {
|
dc2->onMessage([](const variant<binary, string> &message) {
|
||||||
if (holds_alternative<string>(message)) {
|
if (holds_alternative<string>(message)) {
|
||||||
cout << "Received 2: " << get<string>(message) << endl;
|
cout << "Message 2: " << get<string>(message) << endl;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
dc2->send("Hello from 2");
|
dc2->send("Hello from 2");
|
||||||
@ -98,12 +97,12 @@ void test_connectivity() {
|
|||||||
auto dc1 = wdc1.lock();
|
auto dc1 = wdc1.lock();
|
||||||
if (!dc1)
|
if (!dc1)
|
||||||
return;
|
return;
|
||||||
cout << "DataChannel open: " << dc1->label() << endl;
|
cout << "DataChannel 1: Open" << endl;
|
||||||
dc1->send("Hello from 1");
|
dc1->send("Hello from 1");
|
||||||
});
|
});
|
||||||
dc1->onMessage([](const variant<binary, string> &message) {
|
dc1->onMessage([](const variant<binary, string> &message) {
|
||||||
if (holds_alternative<string>(message)) {
|
if (holds_alternative<string>(message)) {
|
||||||
cout << "Received 1: " << get<string>(message) << endl;
|
cout << "Message 1: " << get<string>(message) << endl;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -21,14 +21,24 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
void test_connectivity();
|
void test_connectivity();
|
||||||
|
void test_capi();
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
try {
|
try {
|
||||||
|
std::cout << "*** Running connectivity test..." << std::endl;
|
||||||
test_connectivity();
|
test_connectivity();
|
||||||
|
std::cout << "*** Finished connectivity test" << std::endl;
|
||||||
} catch (const exception &e) {
|
} catch (const exception &e) {
|
||||||
std::cerr << "Connectivity check failed: " << e.what() << endl;
|
std::cerr << "Connectivity test failed: " << e.what() << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
std::cout << "*** Running C API test..." << std::endl;
|
||||||
|
test_capi();
|
||||||
|
std::cout << "*** Finished C API test" << std::endl;
|
||||||
|
} catch (const exception &e) {
|
||||||
|
std::cerr << "C API test failed: " << e.what() << endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user