diff --git a/hosts/common/programs/mpv/default.nix b/hosts/common/programs/mpv/default.nix index 9f6fb4be..473c0b0c 100644 --- a/hosts/common/programs/mpv/default.nix +++ b/hosts/common/programs/mpv/default.nix @@ -91,48 +91,23 @@ let local last_up = cursor.last_event['primary_up'] or { time = 0 } if cursor.hover_raw or last_down.time >= last_up.time then cursor:move(mouse.x, mouse.y) end" - ### patch so that the volume control corresponds to `ao-volume`, i.e. the system-wide volume. + ### patch so that uosc volume control is routed to sane-sysvol. ### this is particularly nice for moby, because it avoids the awkwardness that system volume ### is hard to adjust while screen is on. - ### note that only under alsa (`-ao=alsa`) does `ao-volume` actually correspond to system volume. + ### previously i used ao-volume instead of sane-sysvol: but that forced `ao=alsa` + ### and came with heavy perf penalties (especially when adjusting the volume) substituteInPlace src/uosc/main.lua \ --replace-fail \ - "mp.observe_property('volume', 'number', create_state_setter('volume'))" \ - "mp.observe_property('volume', 'number', update_ao_volume)" + "mp.observe_property('volume'" \ + "mp.observe_property('user-data/sane-sysvol/volume'" \ + --replace-fail 'volume = nil' 'volume = 0' substituteInPlace src/uosc/elements/Volume.lua \ - --replace-fail "mp.commandv('set', 'volume'" "mp.commandv('set', 'ao-volume'" \ - --replace-fail "mp.set_property_native('volume'" "mp.set_property('ao-volume'" - - # `ao-volume` isn't actually an observable property. - # as of 2024/03/02, they *may* be working on that: - # - - # in the meantime, just query the volume every tick (i.e. frame). - # alternative is mpv's JSON IPC feature, where i could notify its socket whenever pipewire volume changes. - cat <> src/uosc/main.lua - function update_ao_volume(_, vol) - if vol == nil then - -- vol will be nil if called manually, instead of via observe_property - vol = mp.get_property('ao-volume') - end - if vol == nil then - vol = 0 - else - vol = tonumber(vol) - end - - if vol ~= state.volume then - set_state('volume', vol) - request_render() - end - end - -- tick seems to occur on every redraw (even when volume is hidden). - -- in practice: for every new frame of the source, or whenever the cursor is moved. - mp.register_event('tick', update_ao_volume) - -- if paused and cursor isn't moving, then `tick` isn't called. fallback to a timer. - mp.add_periodic_timer(2, update_ao_volume) - -- invoke immediately to ensure state.volume is non-nil - update_ao_volume() - EOF + --replace-fail \ + "mp.commandv('set', 'volume'" \ + "mp.set_property_native('user-data/sane-sysvol/volume'" \ + --replace-fail \ + "mp.set_property_native('volume'" \ + "mp.set_property_native('user-data/sane-sysvol/volume'" ''; }); mpv-unwrapped = pkgs.mpv-unwrapped.overrideAttrs (upstream: { @@ -217,6 +192,7 @@ in ".local/state/mpv" ]; fs.".config/mpv/scripts/sane-cast/main.lua".symlink.target = ./sane-cast-main.lua; + fs.".config/mpv/scripts/sane-sysvol/main.lua".symlink.target = ./sane-sysvol-main.lua; fs.".config/mpv/input.conf".symlink.target = ./input.conf; fs.".config/mpv/mpv.conf".symlink.target = ./mpv.conf; fs.".config/mpv/script-opts/osc.conf".symlink.target = ./osc.conf; diff --git a/hosts/common/programs/mpv/sane-sysvol-main.lua b/hosts/common/programs/mpv/sane-sysvol-main.lua new file mode 100644 index 00000000..ee60a963 --- /dev/null +++ b/hosts/common/programs/mpv/sane-sysvol-main.lua @@ -0,0 +1,37 @@ +msg = require('mp.msg') +msg.trace('sane-sysvol: load: begin') + +function subprocess(args) + mp.command_native({ + name = "subprocess", + args = args, + -- these arguments below probably don't matter: copied from sane-cast + detach = false, + capture_stdout = false, + capture_stderr = false, + passthrough_stdin = false, + playback_only = false, + }) +end + +function translate_out(vol) + -- called when mpv wants to set the system-wide volume + local volstr = tostring(vol) .. "%" + msg.trace("setting system-wide volume:", volstr) + if vol == nil then + return + end + subprocess({ + "wpctl", + "set-volume", + "@DEFAULT_AUDIO_SINK@", + volstr + }) +end + +mp.set_property_native('user-data/sane-sysvol/volume', 0) +mp.observe_property('user-data/sane-sysvol/volume', 'native', function(_, val) + translate_out(val) +end) + +msg.trace('sane-sysvol: load: complete')