Skip to content

Protocol

Freykin edited this page Feb 25, 2015 · 19 revisions

Protocol

The core concept is that JSON objects are used to send commands, and receive responses and event notifications. Each packet carries a single JSON object. Most commands are used to get or set a property value.

Commands start with a command object, followed by a sequence object.

{
   _command_ : 
   { 
      _command parameters_
   },
  "Sequence" : 0
}

For example, to query the version number and get basic information about the Workbench controller, send this message to get the current value of the System property:

{
  "GetCommand": {
    "System": {
    }
  },
  "Sequence": 1
}

Workbench will respond with:

{
  "GetResponse": {
    "System": {
      "Version": "Streamware Workbench 2.3.19",
      "Talkers": 8,
      "Listeners": 8
    }
  },
  "Sequence": 1,
  "Status": "OK"
}

Workbench fills out the System property object, and returns a response with the same sequence number as the command. The Status object indicates the result.

InterprocessConnection

Workbench Remote uses the JUCE InterprocessConnection class to send and receive data over a socket. The actual data sent over the socket consists of a four byte magic number, followed by a four byte little-endian message length count in bytes, followed by the JSON string.

For example, to transmit this 45 byte JSON string:

{
 "GetCommand": {
  "System": {
  }
 }, 
 "Sequence": 1
}

the following bytes are sent over the socket:

574f524b			Magic number 'WORK'
2d000000			Byte count (32 bits, endian swapped)
7b22476574436f6d	{"GetCom
6d616e64223a207b	mand": {
2253797374656d22	"System"
3a207b7d7d2c2022	: {}}, "
53657175656e6365	Sequence
223a20317d			": 1}

Strings are sent without a zero terminator.

Workbench Controller Commands and Responses

The following is a list of commands that Workbench Remote can send to the Workbench Controller, and the responses for each command.

GetCommand

GetCommand is a command that requests a property or set of properties from the Workbench Controller. Here is an example GetCommand:

{
  "GetCommand": {
    "Foo": {
    }
  },
  "Sequence": 0
}

The first line, '"GetCommand": {', is the command object. It is interpreted by the Controller as the command being sent across.

The second line, '"Foo": {', is the message contained within the command. It describes the property or set of properties being requested.

The fifth line, '"Sequence": 0', is the sequence number of the command. The Controller will use this as the sequence number for its response to this command.

The second line is the one part of the GetCommand structure that will vary.

Here is an example response to a GetCommand:

{
  "GetResponse": {
    "System": {
      "Version": "Streamware Workbench 2.3.23.16",
      "Talkers": 2,
      "Listeners": 2
    }
  },
  "Sequence": 3,
  "Status": "OK"
}

All responses to GetCommands have three values in common.

First, the GetCommand object is replaced with a GetResponse object.

Second, the sequence number is the same as the sequence number sent along with the original GetCommand message.

Third, the Status string contains a status message. Anything other than a status message of "OK" is an error message that details what went wrong; typically it is due to an invalid GetCommand message being sent.

Below are all the currently implemented properties that can be requested, what sort of responses will be received, and examples of how to structure each of them.

System

Sending a GetCommand asking for the System property will lead to a response containing several important bits of information about the Workbench Controller, such as the version number and the number of talker and listener streams.

Here's a properly structured System GetCommand:

{
  "GetCommand": {
    "System": {
    }
  },
  "Sequence": 0
}

When sending a System GetCommand, the System object is empty, as the Workbench Controller responds with its full system information; it doesn't support requesting specific aspects of its system information.

A response to a System GetCommand is structured like this:

{
  "GetResponse": {
    "System": {
      "Version": "Streamware Workbench 2.3.35",
      "Talkers": 2,
      "Listeners": 2,
	  "BroadRReachSupported": true
    }
  },
  "Sequence": 3,
  "Status": "OK"
}

The structure is similar to the System GetCommand, but there are several new and modified fields.

The System object now contains several name/value pairs, detailed below, along with their variable types.

Name Value Variable Types
Version Version number for the Workbench Controller String
Talkers Number of Talker Streams Number
Listeners Number of Listener Streams Number
BroadRReachSupported Whether BroadR-Reach is supported Boolean

