1. JdPlaySS protocol

1.1. Usage scenarios

  Control the background music host over a network protocol. It supports LAN discovery of and control over the background music host and exposes local and scene music resources together with their controls, and is mainly used by Linux/RTOS gateways.

1.2. Overview

  JdPlaySS is short for JdPlay Server Socket. Drawing on the ideas of the MQTT and DLNA protocols, it is a simple Server Socket based on the TCP protocol. It can be used for LAN background music system control on non-Android/iOS systems (such as Linux gateways) and supports several clients being connected at the same time.

1.3. Interaction diagram

img1

1.4. Conditions & constraints

  The C/S data transfer format is JSON, and the newline character is used as the message separator. Actual newline characters are therefore not allowed inside a message, but escaped newline characters are.

1.5. Discovery protocol

  Device discovery uses the standard mDNS protocol. Use the following commands to discover JdPlaySS devices; the service type is _jdplayss._tcp, the IP address of the JdPlaySS service is 192.168.1.67 and the port number is 8000

$ avahi-browse -a
+   eno1 IPv4 SmartSpeaker H7[1115]                         _jdplayss._tcp       local

$ avahi-browse -r _jdplayss._tcp
+   eno1 IPv4 SmartSpeaker H7[1115]                         _jdplayss._tcp       local
=   eno1 IPv4 SmartSpeaker H7[1115]                         _jdplayss._tcp       local
   hostname = [\040none\041.local]
   address = [192.168.1.67]
   port = [8000]
   txt = ["name=BGM-3588" "id=fe0064a3f0f2b5d73588"]

1.6. Control protocol

1.6.1. Message format

  Data transfer between C and S uses the following fields. Note that seq=0 is reserved for unsolicited feedback from the server.

{
    "type": [int][required] control packet type,
    "seq": [int][optional] control packet sequence number,
    "s0": [string][optional] string parameter 0,
    "s1": [string][optional] string parameter 1,
    "i0": [int][optional] integer parameter 0,
    "i1": [int)[optional] integer parameter 1,
}

1.6.2. Message types

  There are the following message packet types

type value transfer direction description
1 C->S CONNECT: connection request
2 S->C CONNACK: connection response
3 C->S

S->C
PUBLISH: publish message
4 C->S

S->C
PUBACK: publish message acknowledgement
12 C->S PINGREQ: heartbeat request
13 S->C PINGRESP: heartbeat feedback
14 C->S DISCONNECT: disconnection request

1.6.3. Message descriptions

CONNECT

  • i0: version client protocol version, this protocol is 1
  • i1: keepalive heartbeat packet time in seconds, range (10~600 seconds), recommended value 300; the client sends one heartbeat packet or transmits data once every 240 seconds.

CONNACK

  • i0: version server-side protocol version, this protocol is 1
  • i1: 0: success -1: failure
  • s0: the feedback message string, used for debugging

PUBLISH

  Used for message passing between C and S. Two kinds of message are currently supported: control messages (C->S) and unsolicited status feedback messages (S->C). When the client sends a message to the server, the server replies with a PUBACK message; when the server sends feedback to the client on its own initiative, the client does not have to reply with a PUBACK message.

  • seq: [required] message sequence number, incremented from 1 (0: reserved for messages sent on its own initiative by the server)
  • i0: [required] cmd command, the supported commands and parameter settings are as follows.
command value command name direction function request parameters PubAck reply parameters
100 MEDIA_GET_METADATA C->S Get metadata none s0: see metadata
101 MEDIA_PLAY C->S Play none no parameters
102 MEDIA_PAUSE C->S Pause none no parameters
103 MEDIA_NEXT C->S Next track none no parameters
104 MEDIA_PREV C->S Previous track none no parameters
105 MEDIA_SEEK C->S Seek i1: seek position, in seconds no parameters
106 MEDIA_GET_POSITION C->S Get the playback position none s0: current time (seconds): total time (seconds)
107 MEDIA_SET_VOLUME C->S Set the volume i1: volume value (0~100) no parameters
108 MEDIA_GET_VOLUME C->S Get the volume none i1: volume value (0~100)
109 MEDIA_GET_ALL_LOCAL_MEDIA C->S Get the information of all local songs none s0: simple music metadata array
111 MEDIA_SWITCH_PLAY_MODE C->S Switch the playback mode; for radio-type content you are told that mode switching is not supported for radio none no parameters
115 MEDIA_GET_PLAY_MODE C->S Get the current playback mode none

i1: playback mode

0: repeat all

1: repeat one

2: shuffle

