mirror of
https://github.com/ankitects/anki.git
synced 2025-09-21 07:22:23 -04:00
refactor sound code
this addresses a bug where mplayer was sometimes not being restarted when opening a new deck, and should remove the need for atexit or hacks in the GUI code to make sure mplayer is closed
This commit is contained in:
parent
ece9b2eccd
commit
d56bddea2d
1 changed files with 46 additions and 50 deletions
|
@ -8,7 +8,7 @@ Sound support
|
|||
"""
|
||||
__docformat__ = 'restructuredtext'
|
||||
|
||||
import re, sys, threading, time, subprocess, os, signal, atexit, errno
|
||||
import re, sys, threading, time, subprocess, os, signal, errno
|
||||
from anki.hooks import addHook, runHook
|
||||
|
||||
# Shared utils
|
||||
|
@ -123,6 +123,7 @@ mplayerQueue = []
|
|||
mplayerManager = None
|
||||
mplayerReader = None
|
||||
mplayerCond = threading.Condition()
|
||||
mplayerClear = False
|
||||
|
||||
class MplayerReader(threading.Thread):
|
||||
"Read any debugging info to prevent mplayer from blocking."
|
||||
|
@ -140,33 +141,50 @@ class MplayerReader(threading.Thread):
|
|||
class MplayerMonitor(threading.Thread):
|
||||
|
||||
def run(self):
|
||||
global mplayerClear
|
||||
self.mplayer = None
|
||||
self.deadPlayers = []
|
||||
while 1:
|
||||
mplayerCond.acquire()
|
||||
while not mplayerQueue:
|
||||
if not mplayerCond:
|
||||
return
|
||||
mplayerCond.wait()
|
||||
if not self.mplayer:
|
||||
self.startProcess()
|
||||
if self.mplayer != -1 and self.mplayer.poll() is not None:
|
||||
self.mplayer.wait()
|
||||
self.startProcess()
|
||||
nextClears = False
|
||||
while mplayerQueue:
|
||||
item = mplayerQueue.pop(0)
|
||||
if item is None:
|
||||
nextClears = True
|
||||
continue
|
||||
if nextClears:
|
||||
nextClears = False
|
||||
extra = ""
|
||||
mplayerCond.wait()
|
||||
# clearing playing file if mplayer is running
|
||||
if mplayerClear and self.mplayer:
|
||||
self.mplayer.stdin.write("stop\n")
|
||||
if mplayerQueue:
|
||||
# ensure started
|
||||
if not self.mplayer:
|
||||
self.startProcess()
|
||||
# loop through files to play
|
||||
while mplayerQueue:
|
||||
item = mplayerQueue.pop(0)
|
||||
if mplayerClear:
|
||||
mplayerClear = False
|
||||
extra = ""
|
||||
else:
|
||||
extra = " 1"
|
||||
cmd = 'loadfile "%s"%s\n' % (item, extra)
|
||||
self.mplayer.stdin.write(cmd)
|
||||
# wait() on finished processes. we don't want to block on the
|
||||
# wait, so we keep trying each time we're reactivated
|
||||
def clean(pl):
|
||||
if pl.poll() is not None:
|
||||
pl.wait()
|
||||
return False
|
||||
else:
|
||||
extra = " 1"
|
||||
cmd = 'loadfile "%s"%s\n' % (item, extra)
|
||||
self.mplayer.stdin.write(cmd)
|
||||
return True
|
||||
self.deadPlayers = [pl for pl in self.deadPlayers if clean(pl)]
|
||||
mplayerCond.release()
|
||||
|
||||
def kill(self):
|
||||
if not self.mplayer:
|
||||
return
|
||||
try:
|
||||
self.mplayer.stdin.write("quit\n")
|
||||
self.deadPlayers.append(self.mplayer)
|
||||
except:
|
||||
pass
|
||||
self.mplayer = None
|
||||
|
||||
def startProcess(self):
|
||||
try:
|
||||
cmd = mplayerCmd + ["-slave", "-idle"]
|
||||
|
@ -187,8 +205,10 @@ def queueMplayer(path):
|
|||
runHook("soundQueued")
|
||||
|
||||
def clearMplayerQueue():
|
||||
global mplayerClear
|
||||
mplayerCond.acquire()
|
||||
mplayerQueue.append(None)
|
||||
mplayerClear = True
|
||||
mplayerCond.notifyAll()
|
||||
mplayerCond.release()
|
||||
|
||||
def ensureMplayerThreads():
|
||||
|
@ -200,37 +220,13 @@ def ensureMplayerThreads():
|
|||
mplayerReader = MplayerReader()
|
||||
mplayerReader.daemon = True
|
||||
mplayerReader.start()
|
||||
atexit.register(stopMplayer)
|
||||
|
||||
def stopMplayer(restart=False):
|
||||
def stopMplayer():
|
||||
if not mplayerManager:
|
||||
return
|
||||
mplayerCond.acquire()
|
||||
if mplayerManager.mplayer:
|
||||
while 1:
|
||||
try:
|
||||
mplayerManager.mplayer.stdin.write("quit\n")
|
||||
break
|
||||
except OSError, e:
|
||||
if e.errno != errno.EINTR:
|
||||
# osx throws interrupt errors regularly, but we want to
|
||||
# ignore other errors on shutdown
|
||||
break
|
||||
except IOError:
|
||||
# already closed
|
||||
break
|
||||
except ValueError:
|
||||
# already closed
|
||||
break
|
||||
if not restart:
|
||||
mplayerManager.mplayer = -1
|
||||
mplayerCond.notifyAll()
|
||||
mplayerCond.release()
|
||||
mplayerManager.kill()
|
||||
|
||||
def stopMplayerOnce():
|
||||
stopMplayer(restart=True)
|
||||
|
||||
addHook("deckClosed", stopMplayerOnce)
|
||||
addHook("deckClosed", stopMplayer)
|
||||
|
||||
# PyAudio recording
|
||||
##########################################################################
|
||||
|
|
Loading…
Reference in a new issue