Skip to content

PRESET_PLAYBACK

scheilch edited this page Mar 8, 2026 · 2 revisions

🇬🇧 English version

Preset-Wiedergabe – Technische Referenz

Stand: 2026-02-22
Status: Funktionsfähig (MVP)

Dieses Dokument beschreibt, wie OpenCloudTouch (OCT) die Preset-Wiedergabe auf Bose SoundTouch-Geräten nach der Abschaltung der Bose Cloud ermöglicht.

Überblick

SoundTouch-Geräte unterstützen 6 Hardware-Presets (Tasten 1-6). Nach der Cloud-Abschaltung funktionieren die ursprünglichen TuneIn-basierten Presets nicht mehr. OCT bietet eine Alternative über die LOCAL_INTERNET_RADIO-Quelle mit direkten Stream-URLs.

Architektur

┌─────────────────────────────────────────────────────────────────┐
│                    SoundTouch-Gerät                             │
│  1. Ruft /bmx/registry/v1/services beim Booten ab              │
│  2. Speichert Presets lokal (XML)                               │
│  3. Bei Preset-Taste: ruft die Location-URL auf                 │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    OCT-Server                                   │
│  - /bmx/registry/v1/services → Service-Registry                │
│  - /core02/svc-bmx-adapter-orion/prod/orion/station?data=...   │
│    → Dekodiert Base64-JSON, gibt BmxPlaybackResponse zurück     │
└─────────────────────────────────────────────────────────────────┘

Preset-XML-Format

Funktionierendes Format: LOCAL_INTERNET_RADIO

<preset id="4">
  <ContentItem source="LOCAL_INTERNET_RADIO" 
               type="stationurl" 
               location="http://content.api.bose.io:7777/core02/svc-bmx-adapter-orion/prod/orion/station?data={BASE64_DATA}"
               sourceAccount="" 
               isPresetable="true">
    <itemName>Station Name</itemName>
  </ContentItem>
</preset>

Base64-Daten-Payload

Der data-Query-Parameter enthält Base64url-kodiertes JSON:

{
  "streamUrl": "http://absolut-relax.live-sm.absolutradio.de/absolut-relax/stream/mp3",
  "name": "Absolut Relax",
  "imageUrl": "https://example.com/logo.png"
}

Kodierung in PowerShell:

$json = '{"streamUrl":"http://stream.example.com/radio.mp3","name":"My Station"}'
$base64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($json))
# Result: eyJzdHJlYW1VcmwiOiJodHRwOi8vc3RyZWFtLmV4YW1wbGUuY29tL3JhZGlvLm1wMyIsIm5hbWUiOiJNeSBTdGF0aW9uIn0=

Kodierung in Python:

import base64
import json

data = {"streamUrl": "http://stream.example.com/radio.mp3", "name": "My Station"}
base64_data = base64.urlsafe_b64encode(json.dumps(data).encode()).decode()

API-Endpunkte

1. BMX-Registry-Service

Endpunkt: GET /bmx/registry/v1/services

Wird vom Gerät beim Booten aufgerufen. Gibt die verfügbaren Services zurück.

Antwort:

{
  "_links": {
    "bmx_services_availability": {"href": "../servicesAvailability"}
  },
  "askAgainAfter": 60000,
  "bmx_services": [
    {
      "_links": {...},
      "id": {"name": "orion", "value": 999},
      "baseUrl": "http://192.168.178.108:7777/core02/svc-bmx-adapter-orion/prod",
      "assets": {"name": "OCT Radio", "description": "OpenCloudTouch"},
      "streamTypes": ["liveRadio"],
      "askAdapter": false
    }
  ]
}

2. Orion-Stationswiedergabe

Endpunkt: GET /core02/svc-bmx-adapter-orion/prod/orion/station?data={base64}

Wird vom Gerät aufgerufen, wenn eine Preset-Taste gedrückt wird.

Anfrage:

  • data (Query-Parameter): Base64url-kodiertes JSON mit streamUrl, name, imageUrl

Antwort:

{
  "audio": {
    "hasPlaylist": true,
    "isRealtime": true,
    "maxTimeout": 60,
    "streamUrl": "http://absolut-relax.live-sm.absolutradio.de/absolut-relax/stream/mp3",
    "streams": [
      {
        "hasPlaylist": true,
        "isRealtime": true,
        "streamUrl": "http://absolut-relax.live-sm.absolutradio.de/absolut-relax/stream/mp3"
      }
    ]
  },
  "imageUrl": "https://example.com/logo.png",
  "name": "Absolut Relax",
  "streamType": "liveRadio",
  "_links": {
    "bmx_nowplaying": {"href": "http://192.168.178.108:7777/bmx/orion/now-playing"},
    "bmx_reporting": {"href": "http://192.168.178.108:7777/bmx/orion/reporting"}
  }
}