Talkers

Sending a Getcommand asking for the Talkers property will lead to a response containing detailed information about the talker streams.

Here's a properly structured Talkers GetCommand:

{
  "GetCommand": {
    "Talkers": [
      {
        "Index": 0
      },
      {
        "Index": 1
      }
    ]
  },
  "Sequence": 1
}

When sending a Talkers GetCommand, the Talkers object should contain an array of JSON name/value pairs, with the name labeled "Index", and the value being the talker stream index number. In the example above, this command would request the first and second talker stream's information.

A response to a Talkers GetCommand is structured like this:

{
  "GetResponse": {
    "Talkers": [
      {
        "Index": 0,
        "Name": "Talker Stream 1",
        "StreamID": "0",
        "DestinationAddress": "91-e0-f0-00-fe-00",
        "Subtype": 2,
        "ChannelCount": 8,
        "Active": false,
        "FaultInjection": {
          "CorruptPackets": {
            "Enabled": false,
            "Percent": "0"
          },
          "DuplicatePackets": {
            "Enabled": false,
            "Percent": "0"
          },
          "TimestampJitter": {
            "Enabled": false,
            "Percent": "0"
          },
          "TimestampJump": {
            "Enabled": false,
            "Percent": "0",
            "Amount": "0"
          }
        }
      }
    ]
  },
  "Sequence": 1,
  "Status": "OK"
}

The structure is similar to the Talkers GetCommand, but now the Talkers object is filled with an array of detailed information about the requested talker streams.

The Talkers object now contains both name/value pairs, and several objects within it as well.

First, here are the name/value pairs, along with their variable types:

Name Value Variable Types
Index Index of the Talker Stream Number
Name Name of the Talker Stream String
DestinationAddress The Talker Stream's current destination address String
Subtype The Talker Stream's current subtype Number
ChannelCount The Talker Stream's current channel count Number
Active Whether the Talker Stream is active Boolean

Next, we have the FaultInjection Object, which contains several objects detailing the current fault injection settings:

Name Value
CorruptPackets What percentage of packets are corrupted
DuplicatePackets What percentage of packets are duplicated
TimestampJitter How often timestamp jitter is inserted
TimestampJump How often a timestamp jump occurs, and how frequently

The name/value pairs within those objects, along with their variable types, are as follows:

Name Value Variable Types
Enabled Whether fault injection for this type of fault is enabled Boolean
Percent How frequently this type of fault injection occurs String
Amount How large a timestamp jump will occur String

The third name/value pair, Amount, only applies to the TimestampJump object.

Listeners

Sending a Getcommand asking for the Listeners property will lead to a response containing detailed information about the listener streams.

The formatting for the Listeners GetCommand is nearly identical to that of the Talkers GetCommand. Here's a properly structured example:

{
  "GetCommand": {
    "Listeners": [
      {
        "Index": 0
      },
      {
        "Index": 1
      }
    ]
  },
  "Sequence": 2
}

As you can see, the only change is the name for the object inside the GetCommand.

The response, however, is different from that of a Talkers GetResponse. Here's how a Listeners GetResponse is structured:

{
  "GetResponse": {
    "Listeners": [
      {
        "Index": 0,
        "Name": "Listener Stream 1",
        "StreamID": "91e0f000fe000080",
        "DestinationAddress": "91-e0-f0-00-fe-80",
        "Subtype": 2,
        "ChannelCount": 8,
        "Active": false
      }
    ]
  },
  "Sequence": 2,
  "Status": "OK"
}

The Listeners object contains a set of name/value pairs detailing the requested listener stream's information. Here's what each name/value pair refers to, and their variable type:

Name Value Variable Type
Index Index of the Listener Stream Number
Name Name of the Listener Stream String
StreamID The Listener Stream's Stream ID String
DestinationAddress The Listener Stream's current destination address String
Subtype The Listener Stream's current subtype Number
ChannelCount The Listener Stream's current channel count Number
Active Whether the Listener Stream is active Boolean

LinkState

Sending a Getcommand asking for the LinkState property will lead to a response containing detailed information about the link state.

The formatting for the LinkState GetCommand is nearly identical to that of the other GetCommands. Here's a properly structured example:

