Ir al contenido

Recuperar audio del Audio Gateway A100

Descarga audio grabado de un Rhombus A100 Audio Gateway usando la API: obtén manifiestos MPD de DASH, recupera segmentos y reproduce audio mediante WAN VOD.

En esta página

En esta guía, aprenderás a recuperar audio grabado de un Rhombus A100 Audio Gateway usando la API de Rhombus. Vas a:

  1. Llamar a la API para obtener las plantillas de URI de medios
  2. Generar un token de sesión federado para la reproducción por WAN
  3. Descargar el MPD de DASH y los segmentos de audio
  4. Opcionalmente convertir el audio Opus/WebM resultante usando ffmpeg

Rhombus expone el acceso a los medios mediante plantillas de URI en lugar de devolver los bytes de audio sin procesar directamente desde una única respuesta REST.

Requisitos previos

Necesitarás:

  • Un UUID del A100 Audio Gateway (cadena de estilo DeviceFacetUuid / RUUID de Rhombus)
  • Audio grabado que exista y esté disponible (determinado por las licencias de tu dispositivo y la configuración de grabación)
  • Un cliente capaz de:
    • Realizar solicitudes HTTP
    • Analizar XML (para el manifiesto MPD)
    • Escribir los bytes binarios de los segmentos en disco

Pasos de implementación

  1. Obtener los URIs de medios del A100 Audio Gateway

    Llama al endpoint getMediaUris para recuperar las plantillas de URI de tu audio gateway.

    Endpoint: POST /api/audiogateway/getMediaUris

    bash
    curl --request POST \
      --url https://api2.rhombussystems.com/api/audiogateway/getMediaUris \
      --header 'Content-Type: application/json' \
      --header 'x-auth-scheme: api-token' \
      --header 'x-auth-apikey: YOUR_API_KEY' \
      --data '{
        "gatewayUuid": "AAAAAAAAAAAAAAAAAAAAAA.v0"
      }'

    Campos relevantes de la respuesta:

    CampoDescripción
    wanVodMpdUriTemplatePlantilla MPD de WAN VOD (úsala para audio grabado por WAN)
    wanLiveOpusUriTransmisión Opus en vivo por WAN (WebSocket). No termina en /ws: añade /ws antes de conectarte
    wanLiveMpdUriURI MPD en vivo por WAN
    lanVodMpdUrisTemplatesPlantillas de LAN VOD

    Los URI LAN (lanLiveOpusUris, lanLiveMpdUris, lanVodMpdUrisTemplates) los sirve el propio gateway, que por diseño solo acepta tokens federados. Consulta Streaming por LAN para la autenticación y el formato del WebSocket de audio bidireccional.

    El socket Opus en vivo (wanLiveOpusUri más /ws) transporta la escucha y el audio bidireccional. Desde un servidor, autentícalo con los encabezados de tu clave de API o con un access token de OAuth (Authorization: Bearer <token>); en un navegador, usa un token federado como parámetros de consulta. Un token de OAuth necesita el scope read para escuchar y el scope physical para enviar audio de habla: el audio enviado sin physical cierra el socket con el código 1008. Si la credencial se elimina o revoca, o su rol cambia, el socket abierto se cierra con el código 1008 en 60 segundos o menos.

  2. Generar un token de sesión federado

    Desde un servidor, puedes obtener el MPD por WAN y sus segmentos con los encabezados de tu clave de API (x-auth-scheme: api-token y x-auth-apikey) en cada solicitud, o con Authorization: Bearer <token> para un access token de OAuth con el scope read. Esta guía usa en su lugar un token de sesión federado de corta duración, añadido como parámetros de consulta, que también funciona en reproductores que no pueden enviar encabezados. (Esos mismos dos valores también funcionan como encabezados).

    Endpoint: POST /api/org/generateFederatedSessionToken

    bash
    curl --request POST \
      --url https://api2.rhombussystems.com/api/org/generateFederatedSessionToken \
      --header 'Content-Type: application/json' \
      --header 'x-auth-scheme: api-token' \
      --header 'x-auth-apikey: YOUR_API_KEY' \
      --data '{
        "durationSec": 60
      }'

    Respuesta: Devuelve federatedSessionToken y expiresAtMs, el momento en que expira el token en milisegundos Unix.

    Advertencia

    No uses domain en un token que usarás desde un servidor. Un token generado con domain solo funciona en solicitudes cuyo Origin (o, cuando no hay Origin, Referer) es exactamente ese origen, como https://app.example.com. Las solicitudes del lado del servidor no envían ninguno de los dos, así que todas las solicitudes del MPD y de los segmentos fallan con 403 DOMAIN_NOT_ALLOWED. domain debe ser un origen absoluto; un valor como .rhombussystems.com se rechaza al generar el token (400). Consulta El campo domain.

    Consejo

    durationSec vale 3600 (una hora) de forma predeterminada y no puede superar 86400 (24 horas). Para una descarga que tarda más de lo que dura el token, genera un token nuevo antes del expiresAtMs de la respuesta, como hace el ejemplo completo de abajo.

  3. Construir la URL del MPD de WAN VOD

    Toma el wanVodMpdUriTemplate del Paso 1 y realiza la sustitución de cadenas:

    • Reemplaza {START_TIME} con la hora de inicio solicitada (en segundos)
    • Reemplaza {DURATION} con la duración solicitada (en segundos)
    Advertencia

    Las unidades de las marcas de tiempo importan.

    Los endpoints de audio de Rhombus usan segundos desde la época (startTimeSec, durationSec). Si tus marcas de tiempo están almacenadas en milisegundos, conviértelas:

    startTimeSec = startTimeMs / 1000
    durationSec = durationMs / 1000
  4. Obtener el MPD con el token federado

    Añade los parámetros de consulta de autenticación a tu URL del MPD:

    <mpdUri>?x-auth-scheme=federated-token&x-auth-ft=<TOKEN>

    Este MPD es un manifiesto DASH que describe cómo obtener el segmento de inicialización y los segmentos de audio posteriores. En el host de WAN, las URL de segmento del MPD llevan los mismos parámetros de consulta, así que un reproductor DASH que recibe esta URL no necesita nada más.

  5. Descargar y unir los segmentos

    Si construyes tú mismo las URL de los segmentos, como hace esta guía, descárgalos en orden, añadiendo los mismos parámetros de consulta ?x-auth-scheme=federated-token&x-auth-ft=<TOKEN> que usaste para el MPD: los segmentos se sirven desde el mismo host de WAN y usan la misma autenticación:

    1. Segmento de inicialización (p. ej., seg_init_audio.hdr)
    2. Segmentos de medios (p. ej., seg_1.webm, seg_2.webm, ...)
    Información

    Cada segmento dura 2 segundos. Calcula el número de segmentos:

    numSegments = durationSec / 2

    Escribe los bytes del encabezado de inicialización seguidos de los bytes de cada segmento para producir un archivo de audio WebM/Opus válido (48 kHz, mono).


Ejemplo completo en Python

Este ejemplo implementa el flujo de trabajo completo descrito anteriormente:

python
import time

import requests

BASE_URL = "https://api2.rhombussystems.com"
API_KEY = "YOUR_API_KEY"

HEADERS = {
    "Content-Type": "application/json",
    "x-auth-scheme": "api-token",
    "x-auth-apikey": API_KEY,
}


class FederatedToken:
    """Un token de sesión federado para acceso por WAN (sin domain: uso desde servidor), que se vuelve a generar antes de expirar."""

    def __init__(self, duration_sec: int = 3600):
        self.duration_sec = duration_sec  # 86400 (24 horas) como máximo
        self.token = None
        self.expires_at_ms = 0

    def query(self) -> str:
        # Genera un token nuevo cuando falta menos de un minuto para expiresAtMs
        if time.time() * 1000 > self.expires_at_ms - 60_000:
            url = f"{BASE_URL}/api/org/generateFederatedSessionToken"
            resp = requests.post(url, headers=HEADERS, json={"durationSec": self.duration_sec})
            resp.raise_for_status()
            body = resp.json()
            self.token = body["federatedSessionToken"]
            self.expires_at_ms = body["expiresAtMs"]
        return f"?x-auth-scheme=federated-token&x-auth-ft={self.token}"


def get_audio_gateway_media_uris(gateway_uuid: str) -> dict:
    """Obtiene las plantillas de URI de medios para un audio gateway."""
    url = f"{BASE_URL}/api/audiogateway/getMediaUris"
    resp = requests.post(url, headers=HEADERS, json={"gatewayUuid": gateway_uuid})
    resp.raise_for_status()
    return resp.json()


def build_mpd_uri(template: str, start_time_sec: int, duration_sec: int) -> str:
    """Sustituye los marcadores de posición en la plantilla de URI del MPD."""
    return template.replace("{START_TIME}", str(start_time_sec)).replace(
        "{DURATION}", str(duration_sec)
    )


