From 92a004bf8746ebe3f0f4288f645acd1549002029 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 10 Feb 2014 21:07:23 +0100 Subject: [PATCH] lua: add a timer API --- player/lua/defaults.lua | 89 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 10 deletions(-) diff --git a/player/lua/defaults.lua b/player/lua/defaults.lua index 7dca478252..88270253c8 100644 --- a/player/lua/defaults.lua +++ b/player/lua/defaults.lua @@ -63,6 +63,69 @@ local function script_dispatch(event) end end +local timers = {} + +-- Install a one-shot timer. Once the given amount of seconds has passed from +-- now, the callback will be called as cb(), and the timer is removed. +function mp.add_timeout(seconds, cb) + local t = mp.add_periodic_timer(seconds, cb) + t.oneshot = true + return t +end + +-- Install a periodic timer. It works like add_timeout(), but after cb() is +-- called, the timer is re-added. +function mp.add_periodic_timer(seconds, cb) + local t = { + timeout = seconds, + cb = cb, + oneshot = false, + next_deadline = mp.get_timer() + seconds, + } + timers[t] = t + return t +end + +function mp.cancel_timer(t) + if t then + timers[t] = nil + end +end + +-- Return the timer that expires next. +local function get_next_timer() + local best = nil + for t, _ in pairs(timers) do + if (best == nil) or (t.next_deadline < best.next_deadline) then + best = t + end + end + return best +end + +-- Run timers that have met their deadline. +-- Return: next absolute time a timer expires as number, or nil if no timers +local function process_timers() + while true do + local timer = get_next_timer() + if not timer then + return + end + local wait = timer.next_deadline - mp.get_timer() + if wait > 0 then + return wait + else + if timer.oneshot then + timers[timer] = nil + end + timer.cb() + if not timer.oneshot then + timer.next_deadline = mp.get_timer() + timer.timeout + end + end + end +end + -- used by default event loop (mp_event_loop()) to decide when to quit mp.keep_running = true @@ -93,21 +156,27 @@ package.loaded["mp"] = mp package.loaded["mp.msg"] = mp.msg _G.mp_event_loop = function() - wait = 0 + local more_events = true + mp.suspend() while mp.keep_running do - -- Drop all locks - important especially if an error happened while - -- locked, and the error was handled, but the lock not dropped. + local wait = process_timers() + if wait == nil then + wait = 1e20 -- infinity for all practical purposes + end + if more_events then + wait = 0 + end + -- Resume playloop - important especially if an error happened while + -- suspended, and the error was handled, but no resume was done. if wait > 0 then mp.resume("all") end local e = mp.wait_event(wait) - if e.event == "none" then - wait = 1e20 - else - -- Empty the event queue while suspended; otherwise, each - -- event will keep us waiting until the core suspends again. - mp.suspend() - wait = 0 + -- Empty the event queue while suspended; otherwise, each + -- event will keep us waiting until the core suspends again. + mp.suspend() + more_events = (e.event ~= "none") + if more_events then local handler = event_handlers[e.event] if handler then handler(e)