me.fier.aspew/aspew-out.py

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