Giter Club home page Giter Club logo

Comments (32)

jeffRTC avatar jeffRTC commented on August 11, 2024 1

Fine, I will use in single thread for now. I guess all will be okay.

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024 1

Thank you for this. Everything works now!

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

The issue is that your code opens the WebSocket, then immediately returns which destroys it. The API is asynchronous like the JavaScript one, so when returning from open the WebSocket connection is pending. If you wait for some time without returning immediately it should connect properly.

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

pUrl is actually a C pointer passed to Javascript, that's why it is a number. You need to log url, which is a string.

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

But how would you wait?

I haven't found a method to wait.

I tried with while(true) loop and that also didn't work, error was out instantly but browser halted due to high CPU usage

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

Oh yes sorry, you need to return from wasm code. You should actually put the ws smart point as a global variable to keep it alive.

You can also look into emscripten which has some utilities to simulate infinite loops in wasm code.

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

Global vars are really ugly. How did you used this on your game? Was it global vars?

I've looked but you've not used that. There were no signs of loop either other than the render loop

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

Note that I compile with NO_EXIT_RUNTIME which should allow the WS callbacks to run since NO_EXIT_RUNTIME doesn't run destructors.

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

Global variables are ugly in general, however they are necessary here to keep references between calls from Javascript. You can still organize everything cleanly. In fact, I use one global variable only in my game, here engine actually keeps everything alive, including game state:
https://github.com/paullouisageneau/convergence/blob/d8cdcdfc7e3237e7b1c164d3479be3c684a9f8e6/src/main.cpp#L34

The main loop is simulated with emscripten_set_main_loop:
https://github.com/paullouisageneau/convergence/blob/d8cdcdfc7e3237e7b1c164d3479be3c684a9f8e6/src/main.cpp#L46

NO_EXIT_RUNTIME is enabled by default and it does not do what you think it does, see https://emscripten.org/docs/getting_started/FAQ.html

By default Emscripten sets EXIT_RUNTIME=0, which means that we don’t include code to shut down the runtime. That means that when main() exits, we don’t flush the stdio streams, or call the destructors of global C++ objects, or call atexit callbacks. This lets us emit smaller code by default, and is normally what you want on the web: even though main() exited, you may have something asynchronous happening later that you want to execute.

The point is only not to destroy global objects. It means destructors of objects going out of scope are still called, even in the main function scope.

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

The thing is I need to run your websoocket abstraction in pThreads and when we use shared pointer I guess it use main thread.

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

Hmm there is a keyword called thread_local but not sure whether it would work or not

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

You could set a global shared pointer from a thread.

However, multithreading in wasm is an extremely recent functionality that won't be supported everywhere. Note you might need to configure emscripten to output wasm threads rather than converting them to dummy code if you haven't already.

Also, parts of the wrapper might not work because it calls the Javascript API under the hood. For instance, PeerConnection is not accessible to WebWorkers so I think it may also not be accessible to wasm threads.

My point here is that using threads will cause a lot of issues.

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

So I got the Websocket part fixed by using what you suggested. Now, however; the RTC part seems broken.

