ymc - Yamaha MusicCast CLI
Basic controls for your MusicCast speakers from the terminal.
Features:
- discovery
- power on/off
- switch inputs (π)
- volume control
Installation
Go
$ go install github.com/atamanroman/ymc/cmd/ymc@latest
Homebrew
For now atamanroman/taps/ymc is a head-only formula.
$ brew install --HEAD atamanroman/taps/ymc
Usage
RET Turn on/off
β Volume up*
β Volume down*
m Toggle mute
? Show help
q Quit
*Shift: small steps
Build and Run
$ go build -v ./cmd/ymc
$ ./ymc
or just run
$ go run ./...
Contributing
π
Design
TLDR:
- ymc acts as a UPnP & MusicCast controller
- issues SSDP search to find devices
- queries found UPnP devices to get the YXC API URL and subscribe to status events
- then allows controlling MusicCast devices with the YXC API via CLI
(3) GET UPnP description
(4a) GET device info & status info via YXC API
(4b) Subscribe to status changes
(5+) Control speaker via YXC API
βββββββββββββββββββββββββββ>>>βββββββββββββββββββββββββββ
β β
β βΌ
β βββββββββββ
βββββββββ (2) SSDP Search β β
β β (1) SSDP Search Response βMusicCastβ
β ymc ββββββββββ>>>ββββββββββββββββββββ<<<ββββββββββββ Speaker β
β β β β
βββββββββ βββββββββββ
β² β
β β
ββββββββββββββββββββββββββββββββββββββββ<<<ββββββββββββββ
(6) Send proprietary UDP
messages on status changes
βββββββββ Plain UDP
βββββββββ UPNP (UDP)
βββββββββ HTTP
About UPnP, SSDP and YXC
Disclaimer: My knowledge of UPnP and the underlying network protocols is pretty limited, but maybe it makes sense to
describe my current understanding briefly.
Yamaha MusicCast speakers are UPnP (Universal Plug and Play)
devices.
UPnP handles things like discovery, description, control and eventing.
It's built on IP uni-/multicast, UDP higher level protocols
like SSDP (Simple Service Discovery Protocol)
and HTTPU (HTTP).
UPnP devices advertise their services on start and then regularly and broadcast events for status changes.
Then the UPnP controller (ymc) fetches the UPnP description from the device to learn what services it has to offer.
ymc only looks for urn:schemas-upnp-org:device:MediaRenderer:1
devices from manufacturer Yamaha Corporation with
model MusicCast.
The UPnP description contains everything needed to control the UPnP services from this device.
MusicCast devices extend the XML <device>
description with an additional <yamaha:X_device>
element:
<yamaha:X_device>
<yamaha:X_URLBase>http://192.168.178.20:80/</yamaha:X_URLBase>
<yamaha:X_serviceList>
<yamaha:X_service>
<yamaha:X_specType>urn:schemas-yamaha-com:service:X_YamahaRemoteControl:1</yamaha:X_specType>
<yamaha:X_controlURL>/YamahaRemoteControl/ctrl</yamaha:X_controlURL>
<yamaha:X_unitDescURL>/YamahaRemoteControl/desc.xml</yamaha:X_unitDescURL>
</yamaha:X_service>
<yamaha:X_service>
<yamaha:X_specType>urn:schemas-yamaha-com:service:X_YamahaExtendedControl:1</yamaha:X_specType>
<yamaha:X_yxcControlURL>/YamahaExtendedControl/v1/</yamaha:X_yxcControlURL>
<yamaha:X_yxcVersion>1706</yamaha:X_yxcVersion>
</yamaha:X_service>
</yamaha:X_serviceList>
</yamaha:X_device>
This is where the MusicCast Controller (like the iOS App) leaves the UPnP track and starts controlling the device with
the YXC (Yamaha Extended Control) HTTP API.
The state of the MusicCast device can be queried and manipulated over YXC.
It also offers a proprietary (?) unicast UDP stream a controller can register itself on to get status updates.
Unfortunately, there seems to be no official source for the YXC spec (which exists in a basic and advanced version).
Different versions of the PDFs are available though and reverse engineering the HTTP API (very not-RESTful) is easy
enough.
And there's a lot of OSS sample code on GitHub
like Yamaha MusicCast Binding.
This is enough to build a simple CLI controller which can search for devices and manipulate power, inputs and volume.
Advanced MusicCast features like zones and linking are (as of today) out of scope since I
- don't use those features regularly and can always fall back to the app.
- do not own an MusicCast enabled AV receiver, which seems to be required for zones.
There's also the Yamaha Remote Control API (
see tryptophane/yamaha-remote).
The /YamahaRemoteControl/desc.xml
file gives 404 on my speakers, though.
Could be only enabled on AV receivers, but then it's strange that they advertise the service.
My references:
Packages
ymc/musiccast
- code for the YXC API
- subscribes and listens to YXC UDP events
- publishes
Speaker
updates via channel
ymc/internal/ssdp
(based on koron/go-ssd - see Disclaimer)
- handles SSDP via UDP multicast
- does SSDP service discovery to make the speakers visible
- publishes SSDP
Service
events only from Yamaha MusicCast devices via channel
FAQ
Q: Why "ymc"?
A: Yamaha MusicCast CLI
Q: Why Go?
A: Easy to build a cross-platform binary and I like the simplicity.
Q: Why modify the koron/go-ssdp code and not use it as-is?
A: I wanted to publish discovered services via channel, which is not how their API works.
And it seems I'm not clever enough to do SSDP/UDP multicast from scratch.
Disclaimer
This repository is not affiliated with Yamaha Corporation.
Most of the UDP multicast code is copied and then altered from koron/go-ssdp.
See LICENSE-3RD-PARTY for licensing details.
Use on your own risk.