Skip to content

Windows: support Spotify pill via System Media Transport Controls - #383

Closed
Totopo27 wants to merge 3 commits into
Louis-CFM:mainfrom
Totopo27:feat/windows-spotify-pill
Closed

Totopo27 wants to merge 3 commits into
Louis-CFM:mainfrom
Totopo27:feat/windows-spotify-pill

Conversation

@Totopo27

@Totopo27 Totopo27 commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Closes #322

Summary

Linux 0.3.0 brought the Spotify pill and Mochi dancing over MPRIS (#372), leaving Windows with "no music source yet". This implements the native Windows source behind the exact same Tauri commands and shared frontend, using WinRT GlobalSystemMediaTransportControlsSessionManager (GSMTC).

Behavior & Parity

  • No API keys, no network authentication: reads track info and playback state directly from the local Windows media session.
  • Controls: play/pause, next, previous, seek, shuffle, and repeat through the native session.
  • Artwork stream: reads the album cover thumbnail stream (IRandomAccessStreamReference) and converts it to a base64 data URI emitted to the existing spotify-artwork event.
  • Smooth timeline: anchor position and timestamp interpolation matching the frontend's 60 FPS ticker with zero extra CPU load when paused.
  • Open Spotify: focuses the running Spotify window if present, or opens the spotify: protocol URI.
  • Shared frontend: enables support: "yes" on integration_spotify, reusing the card, pill hover controls, and Mochi's dance seamlessly on Windows.

Tests

  • npm test: 361 passed (0 failed).
  • cargo test: 213 + 30 passed (0 failed).
  • Manually tested on Windows 11 with the Spotify desktop client.

@Totopo27

Totopo27 commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Quick update & note on volume control on Windows

While testing and polishing playback controls (shuffle and repeat are working properly over GSMTC), I wanted to share findings regarding the volume slider on Windows:

On macOS, Spotify exposes sound volume via AppleScript, and on Linux it exposes Volume over MPRIS D-Bus, which provides direct 2-way synchronization with Spotify's in-app slider.

On Windows:

  • WinRT GSMTC (GlobalSystemMediaTransportControlsSession) currently has no volume APIs in its specification.
  • The Spotify desktop client (CEF/Chromium) manages its in-app volume slider via internal software gain on PCM samples and exposes no public COM, IPC, or local interface for it.
  • Sending media keys / WM_APPCOMMAND alters the global Windows master volume and triggers the invasive Windows media OSD, which we ruled out.
  • While Windows WASAPI (ISimpleAudioVolume) allows controlling the audio output level of the Spotify process, it does not move the visual slider inside the Spotify desktop app (and moving Spotify's in-app slider does not update WASAPI).

For now, the cleanest path for this PR is to omit the volume bar on Windows rather than shipping an un-synced or misleading slider, and wait to see if Microsoft introduces volume support in a future GSMTC update or if another clean method emerges down the road.

Let me know what you think!

@shakibbinkabir

Copy link
Copy Markdown
Contributor

@Totopo27, a heads-up so this is not reviewed twice: #374 adds the same thing, a Windows source for the Spotify pill read from the system media session, behind #372's commands and page. It was opened about four hours before this one (8 Oct 23:25 UTC, this one 9 Oct 03:38 UTC) and both are still open.

I read your diff against mine. Same API (GlobalSystemMediaTransportControlsSessionManager), same spotify and spotify-artwork events, same integration_spotify going to support: "yes", so the two conflict in spotify.rs, pills.ts and the pill tests. Where they differ:

#374 This one
When it reads On the session's events only; one thread asleep on a channel in between On the events, and again every second while the pill is declared (listen_sessions)
Dependencies More features of the windows crate, Cargo.lock unchanged The same, plus windows-future as a direct dependency
Which session Spotify's two app ids only (Spotify.exe, or one starting with SpotifyAB.SpotifyMusic_) Any app id containing "spotify"
Shuffle and repeat Left off the card on Windows Wired
Volume Spotify's level in the Windows mixer, which does not move Spotify's own slider, as you found Not handled
The pill's label As #372 left it (the track's title) Always "Spotify", on Linux too
Rust tests for the Windows side Six None
Besides the pill A second commit, separate and off by default: a new song opens the island on its card for a moment Nothing else

The shuffle and repeat row is the one I would like to understand, because we found opposite things. On my machine (Windows 11, Spotify 1.303.264 from the Microsoft Store), TryChangeShuffleActiveAsync and TryChangeAutoRepeatModeAsync both return true, and three seconds later the session still reports them off, in Coucou and outside it. That is why #374 hides the two buttons. Which Spotify build did you test with, and did the state change in Spotify itself or only in the card? If the spotify.com build honours them, hiding them everywhere is wrong.

@Totopo27

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed breakdown and heads-up, @shakibbinkabir!

Regarding shuffle and repeat: I tested this against the standalone build from spotify.com (\Spotify.exe). While \TryChangeShuffleActiveAsync\ / \TryChangeAutoRepeatModeAsync\ return \ rue\ on the WinRT side and the session triggers a state update, I can confirm the exact same behavior you observed: Spotify's internal player state does not actually toggle. You were totally right to omit those buttons from the card on Windows — having dead buttons that don't alter the actual playback queue is poor UX.

Looking at #374, your architecture is much cleaner:

  1. Sleeping on WinRT event notifications rather than the 1s fallback polling loop in \listen_sessions.
  2. Keeping \Cargo.lock\ clean without adding \windows-future.
  3. Having comprehensive Rust unit tests around session parsing and clock edge cases.

Since #374 was opened earlier and covers the foundation cleanly (along with the opt-in announcement feature), I'm completely fine with closing this PR in favor of #374 so maintainers can focus review efforts there.

Happy to test #374 on the standalone installer (\spotify.com) side as well if you need verification outside the Store package!

@Totopo27 Totopo27 closed this Oct 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Media pill for Windows (Spotify/System Media Transport Controls)

2 participants