Intona products are engineered and made in Germany. We ship daily worldwide.

IN3035UG: DPLMX API

 

Introduction

The device can be configured over network. It exchanges commands and responses as JSON objects in UDP packets. The main intention is that this is used as API by control programs, although you can also send and receive raw commands manually.

Each UDP packet contains one or multiple commands as JSON objects, formatted as single line of text. These UDP packets are sent to port 7054. The device will respond with an UDP packet containing JSON object, sent back to the sender's IP, MAC and UDP port.

Here is an example:

User => Device
{"command": "set_session", "seq": 123, "session_name": "my session"}
Device reply
{"seq": 123}

This is the "set_session" command, sent with a "session_name" parameter. The reply does not contain an "error" field, which indicates success. The "seq" field is for free use by the sender (but must be a JSON number), and will be sent back with the reply. It can be used to associate responses with commands.

If you make an error (including JSON syntax errors etc.), the response will be formatted accordingly.

Getting started

This section shows how to initialize the device and how to start audio streaming.

Finding the device on the network

Unless configured otherwise, each device uses an automatically assigned link-local IP address (RFC 3927). Addresses start at 169.254.1.0, but are generally unpredictable and unstable. For example, if a device is restarted, it may pick a different address. You should perform device discovery by sending device_info commands to the broadcast address (169.254.255.255). Alternatively, you can use the net_config command to assign a device a static address.

Use the device_id field (queried with device_info) as unique, stable device identifier.

Sending and receiving commands (via CLI on Linux/macOS/msys)

Since the protocol simply sends and receives UDP packets containing JSON text, you can send and receive commands with common open source tools:

rlwrap -S '> ' nc -u 169.254.1.0 7054 | jq

nc sends and receives UDP packets (as text in this case), rlwrap provides line editing and a history, and jq pretty prints JSON responses.

Setting up audio streaming (via CLI)

The device supports SAP (Session Announcement Protocol, RFC 2974) AES67 session discovery. Passive discovery is always active. The device does by default not play any audio from network. The DPLMX network API can be used to play a specific stream.

AES67 sessions can be listed with:

User => Device
{"command": "list_sessions"}
Device reply
{
  "seq": 0,
  "discovered_sessions": [
    {
      "local_id": 1,
      "type": "SAP",
      "unicast_address": "192.168.5.112",
      "name": "HDLM8-225 : 32",
      "streams": [
        {
          "active": false,
          "connection_ip": "239.69.220.121",
          "port": 5004,
          "samplesize": 24,
          "samplerate": 48000,
          "channels": 4
        }
      ]
    },
    {
      "local_id": 2,
      "type": "SAP",
      "unicast_address": "192.168.5.195",
      "name": "CoreAudio (on imac2)_1",
      "streams": [
        {
          "active": true,
          "connection_ip": "239.1.5.195",
          "port": 5004,
          "samplesize": 24,
          "samplerate": 48000,
          "channels": 8
        }
      ]
    }
  ]
}

This example run returned two AES67 sessions. The device is streaming the second one (active field is set to true).

A specific session can be selected with:

User => device
{"command": "set_session", "local_id": 1}

The set_session command has a large number of parameters, which can be used to control every detail about session selection. Internally, every of these parameters is used to match against the internal list of sessions, and the first matching session is selected. By default, no session matches. Using the local_id parameter is special: it actually sets the parameters which, according to the SAP protocol, uniquely identify a session in a stable way.

Using this command persists all set parameters to the device Flash memory. If the device is rebooted, the parameters are restored.

You can view the streaming status with the show_rtp_status command.

Persistence and reboots

Most device settings are persistent. They are written to flash memory after a certain delay (about 1 second). After boot, the settings are restored from flash.

It can take a while until a rebooted device recovers and streams audio. The following processes incur additional delays:

Firmware updates can reset all or some settings.

AES67 support

The device follows the AES67 standard. The following design choices were made:

Firmware updates

The device runs a TFTP server for firmware updates. It accepts firmware binaries under the name "firmware.bin". All other files are rejected. Update can be done with any TFTP client, for example curl:

curl -T path/to/firmware.bin tftp://169.254.1.0

 

UDP API protocol definition and reference

Basics

Network layer

The protocol uses JSON encoded in UTF-8 text, encapsulated in UDP. Each UDP packet payload contains exactly 1 JSON object (a list of fields enclosed with "{" and "}"). A JSON object cannot span multiple UDP packets. A JSON object represents a single command.

UDP packets are exchanged between device and API client. The API client sends a request, to which the device sends a response immediately.

Clients send UDP packets to port 7054. Since the device tries to send a response to every command, you should send the packets with a valid unicast IP address. The device will attempt to send the packet back to the client, using the command packet's source port as destination port for the response packet. Notifications are packets sent by the device without an associated command.

The device does not support IP fragmentation. All commands and responses are assumed to fit within 1472 bytes of UDP payload. Use of any IPv4 option headers is to be avoided. Be aware that UDP is an unreliable protocol. Packet loss and reordering is possible. The device sends exactly one response for each request, and this response could get dropped by the network. If you do not receive any response, you can not know whether the request or response was dropped (or whether the device went offline). You may have to automatically repeat the request until you get a response (assuming the command is idempotent).

JSON

JSON, as used by the DPLMX network protocol, is specified by RFC 8259 and RFC 7493. The protocol requires that all top-level JSON values are JSON objects, and that each UDP packet contains a single JSON object. In particular, it is assumed that JSON numbers use double floats (binary64 in IEEE 754-2008), which limits their integer precision to about 53 bits (see RFC 7493 section 2.2 for details).

The command reference will use the term "integer" for numbers which are representable as 32 bit signed integers.

Commands

Each JSON object sent to the device represents a single command. It contains the following fields:

 

Reponses

Responses indicate success or failure of a previously sent command. Responses are JSON objects and contain the following fields:

Extensibility

JSON was picked as base of the DPLMX protocol to make it easier to extend the protocol in the future. For this reason, both device and clients must make the following assumptions:

Packet drops and reordering

UDP can drop or reorder packets. Clients can use the "seq" field to avoid confusion due to reordering. It can also be used to detect packet drops (for example, if no response for a command is received, the client can issue a "ping" command to check whether the device is still operating). If a response is lost, the client does not know whether the command was executed, or the result status. In this case the client needs to send the command again to be sure.

Retrieving updates and events from a device

There is no mechanism for receiving any kind of events with the API. Poll the device by sending device_info commands.

 

Reference

list_sessions

List discovered AES67 sessions and streams on the network.

Parameters

None.

Response

MemberTypeMeaning
discovered_sessionsArray of sessionsEach item is a discovered session.

Session objects

Each session (entry in discovered_sessions array) is an object of:

MemberTypeMeaning
local_idIntegerDevice-specific, unstable ID for the session
typeStringSession management protocol; currently always "SAP"
unicast_addressStringIP address or domain name of the session creator
nameStringSession name (as reported by the SDP)
streamsArray of streamsMedia streams in the session. Most sessions will have only 1 stream.

Stream objects

Each stream (entry in streams array) is an object of:

MemberTypeMeaning
activeBoolWhether the stream is currently being played by this device. This is true even if
the actual RTP stream is not sending.
connection_ipStringQuad-dotted IP address of the stream (generally RTP multicast address)
portIntegerPort number of the stream
samplesizeIntegerSize of a single (sub-channel) sample in bits; the firmware supports 16 and
24 bit samples (L16 and L24 formats)
samplerateIntegerNominal samples per second (without PTP correction); the firmware
supports 48000 only
channelsIntegerNumber of channels provided by the audio stream

Description

List all currently discovered sessions and their streams in a human readable format. The "local_id" field exists because there is no simple, globally unique identifier for SAP sessions. This value is a local ID, which is used to refer to the session in some other commands.

Since SAP session discovery is passive on the client side, the command does not cause further network operations or delays. It simply reports a snapshot of the current discovery state.

Example

User => Device
{"command": "list_sessions"}
Device reply
{
  "seq": 0,
  "discovered_sessions": [
    {
      "local_id": 1,
      "type": "SAP",
      "unicast_address": "192.168.5.112",
      "name": "HDLM8-225 : 32",
      "streams": [
        {
          "active": false,
          "connection_ip": "239.69.220.121",
          "port": 5004,
          "samplesize": 24,
          "samplerate": 48000,
          "channels": 4
        }
      ]
    },
    {
      "local_id": 2,
      "type": "SAP",
      "unicast_address": "192.168.5.195",
      "name": "CoreAudio (on imac2)_1",
      "streams": [
        {
          "active": true,
          "connection_ip": "239.1.5.195",
          "port": 5004,
          "samplesize": 24,
          "samplerate": 48000,
          "channels": 8
        }
      ]
    }
  ]
}

set_session

Select which AES67 session should be used for audio output.

Parameters

MemberTypeMeaning
session_nameStringOptional session name to match ("s=" field in SDP)
unicast_addressStringOptional unicast IP or domain to match (<unicast-adress> in SDP)
usernameStringOptional username field to match (<username> in SDP)
session_idStringOptional session ID as string (<sess-id> in SDP)
local_idIntegerOptional ID from "list_sessions" command to use
channelsArray of IntegerOptional channel mapping (see below)
media_indexIntegerOptional media index within session (see below)
link_offsetIntegerOptional number of samples constant latency (see below)

The mentioned SDP fields follow RFC 4566, and match their raw values. Omitted fields (as well as fields set to an empty string) do not participate in the matching.

Response

No additional fields. Note that this command will indicate success even if no session is selected. You can use the list_sessions and show_rtp_status commands to poll the current session selection and streaming status.

Description

Set parameters for session matching and maintenance. It's important to realize that the "session_name", "unicast_address", "username", and "session_id" parameters do not set manual AES67 streaming parameters. Instead, they control how discovered sessions should be matched. The first session which matches all set parameters will "win", and will be used for audio streaming.

The parameters set with this command are persisted to Flash memory. This command fully resets the selection state, and previously set parameters are discarded.

The "media_index" parameter selects which stream within a session should be selected. If omitted or if a negative value is passed, the first supported media stream is selected. Otherwise, the exact stream is selected, going by the order in the SDP (e.g. the first stream listed in the SDP has index 0, the second has index 1, and so on). If no stream can be selected, streaming is disabled.

The "link_offset" parameter is the number of samples that can be buffered between the ingress and egress point of the audio in the network. Refer to the AES67 standard for an exact definition. This value is expressed in number of samples in the stream's sample rate. For example, at 48000 Hz, a value of 48 indicates 1 ms network delay. This value needs to be chosen according to network setup and latency requirements. If this value is too small, audio under runs can happen. A large value will be unsatisfying, as it will force the latency by the same value.

The "channels" parameter controls which channels of the RTP stream will be output by the device. This is an array of N integers. N is the number of channels supported by the device. Each array entry selects the source channel index (with index 0 being the first channel). For example if the parameter is set to [4, 0], source channel 4 from the RTP stream is output on hardware channel 0, and source channel 0 is output on hardware channel 1. If the source channel index is out of bounds (such as negative values), silence will be played. Using -1 for silent channels is recommended to avoid warnings.

The "local_id" parameter is special: the parameter itself is not used for matching. Instead, it selects a session directly, and persists the unique ID of the session to flash memory. To be precise, it persists all parameters that according to the SAP RFC form a unique ID of the session. The "local_id" value is not persisted, and is evaluated while the command runs only. Setting "local_id" to -1 explicitly disables streaming, using any other out of bounds values raises an error.

Example

User => Device
{
  "command": "set_session",
  "session_name": "HDLM8-225 : 32",
  "unicast_address": "192.168.5.112",
  "username": "-",
  "link_offset": 48,
  "channels": [0, 1]
}
Device reply
{
  "seq": 0,
}

device_info

General information about device firmware, DSP settings, and more.

Parameters

None.

Response

MemberTypeMeaning
productStringGeneral product ID. Always "ISAAC".
firmware_versionStringFirmware version identifier in "minor.major" form, for example "1.0".
device_idString128 bit unique hardware identifier in hexadecimal, for example
"00313553504e52433033303436303535". This is the MCU's builtin
UUID. It never changes, unless the MCU is physically replaced.
firmware_update_errorStringOptional. If present, a human readable error description on
firmware update errors. Always cleared on reboots.
product_idIntegerProduct ID (see table below).
dspObjectDSP settings (see table below).
netObjectNetwork settings/state (see table below).
uiObjectInformational fields for Seeburg Network Manager (see table below).

Product IDs

The "product_id" field is encoded as follows:

Raw valueName
0(Never used, might happen on major device flash corruption.)
1SEEBURG G Sub 1201 dp++
2SEEBURG G Sub 1501 dp++
3SEEBURG TriSource 10 dp
4SEEBURG X2 dp
5SEEBURG X4 dp
6SEEBURG X6 dp
7SEEBURG X8 dp
10SEEBURG X1 dp

DSP settings

The response "dsp" field is an object with the following fields:

MemberTypeMeaning
muteBooleanAudio output muted setting.
presetIntegerPreset ID (starting from 0). Meaning and range depend on product_id and
bank fields (see table below).
bankIntegerBank ID (starting from 1). Meaning depends on product_id (see table below).
levelIntegerAudio output level (see table below).
delayFloatAudio output delay in meters (range 0-1.8, out of range undefined).
eq_enBooleanEQ processing enabled.
eq0
eq1
eq2
eq3
eq4
ObjectEach of these 5 fields contains information for each EQ band.
See table below for EQ fields.

Bank/Preset mapping

The dsp bank and preset fields depend on the product_id as follows:

product_idbankpreset list
11"LP 120Hz/HP 120Hz"
"LP 160Hz/HP 160Hz"
"LP 160Hz/HP 120Hz"
"LP 120Hz/HP 120Hz + Aux"
"LP 160Hz/HP 160Hz + Aux"
"LP 160Hz/HP 120Hz + Aux"
12"LP 120Hz/L-Series HP 180Hz"
"LP 160Hz/L-Series HP 180Hz"
"LP 120Hz/L-Serie +Low"
"LP 120Hz/L-Series HP 180Hz + Aux"
"LP 160Hz/L-Series HP 180Hz + Aux"
"LP 120Hz/L-Serie +Low + Aux"
13"LP 120Hz + i5"
"LP 160Hz + i4"
"LP 120Hz + GL-Serie xov"
"LP 120Hz + i5 + Aux"
"LP 160Hz + i4 + Aux"
"LP 120Hz + GL-Serie xov + Aux"
21"LP 100Hz/HP 100Hz"
"LP 140Hz/HP 140Hz"
"LP 140Hz/HP 100Hz"
"LP 100Hz/HP 100Hz + Aux"
"LP 140Hz/HP 140Hz + Aux"
"LP 140Hz/HP 100Hz + Aux"
22"LP 120Hz/GL-Series xov Flat"
"LP 120Hz/GL-Series xov -Low"
"LP 120Hz/GL-Series xov +Low"
"LP 120Hz/GL-Series xov Flat + Aux"
"LP 120Hz/GL-Series xov -Low + Aux"
"LP 120Hz/GL-Series xov +Low + Aux"
23"LP 100Hz/K24 xov Flat"
"LP 120Hz/K20 60° Flat"
"LP 120Hz/K20 90° Flat"
"LP 100Hz/K24 xov Flat + Aux"
"LP 120Hz/K20 60° Flat + Aux"
"LP 120Hz/K20 90° Flat + Aux"
31"Flat"
"HP 100Hz"
"Low-Boost"
"Flat (soft)"
"HP 100Hz (soft)"
"Low-Boost (soft)"
32"Flat on-wall"
"HP 100Hz on-wall"
"Low-Boost on-wall"
"Flat on-wall (soft)"
"HP 100Hz on-wall (soft)"
"Low-Boost on-wall (soft)"
33"Flat in-wall"
"HP 100Hz in-wall"
"Low-Boost in-wall"
"Flat in-wall (soft)"
"HP 100Hz in-wall (soft)"
"Low-Boost in-wall (soft)"
41"Flat"
"HP 120Hz"
"Low-Boost"
"Flat (soft)"
"HP 120Hz (soft)"
"Low-Boost (soft)"
51"Flat"
"HP 100Hz"
"Low-Boost"
"Flat (soft)"
"HP 100Hz (soft)"
"Low-Boost (soft)"
61"Flat"
"HP 100Hz"
"Low-Boost"
"Flat (soft)"
"HP 100Hz (soft)"
"Low-Boost (soft)"
71"Flat"
"HP 100Hz"
"Low-Boost"
"Flat (soft)"
"HP 100Hz (soft)"
"Low-Boost (soft)"

In the table above, the third column specifies the list of presets (starting from preset ID 0) for a specific product_id and bank field ID. For example, with product_id=3 and bank=2, preset=0 selects "Flat on-wall", preset=4 selects "HP 100Hz on-wall (soft)", etc. For product_id=3, the range of the bank field is 1-3, and the range of the preset field is 0-5 (each bank has always the same number of presets for a given product). Setting out of range values lead to undefined behavior.

Audio output levels

The "level" field is encoded as follows:

Raw valueGain
0-12 dB
1-9 dB
2-6 dB
3-3 dB
40 dB
5+3 dB
6+6 dB

Out of range values when setting the field lead to undefined behavior.

EQ fields

Each of the eqN fields is an object with the following fields:

MemberTypeMeaning
enBooleanEnable this band. (If the dsp.eq_en field is false, the EQ is disabled regardless
of the value of the en field.)
typeIntegerEQ type ID (see table below.)
freqFloatEQ band frequency (range 10-24000, out of range undefined).
qFloatEQ Q value (range 0.1-100, out of range undefined).
gainFloatEQ gain value in dB (range: -25-25, out of range undefined).

EQ type

The EQ "type" field is encoded as follows:

Raw valueNameMeaning
0NoneSame function as "en" field set to false.
1LSHELF
2PEQ
3PEQ2
4HSHELF

Out of range values when setting the field will lead to an error response.

Network settings/state

The response "net" field is an object with the following fields:

MemberTypeMeaning
macStringCurrent MAC address, formatted as 6 groups of 2 hexadecimal numbers separated
by ":", for example "AB:CD:12:34:56:7E".
ipStringCurrent IP address formatted as quad-dotted IP address, for example "169.254.1.0".
static_ipStringConfigured static IP address (the same as the "ip" field), or "0.0.0.0" if the IP address
should be dynamically allocated.

UI fields

The response "ui" field is an object with the following fields:

MemberTypeMeaning
orderIntegerOrder ID (used for GUI device list sort order).
nameStringUser-assigned device name (max. 127 bytes).
locStringUser-assigned device location text (max. 127 bytes).
memoStringText field for free use (max. 127 bytes).

Description

This command reports general information about device, network status, and DSP settings. Currently it does not include information about AES67 streaming. This command should be used for device discovery.

The "set_params" command is an important companion command. It mirrors most fields in the "device_info" command, and can be used to set the corresponding fields. All references to setting fields in the parameter description above is in context of the "set_params" command.

Example

User => Device
{"command": "device_info"}
Device reply
{
  "seq": 0,
  ...
}

set_params

Write various device settings.

Parameters

