fix some audio issues

- add a pause between feeding mplayer multiple files, as it loses some of them
  otherwise
- in order to do the above, we use mplayerEvt only as a flag and don't make
  the main thread wait anymore
- use a different temporary name for each audio file on windows so we can
  queue up multiple files at a time
This commit is contained in:
Damien Elmes 2012-01-24 22:57:39 +09:00
parent 2a76c8f4f0
commit 302541e0c0

View file

@ -3,7 +3,7 @@
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import re, sys, threading, time, subprocess, os, signal, errno, atexit import re, sys, threading, time, subprocess, os, signal, errno, atexit
import shutil import shutil, random, atexit
from anki.hooks import addHook, runHook from anki.hooks import addHook, runHook
from anki.utils import namedtmp, tmpdir, isWin, isMac from anki.utils import namedtmp, tmpdir, isWin, isMac
@ -86,27 +86,30 @@ class MplayerMonitor(threading.Thread):
self.deadPlayers = [] self.deadPlayers = []
while 1: while 1:
mplayerEvt.wait() mplayerEvt.wait()
if mplayerQueue: mplayerEvt.clear()
# loop through files to play
while mplayerQueue:
# ensure started # ensure started
if not self.mplayer: if not self.mplayer:
self.startProcess() self.startProcess()
# loop through files to play # pop a file
while mplayerQueue: item = mplayerQueue.pop(0)
item = mplayerQueue.pop(0) if mplayerClear:
if mplayerClear: mplayerClear = False
mplayerClear = False extra = ""
extra = "" else:
else: extra = " 1"
extra = " 1" cmd = 'loadfile "%s"%s\n' % (item, extra)
cmd = 'loadfile "%s"%s\n' % (item, extra) try:
try: self.mplayer.stdin.write(cmd)
self.mplayer.stdin.write(cmd) except:
except: # mplayer has quit and needs restarting
# mplayer has quit and needs restarting self.deadPlayers.append(self.mplayer)
self.deadPlayers.append(self.mplayer) self.mplayer = None
self.mplayer = None self.startProcess()
self.startProcess() self.mplayer.stdin.write(cmd)
self.mplayer.stdin.write(cmd) # if we feed mplayer too fast it loses files
time.sleep(1)
# wait() on finished processes. we don't want to block on the # wait() on finished processes. we don't want to block on the
# wait, so we keep trying each time we're reactivated # wait, so we keep trying each time we're reactivated
def clean(pl): def clean(pl):
@ -141,14 +144,13 @@ class MplayerMonitor(threading.Thread):
def queueMplayer(path): def queueMplayer(path):
ensureMplayerThreads() ensureMplayerThreads()
while mplayerEvt.isSet():
time.sleep(0.1)
if isWin and os.path.exists(path): if isWin and os.path.exists(path):
# mplayer on windows doesn't like the encoding, so we create a # mplayer on windows doesn't like the encoding, so we create a
# temporary file instead. oddly, foreign characters in the dirname # temporary file instead. oddly, foreign characters in the dirname
# don't seem to matter. # don't seem to matter.
dir = unicode(tmpdir(), sys.getfilesystemencoding()) dir = unicode(tmpdir(), sys.getfilesystemencoding())
name = os.path.join(dir, "audio"+os.path.splitext(path)[1]) name = os.path.join(dir, "audio%s%s" % (
random.randrange(0, 1000000), os.path.splitext(path)[1]))
f = open(name, "wb") f = open(name, "wb")
f.write(open(path, "rb").read()) f.write(open(path, "rb").read())
f.close() f.close()
@ -171,6 +173,11 @@ def ensureMplayerThreads():
mplayerManager = MplayerMonitor() mplayerManager = MplayerMonitor()
mplayerManager.daemon = True mplayerManager.daemon = True
mplayerManager.start() mplayerManager.start()
# ensure the tmpdir() exit handler is registered first so it runs
# after the mplayer exit
tmpdir()
# clean up mplayer on exit
atexit.register(stopMplayer)
def stopMplayer(*args): def stopMplayer(*args):
if not mplayerManager: if not mplayerManager: