Skip to content

atamanroman/ymc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

28 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ymc - Yamaha MusicCast CLI

Maintainability Test Coverage

YMC Demo

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.

About

Yamaha MusicCast CLI in Go

Resources

License

GPL-3.0, Unknown licenses found

Licenses found

GPL-3.0
LICENSE
Unknown
LICENSE-THIRD-PARTY

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages