Add locking to music.py
Ensure nothing interrupts the stop - release - nullify sequence. Also don't limit how many concurrent fades there can be.
This commit is contained in:
parent
987db155a1
commit
73879c6a99
93
app/music.py
93
app/music.py
@ -8,6 +8,8 @@ from time import sleep
|
||||
|
||||
from log import DEBUG, ERROR
|
||||
|
||||
lock = threading.Lock()
|
||||
|
||||
|
||||
class Music:
|
||||
"""
|
||||
@ -16,7 +18,7 @@ class Music:
|
||||
|
||||
def __init__(self):
|
||||
self.current_track_start_time = None
|
||||
self.fading = False
|
||||
self.fading = 0
|
||||
self.VLC = vlc.Instance()
|
||||
self.player = None
|
||||
self.track_path = None
|
||||
@ -30,18 +32,19 @@ class Music:
|
||||
to hold up the UI during the fade.
|
||||
"""
|
||||
|
||||
DEBUG("music.fade()", True)
|
||||
with lock:
|
||||
DEBUG("music.fade()", True)
|
||||
|
||||
if not self.playing():
|
||||
return None
|
||||
if not self.player:
|
||||
return
|
||||
|
||||
# Only allow one track to fade at a time
|
||||
if self.fading:
|
||||
return
|
||||
self.fading = True
|
||||
if not self.player.get_position() > 0 and self.player.is_playing():
|
||||
return
|
||||
|
||||
thread = threading.Thread(target=self._fade)
|
||||
thread.start()
|
||||
self.fading += 1
|
||||
|
||||
thread = threading.Thread(target=self._fade)
|
||||
thread.start()
|
||||
|
||||
def _fade(self):
|
||||
"""
|
||||
@ -69,27 +72,30 @@ class Music:
|
||||
measures_to_reduce_by = 0
|
||||
for i in range(1, steps + 1):
|
||||
measures_to_reduce_by += i
|
||||
volume_factor = 1 - (measures_to_reduce_by / total_measures_count)
|
||||
volume_factor = 1 - (
|
||||
measures_to_reduce_by / total_measures_count)
|
||||
p.audio_set_volume(int(self.max_volume * volume_factor))
|
||||
sleep(sleep_time)
|
||||
|
||||
self.stop(p)
|
||||
self.fading = False
|
||||
self.fading -= 1
|
||||
|
||||
def get_playtime(self):
|
||||
"Return elapsed play time"
|
||||
|
||||
if not self.player:
|
||||
return None
|
||||
with lock:
|
||||
if not self.player:
|
||||
return None
|
||||
|
||||
return self.player.get_time()
|
||||
return self.player.get_time()
|
||||
|
||||
def get_position(self):
|
||||
"Return current position"
|
||||
|
||||
DEBUG("music.get_position", True)
|
||||
with lock:
|
||||
DEBUG("music.get_position", True)
|
||||
|
||||
return self.player.get_position()
|
||||
return self.player.get_position()
|
||||
|
||||
def play(self, path):
|
||||
"""
|
||||
@ -118,46 +124,49 @@ class Music:
|
||||
get_position seems more reliable.
|
||||
"""
|
||||
|
||||
if self.player:
|
||||
if self.player.get_position() > 0 and self.player.is_playing():
|
||||
return True
|
||||
with lock:
|
||||
if self.player:
|
||||
if self.player.get_position() > 0 and self.player.is_playing():
|
||||
return True
|
||||
|
||||
# We take a copy of the player when fading, so we could be
|
||||
# playing in a fade nowFalse
|
||||
return self.fading
|
||||
# We take a copy of the player when fading, so we could be
|
||||
# playing in a fade nowFalse
|
||||
return self.fading > 0
|
||||
|
||||
def set_position(self, ms):
|
||||
"Set current play time in milliseconds from start"
|
||||
|
||||
return self.player.set_time(ms)
|
||||
with lock:
|
||||
return self.player.set_time(ms)
|
||||
|
||||
def set_volume(self, volume):
|
||||
"Set maximum volume used for player"
|
||||
|
||||
if not self.player:
|
||||
return
|
||||
with lock:
|
||||
if not self.player:
|
||||
return
|
||||
|
||||
self.max_volume = volume
|
||||
self.player.audio_set_volume(volume)
|
||||
self.max_volume = volume
|
||||
self.player.audio_set_volume(volume)
|
||||
|
||||
def stop(self, player=None):
|
||||
"Immediately stop playing"
|
||||
|
||||
DEBUG(f"music.stop(), {player=}", True)
|
||||
with lock:
|
||||
DEBUG(f"music.stop(), {player=}", True)
|
||||
|
||||
if not player:
|
||||
if not self.player:
|
||||
return
|
||||
player = self.player
|
||||
if not player:
|
||||
if not self.player:
|
||||
return
|
||||
player = self.player
|
||||
|
||||
DEBUG(f"music.stop({player=})")
|
||||
DEBUG(f"music.stop({player=})")
|
||||
|
||||
position = player.get_position()
|
||||
player.stop()
|
||||
p = player
|
||||
# Ensure we don't reference player after release
|
||||
player = None
|
||||
DEBUG(f"Releasing player {p=}", True)
|
||||
p.release()
|
||||
position = player.get_position()
|
||||
player.stop()
|
||||
DEBUG(f"Releasing player {player=}", True)
|
||||
player.release()
|
||||
# Ensure we don't reference player after release
|
||||
player = None
|
||||
|
||||
return position
|
||||
return position
|
||||
|
||||
Loading…
Reference in New Issue
Block a user