-
-
Save bitingsock/5e9714efff963c9689b0671d68f195ad to your computer and use it in GitHub Desktop.
--New child with start with the current 'aid' and 'audio-device' of the parent | |
-- non-Windows environments require the use of the 'socat' package | |
local platform_is_windows = (package.config:sub(1, 1) == "\\") | |
local options = require 'mp.options' | |
local o = { | |
pipe_template = platform_is_windows and "\\\\.\\pipe\\mpvDupedAudio" or "~/mpvDupedAudio", --windows format | |
new_child_key = 'Ctrl+A', --Start a new child: 'Ctrl+Shift+a' | |
cycle_child_control_key = 'Ctrl+Alt+A', --Cycle child control: 'Ctrl+Shift+Alt+a' | |
cycle_child_aid_key = 'Ctrl+Alt+a', --Cycle 'aid' of child: 'Ctrl+Alt+a' | |
child_increase_volume_key = 'Ctrl+Alt+WHEEL_UP', --Change volume of child: 'Ctrl+Alt+wheel' | |
child_decrease_volume_key = 'Ctrl+Alt+WHEEL_DOWN', --Change volume of child: 'Ctrl+Alt+wheel' | |
} | |
options.read_options(o) | |
local piper = platform_is_windows and " >" or " | socat - " | |
local mpvexe = "mpv" .. (platform_is_windows and ".com" or "") | |
local pipeInstance = {} | |
local control = 0 | |
local function sync(prop, newVal) | |
local timestamp = mp.get_property("audio-pts") or mp.get_property("time-pos") | |
for k, v in pairs(pipeInstance) do | |
if v then | |
os.execute("echo no-osd set time-pos " .. timestamp .. piper .. o.pipe_template .. k) | |
if prop == "speed" then os.execute("echo no-osd set speed " .. newVal .. piper .. o.pipe_template .. k) end | |
if prop == "pause" then os.execute("echo no-osd set pause " .. newVal .. piper .. o.pipe_template .. k) end | |
end | |
end | |
end | |
local function cycle_aid() | |
os.execute("echo cycle aid" .. piper .. o.pipe_template .. control) | |
end | |
local function switchControl() | |
local lastInstance = 0 | |
for k, v in ipairs(pipeInstance) do | |
if v then | |
lastInstance = k | |
end | |
end | |
if lastInstance == 0 then | |
control = 0 | |
return | |
end | |
if control >= lastInstance then control = 0 end | |
for k, v in ipairs(pipeInstance) do | |
if k > control and v then | |
control = k | |
return | |
end | |
end | |
end | |
local controlling = false | |
local function quit() | |
os.execute("echo quit" .. piper .. o.pipe_template .. control) | |
pipeInstance[control] = false | |
switchControl() | |
print(control) | |
if control == 0 then | |
print(">>> Removed last child <<<") | |
mp.remove_key_binding("quit") | |
mp.remove_key_binding("cycle_aid") | |
mp.remove_key_binding("volumeUP") | |
mp.remove_key_binding("volumeDOWN") | |
mp.unobserve_property(cycle_pause) | |
mp.unobserve_property(syncSpeed) | |
mp.unregister_event(sync) | |
controlling = false | |
else | |
print(">>> Now controlling child: " .. control .. " <<<") | |
end | |
end | |
local function start_child() | |
table.insert(pipeInstance, true) | |
control = #pipeInstance | |
print(">>> Now controlling child: " .. control .. " <<<") | |
mp.commandv("set", "msg-level", mp.get_script_name() .. "=warn") | |
if controlling == false then | |
mp.register_event("playback-restart", sync) | |
mp.add_forced_key_binding("q", "quit", quit) | |
mp.add_forced_key_binding(o.cycle_child_aid_key, "cycle_aid", cycle_aid) | |
mp.add_forced_key_binding(o.child_increase_volume_key, "volumeUP", function() os.execute("echo add volume 5" .. piper .. o.pipe_template .. control) end) | |
mp.add_forced_key_binding(o.child_decrease_volume_key, "volumeDOWN", function() os.execute("echo add volume -5" .. piper .. o.pipe_template .. control) end) | |
mp.add_timeout(0.25, function() | |
mp.observe_property("pause", "string", sync) | |
mp.observe_property("speed", "string", sync) | |
end) | |
controlling = true | |
end | |
mp.command_native_async({ | |
name = "subprocess", | |
args = { | |
mpvexe, | |
mp.get_property("path"), | |
"--speed=" .. mp.get_property("speed"), | |
"--pause=" .. mp.get_property("pause"), | |
"--no-video", | |
"--no-sub", | |
"--osd-level=1", | |
"--aid=" .. mp.get_property("aid"), | |
"--audio-device=" .. mp.get_property("audio-device"), | |
"--input-ipc-server=" .. o.pipe_template .. control, | |
"--start=" .. (mp.get_property("audio-pts") or mp.get_property("time-pos")) | |
}, | |
playback_only = false | |
}, function() end) | |
mp.add_timeout(0.25, function() | |
mp.commandv("set", "msg-level", mp.get_script_name() .. "=status") | |
end) | |
end | |
mp.add_forced_key_binding(o.cycle_child_control_key, "switchControl", function() | |
switchControl() | |
if control == 0 then | |
print(">>> No active children <<<") | |
else | |
print(">>> Now controlling child: " .. control .. " <<<") | |
end | |
end) | |
mp.add_forced_key_binding(o.new_child_key, "start", start_child) | |
mp.register_event("shutdown", function() | |
for k, _ in pairs(pipeInstance) do | |
os.execute("echo quit" .. piper .. o.pipe_template .. k) | |
end | |
end) |
As for the flickering issues (which I haven't been able to reproduce) you can try specifying the command to spawn in a minimized window to see if it helps. as a test, try replacing line 85:
mp.add_forced_key_binding(o.child_increase_volume_key, "volumeUP", function() os.execute("echo add volume 5" .. piper .. o.pipe_template .. control) end)
with
mp.add_forced_key_binding(o.child_increase_volume_key, "volumeUP", function() os.execute('START /MIN CMD.EXE /C "echo add volume 5' .. piper .. o.pipe_template .. control .. '"') end)
then see if volume up (default: Ctrl+Alt+WHEEL_UP) produces the issue.
as for the delay issue, I can only assume your systems are under heavy load. I ran some stressed scenarios and it was a bit out of step but nowhere near 3 seconds. Unfortunately, the only real fix without dependencies would only result in 1 second latency at best as lua's os.time() only produces seconds.
Another possibility is Windows Defender (or some other AV) is analyzing system calls from mpv and delaying it.
I have this problem, constant flickering of a cmd window on all commands passing through.
(Windows 10)
But more importantly i have something like a 3 second lag between the primary and secondary processes... I can't figure this out for the life of me. I even tried controlling the timing offset of the secondary process but it's not moving around (plus no matter what, i dont think a negative offset would even compute, if the secondary one is a dependant stream to the primary, right? IDK tbh.)
Oh and natural Q for Quit just flickers harder instead of quitting anything.
If i hardcode delay by adding
"--audio-delay=-3.6"
at line 107
it syncs perfectly at launch, but will go back to desync if i ever pause or skip.
Maybe useful to reveal that all mpv things like runtime keybinds to change delays, volume change, etc, are allowed from within the child process window, could help someone figure out that they can tune things on the fly... But ofc it is a less than ideal solution, just a workaround. (uuhh wait, this SEEMS to work, it shows my delay is correct at launch, but after a pause/skip, tweaking the delay actually doesn't change anything other than the HUD/UI values. Sigh sorry for the messy comment.)