DTSC Specification (V2 rev2, 2023-10-16)
Packet types
DTSC Packets can currently be these types:
DTSC_HEADpackets are 4 bytesDTSC, followed by 4 bytes length and packed content.DTSC_COMMSpackets are 4 bytesDTCM, followed by 4 bytes length and packed content.DTSC_V1packets are 4 bytesDTPD, followed by 4 bytes length and packed content.DTSC_V2packets are 4 bytesDTP2, followed by 4 bytes length, 4 bytes trackID, 8 bytes time, and packed content.
Note: The length is always without the first 8 bytes counted (i.e. only count everything after the length itself).
Packet content
All packed content is stored in a compact format similar to binary JSON. It is encoded as follows: 1 byte data type, followed by some number of bytes of content:
0x01(signed 64 bits integer): 8 bytes of integer contents, in network byte order (MSB first)0x02(string): 4 bytes of string length (MSB first) followed by length-bytes string contents0xE0(object): an arbitrary amount of [2 bytes (MSB)keysize,keysizebytes string key, a single packed DTSC datatype], followed by the 3-byte sequence0x0000EE0x0A(array): an arbitrary amount of [a single packed DTSC datatype], followed by the 3-byte sequence0x0000EE
Note that there is no float or boolean data type. Both are currently represented by integers. Also note that objects are inherently unsorted/unordered. The default implementation sorts alphabetically by key, but this behaviour should not be depended on or expected.
DTSC_HEAD
The DTSC_HEAD packet contains stream metadata, in the following format:
- Optional flag "
vod": integer 1 if VoD (may appear together with "live" flag if both apply) - Optional flag "
live": integer 1 if live (may appear together with "vod" flag if both apply) - Optional deprecated flag "
merged": integer 1 if data is guaranteed to be ordered between tracks - Optional integer "
bufferwindow": time in ms that is buffered in current live stream - Optional integer "
moreheader": byte offset in current file where a header that overrides this header can be found - Optional integer "
unixzero": Unix time in ms that corresponds with the zero point in the timeline of the stream. Automatically calculated from the greatest-value "lastms" field if missing. - Object "
tracks", containing 0 or more of the following object, keyed by human-readable track name (bold entries only required for VoD streams):- Integer "
trackid": 1-indexed unique track ID - String "
fragments": byte-packed binary string with fragment data (content is version-dependant) - String "
keys": byte-packed binary string with key data (content is version-dependant) - String "
parts": byte-packed binary string with fragment data (content is version-dependant) - Optional string "
ivecs": byte-packed binary string with ivec data for encryption (content is version-dependant) - Integer "
firstms": ms position of first available (i.e. requestable) data packet in track - Integer "
lastms": ms position of last available (i.e. requestable) data packet in track - Integer "
bps": estimate of average bytes per second for data in this track (i.e. byterate, not bitrate) - Optional integer "
missed_frags": count of fragments that have been deleted from the buffer since stream start. - String "
codec": name of data codec for this track (e.g. "AAC", "H264", "HEVC", "Opus", "MP3", etc) - String "
type": human-readable type of track (e.g.: "audio", "video", "meta") - Optional string "
init": binary string with codec initialization data - Optional string "
keysizes": byte-packed binary string with key size data (content is version-dependant) - In case
type == "audio":- Integer "
rate": sampling rate in Hz - Integer "
size": sample size in bytes - Integer "
channels": channel count (e.g. 1 for mono, 2 for stereo, etc)
- Integer "
- In case
type == "video":- Integer "
width": width in pixels of video - Integer "
height": height in pixels of video - Integer "
fpks": frames per kilo-second (e.g. 29.97 FPS = 29970 fpks)
- Integer "
- Integer "
DTSC_V1 and DTSC_V2
DTSC_V1 and DTSC_V2 packets are both data packet types. V1 is deprecated, V2 is the new style. They contain the same data, but V2 has the time and trackid fields exposed near the beginning of the packet as opposed to these being in a variable location. This allows for very fast (re)indexing of these files.
All timestamps are DTS (decoding time stamp / time of arrival for packets) in milliseconds from any arbitrary starting point. The timestamp must not wrap mid-stream, which (since it’s unsigned 64 bits) means the max duration for a stream is just under 600 million years. That should be sufficient for any practical purpose.
V2’s "packed data" is an object containing the fields:
data (string): raw codec data for this packet
keyframe (int): only present if the current packet is a video keyframe, and then set to 1
offset (int): only present if DTS and PTS (presentation time stamp / display time) differ, and contains PTS-DTS. This means it must always be positive, as a packet could never be displayed before it is decoded.
V1 in addition contains the fields:
time (int): the packet timestamp (in V2 this field is part of the header)
trackid (int): the packet’s track ID (in V2 this field is part of the header)
Any additional (non-standardized) fields may or may not be ignored, and may or may not be preserved. Custom field names that are not intended to be made part of this specification in the future should be prefixed by a company or project name to prevent namespace collisions.
Signalling
The DTSC_COMMS packet contains a list of DTSC protocol commands, each an object of:
- String
cmd: command identifier string - Optional variable data types: command arguments
command: play
argument stream: (string) name of stream to play
Requests playback start for the given stream.
command: error
argument msg: (string) error message
Pass through an error message.
command: ok
argument msg: (string) non-error message
Pass through an acceptance/status message.
command: push
argument stream: (string) name of stream to receive
argument password (optional string) password, plaintext
Requests storage for the given stream.
command: hi
argument: salt: (optional string) semi-random string for salting communications this connection
argument: version: (optional string) System/server/whatever version, human-readable
argument: pack_method: (integer) Version of packed data parts in headers (0 = error, 1 = old pre-bigmeta style, 2 = bigmeta style)
Welcome message sent by server to client, indicating protocol version and salt for future passwords. Must await at least 1 hi message with valid salt before a push with password is sent (no waiting is necessary for password-less pushing).
command: reset
Requests a reset of the internal metadata of the other side. Should be followed by a DTSC_HEAD packet.
command: ping
Requests a response from the other side. Any response will do, but pong is a good default.