Unreal Media Server v12 sends ISO-BMFF video/mp4 segments of audio-video encoded with H264/AAC codecs via WebSocket protocol. Segment duration is 30ms for real-time mode and 500ms for buffered mode. Below is the protocol structure for sending data via WebSocket connection. Feel free to implement your own JavaScript player using Unreal Media Server's streaming. Websocket is given a URI of Unreal Media Server's IP address:port, followed by the Alias of the live broadcast configured with Unreal Media Server Configurator Example: ws = new WebSocket("http://10.0.0.140:5119/myipcamera"); No additional requests should be sent to the server; now the server starts streaming; the javascript will receive messages according to the following structure: First byte of the message is the message type: 0: error 1: initialization segment 2: media segment Type 0 message structure: byte[0] -> 0 byte[1] -> reserved for future use bytes[2] and further till the end -> Error message encoded with Unicode (2 bytes per char) message If error message is received, the server will close connection. Type 1 message structure: byte[0] -> 1 byte[1] -> flag specifying if we have a single (audio-only or video-only) stream and if it's a real-time or buffered stream bytes[2] - byte[17] (16 bytes) -> reserved for future use bytes[18] - byte[19] -> the length of the following XML metadata string in bytes. It's a word value (2 bytes integer) length (length of metadata) bytes -> the XML metadata string; mime type is one of the XML fields further bytes till the end -> the initialization segment Message of type 1 will be sent in the beginning and can be sent in the middle of the stream, if server changes the content for "live playlist". Type 2 message structure: byte[0] -> 2 byte[1] -> flag specifying if server's buffer is empty or filling. This flag is used for adaptive streaming algorithm. bytes[2] - byte[5] (4 bytes) -> reserved for future use bytes[6] - byte[9] -> timestamp of the segment in miliseconds, 4 bytes integer bytes[10] and further till the end -> the media segment The following JavaScript function can be used for receiving data: function RunWebSocket() { ws = new WebSocket(sURI); ws.binaryType = "arraybuffer"; ws.onmessage = function(evt) { var byteView = new Uint8Array(evt.data); var segment; if (byteView[0] == 0) //Error { var err = new Uint16Array(evt.data, 2, (evt.data.byteLength - 2) / 2); var str = String.fromCharCode.apply(null, err); ShowMessage("Error: " + str, true); closePlayback(); return; } if (byteView[0] == 1) //Init segment { twoStreams = (byteView[1] == 3) || (byteView[1] == 12); realTimeStream = (byteView[1] == 4) || (byteView[1] == 8) || (byteView[1] == 12); var metadatalenArr = new Uint16Array(evt.data, 18, 1); var metadatalen = metadatalenArr[0]; if (!playerStarted) { playerStarted = true; var metadataArr = new Uint16Array(evt.data, 20, metadatalen / 2); var metadatastr = String.fromCharCode.apply(null, metadataArr); var parser = new DOMParser(); var metadataXML = parser.parseFromString(metadatastr, "text/xml"); mimeCodec = metadataXML.getElementsByTagName("mimetypecodec")[0].childNodes[0].nodeValue; sourceBuffer = mediaSrc.addSourceBuffer(mimeCodec); sourceBuffer.addEventListener('updateend', OnBufferUpdated, false); } segment = new Uint8Array(evt.data, 20 + metadatalen, evt.data.byteLength - 20 - metadatalen); } else if (byteView[0] == 2) //Media segment { if (byteView[1] == 1) bufferFillingCounter++; else bufferEmptyCounter++; latestTimestamp = new DataView(evt.data).getInt32(6, true); segment = new Uint8Array(evt.data, 10, evt.data.byteLength - 10); } if (video.error != null) //Stop playing on error { ShowMessage("Error during playback.", true); closePlayback(); return; } if (sourceBuffer != null) //Add segment to queue or sourceBuffer { if (sourceBuffer.updating || segmentsQueue.length > 0) segmentsQueue.push(segment); else sourceBuffer.appendBuffer(segment); } }; }