Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 53 additions & 5 deletions mpv.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,11 +685,59 @@ def _make_node_str_map(d):


def _event_generator(handle):
while True:
event = _mpv_wait_event(handle, -1).contents
if event.event_id.value == MpvEventID.NONE:
raise StopIteration()
yield event
"""Yield events from the mpv event queue.

Uses a pipe-based wakeup mechanism to avoid deadlocks on macOS where
``mpv_wait_event`` with an infinite timeout can block forever when the
Cocoa main-loop is blocked (see issue #61).
"""
import select as _select

# Create a self-pipe for wakeup signaling.
_wakeup_fd_r, _wakeup_fd_w = os.pipe()

# Keep a reference to the callback so the GC doesn't reclaim it while
# libmpv still holds a pointer to it.
@WakeupCallback
def _wakeup_cb(_userdata):
try:
os.write(_wakeup_fd_w, b'\x00')
except OSError:
pass

_mpv_set_wakeup_callback(handle, _wakeup_cb, None)

try:
while True:
# Wait for either a wakeup byte or a 100 ms timeout.
try:
_ready, _, _ = _select.select([_wakeup_fd_r], [], [], 0.1)
except (OSError, ValueError):
break

if _ready:
# Drain the pipe.
try:
os.read(_wakeup_fd_r, 4096)
except OSError:
break

# Drain all pending mpv events without blocking.
while True:
event = _mpv_wait_event(handle, 0).contents
if event.event_id.value == MpvEventID.NONE:
break
yield event
finally:
# Clean up: close the pipe and unregister the wakeup callback.
# The handle may already be destroyed if we're cleaning up after a
# SHUTDOWN event, so guard the unregister call.
os.close(_wakeup_fd_r)
os.close(_wakeup_fd_w)
try:
_mpv_set_wakeup_callback(handle, WakeupCallback(), None)
except Exception:
pass


def _create_null_term_cmd_arg_array(name, args):
Expand Down