Estoy seguro de que muchos de los lectores de Habr saben, o al menos han oído, sobre el equipo de audio de Onkyo. Los reproductores de red modernos y los receptores de A / V tienen Linux a bordo, así como la capacidad de conexiones de red cableadas / inalámbricas. Onkyo proporciona su aplicación móvil patentada para el control remoto de dicho dispositivo:
Onkyo Controller . Prácticamente no hay información sobre cómo funciona esta aplicación: hay migajas en los foros, así como varios proyectos en github.

Pero puede encontrar en la red una descripción del Protocolo de comunicación serie integrado a través de Ethernet (eISCP), que es la base de esta aplicación. El protocolo es interesante. En Habré no se pudo encontrar un solo artículo sobre este protocolo. Por un lado, no hay nada trágico en esto, ya que esta propiedad no se usa en ninguna parte, excepto Onkyo. Por otro lado, existe la posibilidad de que haya entusiastas que quieran dirigir su propio reproductor o receptor Onkyo por su cuenta. Además, el artículo puede ser de interés para aquellos que, por pura curiosidad teórica, recopilan conocimientos sobre varios protocolos de red. Si está interesado, por favor, debajo del gato.
Hay poca información oficial sobre el tema del artículo. Por lo tanto, confiaré no solo en la documentación encontrada, ya que describe solo los comandos de protocolo, pero no dice nada sobre las características de su uso. Logramos obtener mucha información del análisis del tráfico de red usando tcpdump / wireshark, así como el estudio del firmware del dispositivo. Aquí es donde comenzaré.
El modelo específico de mi dispositivo no es importante. Solo puedo decir que este es un reproductor de red, similar al de la imagen para llamar la atención. Puede reproducir música no solo desde portadores USB externos, sino también desde un servidor de música (DLNA), y también es compatible con servicios de transmisión y radio por Internet como Spotify, Deezer y algo más. Naturalmente, el protocolo debe soportar toda esta diversidad.
Análisis de puerto
Para comenzar a hacer las preguntas correctas en un motor de búsqueda, primero tuve que entender qué tipo de protocolo se usaba generalmente. Es decir, el primer paso es el análisis de puertos. Entonces, el dispositivo está en la red, su dirección es 192.168.1.80. Escanee todo el rango de puertos:
> nmap -sS -p0-65535 -T5 192.168.1.80 PORT STATE SERVICE 80/tcp open http 4545/tcp open worldscores 5000/tcp open upnp 8008/tcp open http 8009/tcp open ajp13 8080/tcp open http-proxy 8888/tcp open sun-answerbook 10001/tcp open scp-config 60128/tcp open unknown
Se descubren muchas cosas interesantes:
- 80 / tcp está claro: esta es la página de configuración del dispositivo. En mi modelo, solo hay configuración de red y actualización de firmware. No hay control de reproducción. A través de él, a través de enlaces dinámicos como "http://192.168.1.80/album_art.cgi", puede acceder a la imagen de la pista que se está reproduciendo actualmente.
- 4545 / tcp: apareció después de la actualización de firmware más reciente. Nmap no sabe nada de él. Al intentar conectarse, envía inmediatamente json con el estado de reproducción actual y envía una actualización cada segundo
Bloque de datos con estado de reproducción { "data": { "fireCast": false, "status": { "duration": 224893, "playBytes": 0 }, "error": "", "matchingMediaRoles": [], "controls": { "previous": true, "next_": true, "seekBytes": true, "seekTime": true, "pause": true, "seekTrack": true }, "mediaRoles": { "title": "", "asciiTitle": "" }, "playId": { "systemMemberId": "Onkyo NS-6130", "timestamp": 447085 }, "state": "playing", "trackRoles": { "mediaData": { "metaData": { "artist": "Ottawan", "album": "Greatest Hits", "serviceID": "Storage_usb2" } }, "title": "Shalala-Song", "flags": { "file": true }, "path": "storage_file_usb2:sda-94DB-FB8F/flac/Disco/Ottawan/Greatest Hits (2007)/05-Shalala-Song.flac", "optPlayingConentInfo": { "playingTrackTotal": 17, "playingTrackNo": 4 }, "icon": "file:///tmp/temp_data_albumArt_3c70a403584dc761cabc88ac0dfbb95c", "type": "audio" } }, "playTime": { "i64_": 139021, "type": "i64_" }, "senderVolume": {}, "senderMute": {}, "sender": "Onkyo-NS-6130-E1EE7F" }
Como dije, este puerto apareció con la última actualización. No hay documentación de la palabra en absoluto. Puede ser útil para desarrollar un panel de control ligero. Pero en esta dirección aún no he cavado. - 5000 / tcp: nmap lo define como Apple AirTunes. Parece ser cierto, ya que el soporte para este protocolo se indica en la documentación.
- 8008 / tcp, 8009 / tcp: el propósito no está claro, nmap no sabe nada sobre ellos.
- 8080 / tcp: http-proxy, cuyo propósito en el contexto de este reproductor no está del todo claro.
- 8888 / tcp: puerto de protocolo Universal Plug and Play (UpnP) . Usando la utilidad gupnp-universal-cp del paquete gupnp-tools, puede ver su descripción:

Al principio se pensó que la administración en la aplicación oficial se implementó sobre la base de este protocolo particular. Como resultó más tarde, estaba equivocado. También probé varios clientes UpnP, tanto móviles como de escritorio. Todos ellos prácticamente no funcionan: algunos comandos de control funcionan, otros no, y es completamente caótico. - 10001 / tcp: similar al puerto de configuración de SCP, pero no está claro cómo usarlo.
- 60128 / tcp - y, finalmente, el personaje principal de este artículo, el puerto del protocolo eISCP. Nmap tampoco sabe nada de él. Abramos el velo del secreto.
Análisis de tráfico
Ahora verifiquemos qué puerto y cómo se comunica la aplicación oficial con el dispositivo. La forma más fácil de hacerlo es en algunos Android rooteados (pero no en el emulador, ya que la aplicación oficial requiere un dispositivo administrado en la misma subred local). Para hacer esto:
- Instale Android tcpdump en un dispositivo Android donde Onkyo Controller ya está instalado
- Vamos al dispositivo Android a través de adb como root:
> adb root && adb shell root@fiber-bs1078:/>
- vaya a cualquier directorio en la tarjeta SD incorporada:
root@fiber-bs1078:/> cd /sdcard/work root@fiber-bs1078:/sdcard/work>
- ejecutar tcpdump (con escritura en archivo)
root@fiber-bs1078:/sdcard/work> tcpdump -vX -i any -w onkyo.dump host 192.168.1.80 tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
- Lanzamos la aplicación Onkyo, y desde allí comenzamos a reproducir música.
- Cuando se escriben unos cientos de paquetes, detenga tcpdump con Cttl + C
- Regresamos a la terminal, donde lanzamos ADB y copiamos el archivo a una computadora que funciona
root@fiber-bs1078:/sdcard/work> exit > adb pull /sdcard/work/onkyo.dump . [100%] /sdcard/work/onkyo.dump
- Lanzamiento de wireshark y vea qué sucede allí.
> wireshark onkyo.dump &
Y de hecho, la comunicación va por el puerto 60128. Por ejemplo, la aplicación envía una solicitud al jugador:

Y él le responde:

Entonces llegamos a la esencia misma del artículo, a saber: ¿qué hay en las imágenes de arriba para tales cartas - ISCP? Esta abreviatura significa Protocolo de control de serie integrado, originalmente diseñado para controlar dispositivos Onkyo a través del puerto RS-232 (hay un viejo
artículo interesante sobre este tema). Más tarde se amplió agregando el prefijo "e" y resultó eISCP - Integra Serial Communication Protocol over Ethernet. Ambas versiones del protocolo se describen en la Documentación técnica: Protocolo de comunicación serie integrado para receptor AV. La primera versión del documento está fechada el 31 de octubre de 2012, la última que se encontró fue el 4 de septiembre de 2017. Todas las versiones que encontré se recopilan en
mi repositorio del proyecto de demostración , del que hablaré más adelante. La presentación adicional se basará tanto en este documento como en experimentos con mi reproductor (que, sin embargo, no se menciona explícitamente en este documento).
Especificación de mensaje
El cliente (por ejemplo, una aplicación móvil) y el dispositivo intercambian mensajes de texto cortos. Si los números están presentes en él, entonces se presentan, como regla, en forma hexadecimal.
El formato del mensaje del cliente al dispositivo es muy simple:

El mensaje comienza con un carácter "!", Luego el código del dispositivo de destino, seguido de tres letras del comando, y luego una cadena de parámetros de longitud arbitraria. Termina con un CR (0x0D) o LF (0x0A), o una combinación de CR + LF.
Dependiendo del comando, el dispositivo responde con el mismo tipo de mensaje (si fue una solicitud de algún parámetro), o con otro tipo o incluso una combinación de mensajes (si fue un comando para una acción compleja como cambiar una pista). El formato de los mensajes enviados por el dispositivo al cliente es el mismo. La diferencia está solo en el último byte:

El documento de descripción del protocolo contiene más de cien comandos diferentes, mi dispositivo admite un poco más de 30 comandos de este documento. Es decir, tanto el conjunto de comandos como los parámetros válidos dependen del dispositivo específico.
Los comandos se pueden agrupar en grupos lógicos. Como ejemplo, destacaría estos:
- Administración general de dispositivos:
- NDN: nombre del dispositivo.
- UPD: comprobación e instalación de una actualización de firmware.
- PWR: encendido / apagado.
- NRI: información extendida del dispositivo.
- NTC: comandos de un control remoto estándar (incluido el control de reproducción).
- CAP: comandos para controlar un amplificador externo conectado al conector RI.
- Información sobre la pista que se está reproduciendo:
- NAL: nombre del álbum.
- NAT: nombre del artista.
- NTI: nombre de la pista.
- NFI: información del archivo de seguimiento (formato, velocidad de bits).
- NJA: una imagen adjunta a una pista (por ejemplo, el emblema de una estación de radio si se selecciona la radio por Internet).
- NTM: posición de tiempo actual en la pista.
- NTS: estado, rebobinado habilitado o no (para radio por Internet, por ejemplo, no permitido).
- NST: Control de reproducción aleatoria y repetición.
- Navegación y gestión de la biblioteca musical:
- SLI: selección de fuente (por ejemplo, USB, servicios de red).
- NSV: seleccione un servicio de red específico (por ejemplo, radio por Internet, servidor de música). La lista de reproducción en mi dispositivo también se relaciona con servicios de red, aunque esto no es del todo obvio desde el punto de vista de la interfaz de usuario. Y cuando apaga la alimentación (se retira de la toma de corriente), esta lista de reproducción se elimina.
- NLT, NLA: navegación a través de secciones (carpetas) de la biblioteca.
- PQA, PQR, PQO: gestión de listas de reproducción: agregar, eliminar, reordenar.
Naturalmente, esta lista está lejos de ser completa, la di solo para mostrar el alcance y las capacidades de este protocolo.
En términos de parámetros, todos los mensajes se pueden dividir en dos grupos. El primer grupo incluye la mayoría de los mensajes. Para este grupo, la cadena de parámetros contiene datos en forma alfanumérica o hexadecimal y se analiza por byte. Por ejemplo, al cambiar al servicio TuneIn Radio, el reproductor envía un mensaje NLT: información sobre el encabezado de la lista actual con el parámetro "0E01000000090100FF0E00TuneIn Radio", que, decodificado de acuerdo con la especificación, proporciona dicha información:
SERVICE=TUNEIN_RADIO; UI=LIST; LAYER=SERVICE_TOP; CURSOR=0; ITEMS=9; LAYERS=1; START=NOT_FIRST; LEFT_ICON=NONE; RIGHT_ICON=TUNEIN_RADIO; STATUS=NONE; title=TuneIn Radio
Casi todos los mensajes tienen el parámetro "QSTN", por ejemplo, "! 1NLTQSTN". Esta solicitud significa una solicitud al jugador para que devuelva la información del estado actual correspondiente a este tipo de mensaje. Funciona casi siempre, pero hay raras excepciones cuando el jugador, dependiendo de su estado de ánimo interno, ignora tales solicitudes.
El segundo grupo son los mensajes, donde el parámetro es XML, que debe analizarse utilizando un analizador XML. En el ejemplo anterior, mientras está en la sección TuneIn Radio, puede enviar una solicitud de NLA a la que se responderá la información sobre la lista activa en XML:
<?xml version="1.0" encoding="utf-8"?> <response status="ok"> <items offset="0" totalitems="9"> <item icontype="F" iconid="29" title="My Presets" selectable="1" /> <item icontype="F" iconid="29" title="Local Radio" selectable="1" /> <item icontype="F" iconid="29" title="Music" selectable="1" /> <item icontype="F" iconid="29" title="Talk" selectable="1" /> <item icontype="F" iconid="29" title="Sports" selectable="1" /> <item icontype="F" iconid="29" title="By Location" selectable="1" /> <item icontype="F" iconid="29" title="By Language" selectable="1" /> <item icontype="F" iconid="29" title="Podcasts" selectable="1" /> <item icontype="F" iconid="29" title="Login" selectable="1" /> </items> </response>
Es decir, el reproductor no solo proporciona información textual (que, por cierto, actualmente se muestra en la pantalla del reproductor), sino que también recomienda un icono adecuado (carpeta, pista de música, pista actualmente en reproducción).
En algunos casos, el jugador quiere mostrar un mensaje de texto en la aplicación del cliente o solicitar parámetros adicionales como el nombre de usuario. Para hacer esto, el reproductor envía un mensaje universal NCP (diálogo universal), donde el XML describe la estructura de lo que debe mostrarse al usuario:
<?xml version="1.0" encoding="utf-8"?> <popup title="Try Deezer Premium+" align="center" type="custom" time="0" uri="resource:///popup"> <label title="" align="center" total="1" uri="resource:///popup/label:0"> <line text="Listening is limited to 30-second clips. Subscribe to enjoy unlimited music!" align="left" uri="resource:///popup/label/line:0" order="0" /> </label> <buttongroup title="" align="center" total="1" uri="resource:///popup/buttongroup:0"> <button text="OK" align="center" uri="/button:0" selected="false" index="0" www="" order="1" /> </buttongroup> </popup>
En respuesta, el jugador espera el mismo mensaje con los campos rellenados (o el botón presionado).
También en formato XML se presenta un mensaje NRI bastante importante: información general sobre el reproductor. El mensaje es lo suficientemente grande, así que lo oculto debajo del spoiler.
Información general del jugador <?xml version="1.0" encoding="utf-8"?> <response status="ok"> <device id="NS-6130"> <brand>ONKYO</brand> <category>NAP-O</category> <year>2016</year> <model>NS-6130</model> <destination>xx</destination> <macaddress>0009B0E1EE7F</macaddress> <modeliconurl>http://192.168.1.80/icon/OAVR_120.jpg</modeliconurl> <friendlyname></friendlyname> <firmwareversion>2110-0000-0000-0010-0000</firmwareversion> <ecosystemversion>200</ecosystemversion> <netservicelist count="9"> <netservice id="0e" value="1" name="TuneIn Radio" account="Username" password="Password" zone="01" enable="01" /> <netservice id="0a" value="1" name="Spotify" zone="01" enable="01" /> <netservice id="12" value="1" name="Deezer" account="Email address" password="Password" zone="01" enable="01" /> <netservice id="18" value="1" name="AirPlay" zone="01" enable="01" /> <netservice id="1b" value="1" name="TIDAL" account="Username" password="Password" zone="01" enable="01" /> <netservice id="00" value="1" name="Music Server" zone="01" enable="01" addqueue="1" sort="1" /> <netservice id="43" value="1" name="FlareConnect" zone="07" enable="0e" /> <netservice id="40" value="1" name="Chromecast built-in" zone="01" enable="01" /> <netservice id="1d" value="1" name="Play Queue" zone="01" enable="01" /> </netservicelist> <zonelist count="4"> <zone id="1" value="1" name="Main" volmax="0" volstep="0" src="1" dst="1" lrselect="0" /> <zone id="2" value="0" name="Zone2" volmax="0" volstep="0" src="0" dst="0" lrselect="0" /> <zone id="3" value="0" name="Zone3" volmax="0" volstep="0" src="0" dst="0" lrselect="0" /> <zone id="4" value="0" name="Zone4" volmax="0" volstep="0" src="0" dst="0" lrselect="0" /> </zonelist> <selectorlist count="3"> <selector id="2b" value="1" name="NET" zone="01" iconid="2b" /> <selector id="29" value="1" name="USB(F)" zone="01" iconid="29" addqueue="1" /> <selector id="2a" value="1" name="USB(R)" zone="01" iconid="2a" addqueue="1" /> </selectorlist> <presetlist count="40"> <preset id="01" band="0" freq="0" name="" /> <preset id="02" band="0" freq="0" name="" /> <preset id="03" band="0" freq="0" name="" /> <preset id="04" band="0" freq="0" name="" /> <preset id="05" band="0" freq="0" name="" /> <preset id="06" band="0" freq="0" name="" /> <preset id="07" band="0" freq="0" name="" /> <preset id="08" band="0" freq="0" name="" /> <preset id="09" band="0" freq="0" name="" /> <preset id="0a" band="0" freq="0" name="" /> <preset id="0b" band="0" freq="0" name="" /> <preset id="0c" band="0" freq="0" name="" /> <preset id="0d" band="0" freq="0" name="" /> <preset id="0e" band="0" freq="0" name="" /> <preset id="0f" band="0" freq="0" name="" /> <preset id="10" band="0" freq="0" name="" /> <preset id="11" band="0" freq="0" name="" /> <preset id="12" band="0" freq="0" name="" /> <preset id="13" band="0" freq="0" name="" /> <preset id="14" band="0" freq="0" name="" /> <preset id="15" band="0" freq="0" name="" /> <preset id="16" band="0" freq="0" name="" /> <preset id="17" band="0" freq="0" name="" /> <preset id="18" band="0" freq="0" name="" /> <preset id="19" band="0" freq="0" name="" /> <preset id="1a" band="0" freq="0" name="" /> <preset id="1b" band="0" freq="0" name="" /> <preset id="1c" band="0" freq="0" name="" /> <preset id="1d" band="0" freq="0" name="" /> <preset id="1e" band="0" freq="0" name="" /> <preset id="1f" band="0" freq="0" name="" /> <preset id="20" band="0" freq="0" name="" /> <preset id="21" band="0" freq="0" name="" /> <preset id="22" band="0" freq="0" name="" /> <preset id="23" band="0" freq="0" name="" /> <preset id="24" band="0" freq="0" name="" /> <preset id="25" band="0" freq="0" name="" /> <preset id="26" band="0" freq="0" name="" /> <preset id="27" band="0" freq="0" name="" /> <preset id="28" band="0" freq="0" name="" /> </presetlist> <controllist count="61"> <control id="Bass" value="0" zone="1" min="-10" max="10" step="2" /> <control id="Treble" value="0" zone="1" min="-10" max="10" step="2" /> <control id="Center Level" value="0" zone="1" min="-12" max="12" step="1" /> <control id="Subwoofer Level" value="0" zone="1" min="-15" max="12" step="1" /> <control id="Subwoofer1 Level" value="0" zone="1" min="-15" max="12" step="1" /> <control id="Subwoofer2 Level" value="0" zone="1" min="-15" max="12" step="1" /> <control id="Phase Matching Bass" value="0" /> <control id="LMD Movie/TV" value="0" code="MOVIE" position="1" /> <control id="LMD Music" value="0" code="MUSIC" position="2" /> <control id="LMD Game" value="0" code="GAME" position="3" /> <control id="LMD THX" value="0" code="04" position="4" /> <control id="LMD Stereo" value="0" code="00" position="4" /> <control id="LMD Direct" value="0" code="01" position="1" /> <control id="LMD Pure Audio" value="0" code="11" position="2" /> <control id="LMD Pure Direct" value="0" code="11" position="1" /> <control id="LMD Auto/Direct" value="0" code="AUTO" position="2" /> <control id="LMD Stereo G" value="0" code="STEREO" position="3" /> <control id="LMD Surround" value="0" code="SURR" position="4" /> <control id="TUNER Control" value="0" /> <control id="TUNER Freq Control" value="0" /> <control id="Info" value="2" /> <control id="Cursor" value="1" /> <control id="Home" value="0" code="HOME" position="2" /> <control id="Setup" value="1" code="MENU" position="2" /> <control id="Quick" value="0" code="QUICK" position="1" /> <control id="Menu" value="0" code="MENU" position="1" /> <control id="AMP Control(RI)" value="1" /> <control id="CD Control(RI)" value="1" /> <control id="CD Control" value="0" /> <control id="BD Control(CEC)" value="0" /> <control id="TV Control(CEC)" value="0" /> <control id="NoPowerButton" value="0" /> <control id="DownSample" value="0" /> <control id="Dimmer" value="1" /> <control id="time_hhmmss" value="1" /> <control id="Zone2 Control(CEC)" value="0" /> <control id="Sub Control(CEC)" value="0" /> <control id="NoNetworkStandby" value="0" /> <control id="NJAREQ" value="1" /> <control id="Music Optimizer" value="0" /> <control id="NoVideoInfo" value="1" /> <control id="NoAudioInfo" value="1" /> <control id="AV Adjust" value="0" /> <control id="Audio Scalar" value="0" /> <control id="Hi-Bit" value="0" /> <control id="Upsampling" value="0" /> <control id="Digital Filter" value="1" /> <control id="DolbyAtmos" value="0" /> <control id="DTS:X" value="0" /> <control id="MCACC" value="0" /> <control id="Dialog Enhance" value="0" /> <control id="PQLS" value="0" /> <control id="CD Control(NewRemote)" value="0" /> <control id="NoVolume" value="1" /> <control id="Auto Sound Retriever" value="0" /> <control id="Lock Range Adjust" value="0" /> <control id="P.BASS" value="0" /> <control id="Tone Direct" value="0" /> <control id="DetailedFileInfo" value="1" /> <control id="NoDABPresetFunc" value="0" /> <control id="S.BASS" value="0" /> </controllist> <functionlist count="10"> <function id="UsbUpdate" value="0" /> <function id="NetUpdate" value="1" /> <function id="WebSetup" value="1" /> <function id="WifiSetup" value="1" /> <function id="Nettune" value="0" /> <function id="Initialize" value="0" /> <function id="Battery" value="0" /> <function id="AutoStandbySetting" value="0" /> <function id="e-onkyo" value="0" /> <function id="UsbDabDongle" value="0" /> </functionlist> <tuners count="0"></tuners> </device> </response>
El conjunto de comandos que tendrá que usar para controlar el dispositivo depende en gran medida de lo que se encuentre en las secciones de lista de control y zonel de este mensaje.
ISCP sobre Ethernet (eISCP)
Los mensajes en el formulario, como escribí anteriormente, están destinados a la transmisión por cable (RS-232). Los receptores más antiguos estaban equipados para esto con un conector RS-232 de 9 pines. Cuando, en lugar de este conector, comenzaron a utilizar una conexión de red (por cable o inalámbrica), tuvimos que envolver estos mensajes en un contenedor para su transmisión a través de TCP / IP. Entonces apareció el protocolo eISCP, donde el mensaje ISCP está envuelto en dicho paquete:

