Skip to content

Retrieving Audio from A100 Audio Gateway

Download recorded audio from a Rhombus A100 Audio Gateway using the API — fetch DASH MPD manifests, retrieve segments, and play back audio over WAN VOD.

On this page

In this guide, you will learn how to retrieve recorded audio from a Rhombus A100 Audio Gateway using the Rhombus API. You will:

  1. Call the API to get media URI templates
  2. Generate a federated session token for WAN playback
  3. Download the DASH MPD and audio segments
  4. Optionally convert the resulting Opus/WebM audio using ffmpeg

Rhombus exposes media access through URI templates rather than returning raw audio bytes directly from a single REST response.

Prerequisites

You will need:

  • An A100 Audio Gateway UUID (Rhombus DeviceFacetUuid / RUUID style string)
  • Recorded audio that exists and is available (determined by your device licensing and recording configuration)
  • A client capable of:
    • Making HTTP requests
    • Parsing XML (for the MPD manifest)
    • Writing binary segment bytes to disk

Implementation steps

  1. Get the A100 Audio Gateway Media URIs

    Call the getMediaUris endpoint to retrieve the URI templates for your 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"
      }'

    Relevant response fields:

    FieldDescription
    wanVodMpdUriTemplateWAN VOD MPD template (use this for recorded audio over WAN)
    wanLiveOpusUriWAN live Opus stream (WebSocket). It doesn't end in /ws: append /ws before you connect
    wanLiveMpdUriWAN live MPD URI
    lanVodMpdUrisTemplatesLAN VOD templates

    LAN URIs (lanLiveOpusUris, lanLiveMpdUris, lanVodMpdUrisTemplates) are served by the gateway itself, which accepts only federated tokens, by design. See Streaming over LAN for authentication and the two-way audio WebSocket format.

    The live Opus socket (wanLiveOpusUri plus /ws) carries listening and two-way talk. From a server, authenticate it with your API key headers or an OAuth access token (Authorization: Bearer <token>); in a browser, use a federated token as query parameters. An OAuth token needs the read scope to listen and the physical scope to send talk audio: audio sent without physical closes the socket with code 1008. If the credential is deleted or revoked, or its role changes, the open socket closes with code 1008 within 60 seconds.

  2. Generate a Federated Session Token

    From a server, you can fetch the WAN MPD and its segments with your API key headers (x-auth-scheme: api-token and x-auth-apikey) on every request, or with Authorization: Bearer <token> for an OAuth access token with the read scope. This guide uses a short-lived federated session token instead, appended as query parameters, which also works in players that can't send headers. (The same two values also work as headers.)

    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
      }'

    Response: Returns federatedSessionToken and expiresAtMs, the time the token expires in Unix milliseconds.

    Warning

    Don't set domain on a token you use from a server. A token minted with domain only works on requests whose Origin (or, when there's no Origin, Referer) is exactly that origin, such as https://app.example.com. Server-side requests send neither, so every MPD and segment request fails with 403 DOMAIN_NOT_ALLOWED. domain must be an absolute origin; a value such as .rhombussystems.com is refused when you mint (400). See The domain field.

    Tip

    durationSec defaults to 3600 (one hour) and can't exceed 86400 (24 hours). For a download that takes longer than the token lasts, mint a new token before the expiresAtMs in the response, as the complete example below does.

  3. Build the WAN VOD MPD URL

    Take the wanVodMpdUriTemplate from Step 1 and perform string substitution:

    • Replace {START_TIME} with your requested start time (in seconds)
    • Replace {DURATION} with your requested duration (in seconds)
    Warning

    Timestamp units matter.

    Rhombus audio endpoints use seconds since epoch (startTimeSec, durationSec). If your timestamps are stored in milliseconds, convert them:

    startTimeSec = startTimeMs / 1000
    durationSec = durationMs / 1000
  4. Fetch the MPD with the Federated Token

    Append the authentication query parameters to your MPD URL:

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

    This MPD is a DASH manifest that describes how to fetch the init segment and subsequent audio segments. On the WAN host, the segment URLs in the MPD carry the same query parameters, so a DASH player given this URL needs nothing else.

  5. Download and Stitch Segments

    If you build the segment URLs yourself, as this guide does, download them in order, appending the same ?x-auth-scheme=federated-token&x-auth-ft=<TOKEN> query parameters you used for the MPD — the segments are served from the same WAN host and use the same authentication:

    1. Init segment (e.g., seg_init_audio.hdr)
    2. Media segments (e.g., seg_1.webm, seg_2.webm, ...)
    Info

    Segments are 2 seconds each. Calculate the number of segments:

    numSegments = durationSec / 2

    Write the init header bytes followed by each segment's bytes to produce a valid WebM/Opus audio file (48 kHz, mono).