def download_wan_vod_audio(
    gateway_uuid: str, start_time_sec: int, duration_sec: int, out_path: str
):
    """Descarga audio grabado de un Rhombus A100 Audio Gateway."""
    # Paso 1: Obtener los URIs de medios
    media = get_audio_gateway_media_uris(gateway_uuid)
    mpd_template = media["wanVodMpdUriTemplate"]

    # Paso 2: Generar el token federado (se renueva antes de expirar)
    ft = FederatedToken(duration_sec=3600)

    # Paso 3: Construir la URL del MPD
    mpd_uri = build_mpd_uri(mpd_template, start_time_sec, duration_sec)

    # Paso 4: Obtener el MPD (autenticado mediante la cadena de consulta)
    mpd_resp = requests.get(mpd_uri + ft.query())
    mpd_resp.raise_for_status()

    # Paso 5: Descargar el segmento de inicialización y los segmentos de medios.
    # Este script construye las URL de los segmentos en lugar de leerlas del
    # MPD, así que añade el token a cada una. (Enviar los encabezados de la API
    # key en cada solicitud también funciona.)
    init_uri = mpd_uri.replace("file.mpd", "seg_init_audio.hdr")
    num_segments = duration_sec // 2

    with open(out_path, "wb") as f:
        # Descargar el segmento de inicialización
        init_resp = requests.get(init_uri + ft.query())
        init_resp.raise_for_status()
        f.write(init_resp.content)

        # Descargar los segmentos de medios
        for i in range(1, int(num_segments) + 1):
            seg_uri = mpd_uri.replace("file.mpd", f"seg_{i}.webm")
            seg_resp = requests.get(seg_uri + ft.query())
            seg_resp.raise_for_status()
            f.write(seg_resp.content)


if __name__ == "__main__":
    gateway_uuid = "AAAAAAAAAAAAAAAAAAAAAA.v0"
    start_time_sec = 1700000000  # Ejemplo: 14 de noviembre de 2023
    duration_sec = 60  # 1 minuto (máx.: 86400 segundos / 24 horas)

    download_wan_vod_audio(
        gateway_uuid=gateway_uuid,
        start_time_sec=start_time_sec,
        duration_sec=duration_sec,
        out_path="rhombus_audio.webm",
    )
    print("Wrote rhombus_audio.webm")

Convertir audio con ffmpeg

El audio descargado está en formato Opus/WebM (48 kHz, mono). Puedes convertirlo a otros formatos usando ffmpeg:

bash
ffmpeg -i rhombus_audio.webm -acodec pcm_s16le rhombus_audio.wav

Solución de problemas

Manifiestos vacíos o segmentos faltantes

Causa: La sustitución de la plantilla usa unidades de tiempo incorrectas.

Solución: Si tus marcas de tiempo están en milisegundos pero la plantilla espera segundos, conviértelas:

python
start_time_sec = start_time_ms // 1000
duration_sec = duration_ms // 1000
La reescritura del MPD no coincide con tu plantilla

Causa: El código asume que el nombre del archivo MPD es file.mpd.

Solución: Si tu plantilla usa un nombre de archivo diferente, ajusta la lógica de reemplazo de cadenas:

python
# Lógica actual
init_uri = mpd_uri.replace("file.mpd", "seg_init_audio.hdr")

# Ajusta para que coincida con tu nombre de archivo real
init_uri = mpd_uri.replace("your_filename.mpd", "seg_init_audio.hdr")
403 en el MPD o en los segmentos

Causa: El token se generó con un domain (403 DOMAIN_NOT_ALLOWED), o el rol de la clave que lo generó no puede ver el audio grabado del gateway.

Solución: Para uso desde un servidor, genera el token sin domain, con una clave cuyo rol pueda ver el gateway, o envía en su lugar los encabezados de tu clave de API. Consulta Medios y transmisiones.

El token expira antes de que se complete la descarga

Causa: La descarga tarda más de lo que dura el token. Las solicitudes fallan entonces con 401 CREDENTIAL_EXPIRED. Un token también deja de funcionar, con un 401, si se revoca o si se elimina la clave de API que lo generó.

Solución: Un token dura 24 horas como máximo, así que no dependas de un durationSec más largo. Genera un token nuevo antes del expiresAtMs de la respuesta de generación y úsalo para los segmentos restantes, como hace FederatedToken en el ejemplo completo.

Referencia de la API

Los siguientes endpoints se usan en esta guía. Visita la pestaña API Reference para ver los esquemas completos de solicitud y respuesta.