use named pipes for mpv on windows

currently using non-blocking mode which involves a sleep in the read
loop - overlapped i/o might be a better option in the future
This commit is contained in:
Damien Elmes 2017-09-30 19:32:48 +10:00
parent 7dc8f82906
commit e8b4d276b4

View file

@ -54,6 +54,9 @@ class MPVCommandError(MPVError):
class MPVTimeoutError(MPVError): class MPVTimeoutError(MPVError):
pass pass
from anki.utils import isWin
if isWin:
import win32file, win32pipe, pywintypes, winerror
class MPVBase: class MPVBase:
"""Base class for communication with the mpv media player via unix socket """Base class for communication with the mpv media player via unix socket
@ -64,7 +67,9 @@ class MPVBase:
default_argv = [ default_argv = [
"--idle", "--idle",
"--no-terminal" "--no-terminal",
"--force-window=no",
"--ontop",
] ]
def __init__(self, window_id=None, debug=False): def __init__(self, window_id=None, debug=False):
@ -119,6 +124,9 @@ class MPVBase:
"""Create a random socket filename which we pass to mpv with the """Create a random socket filename which we pass to mpv with the
--input-unix-socket option. --input-unix-socket option.
""" """
if isWin:
self._sock_filename = "ankimpv"
return
fd, self._sock_filename = tempfile.mkstemp(prefix="mpv.") fd, self._sock_filename = tempfile.mkstemp(prefix="mpv.")
os.close(fd) os.close(fd)
os.remove(self._sock_filename) os.remove(self._sock_filename)
@ -132,8 +140,16 @@ class MPVBase:
time.sleep(0.1) time.sleep(0.1)
try: try:
self._sock = socket.socket(socket.AF_UNIX) if isWin:
self._sock.connect(self._sock_filename) self._sock = win32file.CreateFile(r'\\.\pipe\ankimpv',
win32file.GENERIC_READ | win32file.GENERIC_WRITE,
0, None, win32file.OPEN_EXISTING, 0, None)
win32pipe.SetNamedPipeHandleState(self._sock,
1, # PIPE_NOWAIT
None, None)
else:
self._sock = socket.socket(socket.AF_UNIX)
self._sock.connect(self._sock_filename)
except (FileNotFoundError, ConnectionRefusedError): except (FileNotFoundError, ConnectionRefusedError):
continue continue
else: else:
@ -179,12 +195,25 @@ class MPVBase:
""" """
buf = b"" buf = b""
while not self._stop_event.is_set(): while not self._stop_event.is_set():
r, w, e = select.select([self._sock], [], [], 1) if isWin:
if r: try:
b = self._sock.recv(1024) (n, b) = win32file.ReadFile(self._sock, 4096)
if not b: buf += b
break except pywintypes.error as err:
buf += b if err.args[0] == winerror.ERROR_NO_DATA:
time.sleep(0.1)
continue
elif err.args[0] == winerror.ERROR_BROKEN_PIPE:
return
else:
raise
else:
r, w, e = select.select([self._sock], [], [], 1)
if r:
b = self._sock.recv(1024)
if not b:
break
buf += b
newline = buf.find(b"\n") newline = buf.find(b"\n")
while newline >= 0: while newline >= 0:
@ -264,11 +293,14 @@ class MPVBase:
raise MPVTimeoutError("unable to put request") raise MPVTimeoutError("unable to put request")
# Write the message data to the socket. # Write the message data to the socket.
while data: if isWin:
size = self._sock.send(data) win32file.WriteFile(self._sock, data)
if size == 0: else:
raise MPVCommunicationError("broken sender socket") while data:
data = data[size:] size = self._sock.send(data)
if size == 0:
raise MPVCommunicationError("broken sender socket")
data = data[size:]
def _get_response(self, timeout=None): def _get_response(self, timeout=None):
"""Collect the response message to a previous request. If there was an """Collect the response message to a previous request. If there was an