c# - Streaming WebCamTexture with new Unity 5.1 Transport Layer API -
as question states, have been trying stream webcamtexture client webcam server. both sides (client , server) in unity. later, client deployed android , server desktop application.
currently getting pixels of texture using:
tex.getpixels32(); and serializing them custom serializer (to optimize size). have uncompressed byte array around 3,5mb per frame ready sent. know huge, wanted have transmitted before start compression part , real time part.
the last part of process should send using new unity networktransport static class. has been long time since last time used sockets , rotten. unable have working.
here code server side (omitting serialization code clarity):
void start() { webcamtexture = new webcamtexture(); background.texture = webcamtexture; background.material.maintexture = webcamtexture; webcamtexture.play(); if (!_isstarted) { _isstarted = true; networktransport.init(); m_config = new connectionconfig(); m_communicationchannel = m_config.addchannel(qostype.reliablefragmented); hosttopology topology = new hosttopology(m_config, 12); m_generichostid = networktransport.addhost(topology, 0); byte error; m_connectionid = networktransport.connect(m_generichostid, ip, port, 0, out error); } } void update() { if (!_isstarted) return; networkeventtype recdata = networktransport.receive(out rechostid, out connectionid, out channelid, recbuffer, buffersize, out datasize, out error); switch (recdata) { case networkeventtype.nothing: //1 break; case networkeventtype.connectevent: //2 debug.log("received connection confirmation"); _readytosend = true; break; case networkeventtype.dataevent: //3 break; case networkeventtype.disconnectevent: //4 //one of established connection has been disconnected debug.log(string.format("disconnect host {0} connection {1}", rechostid, connectionid)); break; } if (_readytosend) { _readytosend = false; // send first frame byte[] colourarray = serializeobject(makeserializable(getrendertexturepixels(webcamtexture))); // serialize webcam texture // sending total size byte[] sizetosend = bitconverter.getbytes(colourarray.length); networktransport.send(m_generichostid, m_connectionid, m_communicationchannel, sizetosend, sizetosend.length, out error); byte[] bytes = new byte[bufferlenght]; int remainingbytes = colourarray.length; int index = 0; int = 1; while (remainingbytes >= bufferlenght) { system.buffer.blockcopy(colourarray, index, bytes, 0, bufferlenght); networktransport.send(m_generichostid, m_connectionid, m_communicationchannel, bytes, bytes.length, out error); remainingbytes -= bufferlenght; debug.log(i++ + "remaining bytes: " + remainingbytes + " - error: "+error); index += bufferlenght; } if (remainingbytes > 0) // send last fragment below bufferlenght bytes { system.buffer.blockcopy(colourarray, index, bytes, 0, remainingbytes); networktransport.send(m_generichostid, m_connectionid, m_communicationchannel, bytes, remainingbytes, out error); debug.log("error: "+error); } } } and client side:
void start() { if (!_isstarted) { _isstarted = true; networktransport.init(); m_config = new connectionconfig(); m_communicationchannel = m_config.addchannel(qostype.reliablefragmented); hosttopology topology = new hosttopology(m_config, 12); m_generichostid = networktransport.addhost(topology, port, null); } } void update() { if (!_isstarted) return; int rechostid; int connectionid; int channelid; byte[] recbuffer = new byte[bufferlenght]; int buffersize = bufferlenght; int datasize; byte error; networkeventtype recdata = networktransport.receive(out rechostid, out connectionid, out channelid, recbuffer, buffersize, out datasize, out error); switch (recdata) { case networkeventtype.nothing: //1 break; case networkeventtype.connectevent: //2 //somebody else connect me log.text += string.format("connect host {0} connection {1}\n", rechostid, connectionid); break; case networkeventtype.dataevent: //3 if (!sizereceived) { sizereceived = true; if (datasize == 2) { bytestoreceive = bitconverter.toint16(recbuffer, 0); } else if (datasize == 4) { bytestoreceive = bitconverter.toint32(recbuffer, 0); } debug.log("we receive: "+bytestoreceive); } else { log.text = string.format("received event host {0} connection {1} channel {2} message length {3}\n", rechostid, connectionid, channelid, datasize); log.text += "received " + buffersize + " bytes\n"; bytestoreceive -= buffersize; log.text += "remaining " + bytestoreceive + " bytes\n"; } break; case networkeventtype.disconnectevent: //4 break; } } i know block update function until sent, not important right me, since trying frame transmitted understand how new system works, , proceed there. getting error after first package sent, buffer of 32768 bytes:
no free events long message unityengine.networking.networktransport:send(int32, int32, int32, byte[], int32, byte&) camerastreamer:update() (at assets/scripts/client/camerastreamer.cs:112) i have tried use 1024 buffer, , takes longer show message (after more 100 sent packages).
according this thread, related messages being sent fast , filling queue, none of proposed solutions worked me. appreciate or orientation, since unity documentation poor.
this particular test code / example still have issues unity 5.2 patch.
running code in unity 5.3.4f1, able see error 4 (networkerror.noresource) occurs after 200 packets , stops sending shortly afterwards. presume reason because blocking send , message queue never flushes properly.
i've rewritten code grab webcam image off texture after 2 second delay (because webcam needs time intialise, otherwise send blank image).
afterwards sending through webcam image, single packet per execution of update seems fine. because update had time run , not blocked. send packet , exit update function, moving index , other variables out of update.
hope helps else looking @ this, took me 3 days figure out.
edit: testing, more simple method move out blocking send (while bit) , add co-routine. seems work way well.
Comments
Post a Comment