Fine-grained LAN volume control for JBL 4305P, 4329P and compatible nSDK speakers.
39
A small, touch-friendly LAN volume controller for JBL active speakers using the StreamUnlimited nSDK API. It changes player:volume by exactly one unit per tap, avoiding the large jumps produced by some phone volume buttons.
On some JBL active speakers, iOS AirPlay and Bluetooth volume buttons can move the speaker by several nSDK units at once. The enlarged system slider can select intermediate values, but its useful low-volume area is very small. This controller provides large − and + buttons that always request a one-unit change.
The app runs entirely on the local network. It has no cloud dependency and does not modify speaker firmware.
0.101.2139.0x4f26c1f./api/getData and /api/setData endpoints.player:volume +1 / -1 controllinux/amd64 and linux/arm64Replace SPEAKER_HOSTNAME_OR_ADDRESS with the speaker hostname or LAN address:
docker run -d \
--name jbl-volume \
--restart unless-stopped \
-e JBL_HOST=SPEAKER_HOSTNAME_OR_ADDRESS \
-p 8765:8765 \
ikarishinji/jbl-nsdk-volume-controller:latest
Open:
http://DOCKER_HOSTNAME_OR_ADDRESS:8765/
services:
jbl-volume:
image: ikarishinji/jbl-nsdk-volume-controller:latest
container_name: jbl-volume
restart: unless-stopped
environment:
JBL_HOST: SPEAKER_HOSTNAME_OR_ADDRESS
ports:
- "8765:8765"
Start it with docker compose up -d.
Docker automatically selects the correct image for x86_64/amd64 or aarch64/arm64:
docker pull ikarishinji/jbl-nsdk-volume-controller:latest
docker run -d \
--name jbl-volume \
--restart unless-stopped \
-e JBL_HOST=SPEAKER_HOSTNAME_OR_ADDRESS \
-p 8765:8765 \
ikarishinji/jbl-nsdk-volume-controller:latest
If the page is not reachable from the LAN, allow inbound TCP port 8765 from the LAN zone in the OpenWrt firewall.
| Variable | Default | Description |
|---|---|---|
JBL_HOST | jbl4305p.local | Speaker hostname or LAN address |
JBL_VERIFY_TLS | false | Verify the speaker HTTPS certificate. JBL devices commonly use a self-signed certificate. |
LISTEN_HOST | 0.0.0.0 | HTTP listening address inside the container |
LISTEN_PORT | 8765 | HTTP listening port inside the container |
JBL_IP remains accepted as a backwards-compatible alias for JBL_HOST.
The backend reads player:volume. For each tap it writes the current value plus or minus one through nSDK /api/setData, then reads the state back. Mute uses settings:/mediaPlayer/mute.
The controller does not change hostlink/maxVolume, volumeMap, softvolEnabled, ALSA routing or firmware.
Python 3.11 or newer is sufficient:
JBL_HOST=SPEAKER_HOSTNAME_OR_ADDRESS python server.py
Then open http://localhost:8765/.
docker build -t jbl-nsdk-volume-controller .
Multi-platform build:
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t YOUR_DOCKERHUB_USER/jbl-nsdk-volume-controller:latest \
--push .
MIT
Content type
Image
Digest
sha256:8bf6ef3a0…
Size
16.1 MB
Last updated
6 days ago
docker pull ikarishinji/jbl-nsdk-volume-controller