116 MEDIA_PLAY_TTS C->S Play the TTS text as speech s0: TTS text no parameters
118 MEDIA_PLAY_HINT_PATH C->S Play a hint tone s0: the full path of the hint tone no parameters
119 MEDIA_GET_AUDIO_SOURCE C->S Get the current audio source none s0: the current audio source
120 MEDIA_SET_AUDIO_SOURCE C->S Switch the audio source s0: target audio source no parameters
150 MEDIA_REPORT_METADATA S->C Report the metadata s0: see metadata the client does not have to reply
151 MEDIA_REPORT_PlAY_STATE S->C Report the playback state i1: playback state

0: paused

1: playing

2: buffering finished

the client does not have to reply
152 MEDIA_REPORT_VOLUME S->C Report the volume i1: volume value (0~100) the client does not have to reply
153 MEDIA_REPORT_PLAY_MODE S->C Report the current playback mode i1: playback mode

0: repeat all

1: repeat one

2: shuffle

3: sequential playback

the client does not have to reply
154 MEDIA_REPORT_AUDIO_SOURCE S->C Report the current audio source none s0: current audio source

sdcard: local

bt: Bluetooth

online: online

auxin: external audio
160 MEDIA_GET_SONGLIST S->C Get a playlist

s0.type: json parameter of the requested songs

0: recently played list

1: my favourites

2: my playlists

100: current playlist

s0: array of music or playlist metadata
161 MEDIA_PLAY_SONGLIST C->S Play a playlist s0: music metadata

i1: playback mode
no parameters
200 DEVICE_POWER_ON C->S Turn the screen on none no parameters
201 DEVICE_POWER_OFF C->S Turn the screen off none no parameters
202 DEVICE_POWER_REBOOT C->S Reboot none no parameters
203 DEVICE_GET_POWER_STATUS C->S Get the power state none i1: 0 means powered off, 1 means powered on
204 DEVICE_GET_INFO C->S Get the device information none s0: Xiaoke host information

uuid, name, version and so on
Metadata
{
  "playState": 1,
  "singer": "Andy Lau",
  "songId": "548408",
  "songTitle": "Love You for Ten Thousand Years",
  "songUrl": "http://www.xxx.com/1.mp3",
  "volume": 80
}
Music metadata
{
  "songId": "548408",
  "songTitle": "Love You for Ten Thousand Years",
  "singer": "Andy Lau",
  "source": "migu",
  "type":2 //playlist or song type
}

PUBACK

  • i0: the same as the PUBLISH cmd command value
  • i1, s0: [optional], if a feedback message is needed

  The reply parameters are as shown in the table above

PINGREQ

  no parameters

PINGRESP

  no parameters

DISCONNECT

  no parameters

1.7. Integration & development

1.7.1. Client-side workflow

  1. Discover the background music host device through DLNA device discovery
  2. Establish a socket connection, TCP-connect to port 8000 of the device's IP address, start sending and receiving socket data, and use the newline character as the packet separator.
  3. Send the CONNECT request; sample data sent {"type":1,"i0":1,"i1":240}

    Wait for the server to report that the connection succeeded. Sample received data {"i0":1,"i1":0,"s0":"OK","seq":0,"type":2}
  4. If the connection succeeded, send the PUBLISH/MEDIA_GET_METADATA request to obtain the metadata. Sample data sent{"type":3,"i0":100,"seq":1}
  5. Decide from the playback state whether to read the playback position periodically; if s0.playState=1, send the get-playback-position request, sample data sent {"type":3,"i0":106,"seq":1}
  6. The client has to send data to the server within the KeepAlive period in order to keep the long connection alive, otherwise the server times out and closes the connection on its own initiative. The client also has to check whether PINGREQ/PINGRESP messages or ACK messages are being received; if the client detects a problem with the communication link, it has to reconnect to the server.
  7. The receiving thread may hear messages about changes to the metadata, the playback state and the volume.

1.8. Testing & debugging methods

  1. Open "Settings > Network settings" in the background music system, check the IP address, and connect to the background music system with telnet
telnet ip address 8000
  1. Following the "Client-side workflow" above, test the interaction with commands in the telnet terminal
=> telnet 192.168.1.154 8000
Trying 192.168.1.154...
Connected to 192.168.1.154.
Escape character is '^]'.
{"type":1,"i0":1,"i1":240}                
{"i0":1,"i1":0,"s0":"OK","seq":0,"type":2}
{"type":3,"i0":101,"seq":1}
{"i0":101,"i1":0,"seq":1,"type":4}
{"i0":150,"i1":0,"s0":"{\"playState\":0,\"singer\":\"Brooke White\",\"songId\":\"1552954\",\"songTitle\":\"Let It Be\",\"songUrl\":\"http://mr3.doubanio.com/87b89194e8858151bf1375eb17c96878/0/fm/song/p1552954_128k.mp3\",\"volume\":40}","seq":0,"type":3}
{"i0":151,"i1":2,"seq":0,"type":3}
{"type":3,"i0":102,"seq":1}
{"i0":151,"i1":0,"seq":0,"type":3}
{"i0":102,"i1":0,"seq":1,"type":4}

Send the "connection request" command

{"type":1,"i0":1,"i1":240}

The background music system returns

{"i0":1,"i1":0,"s0":"OK","seq":0,"type":2}

Send the "play" command

{"type":3,"i0":101,"seq":1}

The background music system returns

{"i0":101,"i1":0,"seq":1,"type":4}
{"i0":150,"i1":0,"s0":"{\"playState\":0,\"singer\":\"Brooke White\",\"songId\":\"1552954\",\"songTitle\":\"Let It Be\",\"songUrl\":\"http://mr3.doubanio.com/87b89194e8858151bf1375eb17c96878/0/fm/song/p1552954_128k.mp3\",\"volume\":40}","seq":0,"type":3}
{"i0":151,"i1":2,"seq":0,"type":3}

Send the "pause" command

{"type":3,"i0":102,"seq":1}

The background music system returns

{"i0":151,"i1":0,"seq":0,"type":3}
{"i0":102,"i1":0,"seq":1,"type":4}

1.9. Reference

1.9.1. Constant definitions

  To keep the developer's workload down, the constants are defined as follows:

//JSSS protocol commands
#define CONNECT  1
#define CONNACK  2
#define PUBLISH  3
#define PUBACK  4
#define PINGREQ  12
#define PINGRESP  13
#define DISCONNECT  14

//JSSS protocol media control commands
#define MEDIA_GET_METADATA  100
#define MEDIA_PLAY  101
#define MEDIA_PAUSE  102
#define MEDIA_NEXT  103
#define MEDIA_PREV  104
#define MEDIA_SEEK  105
#define MEDIA_GET_POSITION  106
#define MEDIA_SET_VOLUME  107
#define MEDIA_GET_VOLUME  108
#define MEDIA_GET_ALL_LOCAL_MEDIA  109
#define MEDIA_PLAY_LOCAL_SONG  110
#define MEDIA_SWITCH_PLAY_MODE  111
#define MEDIA_GET_SCENE_MUSICS  112
#define MEDIA_PLAY_SCENE_MUSIC  113
#define MEDIA_PLAY_ONCE_LOCAL_SONG  114
#define MEDIA_GET_PLAY_MODE  115
#define MEDIA_PLAY_TTS  116
#define MEDIA_PLAY_HINT  117
#define MEDIA_PLAY_HINT_PATH  118
#define MEDIA_GET_AUDIO_SOURCE  119
#define MEDIA_SET_AUDIO_SOURCE  120

//JSSS protocol media status feedback commands
#define MEDIA_REPORT_METADATA  150
#define MEDIA_REPORT_PLAY_STATE  151
#define MEDIA_REPORT_VOLUME  152
#define MEDIA_REPORT_PLAY_MODE  153
#define MEDIA_REPORT_AUDIO_SOURCE  154
#define MEDIA_REPORT_PROGRESS  155

#define MEDIA_GET_SONGLIST 160
#define MEDIA_PLAY_SONGLIST 161

//JSSS protocol device control commands
#define DEVICE_POWER_ON  200
#define DEVICE_POWER_OFF  201
#define DEVICE_POWER_REBOOT  202
#define DEVICE_GET_POWER_STATUS  203
#define DEVICE_GET_INFO  204

1.9.2. Commonly used command examples

Connection command

telnet 10.0.0.26 8000
telnet 192.168.1.176 8000
{"type":1,"i0":109,"i1":240}

Get all local songs

{"type":3,"i0":109,"seq":1}

Play local songs

  Note: before playing local songs you must first send the command that retrieves all local songs. s0: simple music metadata array, i1: index to start playback from

{"i0":110,"i1":0,"s0":"[{\"songId\":\"40\",\"songTitle\":\"DreamVillage_GuZheng-pre\"},{\"songId\":\"101\",\"songTitle\":\"A.I.N.Y.-[Love You]\"}]","seq":1,"type":3}

Play a single local song, without repeating the track

  Note: s0 is a single music metadata json string here

{"i0":114,"i1":0,"s0":"{\"songId\":\"40\",\"songTitle\":\"DreamVillage_GuZheng-pre\"}","seq":1,"type":3}