This command mirrors a number of fields in the device_info response. All fields are optional, and only parameters sent with the command are actually set.

MemberTypeOptional, settable sub-fields
dspObjectSettable sub-fields: mute, preset, bank, level, delay, eq_en, eq0, eq1, eq2, eq3, eq4
eq<N> settable sub-sub-fields: en, type, freq, q, gain
netObjectSettable sub-fields: static_ip
uiObjectSettable sub-fields: order, name, loc, memo
product_idIntegerCan only be set if device is uninitialized.

See the device_info command for type and meaning of each field.

Response

Success/error only. If an error happens, and the request contains multiple parameters, it's possible that the request is partially applied. In this case, it's unpredictable which parameters were applied and which not. Use the device_info command to confirm the new values.

If the static_ip field is set, the device may go offline for a while, possibly without being able to send a response for this command.

Description

This command can set most fields which appear in device_info. Name, location, JSON data type, and meaning are exactly the same as the fields in device_info.

Example

This mutes the DSP, and leaves all other parameters untouched:

User => Device
{"command": "set_params", "dsp": { "mute": true }}
Device reply
{"seq": 0}

This sets multiple fields (enable mute, enable EQ 3, set memo to "hello"), and leaves all other parameters untouched:

User => Device
{"command": "set_params", "dsp": { "mute": true, "eq3": {"en": true} },
"ui": { "memo": "hello" } }
Device reply
{"seq": 0}

show_rtp_status

Show information about current AES67 streaming (network to device).

Parameters

None.

Response

MemberTypeMeaning
ipStringIP address of source stream.
portIntegerUDP port of source stream.
clock_offsetIntegerSDP mediaclk parameter (0 if unset)
link_offsetIntegerOffset chosen with set_session command.
samplesizeIntegerAudio sample size in bits per channel
samplerateIntegerAudio sample rate
channelsIntegerNumber of channels sent by source stream.
output_channelsArrayChannels used, as chosen with set_session command.
packet_dropsIntegerNew packet drops since last command.
packet_drop_last_msIntegerAbsolute device time of last packet drop in ms. Can wrap around.
rtp_received_last_msIntegerAbsolute device time of last RTP audio packet received. Can wrap
around.

Description

This shows the status of AES67 streaming, as well as some of the selected parameters.

Example

User => Device
{"command": "show_rtp_status"}
Device reply
{
  "seq": 0,
  ...
}

rtc_get

Read RTC time.

Parameters

None.

Response

MemberTypeMeaning
utcIntegerCurrent time in UTC

Description

Report the current time in UTC from the internal RTC (Real Time Clock). This is maintained independently from the PTP time, and is less precise, but continues progressing while the device is turned off.

Example

User => Device
{"command": "rtc_get"}
Device reply
{
  "seq": 0,
  "utc": 1544017789
}

rtc_set

Set RTC time.

Parameters

MemberTypeMeaning
utcIntegerNew current time in UTC

Response

Success/error only.

Description

Counter part of utc_get.

Example

User => Device
{
  "command": "rtc_set",
  "utc": 1544017789
}
Device reply
{
  "seq": 0,
}

rtc_ntp

Initiate NTP time synchronization.

Parameters

MemberTypeMeaning
ntp_server_ipStringNTP server, formatted as IP address.

Response

Success/error only (this is sent before the NTP server is contacted - it indicates correctness of the command formatting only).

Description

Synchronize with an explicitly specified NTP time server once. This is not like normal NTP operation. The firmware won't attempt to periodically synchronize the time. Instead, the operation ends once a single NTP server packet has been received. whether the time was correctly set should be checked with rtc_get, and there is no event or any other indication whether the time server could even be reached.

Example

User => Device
{
  "rtc_ntp": "rtc_ntp",
  "ntp_server_ip": "192.168.5.132"
}
Device reply
{
  "seq": 0,
}

 

Document version: 15 / Jun 11, 2021 11:51

Download this document as PDF

.
.