Restarting the capture device looks ok

This commit is contained in:
Lars Immisch
2024-04-19 19:53:00 +01:00
parent caafa8ae21
commit ac97e641bc

View File

@@ -7,6 +7,7 @@ import logging
import re import re
import struct import struct
import subprocess import subprocess
import errno
from enum import Enum, auto from enum import Enum, auto
from datetime import datetime, timedelta from datetime import datetime, timedelta
from alsaaudio import (PCM, pcms, PCM_PLAYBACK, PCM_CAPTURE, PCM_NONBLOCK, Mixer, from alsaaudio import (PCM, pcms, PCM_PLAYBACK, PCM_CAPTURE, PCM_NONBLOCK, Mixer,
@@ -98,9 +99,6 @@ class Loopback(object):
self.silence_start = None self.silence_start = None
self.reactor = None self.reactor = None
self.queue = []
@staticmethod @staticmethod
def compute_energy(data): def compute_energy(data):
values = struct.unpack(f'{len(data)//2}h', data) values = struct.unpack(f'{len(data)//2}h', data)
@@ -130,7 +128,8 @@ class Loopback(object):
# start reading data # start reading data
size, data = self.capture.read() size, data = self.capture.read()
if size: if size:
self.queue.append(data) logging.warning(f'initial data discarded ({size} bytes)')
# self.queue.append(data)
self.state = LoopbackState.LISTENING self.state = LoopbackState.LISTENING
@@ -164,7 +163,7 @@ class Loopback(object):
period_size = self.playback.info()['period_size'] period_size = self.playback.info()['period_size']
logging.info(f'opened playback device with period_size {period_size}') logging.info(f'opened playback device with period_size {period_size}')
except ALSAAudioError as e: except ALSAAudioError as e:
logging.info('opening PCM playback device failed: %s', e) logging.warning('opening PCM playback device failed: %s', e)
self.state = LoopbackState.DEVICE_BUSY self.state = LoopbackState.DEVICE_BUSY
return self.state return self.state
elif self.state == LoopbackState.DEVICE_BUSY: elif self.state == LoopbackState.DEVICE_BUSY:
@@ -196,12 +195,12 @@ class Loopback(object):
logging.warning(f'POLLERR for capture - reopening capture device: {state_names[self.capture.state()]}') logging.warning(f'POLLERR for capture - reopening capture device: {state_names[self.capture.state()]}')
self.reactor.unregister(self.capture_pd) self.reactor.unregister(self.capture_pd)
self.capture.drop()
self.capture.close() self.capture.close()
self.capture = PCM(**self.capture_args) self.capture = PCM(**self.capture_args)
self.capture_pd = PollDescriptor.from_alsa_object('capture', self.capture) self.capture_pd = PollDescriptor.from_alsa_object('capture', self.capture)
self.reactor.register(self.capture_pd, self) self.reactor.register(self.capture_pd, self)
return True
'''called when data is available for reading''' '''called when data is available for reading'''
self.last_capture_event = datetime.now() self.last_capture_event = datetime.now()
@@ -213,7 +212,6 @@ class Loopback(object):
# the usecase is a USB capture device where we get perfect silence when it's idle # the usecase is a USB capture device where we get perfect silence when it's idle
# compute the energy and go back to LISTENING if nothing is captured # compute the energy and go back to LISTENING if nothing is captured
energy = self.compute_energy(data) energy = self.compute_energy(data)
logging.debug(f'energy: {energy}')
if energy == 0: if energy == 0:
if self.silence_start is None: if self.silence_start is None:
self.silence_start = datetime.now() self.silence_start = datetime.now()
@@ -228,22 +226,17 @@ class Loopback(object):
if self.set_state(LoopbackState.PLAYING) != LoopbackState.PLAYING: if self.set_state(LoopbackState.PLAYING) != LoopbackState.PLAYING:
return False return False
self.queue.append(data)
if len(self.queue) <= 2:
logging.info(f'buffering: {len(self.queue)}')
return False
try:
data = self.pop()
if data: if data:
space = self.playback.avail() space = self.playback.avail()
logging.debug(f'space: {space}')
if space > 0: if space > 0:
written = self.playback.write(data) written = self.playback.write(data)
logging.debug(f'wrote {written} bytes while space was {space}') if written == -errno.EPIPE:
except ALSAAudioError: logging.warning('playback underrun')
logging.error('underrun', exc_info=1) self.playback.write(data)
silence = ''
if energy == 0:
silence = '(silence)'
logging.debug(f'wrote {written} bytes while space was {space} {silence}')
return True return True
@@ -326,7 +319,7 @@ class Reactor(object):
polldescriptor, handler = self.descriptors[fd] polldescriptor, handler = self.descriptors[fd]
# very chatty - log all events # very chatty - log all events
logging.debug(f'{polldescriptor.name}: {poll_desc(ev)} ({ev})') # logging.debug(f'{polldescriptor.name}: {poll_desc(ev)} ({ev})')
handler(fd, ev, polldescriptor.name) handler(fd, ev, polldescriptor.name)