{
  "GetCommand": {
    "LinkState": {
    }
  },
  "Sequence": 13
}

The response for a LinkState GetCommand is different from how the previous responses have been structured. Here's how a LinkState GetResponse is structured:

{
  "GetResponse": {
    "LinkState": {
	  "ConnectState": false,
	  "DuplexState": "full duplex",
	  "TransmitSpeed": 0,
	  "ReceiveSpeed": 0,
	  "AutoNegotiation": false,
	  "EthernetMode": "BroadR-Reach",
	  "BroadRReachMode": "Master" 
    }
  },
  "Sequence": 13,
  "Status": "OK"
}

The LinkState object contains a set of name/value pairs detailing the linkstate's information. Here's what each name/value pair refers to, and their variable type:

Name Value Variable Type
ConnectState Whether the link is connected Boolean
DuplexState The current duplex state String
TransmitSpeed The transmit speed Number
ReceiveSpeed The receive speed Number
AutoNegotiation Whether it is set to auto negotiate Boolean
EthernetMode The ethernet mode String
BroadRReachMode The BroadR-Reach mode String

WorkbenchSettings

Sending a Getcommand asking for the WorkbenchSettings property will lead to a response containing detailed information about settings for Workbench.

The formatting for the WorkbenchSettings GetCommand is nearly identical to that of the other GetCommands. Here's a properly structured example:

{
  "GetCommand": {
    "WorkbenchSettings": {
    }
  },
  "Sequence": 13
}

The response for a WorkbenchSettings GetCommand is different from how the previous responses have been structured. Here's how a WorkbenchSettings GetResponse is structured:

