Skip to main content

Module media

Module media 

Source
Expand description

Pause and resume external media around breaks (issue #77).

When the user enables “Pause media while a break is showing”, the scheduler calls on_break_start as a break overlay opens and on_break_end when it closes. Notification-only breaks don’t block the screen and have no defined end, so they intentionally don’t reach here — only the overlay path (fire_break) does.

Platform behaviour differs by what each OS lets us inspect:

  • Linux is precise. We enumerate MPRIS players on the session bus via the gdbus CLI (the same dependency-free approach the DnD probe uses), pause only the players currently reporting Playing, remember them, and resume exactly those when the break ends.
  • macOS / Windows have no portable way to enumerate players, so we synthesise the system Play/Pause media key — a best-effort toggle. Because the key is a toggle (there’s no separate “pause” key), we only send it when an “is media actually playing?” probe says yes, so we don’t accidentally start media that was paused: a real audio-output probe that tells a paused player apart from one merely holding the audio device open — a CoreAudio process tap on macOS (#233) and a WASAPI endpoint peak meter on Windows (#234). The matching resume sends the same key again.

The testable core is pure and lives at module scope so it compiles and is unit-tested on every OS, mirroring crate::video: the gdbus output parsers and the “which players are Playing” decision (Linux), and the “may the blind toggle fire?” guards (media_key_pause_allowed / media_key_resume_allowed, macOS/Windows). The guards keep the toggle from ever starting media the user had paused (#104): pause only when the platform probe says something is playing, and resume only a toggle we ourselves sent.

Modules§

linux 🔒

Enums§

PlaybackStatus 🔒
Playback state from an MPRIS player’s PlaybackStatus property.
ResumeToken 🔒
Records the action a break-start pause took.

Constants§

MPRIS_DBUS_DEST 🔒
MPRIS_DBUS_PATH 🔒
MPRIS_PLAYER_IFACE 🔒
MPRIS_PLAYER_PATH 🔒
SILENCE_THRESHOLD 🔒
A measured output peak above this counts as real audio. Digital silence is ~0.0, so any small positive floor cleanly separates a paused player (no output) from an active one; the margin ignores denormal/dither noise.

Statics§

ENABLED 🔒
Mirrors Settings::pause_media_during_breaks. The scheduler refreshes this each tick so the synchronous overlay path (on_break_start) can read it without locking the async settings mutex.
RESUME 🔒
What on_break_start did, so on_break_end reverses exactly that and never blindly toggles media that was already paused.

Functions§

is_audible 🔒
Pure decision shared by both audio-output probes: is a measured peak amplitude loud enough to be real playback? One threshold so the macOS tap (#233) and the Windows peak meter (#234) judge “audible” identically instead of drifting apart behind two copies. Pure, so it’s unit-tested without FFI on every OS (like media_key_pause_allowed just above).
lock_resume 🔒
A poisoned lock only means a previous holder panicked; the media state is best-effort, so recover the guard and carry on rather than panic.
media_key_pause_allowed 🔒
Decide whether the macOS/Windows blind Play/Pause toggle may fire on break start. The toggle has no separate “pause” key, so sending it when nothing is playing would start media the user had paused (issue #104). We therefore only allow it when the platform’s “is media actually playing?” probe says yes — a real audio-output probe on both macOS (a CoreAudio tap, #233) and Windows (a WASAPI peak meter, #234). Pure so it’s unit-tested without FFI on every OS.
media_key_resume_allowed 🔒
Decide whether the resume toggle may fire on break end. Only reverse a toggle we actually sent — never blindly hit the media key for a break we did not pause, so we can’t start media the user left paused (#104). Pure so it’s unit-tested without FFI on every OS.
on_break_end
Called as a break overlay closes. Resumes whatever on_break_start paused. Deliberately NOT gated on ENABLED: if the user toggled the feature off mid-break, we still resume what we paused.
on_break_end_with 🔒
Testable core of on_break_end: always drains the stored token and hands it to the injected resume action (see on_break_start_with for why the action is injected rather than called directly).
on_break_start
Called as a break overlay opens. No-op unless the feature is enabled. Performs the (fast, infrequent) platform media-pause inline.
on_break_start_with 🔒
Testable core of on_break_start: the enabled-gate and token bookkeeping, with the platform pause action injected. The injection keeps unit tests off the real key-send — platform_pause posts a genuine system Play/Pause media key on macOS/Windows, which would toggle whatever the developer is playing every time the suite runs.
parse_mpris_names 🔒
Parse gdbus call … org.freedesktop.DBus.ListNames output into the MPRIS player bus names. gdbus prints one GVariant tuple, e.g. ([... 'org.mpris.MediaPlayer2.vlc', 'org.freedesktop.DBus', ...],); we collect every single-quoted token with the MPRIS prefix, de-duped.
parse_playback_status 🔒
Parse gdbus call … Properties.Get … PlaybackStatus output. gdbus prints the variant-wrapped value, e.g. (<'Playing'>,).
plan_and_pause 🔒
List MPRIS players, pause the ones currently Playing, and return a token naming exactly those (so resume reverses only what we paused).
platform_pause 🔒
platform_resume 🔒
player_method 🔒
players_to_pause 🔒
Given each player’s status, the bus names to pause: only those actively Playing. Pure, so the pause set is testable without a session bus.
resume_all 🔒
Resume the named players (those a prior plan_and_pause paused).
set_enabled
Mirror the current setting into the process-wide flag. Called by the scheduler run loop once per tick.

Type Aliases§

DbusCall 🔒
A session-bus call: (dest, object_path, method, args) -> stdout, or None on failure. The production impl shells out to gdbus; tests pass a fake.