paullouisageneau / datachannel-wasm Goto Github PK
View Code? Open in Web Editor NEWC++ WebRTC Data Channels and WebSockets for WebAssembly in browsers
License: MIT License
C++ WebRTC Data Channels and WebSockets for WebAssembly in browsers
License: MIT License
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);
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);
}
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?
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.
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!
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...
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
Can this library create a WASM datachannel in a ServiceWorker
and communicate with window
?
In the source code window
is referenced. ServiceWorker
does not have a window
. globalThis
can be substituted for window
below if in fact datachannel-wasm can be created in a ServiceWorker
(or Worker).
datachannel-wasm/wasm/js/webrtc.js
Line 152 in bb1da1b
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);
}
How do you think about using stringToUTF8 from https://emscripten.org/docs/api_reference/preamble.js.html? In case you are okay with using stringToUTF8, as it is a part of emscripten, in effort to follow the herd to receive free updates (though this function is not something that is likely to change over time), I would like to try using stringToUTF8!
can you provide a wasm file? and a demo? thank you !
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,
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.
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.
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.
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.
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?
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.
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.
Hi, this wasm lib work to Nodejs ? Nodejs not support native webrtc. I can extend functionality with this library for nodejs ?
Could tracks and media transport be supported?
if no, can u explain the problem
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?
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!
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
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!
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!
So I managed to get dynCall by linking with -sEXPORTED_RUNTIME_METHODS=["dynCall"] -sDYNCALLS=1
, but now I'm getting this error about not having free(). I've tried doing -sEXPORTED_RUNTIME_METHODS=["dynCall","_free"]
when I link but It doesn't appear to do anything
Specifically i'm looking at the free() calls from handleCandidate and handeDescription
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?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.