{
  "GetResponse": {
    "WorkbenchSettings": {
	  "StaticPTPRole": "Grandmaster",
	  "PTPSendFollowupTLV": true,
	  "PTPSendAnnounce": false,
	  "PTPSendsignalingFlag": false,
	  "PTPDelayRequest": {
	    "Enabled": true,
	    "Milliseconds": 1000 
      },
	  "TalkerPresentationOffsetMsec": 0,
	  "ListenerPresentationOffsetMsec": 0,
	  "SpdifLocked": false,
	  "EthernetMode": "BroadR-Reach",
	  "BroadRReachMode": "Master"
  },
  "Sequence": 13,
  "Status": "OK"
}

The WorkbenchSettings object contains a set of name/value pairs detailing the settings tab of Workbench. Here's what each name/value pair refers to, and their variable type:

Name Value Variable Type
StaticPTPRole What the PTP role is set to String
PTPSendFollowupTLV Whether Workbench is sending Followup TLV's Boolean
PTPSendAnnounce Whether Workbench is sending announce messages Boolean
PTPSendsignalingFlag Whether Workbench is sending signaling messages Boolean
PTPDelayRequest Object containing DelayRequest information Object
TalkerPresentationOffsetMsec The talker presentation time offset Number
ListenerPresentationOffsetMsec The talker presentation time offset Number
SpdifLocked Whether Spdif is locked Boolean
EthernetMode The ethernet mode String
BroadRReachMode The BroadR-Reach mode String

Inside the Workbench object is another object, labeled PTPDelayRequest. It contains two name/value pairs, detailed below:

Name Value Variable Type
Enabled Whether Workbench is sending delay requests Boolean
Milliseconds How frequently Workbench is sending delay requests Number

The second field, Milliseconds, will not be present if Enabled is set to false.

SetCommand

SetCommand is a command that tells the Workbench Controller to change the value of a property. Here is an example SetCommand:

{
  "SetCommand": {
    "Talkers": [
      {
        "Index": 0,
        "StreamID": "0"
      }
    ]
  },
  "Sequence": 0
}

There are several implemented SetCommands, documented below:

Talkers/Listeners

A Talker/Listener SetCommand needs to specify if it is setting a property for a talker or listener stream, and which talker or listener steam it wants to set the property for. You can set multiple properties for multiple streams in the same SetCommand; however, you cannot set the properties for both talker and listener streams in the same SetCommand.

Here's an example Talker SetCommand, setting some properties for 2 talker streams:

{
  "SetCommand": {
    "Talkers": [
      {
        "Index": 0,
        "StreamID": "0",
        "ChannelCount": 5
      },
      {
        "Index": 1,
        "Subtype: 2
      }
    ]
  },
  "Sequence": 24
}

For both talker and listener streams, here are the properties you can set, and their variable type:

Name Value Variable Type
DestinationAddress The stream's current destination address String
Subtype The stream's current subtype Number
ChannelCount The stream's current channel count Number
Active Whether the stream is active Boolean
StreamID The stream's Stream ID String
AutoStart Whether the stream should start upon start-up Boolean

A response to a Talker/Listener SetCommand is structured like this:

{
  "SetResponse": {
    "Talkers": [
      {
        "Index": 0
      }
    ]
  },
  "Sequence": 29,
  "Status": "OK"
}

The SetResponse will contain the indexes of the talker or listener streams that were set, along with a status message. If the status message is anything other than "OK", it is an error message, typically meaning an invalid value was sent for a property, such as an out of range subtype.

WorkbenchSettings

A WorkbenchSettings SetCommand lets you modify a variety of settings for Workbench. Here's an example of a WorkbenchSettings SetCommand:

{
  "SetCommand": {
    "WorkbenchSettings": {
      "StaticPTPRole": "Follower"
    }
  },
  "Sequence": 53
}

Here are the properties that can be set via a WorkbenchSettings SetCommand:

Name Value Variable Type
StaticPTPRole What the PTP role is set to String
PTPSendFollowupTLV Whether Workbench is sending Followup TLV's Boolean
PTPSendAnnounce Whether Workbench is sending announce messages Boolean
PTPSendsignalingFlag Whether Workbench is sending signaling messages Boolean
TalkerPresentationOffsetMsec The talker presentation time offset Number
ListenerPresentationOffsetMsec The talker presentation time offset Number
SpdifLocked Whether Spdif is locked Boolean
EthernetMode The ethernet mode String
BroadRReachMode The BroadR-Reach mode String

There are two properties that require being inside a PTPDelayRequest object within the WorkbenchSettings object:

Name Value Variable Type
Enabled Whether Workbench is sending delay requests Boolean
Milliseconds How frequently Workbench is sending delay requests Number

Here's an example WorkbenchSettings SetCommand, setting the values within the PTPDelayRequest object:

{
  "SetCommand": {
    "WorkbenchSettings": {
      "PTPDelayRequest": {
        "Enabled": true,
        "Milliseconds": 2000
      }
    }
  },
  "Sequence": 56
}

A response to a WorkbenchSettings SetCommand is structured like this:

{
  "GetResponse": {
    "WorkbenchSettings": {
    }
  },
  "Sequence": 204,
  "Status": "OK"
}

The SetResponse will contain a sequence number and a status message. The sequence number should match the sequence number of the SetCommand it is responding to, and the status message should say OK.If the status message is anything other than "OK", it is an error message, typically meaning an invalid value was sent for a property.

Workbench Controller Event Notifications

There are times when the Workbench Controller will send unsolicited messages to the Workbench Remote.

Currently there is only one message type that is sent unsolicited, which is documented below.

PropertyChanged

A PropertyChanged message is sent from the Workbench Controller to the Workbench Remote whenever a stream's property is changed directly on the Workbench Controller.

It uses its own set of sequence numbers, and therefore bypasses the usual error checking of sequence numbers matching previously sent commands.

Here is an example of a PropertyChanged message:

{
  "PropertyChanged": {
    "Talkers": [
      {
        "Index": 0,
        "StreamID": "2"
      }
    ]
  },
  "Sequence": 19
}

These messages will only contain a single changed property value. In the above example, the StreamID for the first talker stream was changed on the Workbench Controller.

The Workbench Remote updates these properties accordingly as they come in; this way, you do not have to request the talker or listener stream's information again after it has been changed locally on the Workbench Controller; the Workbench Remote will have the new values as soon as you make the change on the Workbench Controller.

The exception to this is when the link state has changed. When that happens, Workbench will send a fully detailed link state object, containing everything that changed. It will look almost identical to the LinkState object structure listed up above, but will have the property PropertyChanged instead of GetResponse.