Use PUB/Sub for voice sending (auto socket recovery_
This commit is contained in:
parent
8f68505ff4
commit
e8bfa8a6da
2 changed files with 47 additions and 25 deletions
|
@ -14,7 +14,7 @@ logger = logging.getLogger("client")
|
|||
|
||||
class VoiceServer(object):
|
||||
"""A UDP server, providing mic data at 16 kHz"""
|
||||
def __init__(self, voice_port: int, input_rate: int, input_name: str = None, target_rate: int = 16000):
|
||||
def __init__(self, loop, 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
|
||||
|
@ -22,6 +22,8 @@ class VoiceServer(object):
|
|||
self.clients = []
|
||||
self.laststate = None
|
||||
self.input_name = input_name
|
||||
self.ctx = Context.instance()
|
||||
self.loop = loop
|
||||
|
||||
def get_input_idx(self):
|
||||
input_device_idx = None
|
||||
|
@ -46,17 +48,20 @@ class VoiceServer(object):
|
|||
# chunk 4096, with 2 bytes per frame gives len(in_data) of 8192
|
||||
# rate converted 44k1 -> 16k gives len(f) == 2972 (16/44.1 * 8192)
|
||||
f, self.laststate = audioop.ratecv(in_data, 2, 1, self.input_rate, self.target_rate, self.laststate)
|
||||
|
||||
for s in self.clients:
|
||||
try:
|
||||
s.send(f)
|
||||
except Exception as e:
|
||||
self.clients.remove(s)
|
||||
logger.warn("Error sending to {}, {}".format(s.getsockname(), e))
|
||||
pass
|
||||
|
||||
|
||||
# for s in self.clients:
|
||||
try:
|
||||
# self.loop.call_soon_threadsafe()
|
||||
self.loop.call_soon_threadsafe( self.voice_socket.send, f )
|
||||
# s.send(f)
|
||||
except Exception as e:
|
||||
# self.clients.remove(s)
|
||||
logger.warn("Error sending to {}".format(e))
|
||||
pass
|
||||
return (None, pyaudio.paContinue)
|
||||
|
||||
def start(self):
|
||||
async def start(self):
|
||||
FORMAT = pyaudio.paInt16
|
||||
CHANNELS = 1
|
||||
CHUNK = 4096
|
||||
|
@ -76,18 +81,24 @@ class VoiceServer(object):
|
|||
|
||||
while not self.stopped:
|
||||
try:
|
||||
self.voice_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.voice_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
address = ('', self.voice_port)
|
||||
address = "tcp://*:{}".format(self.voice_port)
|
||||
self.voice_socket = self.ctx.socket(zmq.PUB)
|
||||
# self.voice_socket.setsockopt(zmq.CONFLATE, 1)
|
||||
self.voice_socket.bind(address)
|
||||
self.voice_socket.listen(5)
|
||||
|
||||
# self.voice_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# self.voice_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
# address = ('', self.voice_port)
|
||||
# self.voice_socket.bind(address)
|
||||
# self.voice_socket.listen(5)
|
||||
|
||||
read_list = [self.voice_socket]
|
||||
# read_list = [self.voice_socket]
|
||||
logger.info( "Waiting for voice connections on {}".format(address) )
|
||||
while not self.stopped:
|
||||
(clientsocket, address) = self.voice_socket.accept()
|
||||
logger.info( "Got voice connection from {}".format(address))
|
||||
self.clients.append(clientsocket)
|
||||
await asyncio.sleep(1)
|
||||
# (clientsocket, address) = self.voice_socket.accept()
|
||||
# logger.info( "Got voice connection from {}".format(address))
|
||||
# self.clients.append(clientsocket)
|
||||
|
||||
logger.info( "Stop recording & streaming")
|
||||
self.voice_socket.close()
|
||||
|
@ -214,7 +225,10 @@ class Hugvey(object):
|
|||
return await self.cmd_server.command_listener()
|
||||
|
||||
def start(self):
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
self.voice_server = VoiceServer(
|
||||
loop = loop,
|
||||
voice_port = int(self.config['voice']['port']),
|
||||
input_rate = int(self.config['voice']['input_rate']),
|
||||
input_name = self.config['voice']['input_name'],
|
||||
|
@ -225,11 +239,10 @@ class Hugvey(object):
|
|||
cmd_address = self.config['events']['cmd_address'],
|
||||
publish_address = self.config['events']['publish_address'],
|
||||
)
|
||||
loop = asyncio.get_event_loop()
|
||||
logger.info('start')
|
||||
# self.voice_server.asyncStart(loop)
|
||||
# loop.run_until_complete(self.voice_server.start())
|
||||
asyncio.ensure_future(self.voice_server.asyncStart(loop))
|
||||
asyncio.ensure_future(self.voice_server.start())
|
||||
asyncio.ensure_future(self.cmd_server.command_listener())
|
||||
asyncio.ensure_future(self.cmd_server.event_sender())
|
||||
self.cmd_server.showMyself()
|
||||
|
|
|
@ -3,6 +3,8 @@ Consume a given Hugvey audio socket, and stream into the given services to emit
|
|||
"""
|
||||
import socket
|
||||
import logging
|
||||
from zmq.asyncio import Context
|
||||
import zmq
|
||||
|
||||
logger = logging.getLogger("streamer")
|
||||
|
||||
|
@ -22,17 +24,24 @@ class AudioStreamer(object):
|
|||
async def run(self):
|
||||
self.isRunning = True
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
address = "tcp://{}:{}".format(self.address, self.port)
|
||||
self.ctx = Context.instance()
|
||||
self.socket = self.ctx.socket(zmq.SUB)
|
||||
self.socket.subscribe('')
|
||||
# self.socket.setsockopt(zmq.CONFLATE, 1)
|
||||
self.socket.connect(address)
|
||||
|
||||
# s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
logger.info("Attempt connection on {}:{}".format(self.address, self.port))
|
||||
s.connect((self.address, self.port))
|
||||
|
||||
# s.connect((self.address, self.port))
|
||||
#
|
||||
while self.isRunning:
|
||||
data = s.recv(self.chunk)
|
||||
data = await self.socket.recv()
|
||||
# logger.debug('chunk received')
|
||||
self.process(data)
|
||||
|
||||
logger.info("Close socket on {}:{}".format(self.address, self.port))
|
||||
s.close()
|
||||
self.socket.close()
|
||||
|
||||
def stop(self):
|
||||
self.isRunning = False
|
||||
|
|
Loading…
Reference in a new issue