New configuration for ridgid card selection by client

This commit is contained in:
Ruben van de Ven 2019-04-11 17:47:05 +02:00
parent a9c3d7ba12
commit 6182362acc
2 changed files with 132 additions and 43 deletions

View File

@ -5,11 +5,13 @@ voice:
input_rate: 44100
target_rate: 16000
port: 4444
input_name: null
file_address: "http://hugveycmd.local:8888"
play_device: 0 # alsa mixer nr
play_volume: 80
play_audiodev: "hw:2,0" # sox AUDIODEV
input_name: 'AK5371'
output_name: 'USB Audio Device'
input_mixer: 'Mic'
output_mixer: 'PCM'
input_volume: 90
output_volume: 60
file_address: "http://hugveycmd.local:8888"

View File

@ -36,14 +36,14 @@ def setLogger(hv_id):
class VoiceServer(object):
"""A UDP server, providing mic data at 16 kHz"""
def __init__(self, loop, hugvey, voice_port: int, input_rate: int, input_name: str = None, target_rate: int = 16000):
self.voice_port = voice_port
self.input_rate = input_rate
self.target_rate = target_rate
def __init__(self, loop, hugvey, config):
self.config = config
self.input_rate = self.config['voice']['input_rate']
self.target_rate = self.config['voice']['target_rate']
self.stopped = True
self.clients = []
self.laststate = None
self.input_name = input_name
self.ctx = Context.instance()
self.loop = loop
self.hugvey = hugvey
@ -52,23 +52,100 @@ class VoiceServer(object):
self.mic_prerol_sec = .3
self.prerol_frame_count = math.ceil(self.input_rate / self.chunk)
self.prerol_frames = collections.deque(maxlen = self.prerol_frame_count)
def get_input_idx(self):
self.p = pyaudio.PyAudio()
# wait a sec for the input devices to come up
logger.debug('wait for mic')
time.sleep(3)
logger.debug('done waiting for mic')
self.info = self.get_card_info()
def get_card_info(self):
output_device_idx = None
input_device_idx = None
# input_device_idx = 6
# input_device_idx = 0
devices_count = self.p.get_device_count()
for i in range(devices_count):
dev = self.p.get_device_info_by_index(i)
if input_device_idx is None and dev['maxInputChannels'] > 0:
if (self.input_name and self.input_name in dev['name']) or \
(not self.input_name and dev['name'] != 'default'):
input_device_idx = dev['index']
logger.info("Use device {0}: {1}".format(
if output_device_idx is None and dev['maxOutputChannels'] > 0:
if (self.config['voice']['output_name'] and self.config['voice']['output_name'] in dev['name']) or \
(not self.config['voice']['output_name'] and dev['name'] != 'default'):
output_device_idx = dev['index']
logger.info("Use output device {0}: {1}".format(
dev['index'], dev['name']))
logger.debug("{} {:0d} {}".format(
"* " if input_device_idx == i else "- ", i, dev['name']))
return input_device_idx
if input_device_idx is None and dev['maxInputChannels'] > 0:
if (self.config['voice']['input_name'] and self.config['voice']['input_name'] in dev['name']) or \
(not self.config['voice']['input_name'] and dev['name'] != 'default'):
input_device_idx = dev['index']
logger.info("Use input device {0}: {1}".format(
dev['index'], dev['name']))
logger.debug("{} {:0d} {} (i: {}, o: {})".format(
"< " if output_device_idx == i else "> " if input_device_idx == i else "- ", i, dev['name'],
dev['maxInputChannels'],
dev['maxOutputChannels']))
# Don't continue without pyAudio indexes
if input_device_idx is None:
raise Exception("Input device is not found: {}".format(self.config['voice']['input_name']))
if output_device_idx is None:
raise Exception("Output device is not found: {}".format(self.config['voice']['output_name']))
try:
# get eg: "hw:1,0" or "hw:0,3" -> used by Sox' play
output_device_name = self.p.get_device_info_by_index(output_device_idx)['name'].split("(",1)[1][:-1]
# get eg: "hw:1" or "hw:0" -> used by alsaaudio.Mixer(device=..)
output_card_name = output_device_name.split(",",1)[0]
except IndexError as e:
output_device_name = None
output_card_name = None
try:
input_device_name = self.p.get_device_info_by_index(input_device_idx)['name'].split("(",1)[1][:-1]
input_card_name = input_device_name.split(",",1)[0]
except IndexError as e:
input_device_name = None
input_card_name = None
print(output_device_name, input_device_name)
return {
'input': {
'idx': input_device_idx,
'device': input_device_name,
'card': input_card_name
},
'output': {
'idx': output_device_idx,
'device': output_device_name,
'card': output_card_name
}
}
#
# def get_output_idxs(self):
# pass
#
# def get_input_idx(self):
# input_device_idx = None
# # input_device_idx = 6
# # input_device_idx = 0
# devices_count = self.p.get_device_count()
# for i in range(devices_count):
# dev = self.p.get_device_info_by_index(i)
# if input_device_idx is None and dev['maxInputChannels'] > 0:
# if (self.input_name and self.input_name in dev['name']) or \
# (not self.input_name and dev['name'] != 'default'):
# input_device_idx = dev['index']
# logger.info("Use device {0}: {1}".format(
# dev['index'], dev['name']))
# logger.debug("{} {:0d} {}".format(
# "* " if input_device_idx == i else "- ", i, dev['name']))
# return input_device_idx
def onBuffer(self, in_data, frame_count, time_info, status):
if self.input_rate == self.target_rate:
@ -108,13 +185,28 @@ class VoiceServer(object):
CHANNELS = 1
CHUNK = 4096
self.p = pyaudio.PyAudio()
self.stopped = False
# wait a sec for the input devices to come up
logger.debug('wait for mic')
await asyncio.sleep(3)
logger.debug('done waiting for mic')
if 'alsaaudio' in sys.modules:
if self.config['voice']['input_mixer'] and self.config['voice']['input_volume'] and self.info['input']['card']:
logger.info("Set input volume on {}/{} to {}".format(
self.config['voice']['input_mixer'],
self.info['input']['card'],
self.config['voice']['input_volume']
))
alsaaudio.Mixer(self.config['voice']['input_mixer'], device=self.info['input']['card']).setvolume(
self.config['voice']['input_volume'])
if self.config['voice']['output_mixer'] and self.config['voice']['output_volume'] and self.info['output']['card']:
logger.info("Set output volume on {}/{} to {}".format(
self.config['voice']['output_mixer'],
self.info['output']['card'],
self.config['voice']['output_volume']
))
alsaaudio.Mixer(self.config['voice']['output_mixer'], device=self.info['output']['card']).setvolume(
self.config['voice']['output_volume'])
stream = self.p.open(
format=FORMAT,
@ -123,12 +215,12 @@ class VoiceServer(object):
input=True,
frames_per_buffer=CHUNK,
stream_callback=self.onBuffer,
input_device_index=self.get_input_idx()
input_device_index=self.info['input']['idx']
)
while not self.stopped:
try:
address = "tcp://*:{}".format(self.voice_port + self.hugvey.id)
address = "tcp://*:{}".format(self.config['voice']['port'] + self.hugvey.id)
self.voice_socket = self.ctx.socket(zmq.PUB)
self.voice_socket.bind(address)
@ -334,26 +426,21 @@ class Hugvey(object):
logger.debug('Hugvey {}, reporting'.format(self.id))
loop = asyncio.get_event_loop()
if self.config['voice']['play_device'] and 'alsaaudio' in sys.modules:
alsaaudio.Mixer(self.config['voice']['play_device']).setvolume(
self.config['voice']['play_volume'])
self.voice_server = VoiceServer(
loop=loop,
hugvey=self,
config=self.config
)
self.cmd_server = CommandHandler(
hugvey_id=self.id,
cmd_address=self.config['events']['cmd_address'],
publish_address=self.config['events']['publish_address'],
file_address=self.config['voice']['file_address'],
play_audiodev=self.config['voice']['play_audiodev']
)
self.voice_server = VoiceServer(
loop=loop,
hugvey=self,
voice_port=int(self.config['voice']['port']),
input_rate=int(self.config['voice']['input_rate']),
input_name=self.config['voice']['input_name'],
target_rate=int(self.config['voice']['target_rate']),
play_audiodev=self.voice_server.info['output']['device']
)
logger.info('start')
# self.voice_server.asyncStart(loop)
# loop.run_until_complete(self.voice_server.start())