Giter Club home page Giter Club logo

datachannel-wasm's Introduction

Hello, I'm Paul-Louis ๐Ÿ‘‹

  • ๐Ÿ‘จ I'm a Software Engineer and Computer Science PhD from France.
  • ๐Ÿ”ญ I like working on network protocols and applications, particularly distributed ones.
  • ๐Ÿ’ป I have a wide range of interests in new technologies, from video game graphics to robotics and 3D printing.
  • โญ I'm a WebRTC expert and the author of libdatachannel, a C/C++ WebRTC standalone library.
  • โ™ฅ๏ธ I'm looking for sponsors to continue maintaining open-source projects.
  • ๐Ÿ“ซ Please find my contact information and rรฉsumรฉ on paul-louis.ageneau.org
  • ๐ŸŽฉ Check out my blog where I tinker with stuff on chapelierfou.org
  • ๐Ÿ‘ Follow me on GitHub or Mastodon
  • ๐Ÿ˜„ Pronouns: he/him

Some of my open source projects:

I'm a contributor to node-datachannel, Node.js bindings for libdatachannel.

I've also been contributing to WebTorrent, and libtorrent, in which I added WebTorrent support. This first native WebTorrent implementation opens exciting possibilities for Peer-to-Peer file exchanges between Web browsers and native clients!

Otherwise, I like working on robots and tinkering with Minitels! Check out my blog ๐Ÿค–

datachannel-wasm's People

Contributors

eugeneko avatar gitter-badger avatar golgirihm avatar hanseuljun avatar jwric avatar paullouisageneau avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

datachannel-wasm's Issues

Using Multithreading

Hi, I am using your library and it works great. However, I have the problem, that my performance in the communication part is quite slow. I believe that the reason is, that I only use the "main thread" for sending and the rest of the program is multithreaded and therefore needs to wait for the sending. Is there a way, that sending also works with different threads? When I try to send on another thread than the main thread I get Pthread 0x00601ec0 sent an error! TypeError: can't access property "readyState", dataChannel is undefined.

Thanks for your help!

Nodejs support

Hi, this wasm lib work to Nodejs ? Nodejs not support native webrtc. I can extend functionality with this library for nodejs ?

Match libdatachannel's reliability.hpp

Hello!

First off, thank you for the wonderful libraries. They are incredibly useful!

