-
Notifications
You must be signed in to change notification settings - Fork 43
/
audio_playback_bg.py
65 lines (57 loc) · 2.58 KB
/
audio_playback_bg.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
import time
import pyaudio
import wave
import threading
# Audio background playback class (wav format is supported)
class audio_playback_bg:
def __init__(self, wavfile:str, audio): # audio = pyaudio object
with wave.open(wavfile, 'rb') as wav:
if wav.getsampwidth() != 2: # Checking bits/sampling (bytes/sampling)
raise RuntimeError("wav file {} does not have int16 format".format(wavfile))
if wav.getframerate() != 16000: # Checking sampling rate
raise RuntimeError("wav file {} does not have 16kHz sampling rate".format(wavfile))
self.wavdata = wav.readframes(wav.getnframes())
self.lock = threading.Lock()
self.thread = threading.Thread(target=self.play_thread)
self.exit_flag = False
self.play_flag = False
self.play_buf = None # Current playback buffer
self.audio = audio # PyAudio object
self.frame_size = 2048 # Audio frame size (samples / frame)
self.sampling_rate = 16000 # Audio sampling rate
self.playback_stream = self.audio.open(format=pyaudio.paInt16, channels=1, rate=self.sampling_rate, output=True, frames_per_buffer=self.frame_size)
self.thread.start()
def __del__(self):
self.terminate_thread()
def terminate_thread(self):
self.exit_flag = True
self.thread.join()
def play_thread(self):
while self.exit_flag == False:
if self.play_flag == False:
time.sleep(0.1)
continue
if self.play_buf is None:
self.play_buf = self.wavdata[:]
# Cut out an audio frame from the playback buffer
if len(self.play_buf) > self.frame_size*2:
play_data = self.play_buf[:self.frame_size*2]
self.play_buf = self.play_buf[self.frame_size*2:]
else:
play_data = (self.play_buf+b'\0\0'*self.frame_size)[:self.frame_size*2]
self.lock.acquire()
self.play_flag = False
self.lock.release()
self.play_buf = None
# Playback an audio frame
self.playback_stream.write(frames=play_data, num_frames=self.frame_size)
time.sleep(0.1) # 16KHz, 2048samples = 128ms. Wait must be shorter than 128ms.
def play(self):
self.lock.acquire()
self.play_flag = True
self.lock.release()
def stop(self):
self.play_buf = None
self.lock.acquire()
self.play_flag = False
self.lock.release()