forked from theyosh/TerrariumPI
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathterrariumAudio.py
125 lines (95 loc) · 3.25 KB
/
terrariumAudio.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# -*- coding: utf-8 -*-
import terrariumLogging
logger = terrariumLogging.logging.getLogger(__name__)
from gevent import sleep
import psutil
from subprocess import PIPE
import threading
import copy
import alsaaudio
import tempfile
import random
from terrariumUtils import terrariumUtils, classproperty
class terrariumAudio(object):
@classproperty
def available_soundcards(__cls__):
soundcards = []
for i in alsaaudio.card_indexes():
try:
(name, longname) = alsaaudio.card_name(i)
soundcards.append({'index' : int(i), 'name' : longname})
except Exception as ex:
# Just ignore error, and skip it
pass
return soundcards
@classmethod
def volume(__cls__, hw, value = None):
try:
mixer = alsaaudio.Mixer(control='PCM',cardindex=hw)
except alsaaudio.ALSAAudioError as ex:
mixer = alsaaudio.Mixer(control='Headphone',cardindex=hw)
if value is None:
# We get stereo volume but asume that left and right channel are at the same volume.
return mixer.getvolume()[0]
else:
value = max(0,min(120,120 * (value/100)))
mixer.setvolume(int(value),alsaaudio.MIXER_CHANNEL_ALL)
class terrariumAudioPlayer(object):
CMD = '/usr/bin/ffmpeg'
def __init__(self, hw, playlists = [], shuffle = False, repeat = False):
self.__hw = hw
self.__stop = False
self.__player = {
'ffmpeg' : None,
'thread' : None,
'exit_status' : None
}
self.playlists = playlists
self.shuffle = shuffle
self.repeat = repeat
def __run(self):
self.__stop = False
for playlist in self.playlists:
if self.__stop:
break
files = copy.copy(playlist['files'])
if playlist.get('shuffle'):
random.shuffle(files)
self.volume(playlist.get('volume',80))
repeat = playlist.get('repeat',False)
first_start = True
while not self.__stop and (repeat or first_start):
first_start = False
playlist = [ f'file \'{audiofile}\'' for audiofile in files]
with tempfile.NamedTemporaryFile() as fp:
fp.write('\n'.join(playlist).encode())
fp.flush()
cmd = f'{self.CMD} -hide_banner -nostdin -v 0 -f concat -safe 0 -i {fp.name} -f alsa hw:{self.__hw}'.split(' ')
self.__player['ffmpeg'] = psutil.Popen(cmd, stdout=PIPE)
self.__player['exit_status'] = self.__player['ffmpeg'].poll()
while self.__player['exit_status'] is None:
self.__player['exit_status'] = self.__player['ffmpeg'].poll()
sleep(1)
self.__player['ffmpeg'] = None
def play(self):
if self.running:
self.stop()
if len(self.playlists) > 0:
self.__player['thread'] = threading.Thread(target=self.__run)
self.__player['thread'].start()
def stop(self):
self.__stop = True
if self.running:
self.__player['ffmpeg'].terminate()
self.__player['thread'].join()
@property
def playlists(self):
return self.__playlists
@playlists.setter
def playlists(self, playlists):
self.__playlists = copy.copy(playlists)
@property
def running(self):
return self.__player['ffmpeg'] is not None and self.__player['ffmpeg'].poll() is None
def volume(self, value):
terrariumAudio.volume(int(self.__hw), int(value))