I have a project that uses libdatachannel in conjuction with datachannel-wasm. Recently, I pulled to a newer version of libdatachannel, and found that I had a build error due to the refactor of the data channel reliability API (#1031). I was able to fix this error in one part of my project (the native app), but it breaks the other part of the project (the web app).

Is there a plan to update datachannel-wasm to match the reliability in the latest libdatachannel?

a wish about the license

Hello Paul-Louis,

First of all, I really really appreciate the help I've received already so this is more like a wish, nothing more than that.

Currently, this repository is under AGPL. As I have very much enjoyed your other libraries, I wanted to ask whether it would be possible to let this repository stay under LGPL as your other libraries.

If that is possible, I can promise

  1. making this repository to work with Emscripten 2.0 (currently there are some minor issues, e.g., dynCall_sig() functions got removed recently)
    and
  2. try adding some rudimentary support for media transports.

Of course I am working on them because of my work, so I am not doing some humanitarian work here, just hoping them to give you a second thought!

Add support for sending std::vector<uint8_t> type over DC>

Since send method only support std::byte and string types, I have to make a copy to cast into std::byte and if there is a direct support for std::vector<uint8_t> it would improve performance. The case is I read from a Stream and send the data through DataChannel and I use convertJSArrayToNumberVector to get close to zero copy from JS side.

it would be also good to remove casting again to char* type when you are passing this back to the JS side since uint8_t type already match with JS Uint8

        auto rawBuffer = emscripten::convertJSArrayToNumberVector<uint8_t>(reader["value"]);

        std::vector<std::byte> buffer(rawBuffer.size() + 1);

        std::transform(rawBuffer.begin(), rawBuffer.end(), buffer.begin(), [] (uint8_t i) { 
            return std::byte(i); 
        });

        if (auto channel = dc.lock())
        {
            channel->send(buffer);
        }

Copy and Paste troubles

I'm trying to use this library in a simple copy-paste situation such as set out in the example of https://github.com/paullouisageneau/libdatachannel/tree/master/examples/copy-paste

Instead of reading from std::cin I copy paste offers and answers into html text boxes. However I'm unable to setup a connection in this manner. I always get a "WebRTC: ICE failed, add a TURN server and see about:webrtc for more details" on Firefox or Chrome never seems to progress further than the [State: Connecting] state.

Here is the main code adapted from the libdatachannel example:

std::shared_ptr<rtc::PeerConnection> pc; 
std::shared_ptr<rtc::DataChannel> dc;

EM_JS(void, putDescriptionInOfferBox, (const char* string_pointer), {
	document.getElementById('offer').value = UTF8ToString(string_pointer);  
});

EM_JS(void, putCandidateInCandidateBox, (const char* string_pointer), {
	document.getElementById('candidate').value = UTF8ToString(string_pointer);  
});

EM_JS(void, addChatMessage, (const char* string_pointer), {
	var out = document.getElementById('output');
	out.value = UTF8ToString(string_pointer);  
});

extern "C" {
	void createOffer() {
		dc = pc->createDataChannel("test2");

		dc->onOpen([&]() { std::cout << "[DataChannel open: " << dc->label() << "]" << std::endl; });

		dc->onClosed([&]() { std::cout << "[DataChannel closed: " << dc->label() << "]" << std::endl; });

		dc->onMessage([](std::variant<rtc::binary, rtc::string> message) {
			if (std::holds_alternative<rtc::string>(message)) {
				rtc::string sMessage = std::get<rtc::string>(message);
				std::cout << "[Received message: " << sMessage << "]" << std::endl;
				addChatMessage(sMessage.c_str());
			}
		});
	}
}

extern "C" {
	void addRemoteDescriptionOffer(char* cc) {
		std::string sdp = std::string(cc);
		pc->setRemoteDescription(rtc::Description(sdp, rtc::Description::Type::Offer));
	}
}

extern "C" {
	void addRemoteDescriptionAnswer(char* cc) {
		std::string sdp = std::string(cc);
		pc->setRemoteDescription(rtc::Description(sdp, rtc::Description::Type::Answer));
	}
}

extern "C" {
	void addRemoteCandidate(char* cc) {
		std::string candidate = std::string(cc);
		std::cout << candidate << std::endl;
		pc->addRemoteCandidate(rtc::Candidate(candidate, "0"));
	}
}

extern "C" {
	void sendMessage(char* cc) {
		if (!dc->isOpen()) {
			std::cout << "** Channel is not Open ** " << std::endl;
		} else {
			std::cout << "[Message]: ";
			std::string message(cc);
			dc->send(message);
		}
	}	
}


inline const char* toString(rtc::PeerConnection::State s)
{
    switch (s)
    {
        case rtc::PeerConnection::State::New:   return "New";
        case rtc::PeerConnection::State::Connecting:   return "Connecting";
        case rtc::PeerConnection::State::Disconnected: return "Disconnected";
		case rtc::PeerConnection::State::Failed: return "Failed";
		case rtc::PeerConnection::State::Closed: return "Closed";
        default:      return "Disconnected";
    }
}

inline const char* toString(rtc::PeerConnection::GatheringState s)
{
    switch (s)
    {
        case rtc::PeerConnection::GatheringState::New:   return "New";
        case rtc::PeerConnection::GatheringState::InProgress:   return "InProgress";
        case rtc::PeerConnection::GatheringState::Complete: return "Complete";
        default:      return "Disconnected";
    }
}

int main(int, char**)
{
	rtc::Configuration config;
	config.iceServers.emplace_back("stun:stun.1.google.com:19302");

	pc = std::make_shared<rtc::PeerConnection>(config);

	pc->onLocalDescription([](rtc::Description description) {
		putDescriptionInOfferBox(rtc::string(description).c_str());
	});

	pc->onLocalCandidate([](rtc::Candidate candidate) {
		putCandidateInCandidateBox(rtc::string(candidate).c_str());
	});

	pc->onStateChange(
	    [](rtc::PeerConnection::State state) { std::cout << "[State: " << toString(state) << "]" << std::endl;});

	pc->onGatheringStateChange([](rtc::PeerConnection::GatheringState state) {
		std::cout << "[Gathering State: " << toString(state) << "]" << std::endl;
	});

	pc->onDataChannel([&](std::shared_ptr<rtc::DataChannel> _dc) {
		if(!dc) { //only the answerer has to create a new dc object
			std::cout << "[Got a DataChannel with label: " << _dc->label() << "]" << std::endl;
			dc = _dc;

			dc->onClosed([&]() { std::cout << "[DataChannel closed: " << dc->label() << "]" << std::endl; });

			dc->onMessage([](std::variant<rtc::binary, rtc::string> message) {
				if (std::holds_alternative<rtc::string>(message)) {
					rtc::string sMessage = std::get<rtc::string>(message);
					std::cout << "[Received message: " << sMessage << "]" << std::endl;
					addChatMessage(sMessage.c_str());
				}
			});
		}
	});

    emscripten_set_main_loop_arg(main_loop, nullptr, 0, true);
}


static void main_loop(void* arg)
{

}

and the html front end

<html lang="en-us">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/>
    <title>WebRTC - Copy and Paste</title>
    <style>
        body { margin: 0; background-color: powderblue; }
        .emscripten {
            position: relative;
            top: 0px;
            left: 0px;
            margin: 0px;
            border: 0;
            /*width: 100%; //this will set canvas size full screen
            height: 100%;*/
            overflow: hidden;
            display: block;
            image-rendering: optimizeSpeed;
            image-rendering: -moz-crisp-edges;
            image-rendering: -o-crisp-edges;
            image-rendering: -webkit-optimize-contrast;
            image-rendering: optimize-contrast;
            image-rendering: crisp-edges;
            image-rendering: pixelated;
            -ms-interpolation-mode: nearest-neighbor;
        }
    </style>
  </head>
  <body>
    <script>
      function setDescriptionOffer() {
        var s = document.getElementById('answerdescription').value;
        var ptr = allocate(intArrayFromString(s), ALLOC_NORMAL);

        _addRemoteDescriptionOffer(ptr);

        _free(ptr)
      }

      function setCandidate() {
        var s = document.getElementById('answercandidate').value;
        var ptr = allocate(intArrayFromString(s), ALLOC_NORMAL);

        _addRemoteCandidate(ptr);

        _free(ptr)
      }
    </script>

    <p id=stat></p>
    <button id="button" onclick="_createOffer()">Offer:</button>
    <textarea id="offer"></textarea> 
    <textarea id="candidate"></textarea><br> 
    
    <button id="buttonOffer" onclick="setDescriptionOffer()">set Offer:</button>
    <textarea id="answerdescription" placeholder="Paste Description. And press Enter"></textarea>
    
    <button id="buttonCandidate" onclick="setCandidate()">set Candidate:</button> 
    <textarea id="answercandidate" placeholder="Paste Candidate. And press Enter"></textarea><br>

    <br>
    <br>
    Chat: <input id="chat"><br>
	  <pre id="output">Chat: </pre>

    <script>
      chat.onkeypress = function(e) {
        if (e.keyCode != 13) return;
        var s = chat.value;
        var ptr = allocate(intArrayFromString(s), ALLOC_NORMAL);

        _sendMessage(ptr);

        _free(ptr)
        console.log(chat.value);
        chat.value = "";
      };
    </script>
    {{{ SCRIPT }}}
  </body>
</html>

I use it in the following manner. I have two tabs. The 'offerer' tab creates the initial data connection and offer, which are copy pasted to the 'answerer'. Which in turn generates an answer that gets pasted to the offerer. The same thing for the candidates. I built and ran the libdatachannel offerer and answerer example and it seems to be the exact same process and in that case I was able to set up a connection.

One thing that does allow me to make a connection is when I copy the answer from the "about:webrtc" page after pasting in the offer from the offerer. This immediately allows me to setup a connection and creates a functioning datachannel between the tabs without having to specify the candidates manually. This seems to be because the ICE candidates are already enumerated in the localdescription SDP. When I call WEBRTC.peerConnection[1].localDescription.sdp from the console I also get this version of the answer. However, I am unable to obtain the same localdescription using this library. Is there a way this is easily achieved? Why is the call to WEBRTC.peerConnection[1].localDescription.sdp in the javascript portion of the library giving a different result as when doing it in the console?

Any assistance would be appreciated.

usecase

Hi, I was wondering what the usecase is for using datachannel-wasm assuming most browsers capable of wasm should also be capable of datachannels as well?

Standalone build errors

Raw build didn't work for me on first attempt. Any ideas?

/datachannel-wasm/build-emscripten$ make -j2

[ 20%] Building CXX object CMakeFiles/datachannel-wasm.dir/wasm/src/channel.cpp.o
[ 40%] Building CXX object CMakeFiles/datachannel-wasm.dir/wasm/src/datachannel.cpp.o
In file included from /home/jacob/projects/datachannel-wasm/wasm/src/datachannel.cpp:22:
/home/jacob/projects/datachannel-wasm/wasm/include/rtc/datachannel.hpp:38:47: error: non-virtual member function marked 'override' hides virtual member function
        void send(std::variant<binary, string> data) override;
                                                     ^
/home/jacob/projects/datachannel-wasm/wasm/include/rtc/channel.hpp:37:15: note: hidden overloaded virtual function 'rtc::Channel::send' declared here: type mismatch at 1st parameter ('const std::variant<binary, string> &' (aka 'const variant<vector<std::byte>, basic_string<char, char_traits<char>, allocator<char>>> &') vs 'std::variant<binary, string>' (aka 'variant<vector<std::byte>, basic_string<char, char_traits<char>, allocator<char>>>'))
        virtual void send(const std::variant<binary, string> &data) = 0;
                     ^
In file included from /home/jacob/projects/datachannel-wasm/wasm/src/datachannel.cpp:22:
/home/jacob/projects/datachannel-wasm/wasm/include/rtc/datachannel.hpp:32:7: warning: abstract class is marked 'final' [-Wabstract-final-class]
class DataChannel final : public Channel {
      ^
/home/jacob/projects/datachannel-wasm/wasm/include/rtc/channel.hpp:37:15: note: unimplemented pure virtual method 'send' in 'DataChannel'
        virtual void send(const std::variant<binary, string> &data) = 0;
                     ^
/home/jacob/projects/datachannel-wasm/wasm/src/channel.cpp:60:15: error: out-of-line definition of 'triggerMessage' does not match any declaration in 'rtc::Channel'
void Channel::triggerMessage(const std::variant<binary, string> &data) {
              ^~~~~~~~~~~~~~
/home/jacob/projects/datachannel-wasm/wasm/include/rtc/channel.hpp:53:30: note: type of 1st parameter of member declaration does not match definition ('std::variant<binary, string>' (aka 'variant<vector<std::byte>, basic_string<char, char_traits<char>, allocator<char>>>') vs 'const std::variant<binary, string> &' (aka 'const variant<vector<std::byte>, basic_string<char, char_traits<char>, allocator<char>>> &'))
        virtual void triggerMessage(std::variant<binary, string> data);
                                    ^
1 warning and 1 error generated.
em++: error: '/home/jacob/projects/emsdk/upstream/bin/clang++ -target wasm32-unknown-emscripten -D__EMSCRIPTEN_major__=2 -D__EMSCRIPTEN_minor__=0 -D__EMSCRIPTEN_tiny__=8 -D_LIBCPP_ABI_VERSION=2 -Dunix -D__unix -D__unix__ -Werror=implicit-function-declaration -Xclang -nostdsysteminc -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/include/libcxx -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/lib/libcxxabi/include -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/include/compat -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/include -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/include/libc -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/lib/libc/musl/arch/emscripten -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/local/include -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/include/SSE -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/include/neon -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/lib/compiler-rt/include -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/lib/libunwind/include -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/cache/wasm/include -DEMSCRIPTEN -fignore-exceptions -I/home/jacob/projects/datachannel-wasm/wasm/include -I/home/jacob/projects/datachannel-wasm/wasm/include/rtc -std=gnu++17 -o CMakeFiles/datachannel-wasm.dir/wasm/src/datachannel.cpp.o -c /home/jacob/projects/datachannel-wasm/wasm/src/datachannel.cpp -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/include/SDL -c -o CMakeFiles/datachannel-wasm.dir/wasm/src/datachannel.cpp.o -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr' failed (1)
make[2]: *** [CMakeFiles/datachannel-wasm.dir/build.make:78: CMakeFiles/datachannel-wasm.dir/wasm/src/datachannel.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....
1 error generated.
em++: error: '/home/jacob/projects/emsdk/upstream/bin/clang++ -target wasm32-unknown-emscripten -D__EMSCRIPTEN_major__=2 -D__EMSCRIPTEN_minor__=0 -D__EMSCRIPTEN_tiny__=8 -D_LIBCPP_ABI_VERSION=2 -Dunix -D__unix -D__unix__ -Werror=implicit-function-declaration -Xclang -nostdsysteminc -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/include/libcxx -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/lib/libcxxabi/include -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/include/compat -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/include -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/include/libc -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/lib/libc/musl/arch/emscripten -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/local/include -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/include/SSE -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/include/neon -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/lib/compiler-rt/include -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/lib/libunwind/include -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/cache/wasm/include -DEMSCRIPTEN -fignore-exceptions -I/home/jacob/projects/datachannel-wasm/wasm/include -I/home/jacob/projects/datachannel-wasm/wasm/include/rtc -std=gnu++17 -o CMakeFiles/datachannel-wasm.dir/wasm/src/channel.cpp.o -c /home/jacob/projects/datachannel-wasm/wasm/src/channel.cpp -Xclang -isystem/home/jacob/projects/emsdk/upstream/emscripten/system/include/SDL -c -o CMakeFiles/datachannel-wasm.dir/wasm/src/channel.cpp.o -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr' failed (1)
make[2]: *** [CMakeFiles/datachannel-wasm.dir/build.make:64: CMakeFiles/datachannel-wasm.dir/wasm/src/channel.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/datachannel-wasm.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

send Bytes over DataChannel

I try to establish a communication over WebRTC using the library. The connection works fine and also sending strings over the connection works. However, when trying to send bytes instead of strings, I always get the following error in the browser:
RTCDataChannel.send: Argument 1 can't be a SharedArrayBuffer or an ArrayBufferView backed by a SharedArrayBuffer

This also happens if I only try to send a very simple byte like:
std::byte b{42}; dc->send(&b, 1);

onBufferedAmountLow is annoying

I made a wrapper around dc.send that automatically schedule the message to be send once onBufferedAmountLow event received.

But the problem is that this event not always get invoked as I expected thus leaving messages not being able to send.

class DataChannelWrapper {
    private:
        int requestCount{};

        std::queue<std::string> messageQueue;
    public:
        std::shared_ptr<rtc::DataChannel> dc;

        void onBufferedAmountLow();

        bool send(std::string message);
};

inline bool DataChannelWrapper::send(std::string message) {
    if (dc)
    {
        if(requestCount == 0) {       
            bool status = dc->send(reinterpret_cast<rtc::byte *>(message.data()), message.size());

            if(status) {

                requestCount++;
            }

            return status;
        } else {
            requestCount++;

            // Schedule 
            messageQueue.push(message);

            return true;
        }
    } else {
        std::cout << "Shared Pointer is null" << "\n";

        return false;
    }
}

inline void DataChannelWrapper::onBufferedAmountLow() {
    std::cout << "onBufferedAmountLow reached" << "\n";
    
    if(messageQueue.empty()) {
        std::cout << "Empty Message Queue" << "\n";

        return;
    }

    auto message = messageQueue.front();

    dc->send(reinterpret_cast<rtc::byte *>(message.data()), message.size());

    std::cout << "Sent a message from Queue" << "\n";

    messageQueue.pop();

    requestCount--;
}

What can be done to fix this?

Usage of IceServer as a struct in Configuration

To support TURN, username and password needs to be provided. And for doing this, I think struct IceServer should be added and std::vector should be a member variable of Configuration instead of std::vectorstd::string. This will increase the compatibility of datachannel-wasm to the current version of libdatachannel.

I plan to do this, but first mentioning it here since the change won't be 100% backward compatible, though the difference would be trivial enough to catch up. Let me know if this is not what you want.

Native build not building

Rebonjour! I'm trying to build the lowest-level datachannel I can to use the Prolog foreign interface/compiler... in attempting to build this subset for native after cmake -B build-native, in the directory 'build-native' the make doesn't yield anything.

I'm very new to the c/c++ build environment and would definitely try to troubleshoot if I knew more. Any help would be appreciated!

WebSocket error unknown

Code,

#include "rtc/wasm-rtc.hpp"
#include <memory>
#include <iostream>


int main() {
    auto ws = std::make_shared<rtc::WebSocket>();

    ws->onError([](std::string s) {
        std::cout << "WebSocket error"
                  << s
                  << "\n";
    });

    ws->open("ws://whatever.com");

    return 0;
}

Compile with,

em++ main.cpp ^
C:/testPro/testPro/deps/datachannel-wasm/wasm/src/channel.cpp C:/testPro/testPro/deps/datachannel-wasm/wasm/src/datachannel.cpp ^
C:/testPro/testPro/deps/datachannel-wasm/wasm/src/peerconnection.cpp C:/testPro/testPro/deps/datachannel-wasm/wasm/src/websocket.cpp ^
-o testMe.js --bind -Oz -I C:/testPro/testPro -I C:\testPro\testPro\deps\datachannel-wasm\wasm\include ^
-I C:\testPro\testPro\deps\datachannel-wasm\wasm\include\rtc ^
--js-library C:/testPro/testPro/deps/datachannel-wasm/wasm/js/webrtc.js ^
--js-library C:/testPro/testPro/deps/datachannel-wasm/wasm/js/websocket.js ^
-lpthread ^
-s EXPORT_ALL=1 -std=c++1z  -s MODULARIZE=1 -g4 -s "EXPORT_NAME='testMe'" ^ 
-s DISABLE_EXCEPTION_CATCHING=0 -s ASYNCIFY=1 -s NO_EXIT_RUNTIME=1 -s WASM=1  ^ 
-s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap']" -s ALLOW_MEMORY_GROWTH=1 -DNDEBUG=1

Result,

WebSocket error unknown Uncaught 5279544

Real world app stack-trace,

Screenshot_26

To debug the error, I've modified the ./wasm/websocket.js as follows,

		wsCreateWebSocket: function(pUrl) {
			var url = UTF8ToString(pUrl);
			console.log(pUrl)
			if(!window.WebSocket) return 0;
			return WEBSOCKET.registerWebSocket(new WebSocket(url));
		},

The function console log 5279128 and I have no idea why it console log a numeric type data.

Concerns about Async operations

I see a lot of issues lately and I probably think your events causing this. As per emscripten docs,

While waiting on an asynchronous operation browser events can happen. That is often the point of using Asyncify, but unexpected events can happen too. For example, if you just want to pause for 100ms then you can call emscripten_sleep(100), but if you have any event listeners, say for a keypress, then if a key is pressed the handler will fire. If that handler calls into compiled code, then it can be confusing, since it starts to look like coroutines or multithreading, with multiple executions interleaved.

It is not safe to start an async operation while another is already running. The first must complete before the second begins.

Such interleaving may also break assumptions in your codebase. For example, if a function uses a global and assumes nothing else can modify it until it returns, but if that function sleeps and an event causes other code to change that global, then bad things can happen.

My application too heavy on Asyncify. I just wondering what are your thoughts on this?

For example,

If you call this function 1000 times from JS side, the said behavior happen..

void foo(emscripten::val data) {
        emscripten_sleep(100);
}

Missing rtc* functions during linking

I have built datachannel-wasm according to the README except i added emscripten pthread support.
When i try to link like this:

em++ -s USE_PTHREADS=1 -pthread -s PTHREAD_POOL_SIZE=navigator.hardwareConcurrency -L../third/datachannel-wasm/build/ -s INITIAL_MEMORY=419430400 -s TOTAL_STACK=52428800 -s WASM_BIGINT -s "EXPORTED_FUNCTIONS=['_load_image', '_main' ]" -s EXPORTED_RUNTIME_METHODS='["ccall"]' -s FORCE_FILESYSTEM=1 -s STB_IMAGE=1 -s USE_SDL_IMAGE=1 -s USE_SDL_TTF=1 -s USE_LIBPNG=1 -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s STACK_OVERFLOW_CHECK=0 -s ASSERTIONS=0 -s SAFE_HEAP=0 --closure 1-o some.js some1.o some1.o -lm `pkg-config --libs sdl` -ldatachannel-wasm -lwebsocket.js

I get the following errors:
warning: undefined symbol: rtcAddRemoteCandidate (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcCreateDataChannel (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcCreatePeerConnection (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcDeleteDataChannel (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcDeletePeerConnection (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcGetBufferedAmount (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcGetDataChannelLabel (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcSendMessage (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcSetBufferedAmountLowCallback (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcSetBufferedAmountLowThreshold (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcSetDataChannelCallback (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcSetErrorCallback (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcSetGatheringStateChangeCallback (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcSetLocalCandidateCallback (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcSetLocalDescriptionCallback (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcSetMessageCallback (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcSetOpenCallback (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcSetRemoteDescription (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcSetSignalingStateChangeCallback (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcSetStateChangeCallback (referenced by top-level compiled C/C++ code)
warning: undefined symbol: rtcSetUserPointer (referenced by top-level compiled C/C++ code)

What am i doing wrong?

AS option?

Well, It turns out Chrome at least allow to bypass the message size limit by overriding AS Option in SDP so you don't have to listen the events to re-try.

See below comment from https://chromium.googlesource.com/external/webrtc/+/master/api/peer_connection_interface.h

// SetBitrate limits the bandwidth allocated for all RTP streams sent by
// this PeerConnection. Other limitations might affect these limits and
// are respected (for example "b=AS" in SDP)

Historically, this trick has been used by ShareFest application to increase the bandwith limits. See the code,

        transformOutgoingSdp:function (sdp) {
            var split = sdp.split("b=AS:30");
            if(split.length > 1)
                var newSDP = split[0] + "b=AS:1638400" + split[1];
            else
                newSDP = sdp;
            return newSDP;
        }

However, I can't find b=AS in the SDP emitted by this library.

Here is the SDP emitted by this library,

v=0\r\no=- 5271206548905663712 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS\r\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 0.0.0.0\r\na=ice-ufrag:k28H\r\na=ice-pwd:fN8a+9MKrgHDH6oLW2FdpuoF\r\na=ice-options:trickle\r\na=fingerprint:sha-256 EA:D1:13:F7:B1:D6:B9:DD:73:14:79:DD:B3:A9:73:DF:C9:BF:F0:29:19:5D:71:BB:18:52:4F:CF:64:61:1F:A3\r\na=setup:actpass\r\na=mid:0\r\na=sctp-port:5000\r\na=max-message-size:262144\r\n

The only thing I find on this library's SDP is the max-message-size but I don't think Chrome respect this property at all.

suggestion about removing libdatachannel as a submodule

Hi paullouisageneau,

How do you think about removing libdatachannel as a submodule from this repository? A person using libdatachannel and datachannel-wasm together can add both of them as submodules and then add an if statement in their cmake code. As datachannel-wasm is a partial implementation of libdatachannel for wasm without actual code dependency, I think this can make this repository lighter! Versioning can be done by adding a line to the readme file or by adding a Version file.

This improvement would become visible when working with a forked version of libdatachannel with datachannel-wasm. Currently, this leads to having two copies of libdatachannel since there is a forked one and another one inside datachannel-wasm.

And thanks for your continuing work!

datachannel-wasm with C based code

I have used libdatachannel to create a tool that uses signalling, datachannel, and websockets. It is implemented using the capi.c file which is described in the DOC.md file in the repo.

This is building and running on mac and linux well.

I would also like to run the same code, after passing through Emscripten, in a web browser. I had overlooked that datachannel-wasm only mentions C++, rather than C/C++ listed for libdatachannel.

I'm missing why C isn't supported by datachannel-wasm.

I see that the .js files provided in datachannel-wasm look like it has a similar list to the rtc* functions in libdatachannel. Also that libdatachannel the capi.c file seems to just call the existing C++ code, and so it wasn't clear why that same model couldn't apply here too.

I tried to copy across the capi.c to datachannel-wasm but had problems with missing imports/functions. I think some of these are related to media functionality that I'm not using. Would trimming back capi.c to only access the c++ code that was present in datachannel-wasm be a solution?

If it's not possible to support code that uses capi.c (or a trimmed back version), then adding a warning about this in the DOC.md might help someone else not overlook the lack of C support in datachannel-wasm.

Thanks for your help.

Failed to execute 'createDataChannel' on 'RTCPeerConnection': RTCDataChannel cannot have both max retransmits and max lifetime

I basically can't do pc->createDataChannel("label") on either chrome or firefox. I've looked into the javascript and it seems like this exception gets always thrown if both maxRetransmits and maxPacketLifeTime are in the datachannelInit, even if they're both null.

After that I just get a ton of "Module.dynCall is not a function" errors. is there some emscripten flag I am supposed to toggle? I can't find any information about this "dynCall" thing...

How about adding fibers/coroutines for DC's send method?

I aware that we have an ongoing issue; however, I found a way to mimic threading like experience in browsers for DataChannel.send() method.

Fibers/Coroutines can archive concurrency without web workers. I'm unsure about implementation details.

http://js-coroutines.com/

If you look at this lib, it claims "Avoid the jank without having to resort to Worker threads or worry about glitches when you get your results back from them." which is quite sexy for me.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.