std::shared_ptr<rtc::PeerConnection>
RTCTransport::createPeerConnection(const rtc::Configuration &config, std::weak_ptr<rtc::WebSocket> ws, std::string id)
{
    auto pc = std::make_shared<rtc::PeerConnection>(config);

    std::cout << "DEBUG: createPeerConnection has been called" << "\n";

    pc->onLocalDescription([ws, id](rtc::Description description) {
        nlohmann::json message = {{"id", id}, {"type", description.typeString()}, {"sdp", std::string(description)}};

        auto socket = ws.lock();

        if (socket)
        {
            socket->send(message.dump());
        }
    });

    pc->onLocalCandidate([ws, id](rtc::Candidate candidate) {
        nlohmann::json message = {{"id", id},
                                  {"type", "candidate"},
                                  {"candidate", std::string(candidate)},
                                  {"sdpMid", candidate.mid()}};

        auto socket = ws.lock();

        if (socket)
        {
            socket->send(message.dump());
        }
    });

    peerConnectionMap.emplace(id, pc);
    return pc;
}
ws->onOpen([&]() {
      std::cout << "WebSocket connected, signaling ready"
                << "\n";   /// THIS PRINTS

      auto pc = createPeerConnection(config, ws, localID); /// BUT THIS FAILS
      auto dc = pc->createDataChannel(localID);

      dc->onOpen([dc](){
          std::cout << "Data Channel is ready" << "\n";
          dc->send("Heyyyyyyy from Client");
      });

The call to createPeerConnection function in same class fails!

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

What do you mean by "this fails"?

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

Note you have the same problem as before, pc needs to be stored somewhere otherwise it will be destroyed immediately when leaving the scope.

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

Duh!

WebWorkers only support QUIC based Data Channel

paullouisageneau/libdatachannel#111

but your lib has not added that yet

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

The problem is there is virtually no browser support for WebRTC with QUIC for now.

RTCQuicTransport is actually a whole different stack and a whole new API replacing RTCPeerConnection and RTCDataChannel. As of today it's only available on recent Chromium with a developper flag enabled, and documentation is really lacking, I have only seen an ORTC draft published last month.

Don't expect this to be available soon, sadly it'll take some time.

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

I made a global var called std::shared_ptr<rtc::PeerConnection> pc; and the code now looks like this,

ws->onOpen([&]() {
      std::cout << "WebSocket connected, signaling ready"
                << "\n";   /// THIS PRINTS

      pc = createPeerConnection(config, ws, localID); /// BUT THIS FAILS
      auto dc = pc->createDataChannel(localID);

      dc->onOpen([dc](){
          std::cout << "Data Channel is ready" << "\n";
          dc->send("Heyyyyyyy from Client");
      });

But the call to function fails. JS console output again a numeric type value Uncaught 5281056

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

It means there is an uncaught exception, you should add a try/catch block inside the onOpen callback to display it. Also, you should also store the DataChannel somewhere.

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

But why store DC somewhere since WS already stored somewhere?

In my non-wasm code, I didn't do that.

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

Here it will work by chance because the DataChannel onOpen callback will keep a reference. In practice, it's better to pass a weak pointer to allow the DataChannel destruction and prevent a possible memory leak if you forget to close the DataChannel manually.

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

I printed out the error.

Error: allocator::allocate(size_t n) 'n' exceeds maximum supported size

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

Some argument is probably corrupt. How is config allocated?

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

Like this

void RTCTransport::initialize(std::string &WebSocketEndpoint, std::vector<std::string> &iceServers)
{
    //"stun:stun.services.mozilla.com:3478"
    for (const auto &i : iceServers)
    {
        config.iceServers.emplace_back(i);
    }

config is equals to rtc::Configuration config; in RTCTransport class

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

OK, and is the RTCTransport instance a global variable?

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

No.

int main() {
    RTCTransport network;

    std::string endpoint = "ws://whatever.com";

    std::vector<std::string> ICEServers;

    ICEServers.push_back("stun:stun.services.mozilla.com:3478");

    network.initialize(endpoint, ICEServers);
}

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

Well that's your problem, and it's always the same problem. At the end of main, network will be destroyed, so when the onOpen callback is called, it does not exist anymore, and references on it become invalid.

You must not use things allocated in the main function scope in callbacks, you have to allocate them globally.

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

That seems fixed but now getting this error

Error: WebSocket string messages are not supported

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

Oh yes, this is something I need to add to the wrapper, I only use binary messages in my game. For now you can send the messages as rtc::binary.

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

How to convert string to rtc::binary type?

from datachannel-wasm.

jeffRTC avatar jeffRTC commented on August 11, 2024

Perhaps from nlohman directly

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

You can do something like:

std::string str = json.dump();
auto *data = reinterpret_cast<rtc::byte*>(str.data());
socket->send(rtc::binary(data, data+str.size()));

and the other way around:

auto *data = reinterpret_cast<char*>(bin.data());
std::string str(data, data + bin.size());

I'll add string message support when I get the time, it shouldn't be too complex.

from datachannel-wasm.

paullouisageneau avatar paullouisageneau commented on August 11, 2024

@jeffRTC I added support for string messages in 90fdaaa

from datachannel-wasm.

Related Issues (20)

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.