preliminary work to allow dynamic audio format switching

This commit is contained in:
Jakob Ketterl 2024-07-10 13:49:40 +02:00
parent a9f47be96d
commit 853ee5b024
4 changed files with 57 additions and 8 deletions

View file

@ -1,4 +1,4 @@
from csdr.chain.demodulator import BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, HdAudio, \ from csdr.chain.demodulator import BaseDemodulatorChain, FixedIfSampleRateChain, DynamicAudioRateChain, HdAudio, \
MetaProvider, DabServiceSelector, DialFrequencyReceiver MetaProvider, DabServiceSelector, DialFrequencyReceiver
from csdr.module import PickleModule from csdr.module import PickleModule
from csdreti.modules import EtiDecoder from csdreti.modules import EtiDecoder
@ -58,8 +58,10 @@ class MetaProcessor(PickleModule):
self.shifter.setRate(0) self.shifter.setRate(0)
class Dablin(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, HdAudio, MetaProvider, DabServiceSelector, DialFrequencyReceiver): class Dablin(BaseDemodulatorChain, FixedIfSampleRateChain, DynamicAudioRateChain, HdAudio, MetaProvider, DabServiceSelector, DialFrequencyReceiver):
def __init__(self): def __init__(self):
self.audioRate = 48000
shift = Shift(0) shift = Shift(0)
self.decoder = EtiDecoder() self.decoder = EtiDecoder()
@ -77,7 +79,7 @@ class Dablin(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain,
shift, shift,
self.decoder, self.decoder,
self.dablin, self.dablin,
Downmix(Format.FLOAT), Downmix(Format.SHORT),
] ]
super().__init__(workers) super().__init__(workers)
@ -90,8 +92,8 @@ class Dablin(BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain,
def getFixedIfSampleRate(self) -> int: def getFixedIfSampleRate(self) -> int:
return 2048000 return 2048000
def getFixedAudioRate(self) -> int: def getAudioRate(self) -> int:
return 48000 return self.audioRate
def stop(self): def stop(self):
self.processor.stop() self.processor.stop()

View file

@ -2,6 +2,10 @@ from csdr.chain import Chain
from abc import ABC, ABCMeta, abstractmethod from abc import ABC, ABCMeta, abstractmethod
from pycsdr.modules import Writer from pycsdr.modules import Writer
import logging
logger = logging.getLogger(__name__)
class FixedAudioRateChain(ABC): class FixedAudioRateChain(ABC):
@abstractmethod @abstractmethod
@ -9,6 +13,39 @@ class FixedAudioRateChain(ABC):
pass pass
class DynamicAudioRateListener(ABC):
@abstractmethod
def onAudioRateChange(self, rate: int):
pass
class DynamicAudioRateChain(ABC):
def __init__(self):
self.listeners = []
super().__init__()
def addListener(self, listener: DynamicAudioRateListener):
if listener in self.listeners:
return
self.listeners.append(listener)
def removeListener(self, listener: DynamicAudioRateListener):
if listener not in self.listeners:
return
self.listeners.remove(listener)
def fireAudioRateChange(self, rate: int):
for listener in self.listeners:
try:
listener.onAudioRateChange(rate)
except:
logger.exception("error while sending audio rate change")
@abstractmethod
def getAudioRate(self) -> int:
pass
class FixedIfSampleRateChain(ABC): class FixedIfSampleRateChain(ABC):
@abstractmethod @abstractmethod
def getFixedIfSampleRate(self) -> int: def getFixedIfSampleRate(self) -> int:

View file

@ -7,7 +7,7 @@ class DablinModule(ExecModule):
self.serviceId = 0 self.serviceId = 0
super().__init__( super().__init__(
Format.CHAR, Format.CHAR,
Format.FLOAT, Format.SHORT,
self._buildArgs() self._buildArgs()
) )

View file

@ -5,7 +5,7 @@ from owrx.modes import Modes, DigitalMode
from csdr.chain import Chain from csdr.chain import Chain
from csdr.chain.demodulator import BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, HdAudio, \ from csdr.chain.demodulator import BaseDemodulatorChain, FixedIfSampleRateChain, FixedAudioRateChain, HdAudio, \
SecondaryDemodulator, DialFrequencyReceiver, MetaProvider, SlotFilterChain, SecondarySelectorChain, \ SecondaryDemodulator, DialFrequencyReceiver, MetaProvider, SlotFilterChain, SecondarySelectorChain, \
DeemphasisTauChain, DemodulatorError, RdsChain, DabServiceSelector DeemphasisTauChain, DemodulatorError, RdsChain, DabServiceSelector, DynamicAudioRateChain, DynamicAudioRateListener
from csdr.chain.selector import Selector, SecondarySelector from csdr.chain.selector import Selector, SecondarySelector
from csdr.chain.clientaudio import ClientAudioChain from csdr.chain.clientaudio import ClientAudioChain
from csdr.chain.fft import FftChain from csdr.chain.fft import FftChain
@ -35,7 +35,7 @@ class ClientDemodulatorSecondaryDspEventClient(ABC):
pass pass
class ClientDemodulatorChain(Chain): class ClientDemodulatorChain(Chain, DynamicAudioRateListener):
def __init__(self, demod: BaseDemodulatorChain, sampleRate: int, outputRate: int, hdOutputRate: int, audioCompression: str, secondaryDspEventReceiver: ClientDemodulatorSecondaryDspEventClient): def __init__(self, demod: BaseDemodulatorChain, sampleRate: int, outputRate: int, hdOutputRate: int, audioCompression: str, secondaryDspEventReceiver: ClientDemodulatorSecondaryDspEventClient):
self.sampleRate = sampleRate self.sampleRate = sampleRate
self.outputRate = outputRate self.outputRate = outputRate
@ -101,11 +101,16 @@ class ClientDemodulatorChain(Chain):
if self.demodulator is not None: if self.demodulator is not None:
self.demodulator.stop() self.demodulator.stop()
if isinstance(self.demodulator, DynamicAudioRateChain):
self.demodulator.removeListener(self)
self.demodulator = demodulator self.demodulator = demodulator
self.selector.setOutputRate(self._getSelectorOutputRate()) self.selector.setOutputRate(self._getSelectorOutputRate())
if isinstance(self.demodulator, DynamicAudioRateChain):
self.demodulator.addListener(self)
clientRate = self._getClientAudioInputRate() clientRate = self._getClientAudioInputRate()
self.demodulator.setSampleRate(clientRate) self.demodulator.setSampleRate(clientRate)
@ -155,6 +160,8 @@ class ClientDemodulatorChain(Chain):
def _getClientAudioInputRate(self): def _getClientAudioInputRate(self):
if isinstance(self.demodulator, FixedAudioRateChain): if isinstance(self.demodulator, FixedAudioRateChain):
return self.demodulator.getFixedAudioRate() return self.demodulator.getFixedAudioRate()
elif isinstance(self.demodulator, DynamicAudioRateChain):
return self.demodulator.getAudioRate()
elif isinstance(self.secondaryDemodulator, FixedAudioRateChain): elif isinstance(self.secondaryDemodulator, FixedAudioRateChain):
return self.secondaryDemodulator.getFixedAudioRate() return self.secondaryDemodulator.getFixedAudioRate()
else: else:
@ -395,6 +402,9 @@ class ClientDemodulatorChain(Chain):
if isinstance(self.demodulator, RdsChain): if isinstance(self.demodulator, RdsChain):
self.demodulator.setRdsRbds(self.rdsRbds) self.demodulator.setRdsRbds(self.rdsRbds)
def onAudioRateChange(self, rate: int):
self.clientAudioChain.setInputRate(self._getClientAudioInputRate())
class ModulationValidator(OrValidator): class ModulationValidator(OrValidator):
""" """