Send and receive objects through WebRTC data channel

1.6k views Asked by At

In my project, I am using WebRTC to connect between 2 client using the aiortc package.

I am using this example code and it works, but it seems I can't send non-string data in the data channel.

This is what I send in the data channel (modified the code in the start function in client.js file):

dc.onopen = function() {
    dataChannelLog.textContent += '- open\n';
    dcInterval = setInterval(function() {
        let message = new DataObject(/*All the parameters*/);
        dataChannelLog.textContent += '> ' + message + '\n';
        dc.send(message);
    }, 100);
};

Where DataObject is a class I created that contains the data I want to send.

The Python client receives [object Object] as a string. I expected it will send the bytes representing the object that I can convert back in Python to a normal class.

I know that a workaround for this is to convert the object to a string-format (like JSON), but I prefer not to do it because I am sending the objects very frequently (and every object contains a large array in it) and I am sure it will lead to a performance issues.

So my question is, how can I send the object through the data channel without converting to a string¿

EDIT: If it helps, I can use an array instead of an object to represent my data. But again, it is still sent and received as a string.

2

There are 2 answers

0
SagiZiv On BEST ANSWER

Thanks o-jones for the detailed answer.

In my case it was fairly simple, because I was able to represent all my data as an array.

The main issue I had is that I didn't know the send function has an "overload" that accepts bytes array

After realizing that, I created a Float32Array in Javascript to hold my data and send it.

And in the Python side, I read this data and converted it to a float array using struct.unpack function.

Something like that:

Javascript side:

dc.onopen = function() {
    dataChannelLog.textContent += '- open\n';
    dcInterval = setInterval(function() {
        let dataObj = new DataObject(/*All the parameters*/);
        let data = new Float32Array(3); // Build an array (in my case 3 floats array)

        // Insert the data into the array
        data[0] = dataObj.value1;
        data[1] = dataObj.value2;
        data[2] = dataObj.value3;

        // Send the data
        dc.send(data);
    }, 100);
};

Python side:

import struct

def message_received(message: str | bytes) -> None:
    if isinstance(message, str):
        return  # Don't handle string messages

    # Read 3 floats from the bytes array we received.
    data = struct.unpack('3f', message)
1
O. Jones On

You need some sort of serializer function to convert your Javascript object into a stream of bytes. Those bytes don't have to be readable as text. You can't just send a Javascript object.

The built-in robust and secure serializer is, of course JSON.stringify(). As you've pointed out JSON is a verbose format.

To avoid using JSON, you'll need to create your own serializer in Javascript and deserializer in Python. Those will most likely be custom code for your particular object type. For best results, you'll copy the attributes of your object, one by one, into a Uint8Array, then send that.

You didn't tell us anything about your object, so it's hard to help you further.

If this were my project I'd get everything working with JSON and then do the custom serialization as a performance enhancement.