Complete Python example

This example implements the full workflow described above:

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:
    """A federated session token for WAN access (no domain: server-side use), minted again before it expires."""

    def __init__(self, duration_sec: int = 3600):
        self.duration_sec = duration_sec  # at most 86400 (24 hours)
        self.token = None
        self.expires_at_ms = 0

    def query(self) -> str:
        # Mint a new token when this one is within a minute of 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:
    """Get media URI templates for an 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:
    """Substitute placeholders in the MPD URI template."""
    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
):
    """Download recorded audio from a Rhombus A100 Audio Gateway."""
    # Step 1: Get media URIs
    media = get_audio_gateway_media_uris(gateway_uuid)
    mpd_template = media["wanVodMpdUriTemplate"]

    # Step 2: Generate federated token (renewed before it expires)
    ft = FederatedToken(duration_sec=3600)

    # Step 3: Build MPD URL
    mpd_uri = build_mpd_uri(mpd_template, start_time_sec, duration_sec)

    # Step 4: Fetch MPD (authenticated via query string)
    mpd_resp = requests.get(mpd_uri + ft.query())
    mpd_resp.raise_for_status()

    # Step 5: Download init segment and media segments.
    # This script builds the segment URLs itself instead of reading them from
    # the MPD, so it appends the token to each one. (Sending the API key
    # headers on every request also works.)
    init_uri = mpd_uri.replace("file.mpd", "seg_init_audio.hdr")
    num_segments = duration_sec // 2

    with open(out_path, "wb") as f:
        # Download init segment
        init_resp = requests.get(init_uri + ft.query())
        init_resp.raise_for_status()
        f.write(init_resp.content)

        # Download media segments
        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  # Example: November 14, 2023
    duration_sec = 60  # 1 minute (max: 86400 seconds / 24 hours)

    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")

Converting audio with ffmpeg

The downloaded audio is in Opus/WebM format (48 kHz, mono). You can convert it to other formats using ffmpeg:

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

Troubleshooting

Empty manifests or missing segments

Cause: Template substitution uses wrong time units.

Solution: If your timestamps are in milliseconds but the template expects seconds, convert them:

python
start_time_sec = start_time_ms // 1000
duration_sec = duration_ms // 1000
MPD rewrite doesn't match your template

Cause: The code assumes the MPD filename is file.mpd.

Solution: If your template uses a different filename, adjust the string replacement logic:

python
# Current logic
init_uri = mpd_uri.replace("file.mpd", "seg_init_audio.hdr")

# Adjust to match your actual filename
init_uri = mpd_uri.replace("your_filename.mpd", "seg_init_audio.hdr")
403 on the MPD or segments

Cause: The token was minted with a domain (403 DOMAIN_NOT_ALLOWED), or the role of the key that minted it can't view the gateway's recorded audio.

Solution: Mint the token without domain for server-side use, from a key whose role can view the gateway, or send your API key headers instead. See Media and streams.

Token expires before download completes

Cause: The download takes longer than the token lasts. Requests then fail with 401 CREDENTIAL_EXPIRED. A token also stops working, with a 401, if it's revoked or the API key that minted it is deleted.

Solution: A token lasts at most 24 hours, so don't rely on a longer durationSec. Mint a new token before the expiresAtMs in the mint response and use it for the remaining segments, as FederatedToken in the complete example does.

API reference

The following endpoints are used in this guide. Visit the API Reference tab for full request and response schemas.