Browse Source

Added sendBuffer() methods to DataChannel

Paul-Louis Ageneau 5 years ago
parent
commit
aa55aa76df
3 changed files with 55 additions and 19 deletions
  1. 33 0
      include/rtc/datachannel.hpp
  2. 10 5
      include/rtc/message.hpp
  3. 12 14
      src/datachannel.cpp

+ 33 - 0
include/rtc/datachannel.hpp

@@ -28,6 +28,7 @@
 #include <atomic>
 #include <chrono>
 #include <functional>
+#include <type_traits>
 #include <variant>
 
 namespace rtc {
@@ -48,6 +49,9 @@ public:
 	void send(const byte *data, size_t size);
 	std::optional<std::variant<binary, string>> receive();
 
+	template <typename Buffer> void sendBuffer(const Buffer &buf);
+	template <typename Iterator> void sendBuffer(Iterator first, Iterator last);
+
 	size_t available() const;
 	size_t availableSize() const;
 
@@ -61,6 +65,7 @@ public:
 
 private:
 	void open(std::shared_ptr<SctpTransport> sctpTransport);
+	void outgoing(mutable_message_ptr message);
 	void incoming(message_ptr message);
 	void processOpenMessage(message_ptr message);
 
@@ -81,6 +86,34 @@ private:
 	friend class PeerConnection;
 };
 
+template <typename Buffer> std::pair<const byte *, size_t> to_bytes(const Buffer &buf) {
+	using T = typename std::remove_pointer<decltype(buf.data())>::type;
+	using E = typename std::conditional<std::is_void<T>::value, byte, T>::type;
+	return std::make_pair(static_cast<const byte *>(static_cast<const void *>(buf.data())),
+	                      buf.size() * sizeof(E));
+}
+
+template <typename Buffer> void DataChannel::sendBuffer(const Buffer &buf) {
+	auto [bytes, size] = to_bytes(buf);
+	auto message = std::make_shared<Message>(size);
+	std::copy(bytes, bytes + size, message->data());
+	outgoing(message);
+}
+
+template <typename Iterator> void DataChannel::sendBuffer(Iterator first, Iterator last) {
+	size_t size = 0;
+	for (Iterator it = first; it != last; ++it)
+		size += it->size();
+
+	auto message = std::make_shared<Message>(size);
+	auto pos = message->begin();
+	for (Iterator it = first; it != last; ++it) {
+		auto [bytes, size] = to_bytes(*it);
+		pos = std::copy(bytes, bytes + size, pos);
+	}
+	outgoing(message);
+}
+
 } // namespace rtc
 
 #endif

+ 10 - 5
include/rtc/message.hpp

@@ -30,24 +30,29 @@ namespace rtc {
 struct Message : binary {
 	enum Type { Binary, String, Control };
 
+	Message(size_t size) : binary(size), type(Binary) {}
+
 	template <typename Iterator>
-	Message(Iterator begin_, Iterator end_, Type type_ = Binary, unsigned int stream_ = 0,
-	        std::shared_ptr<Reliability> reliability_ = nullptr)
-	    : binary(begin_, end_), type(type_), stream(stream_), reliability(reliability_) {}
+	Message(Iterator begin_, Iterator end_, Type type_ = Binary)
+	    : binary(begin_, end_), type(type_) {}
 
 	Type type;
-	unsigned int stream;
+	unsigned int stream = 0;
 	std::shared_ptr<Reliability> reliability;
 };
 
 using message_ptr = std::shared_ptr<const Message>;
+using mutable_message_ptr = std::shared_ptr<Message>;
 using message_callback = std::function<void(message_ptr message)>;
 
 template <typename Iterator>
 message_ptr make_message(Iterator begin, Iterator end, Message::Type type = Message::Binary,
                          unsigned int stream = 0,
                          std::shared_ptr<Reliability> reliability = nullptr) {
-	return std::make_shared<Message>(begin, end, type, stream, reliability);
+	auto message = std::make_shared<Message>(begin, end, type);
+	message->stream = stream;
+	message->reliability = reliability;
+	return message;
 }
 
 } // namespace rtc

+ 12 - 14
src/datachannel.cpp

@@ -80,29 +80,18 @@ void DataChannel::close() {
 }
 
 void DataChannel::send(const std::variant<binary, string> &data) {
-	if (mIsClosed || !mSctpTransport)
-		return;
-
 	std::visit(
-	    [this](const auto &d) {
+	    [&](const auto &d) {
 		    using T = std::decay_t<decltype(d)>;
 		    constexpr auto type = std::is_same_v<T, string> ? Message::String : Message::Binary;
 		    auto *b = reinterpret_cast<const byte *>(d.data());
-		    // Before the ACK has been received on a DataChannel, all messages must be sent ordered
-		    auto reliability = mIsOpen ? mReliability : nullptr;
-		    auto message = make_message(b, b + d.size(), type, mStream, reliability);
-		    mSctpTransport->send(message);
+		    outgoing(std::make_shared<Message>(b, b + d.size(), type));
 	    },
 	    data);
 }
 
 void DataChannel::send(const byte *data, size_t size) {
-	if (mIsClosed || !mSctpTransport)
-		return;
-
-	auto reliability = mIsOpen ? mReliability : nullptr;
-	auto message = make_message(data, data + size, Message::Binary, mStream, reliability);
-	mSctpTransport->send(message);
+	outgoing(std::make_shared<Message>(data, data + size, Message::Binary));
 }
 
 std::optional<std::variant<binary, string>> DataChannel::receive() {
@@ -179,6 +168,15 @@ void DataChannel::open(shared_ptr<SctpTransport> sctpTransport) {
 	mSctpTransport->send(make_message(buffer.begin(), buffer.end(), Message::Control, mStream));
 }
 
+void DataChannel::outgoing(mutable_message_ptr message) {
+	if (mIsClosed || !mSctpTransport)
+		return;
+	// Before the ACK has been received on a DataChannel, all messages must be sent ordered
+	message->reliability = mIsOpen ? mReliability : nullptr;
+	message->stream = mStream;
+	mSctpTransport->send(message);
+}
+
 void DataChannel::incoming(message_ptr message) {
 	switch (message->type) {
 	case Message::Control: {