[SOLVED] [WebGL] returning a byte[] from jslib to unity

How do I return bytes from my .jslib to unity?

After reading Unity - Manual: Interaction with browser scripting I guess I’ll have to _malloc the memory, copy the ArrayBuffer, probably return the pointer to the malloced memory…

But how do I get the length of the array in unity, and who’s responsible for freeing?

just stumbled upon Emscripten: Pointers and Pointers … I think this might help…

What you can do:

Make a function where you pass in a buffer and buffer size, and which returns a length.

If the passed buffer is large enough, it will write to the buffer and return the length it wrote.

If the passed buffer is to small, it will only return the required length.

So, you can call it once passing 0 as buffer length, get the required length in the return value, allocate an array of that size and pass that when you call the function again.

1 Like

I did it… if someone’s curious, here’s my hacky way to do it :slight_smile:

the part in the html template

<script type='text/javascript'>
function sendfile(e){
    var files = e.target.files;
    for (var i = 0, f; f = files[i]; i++) {
        var reader = new FileReader();
        reader.onload = (function(file) {
            return function(e) {
                (window.filedata = window.filedata ? window.filedata : {})[file.name] = e.target.result;
                SendMessage("DaefObject", "FileUpload", file.name);
            }
        })(f);
        reader.readAsArrayBuffer(f);
    }
}
</script>
<input style="color:#ccc;" type="file" multiple="false" id="fileuploader" onchange="sendfile(event);return false;">

the unity part

    public void FileUpload(string filename) {
        var length = GetFileDataLength(filename);
        Alert(length.ToString());

        var ptr = GetFileData(filename);
        var data = new byte[length];
        Marshal.Copy(ptr, data, 0, data.Length);
        FreeFileData(filename);

        Alert(Encoding.ASCII.GetString(data));
    }

the jslib part

var LibraryFileOpen = {
   Alert: function(msgptr) {
     window.alert(Pointer_stringify(msgptr));
   },
   GetFileData: function(filenameptr) {
     var filename = Pointer_stringify(filenameptr);
     var filedata = window.filedata[filename];
     var ptr = (window.fileptr = window.fileptr ? window.fileptr : {})[filename] = _malloc(filedata.byteLength);
     var dataHeap = new Uint8Array(HEAPU8.buffer, ptr, filedata.byteLength);
     dataHeap.set(new Uint8Array(filedata));
     return ptr;
   },
   GetFileDataLength: function(filenameptr) {
     var filename = Pointer_stringify(filenameptr);
     console.log("GetFileDataLength");
     console.log(filename);
     console.log(window);
     console.log(window.filedata);
     return window.filedata[filename].byteLength;
   },
   FreeFileData: function(filenameptr) {
     var filename = Pointer_stringify(filenameptr);
     _free(window.fileptr[filename]);
     delete window.fileptr[filename];
     delete window.filedata[filename];
   }
};

mergeInto(LibraryManager.library, LibraryFileOpen);
5 Likes

Sorry for necroposting… This is pretty much the only resource i could find about this topic, so here goes.

For some reason, SendMessage doesn’t work for me. It did earlier, when I tried to do it in a different way, but now I copied your code to test it out and i get an alert (“ReferenceError: SendMessage is not defined”).

As I said, I was able to SendMessage before, but in the context of your HTML it just won’t work.

Any ideas?

The Unity WebGL application is now loaded into an object in the default template. All you’d need to do is access SendMessage from the object.

So instead of:

SendMessage(“object”, “func”, data);

You’d call (if your object is called gameInstance):

gameInstance.SendMessage(“object”, “func”, data);

From the documentation:

var gameInstance = UnityLoader.instantiate("gameContainer", "Build/build.json", {onProgress: UnityProgress});

THANK YOU

goddamn, is there any documentation of the JSlib functionality in unity? its the 3rd time something should’ve worked that got changed some time along the way.

The documentation(Unity - Manual: Interaction with browser scripting) still has the old way…

@mnml Thanks a lot for this code, saved me a ton of time! One thing though - does the heap allocated in GetFileData ever get freed? [EDIT: after re-reading the code, yes it does!]

@mnml
Very… very smart, thx !

can we pass video streaming data to unity c# from javascript?
if yes how? and how to play video in unity webgl from steaming data?
please help me out.

can you use this to replace UnityWebRequest for larger files to avoid memory allocation that can’t be freed later?