Gerätekonfiguration

Erforderliche hosts-Datei-Einträge

Das Gerät muss Bose-Domains zum OCT-Server umleiten:

192.168.178.108  streaming.bose.com
192.168.178.108  content.api.bose.io
192.168.178.108  events.api.bosecm.com
192.168.178.108  bmx.bose.com

XML-Einstellungen des Geräts

Wichtige Einstellungen in der /mnt/nv/product.xml des Geräts:

<margeURL>http://content.api.bose.io:7777</margeURL>
<statsServerUrl>http://content.api.bose.io:7777/stats</statsServerUrl>

Vollständiges Beispiel

1. Stream-Daten kodieren

import base64
import json

stream_data = {
    "streamUrl": "http://absolut-relax.live-sm.absolutradio.de/absolut-relax/stream/mp3",
    "name": "Absolut Relax",
    "imageUrl": ""
}
encoded = base64.urlsafe_b64encode(json.dumps(stream_data).encode()).decode()
print(encoded)
# eyJzdHJlYW1VcmwiOiJodHRwOi8vYWJzb2x1dC1yZWxheC5saXZlLXNtLmFic29sdXRyYWRpby5kZS9hYnNvbHV0LXJlbGF4L3N0cmVhbS9tcDMiLCJuYW1lIjoiQWJzb2x1dCBSZWxheCIsImltYWdlVXJsIjoiIn0=

2. Preset auf dem Gerät speichern

$preset = @"
<preset id="4">
  <ContentItem source="LOCAL_INTERNET_RADIO" 
               type="stationurl" 
               location="http://content.api.bose.io:7777/core02/svc-bmx-adapter-orion/prod/orion/station?data=eyJzdHJlYW1VcmwiOiJodHRwOi8vYWJzb2x1dC1yZWxheC5saXZlLXNtLmFic29sdXRyYWRpby5kZS9hYnNvbHV0LXJlbGF4L3N0cmVhbS9tcDMiLCJuYW1lIjoiQWJzb2x1dCBSZWxheCIsImltYWdlVXJsIjoiIn0="
               sourceAccount="" 
               isPresetable="true">
    <itemName>Absolut Relax OCT</itemName>
  </ContentItem>
</preset>
"@

Invoke-RestMethod -Uri "http://192.168.178.79:8090/preset" -Method Post -Body $preset -ContentType "application/xml"

3. Preset abspielen

$key = '<key state="press" sender="Gabbo">PRESET_4</key>'
Invoke-RestMethod -Uri "http://192.168.178.79:8090/key" -Method Post -Body $key -ContentType "application/xml"

4. Wiedergabe überprüfen

Invoke-RestMethod -Uri "http://192.168.178.79:8090/now_playing"
# Gibt zurück: source=LOCAL_INTERNET_RADIO, playStatus=PLAY_STATE

Warum nicht TuneIn?

Die ursprüngliche TuneIn-Quelle (source="TUNEIN") erfordert zusätzliche Bose-proprietäre Endpunkte, die komplex per Reverse Engineering nachzubilden sind. Beim Versuch der TuneIn-Wiedergabe gibt das Gerät HTTP 500 zurück.

LOCAL_INTERNET_RADIO ist einfacher:

  • Das Gerät ruft die location-URL direkt auf
  • OCT dekodiert den Base64-Payload
  • Gibt die Stream-URL im BMX-Format zurück
  • Das Gerät spielt den Stream ab

Fehlerbehebung

Gerät ruft OCT nicht auf

  1. hosts-Datei prüfen: ssh root@device "cat /etc/hosts"
  2. OCT-Erreichbarkeit testen: curl http://oct-server:7777/health
  3. Gerät nach Änderungen an der hosts-Datei neu starten

Preset spielt nicht ab

  1. OCT-Logs prüfen: podman logs opencloudtouch-local
  2. Orion-Endpunkt verifizieren: curl "http://oct:7777/core02/svc-bmx-adapter-orion/prod/orion/station?data=..."
  3. Sicherstellen, dass die Stream-URL eine gültige MP3/AAC-URL ist

BMX-Registry lädt nicht

  1. Prüfen, ob der /bmx/registry/v1/services-Endpunkt gültiges JSON zurückgibt
  2. Sicherstellen, dass das _links-Feld vorhanden ist (vom Gerät benötigt)
  3. Prüfen, ob askAgainAfter nicht zu kurz ist (mindestens 60000ms)

Zugehörige Dateien

Clone this wiki locally