161 lines
3.8 KiB
Python
Executable File
161 lines
3.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import sys
|
|
import os
|
|
import threading
|
|
import queue
|
|
import time
|
|
import math
|
|
import pyaudio
|
|
unbufferedStdout = os.fdopen(sys.stdout.fileno(),"wb",0) # Make unbuffered stdout
|
|
audioQueue = queue.Queue()
|
|
|
|
lastTime = 0
|
|
def legacyTimeMethod():
|
|
currentTime = time.clock()
|
|
if lastTime == 0:
|
|
lastTime = currentTime
|
|
return 0
|
|
|
|
timeSpent = currentTime - lastTime
|
|
lastTime = currentTime
|
|
return timeSpent
|
|
|
|
timeMethod = legacyTimeMethod
|
|
try:
|
|
timeMethod = time.perf_counter
|
|
except Exception:
|
|
pass
|
|
|
|
class inThread(threading.Thread):
|
|
def __init__(self):
|
|
threading.Thread.__init__(self)
|
|
|
|
def run(self):
|
|
try:
|
|
while True:
|
|
b = sys.stdin.buffer.read(audioFrameSize)
|
|
if b == b"": return
|
|
audioQueue.put(b)
|
|
except KeyboardInterrupt:
|
|
pass
|
|
|
|
def getAudioFrame():
|
|
global lastFrame
|
|
global audioStore
|
|
data = lastFrame
|
|
|
|
#print(audioQueue.qsize())
|
|
if audioQueue.qsize() > 0:
|
|
while audioQueue.qsize() > audioStore + 1:
|
|
data = audioQueue.get(False)
|
|
data = audioQueue.get(False)
|
|
|
|
lastFrame = data
|
|
return data
|
|
|
|
def streamHandler(in_data, frame_count, time_info, status):
|
|
data = b""
|
|
data += getAudioFrame()
|
|
return (data, pyaudio.paContinue)
|
|
|
|
def parseFlags():
|
|
rtn = []
|
|
for arg in sys.argv[1:]:
|
|
arg = arg.replace(" ","")
|
|
arg = arg.replace("\t","")
|
|
arg = arg.replace("\r","")
|
|
arg = arg.replace("\n","")
|
|
if arg[0] != "-": continue
|
|
if arg == "-": continue
|
|
|
|
if arg[:2] == "--":
|
|
rtn.append(arg[2:])
|
|
continue
|
|
|
|
for i in arg[1:]:
|
|
rtn.append(i)
|
|
|
|
return rtn
|
|
|
|
def parseSettings():
|
|
rtn = {}
|
|
for arg in sys.argv[1:]:
|
|
arg = arg.split("=",1)
|
|
if len(arg) < 2: arg.append("")
|
|
arg[0] = arg[0].strip(" \t\r\n")
|
|
arg[1] = arg[1].strip(" \t\r\n")
|
|
rtn[arg[0]] = arg[1]
|
|
return rtn
|
|
|
|
def getSetting(lst,tp,keys,default = None):
|
|
for key in keys:
|
|
if key in lst:
|
|
return tp(lst[key])
|
|
return default
|
|
|
|
flags = parseFlags()
|
|
|
|
if "l" in flags:
|
|
devices = {}
|
|
audio = pyaudio.PyAudio()
|
|
defaultDevice = audio.get_default_host_api_info()["defaultOutputDevice"]
|
|
devices["default"] = defaultDevice
|
|
for i in range(0, audio.get_device_count()):
|
|
info = audio.get_device_info_by_index(i)
|
|
if info["maxOutputChannels"] == 0: continue
|
|
|
|
devices[i] = {
|
|
"name": info["name"],
|
|
"api": audio.get_host_api_info_by_index(info["hostApi"])["name"]
|
|
}
|
|
|
|
if not "h" in flags:
|
|
import json
|
|
print(json.dumps(devices))
|
|
else:
|
|
print("\nAvailable output devices:")
|
|
for i in devices:
|
|
if i == "default": continue
|
|
st = str(i)+ ": " +devices[i]["name"]+ " [" +devices[i]["api"]+ "]"
|
|
if i == defaultDevice: st = st + " *"
|
|
print(st)
|
|
sys.exit(0)
|
|
|
|
settings = parseSettings()
|
|
audioFormat = getSetting(settings,str,["f","format"],"paUInt8")
|
|
audioChannels = getSetting(settings,int,["c","channel","channels"],1)
|
|
audioRate = getSetting(settings,int,["r","rate","bitrate"],8000)
|
|
audioBuffer = getSetting(settings,float,["b","buffer","buffersize"],0.05)
|
|
audioStore = getSetting(settings,float,["s","store"],0.3)
|
|
audioDevice = getSetting(settings,int,["d","device"],None)
|
|
if audioDevice == -1: audioDevice = None
|
|
|
|
letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
audioBitrate = audioFormat
|
|
audioFormat = getattr(pyaudio,audioFormat)
|
|
for letter in letters: audioBitrate = audioBitrate.replace(letter,"")
|
|
audioBitrate = int(audioBitrate)
|
|
audioBuffer = round(audioRate * audioBuffer)
|
|
audioFrameSize = int(float(audioChannels) * (audioBitrate / 8) * audioBuffer)
|
|
audioStorePerSecond = audioBuffer / audioRate
|
|
audioStore = math.ceil(audioStore / audioStorePerSecond)
|
|
lastFrame = bytearray(int(audioFrameSize))
|
|
|
|
kwargs = {
|
|
"output": True,
|
|
"output_device_index": audioDevice,
|
|
"format": audioFormat,
|
|
"channels": audioChannels,
|
|
"frames_per_buffer": audioBuffer,
|
|
"rate": audioRate,
|
|
"stream_callback": streamHandler
|
|
}
|
|
|
|
audio = pyaudio.PyAudio()
|
|
stream = audio.open(**kwargs)
|
|
inThread().start()
|
|
try:
|
|
while stream.is_active():
|
|
time.sleep(0.1)
|
|
except KeyboardInterrupt:
|
|
pass |