Debajo del spoiler se encuentra el código del procedimiento que genera completamente dicho paquete para un mensaje con un código dado (código variable), una cadena de parámetros (parámetros variables) y una versión de protocolo dada (versión variable). Como el procedimiento es bastante simple, me parece que el código Java dirá mucho más que mil palabras.
Procedimiento para generar un mensaje eISCP private final static int MIN_MSG_LENGTH = 22; private final static String MSG_START = "ISCP"; private final static Character START_CHAR = '!'; private final static int LF = 0x0A; ... byte[] getBytes() { if (headerSize + dataSize < MIN_MSG_LENGTH) { return null; } final byte[] bytes = new byte[headerSize + dataSize]; Arrays.fill(bytes, (byte) 0);
Si alguien está interesado,
aquí está mi implementación de protocolo de ejemplo para la
versión de especificación 1.40 . También le daré un enlace a
este repositorio . Implementa una biblioteca de mensajes y una utilidad de línea de comandos en Python, así como enlaces a otros proyectos similares.
Implementación de intercambio de información
Los mensajes en sí, originalmente diseñados para la transmisión por cable de baja velocidad, son bastante pequeños. Además, el reproductor en sí también es bastante modesto: en el contexto de una gran cantidad de estadísticas enviadas en algún lugar al servidor condicional de Amazon, la cantidad de información que el jugador brinda voluntariamente al cliente a través de ISCP es escasa. En la especificación del protocolo no hay una palabra sobre cuándo y bajo qué condiciones el jugador envía esta o aquella información. Por lo tanto, tuve que experimentar el tiempo suficiente para que el cliente móvil siempre tuviera toda la información necesaria sobre el estado actual del dispositivo.
En general, la comunicación con el jugador se basa en un esquema de solicitud / respuesta. Además, en ciertas situaciones, una sola solicitud no estará limitada. Hay varios eventos clave para mi reproductor que deben manejarse:
- Establece una conexión. En el momento de la conexión, el reproductor puede estar en modo de espera o encendido, puede estar en modo de reproducción o pausa. También es importante averiguar de inmediato en qué posición se encuentra el conmutador de canal de entrada, en los servicios de red o USB.
Por lo tanto, inmediatamente después de establecer la conexión, tiene sentido enviar solicitudes PWR (activas o en estado de espera), UPD (hay una actualización de firmware), NRI (información general sobre el dispositivo), SLI (posición del interruptor de entrada), NJA (modo de transmisión de la imagen de la pista - por enlace o transmisión). Mi reproductor envía específicamente el estado de reproducción y la posición actual por iniciativa propia. - Comience la reproducción. En esta situación, el jugador envía toda la información sobre la pista. Pero cuando se conecta, cuando el jugador ya está jugando algo, el jugador no envía nada. Además, cuando el jugador cambia la pista, no se envía toda la información.
Una solución universal, aunque con muchos recursos, era rastrear el mensaje NST (estado de reproducción), y si este estado cambiaba a "Reproducir", enviar inmediatamente 7 solicitudes: NAT (artista), NAL (título del álbum), NTI (título de la pista), NFI (información de archivo), NTR (número de pista), NTM (tiempo de reproducción actual), NMS (menú de pista). Hay características en el firmware del reproductor. Por ejemplo, cuando se reproduce una lista de reproducción, el jugador no quiere regalar el número de la pista que se está reproduciendo. Pero, en general, puede aprender con suficiente detalle el estado actual de la reproducción. - ( ) . - . , . — 14 !
10-27 16:12:20.272: NLU[00080011; 8/17] 10-27 16:12:27.338: NTI[09-Roses Are Red.flac] 10-27 16:12:27.342: NAL[] 10-27 16:12:27.342: NAT[] 10-27 16:12:27.342: NDN[] 10-27 16:12:27.343: NJA/1937[2-...; TYPE=URL; PACKET=NOT_USED; URL=http://192.168.1.80/album_art.cgi; RAW(null)] 10-27 16:12:27.649: NMS[xxxxxS1f1; TRACK_MENU=DISABLE; POS_FEED=DISABLE; NEG_FEED=DISABLE; TIME_SEEK=ENABLE; TIME_DISPLAY=ELAPSED_TOTAL; ICON=USB_REAR] 10-27 16:12:27.649: NTR[0009; 0011] 10-27 16:12:27.649: NFI[/44.1kHz/16bit; FORMAT=; FREQUENCY=44.1kHz; BITRATE=16bit] 10-27 16:12:27.649: NLT[F1020000000B060002FF00Aquarium (1997); SERVICE=USB_REAR; UI=LIST; LAYER=UNDER_2ND_LAYER; CURSOR=0; ITEMS=11; LAYERS=6; START=NOT_FIRST; LEFT_ICON=USB; RIGHT_ICON=NONE; STATUS=NONE; title=Aquarium (1997)] 10-27 16:12:27.724: NLS[C0P; INF_TYPE=CURSOR; LINE_INFO=0; PROPERTY=NO; UPD_TYPE=PAGE; LIST_DATA=null] 10-27 16:12:27.727: NLS[U0-Happy Boys & Girls; INF_TYPE=UNICODE; LINE_INFO=0; PROPERTY=NO; UPD_TYPE=NO; LIST_DATA=Happy Boys & Girls] 10-27 16:12:27.734: NLS[U1-My Oh My; INF_TYPE=UNICODE; LINE_INFO=1; PROPERTY=NO; UPD_TYPE=NO; LIST_DATA=My Oh My] 10-27 16:12:27.737: NLS[U2-Barbie Girl; INF_TYPE=UNICODE; LINE_INFO=2; PROPERTY=NO; UPD_TYPE=NO; LIST_DATA=Barbie Girl] 10-27 16:12:27.740: NLS[U3-Good Morning Sunshine; INF_TYPE=UNICODE; LINE_INFO=3; PROPERTY=NO; UPD_TYPE=NO; LIST_DATA=Good Morning Sunshine] 10-27 16:12:27.760: NLA[X0002S000...; RESP=X; SEQ_NR=2; STATUS=S; UI=LIST; XML=<?xml version="1.0" encoding="utf-8"?><response status="ok"><items offset="0" totalitems="11" ><item icontype="M" iconid="2d" title="Happy Boys & Girls" selectable="1" /><item icontype="M" iconid="2d" title="My Oh My" selectable="1" /><item icontype="M" iconid="2d" title="Barbie Girl" selectable="1" /><item icontype="M" iconid="2d" title="Good Morning Sunshine" selectable="1" /><item icontype="M" iconid="2d" title="Doctor Jones" selectable="1" /><item icontype="M" iconid="2d" title="Heat Of The Night" selectable="1" /><item icontype="M" iconid="2d" title="Be A Man" selectable="1" /><item icontype="M" iconid="2d" title="Lollipop (Candyman)" selectable="1" /><item icontype="0" iconid="36" title="Roses Are Red" selectable="1" /><item icontype="M" iconid="2d" title="Turn Back Time" selectable="1" /><item icontype="M" iconid="2d" title="Calling You" selectable="1" /></items></response>] 10-27 16:12:29.697: NTI[Roses Are Red] 10-27 16:12:29.718: NJA/1952[2-...; TYPE=URL; PACKET=NOT_USED; URL=http://192.168.1.80/album_art.cgi; RAW(null)] 10-27 16:12:30.248: NAL[Aquarium] 10-27 16:12:30.248: NAT[Aqua] 10-27 16:12:30.248: NDN[] 10-27 16:12:30.248: NMS[xxxxxS1f1; TRACK_MENU=DISABLE; POS_FEED=DISABLE; NEG_FEED=DISABLE; TIME_SEEK=ENABLE; TIME_DISPLAY=ELAPSED_TOTAL; ICON=USB_REAR] 10-27 16:12:30.248: NTR[0009; 0011] 10-27 16:12:30.248: NFI[FLAC/44.1kHz/16bit; FORMAT=FLAC; FREQUENCY=44.1kHz; BITRATE=16bit] 10-27 16:12:30.248: NLT[F1020000000B060002FF00Aquarium (1997); SERVICE=USB_REAR; UI=LIST; LAYER=UNDER_2ND_LAYER; CURSOR=0; ITEMS=11; LAYERS=6; START=NOT_FIRST; LEFT_ICON=USB; RIGHT_ICON=NONE; STATUS=NONE; title=Aquarium (1997)] 10-27 16:12:30.248: NMS[xxxxxS1f1; TRACK_MENU=DISABLE; POS_FEED=DISABLE; NEG_FEED=DISABLE; TIME_SEEK=ENABLE; TIME_DISPLAY=ELAPSED_TOTAL; ICON=USB_REAR] 10-27 16:12:30.248: NFI[FLAC/44.1kHz/16bit; FORMAT=FLAC; FREQUENCY=44.1kHz; BITRATE=16bit] 10-27 16:12:30.248: NLT[F1020000000B060002FF00Aquarium (1997); SERVICE=USB_REAR; UI=LIST; LAYER=UNDER_2ND_LAYER; CURSOR=0; ITEMS=11; LAYERS=6; START=NOT_FIRST; LEFT_ICON=USB; RIGHT_ICON=NONE; STATUS=NONE; title=Aquarium (1997)] 10-27 16:12:34.815: NMS[xxxxxS1f1; TRACK_MENU=DISABLE; POS_FEED=DISABLE; NEG_FEED=DISABLE; TIME_SEEK=ENABLE; TIME_DISPLAY=ELAPSED_TOTAL; ICON=USB_REAR] 10-27 16:12:34.819: NFI[FLAC/44.1kHz/16bit; FORMAT=FLAC; FREQUENCY=44.1kHz; BITRATE=16bit] 10-27 16:12:34.860: NLT[F1020000000B060002FF00Aquarium (1997); SERVICE=USB_REAR; UI=LIST; LAYER=UNDER_2ND_LAYER; CURSOR=0; ITEMS=11; LAYERS=6; START=NOT_FIRST; LEFT_ICON=USB; RIGHT_ICON=NONE; STATUS=NONE; title=Aquarium (1997)]
, . , , , .
Como ejemplo, daré un enlace a mi repositorio con la aplicación de Android para el control remoto del reproductor Onkyo NS-6130. Existe la posibilidad de que también funcione con el Onkyo NS-6170. Pero no podrá usarlo con ningún receptor de Onkyo, ya que toda la interfaz de la aplicación está diseñada específicamente para reproducir y administrar la biblioteca de música, que, por regla general, no está en los receptores. Por lo tanto, no tengo planes de distribuir de alguna manera esta aplicación, aquí escribo sobre ella solo como un ejemplo de la implementación de este protocolo.La estructura de la aplicación es simple, el diseño es minimalista. Solo hay tres pestañas:- . , . , RI Onkyo. , , , .



A diferencia de una aplicación patentada, es 10 veces más pequeña, más receptiva, admite orientación de pantalla horizontal y varios temas de diseño. Cubre todo el rango de mis tareas por completo, aunque las hay y dónde expandirlas. Sin embargo, también, a diferencia de una aplicación patentada, no es universal.Si después de leer este artículo, uno de los propietarios de dispositivos Onkyo quiere experimentar con su copia, espero que este material y mi aplicación de ejemplo bajen el umbral para ingresar al tema.Gracias por su atencion!