Get the current audio source

  Note: there are four values of the s0 parameter: sdcard local, bt Bluetooth, online online, auxin external audio

{"i0":119,"seq":1,"type":3}
{"i0":119,"i1":0,"s0":"sdcard","seq":1,"type":4}

Get my playlist list

{"i0":160,"i1":1,"seq":1,"type":3, "s0":"{\"type\":2}"}

Play a playlist

{"i0":161,"i1":1,"seq":1,"type":3,"s0":"{\"songTitle\":\"Test\",\"songId\":\"261aba01-760f-47\",\"singer\":\"\",\"source\":\"\",\"type\":2}"}

Get the current playlist

{"i0":160,"seq":1,"type":3, "s0":"{\"type\":100}"}

Play one song of the current playlist

  Note: i1 is the number of the song to be played

{"i0":161,"i1":1,"seq":1,"type":3,"s0":"{\"type\":100}"}

Switch the audio source

  Note: after switching to the local or the online audio source you have to send the play command before a song can be played

  To play local songs, combine the 109 (get the local songs) and 110 (play a local song) commands above

  To shuffle online songs at random, combine the 120 (switch to the online audio source) and 101 (play a song) commands

C -> S 
{"i0":120,"s0":"online","seq":1,"type":3}
{"i0":120,"s0":"bt","seq":1,"type":3}
{"i0":120,"s0":"sdcard","seq":1,"type":3}
{"i0":120,"s0":"auxin","seq":1,"type":3}

S -> C 
{"i0":120,"i1":0,"seq":1,"type":4}

  an i1 value of 0 means the audio source was switched successfully, -1 means switching the audio source failed

Play

{"i0":101,"seq":1,"type":3}

Get the metadata of the current music

C -> S
{"type":3,"i0":100,"seq":1}

S -> C
{"i0":100,"i1":0,"s0":"{\"playState\":1,\"singer\":\"Harry Styles\",\"songId\":\"003luGpS16qZgi\",\"songTitle\":\"Sweet Creature\",\"songUrl\":\"http://dl.stream.qqmusic.qq.com/C400003luGpS16qZgi.m4a?vkey=E3EDE3145DFD5364AA8DE7315B218A9A963C25BA76AD47D7760486319CB9A3980125E46BD1A19BF0FBC94D2099B32DD27B0B104FF236EBE5&guid=5358354936&fromtag=30\",\"volume\":7}","seq":1,"type":4}

Switch the playback mode

{"type":3,"i0":111,"seq":4}

1.10. FAQ

E: the turn-screen-on/turn-screen-off operations only apply to devices with a screen
Q: why does the server-side socket connection close on its own initiative

  A: please check whether a PING or PUBLISH command was sent within the KeepAlive period

Q: why is the client unable to publish a message

  A: please check whether the seq field is set to a non-zero value and is being incremented actively

Q: testing on Windows with PuTTY

  A:

img2

Send the connection request{"type":1,"i0":1,"i1":240}

img3

Q: strategy for obtaining the information of the currently playing song

  A: once the socket is connected you only have to send the MEDIA_GET_METADATA command once to obtain the information of the currently playing song. As long as the socket connection stays open, the song information is reported actively through MEDIA_REPORT_PlAY_STATE from then on.

Q: which newline character should be used

  A: the newline character is \n throughout

Q: how do I get the device ID of the Xiaoke host

  A: when the device is discovered, the notify packet contains the device ID

Q: what playback modes are there

  A:

  • 0 repeat all REPEAT_ALL
  • 1 repeat one REPEAT_ONE
  • 2 shuffle SHUFFLE
  • 3 sequential playback ORDER
Q: changes to which information are reported by the server on its own initiative

  A: once the song, volume, playback state or playback mode changes on the Xiaoke host, the new state is reported on its own initiative

Q: how do I get the playback progress

  A: for the current playback progress, C has to query S actively, command: MEDIA_GET_POSITION

Q: the client sends an M-SEARCH packet but the server does not answer right away

  A: SSDP packets are multicast packets and may therefore be lost. Each time you send a search packet you can send several

Q: if the network is poor, when does Xiaoke close the connection on its own initiative, and is there a reconnection mechanism

  A: in JSSS Xiaoke acts as the server and does not decide to disconnect based on the network conditions. It does reconnect: the client has to send data to the server within the KeepAlive period to keep the long connection alive, otherwise the server times out and closes the connection on its own initiative. The client also has to check whether PINGREQ/PINGRESP messages or ACK messages are being received; if the client detects a problem with the communication link, it has to reconnect to the server.

results matching ""

    No results matching ""