CDJ HID Protocol

Background

Historically, DJ controllers (meaning hardware whose purpose is to communicate with digital DJ Software) have been using MIDI over USB. With increasing complexity, the protocol became a bottleneck for certain applications, causing Hardware-manufacturers to start transmitting data via HID. This allows for comparatively simple mechanisms such as simply serializing the status of controls on the controller into a buffer of fixed format but also creating complex proprietary binary protocols involving data fragmented over multiple HID packets, handshakes, variable-length data, etc.

The PioneerDJ CDJ-2000NXS2 has many different ways to communicate with other devices such as other CDJs or Mixers. One if these methods is using a custom Network Protocol called ProDJLink whose reverse engineering efforts have inspired this project as well.

Protocol primitives

Simple header

Every Packet being sent and received to and from the CDJs shares this common header:

0123456789abcdefdecktype001020Packet rest according to type (padded with 00)30

The first byte "deck" uses the more significant nibble to indicate the source/destination deck. It uses 0 for controllers which only have/represent a single deck such as a CDJ and 1-based deck numbers for controllers with multiple decks such as the XDJ-XZ. The "type" byte indicates the type of message being transmitted. This format limits the maximum amount of data transmitted to 62 Bytes which is not sufficient for transmitting larger strings or other binary data such as images. For these purposes, the protocol uses an extended header

Extended Header

Packets with an extended header are able to transmit Bytes (~3.8MB) of data.

0123456789abcdefdecktypeIL001020Packet rest according to type (padded with 00)30

L denotes the number of packets the data following takes up while I indicates the index of the packet fragment in the current stream. Both ushorts encoded in little-endian byte order.

Sysex Extended Header

For packets exchanged via Sysex (such as the DJM-750MK2 and DJM-250MK2), the header has a slightly different format again:

0123456789abcdeff04005spread USB-PID00001020inner packet data307f

The green 0xf0 is just the sysex start. After which follows an extended manufacturer ID (likely the one belonging to Pioneer/AlphaTheta). The four bytes following seem to be the USB Product ID (PID), seemingly followed by the deck index (0x00 for mixers). Afterwards, the inner data follows which is terminated by trailing Sysex EOX (0x7F). Thank you František Kučera a.k.a. xkucf03 for their work on the DJM-250MK2 which helped me spot these differences in the sysex version.

since the PID is 16-bits long (8-bit bytes), but sysex only transmits 7-bit bytes, the 4 4-bit nibbles of the PID are then spaced out over the four 7-bit bytes in the sysex (each nibble occupying the 4 least significant bits).

TLV Structure

Some parts of the Protocol utilize a TLV structure:

TL

These TLV structures can occur nested (for example in the handshake) It seems T only indirectly describes the actual type of data in the buffer. Instead T indicates what the data is actually used for, which in turn describes the actual type of the data.

Thanks

An enormous thanks to James Elliot (@brunchboy) from Deep Symmetry for not only creating bytefield-svg which allowed me to create these awesome bytefield diagrams but also for all of his previous research into the ProDJLink Protocol as well as helping me in the setup of this wiki, using bytefield-svg and supplying me with some USB-Captures of the XDJ-XZ. Also thanks to Ard van Breemen for helping out with his in-depth knowledge of the USB protocol. In addition I also want to thank František Kučera for using my research in his effort to bring Linux Support to the DJM-250MK2 and correcting me in his blogpost. I’d also like to thank Ashley Skye for [contributing the Rekordbox vendor Device ID for the DJM-900NXS2](https://github.com/Swiftb0y/CDJHidProtocol/pull/7)