Removed stupid handleMessages from streammanager.
This commit is contained in:
parent
200ee69e2a
commit
16390352dc
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "STL-Threadsafe"]
|
||||||
|
path = STL-Threadsafe
|
||||||
|
url = https://github.com/miachm/STL-Threadsafe
|
@ -136,7 +136,6 @@ set(CMAKE_C_FLAGS_RELEASE "-O2 -mfpmath=sse -march=x86-64 -mtune=native \
|
|||||||
# ############################# End compilation flags
|
# ############################# End compilation flags
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Python searching.
|
# Python searching.
|
||||||
set(Python_ADDITIONAL_VERSIONS "3.8")
|
set(Python_ADDITIONAL_VERSIONS "3.8")
|
||||||
set(python_version_windll "38")
|
set(python_version_windll "38")
|
||||||
@ -151,10 +150,8 @@ if(LASP_FFTPACK_BACKEND)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include_directories(
|
include_directories(lasp/c)
|
||||||
lasp/c
|
include_directories(STL-Threadsafe/include)
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory(lasp)
|
add_subdirectory(lasp)
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
|
||||||
|
1
STL-Threadsafe
Submodule
1
STL-Threadsafe
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 08b2d9e7f487121088a817071d1d42b2736996e9
|
@ -16,16 +16,15 @@ from typing import List
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from .device import Daq, DaqChannel, DaqConfiguration, DeviceInfo
|
from .device import Daq, DaqChannel, DaqConfiguration, DeviceInfo
|
||||||
|
from .filter import highpass
|
||||||
from .lasp_atomic import Atomic
|
from .lasp_atomic import Atomic
|
||||||
from .lasp_common import AvType
|
from .lasp_common import AvType
|
||||||
from .lasp_multiprocessingpatch import apply_patch
|
from .lasp_multiprocessingpatch import apply_patch
|
||||||
from .filter import highpass
|
|
||||||
from .wrappers import SosFilterBank
|
from .wrappers import SosFilterBank
|
||||||
|
|
||||||
apply_patch()
|
apply_patch()
|
||||||
|
|
||||||
|
__all__ = ["StreamManager", "ignoreSigInt", "StreamStatus"]
|
||||||
__all__ = ['StreamManager', 'ignoreSigInt', 'StreamStatus']
|
|
||||||
|
|
||||||
|
|
||||||
def ignoreSigInt():
|
def ignoreSigInt():
|
||||||
@ -66,7 +65,6 @@ class StreamMsg(Enum):
|
|||||||
getStreamMetaData = auto()
|
getStreamMetaData = auto()
|
||||||
endProcess = auto()
|
endProcess = auto()
|
||||||
scanDaqDevices = auto()
|
scanDaqDevices = auto()
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Second part, status messages that are send back on all listeners
|
Second part, status messages that are send back on all listeners
|
||||||
"""
|
"""
|
||||||
@ -107,7 +105,7 @@ class AudioStream:
|
|||||||
processCallback: callback function that will be called from a different
|
processCallback: callback function that will be called from a different
|
||||||
thread, with arguments (AudioStream, in
|
thread, with arguments (AudioStream, in
|
||||||
"""
|
"""
|
||||||
logging.debug('AudioStream()')
|
logging.debug("AudioStream()")
|
||||||
|
|
||||||
# self.running = Atomic(False)
|
# self.running = Atomic(False)
|
||||||
# self.aframectr = Atomic(0)
|
# self.aframectr = Atomic(0)
|
||||||
@ -134,15 +132,13 @@ class AudioStream:
|
|||||||
en_out_ch = daqconfig.getEnabledOutChannels()
|
en_out_ch = daqconfig.getEnabledOutChannels()
|
||||||
|
|
||||||
if en_in_ch == 0 and en_out_ch == 0:
|
if en_in_ch == 0 and en_out_ch == 0:
|
||||||
raise RuntimeError('No enabled input / output channels')
|
raise RuntimeError("No enabled input / output channels")
|
||||||
elif en_out_ch == 0 and avtype in (AvType.audio_duplex,
|
elif en_out_ch == 0 and avtype in (AvType.audio_duplex, AvType.audio_output):
|
||||||
AvType.audio_output):
|
raise RuntimeError("No enabled output channels")
|
||||||
raise RuntimeError('No enabled output channels')
|
elif en_in_ch == 0 and avtype in (AvType.audio_input, AvType.audio_duplex):
|
||||||
elif en_in_ch == 0 and avtype in (AvType.audio_input,
|
raise RuntimeError("No enabled input channels")
|
||||||
AvType.audio_duplex):
|
|
||||||
raise RuntimeError('No enabled input channels')
|
|
||||||
|
|
||||||
logging.debug('Ready to start device...')
|
logging.debug("Ready to start device...")
|
||||||
samplerate = self.daq.start(self.streamCallback)
|
samplerate = self.daq.start(self.streamCallback)
|
||||||
|
|
||||||
# Create required Highpass filters for incoming data
|
# Create required Highpass filters for incoming data
|
||||||
@ -151,7 +147,7 @@ class AudioStream:
|
|||||||
# Simple filter with a single bank and one section
|
# Simple filter with a single bank and one section
|
||||||
if ch.highpass > 0:
|
if ch.highpass > 0:
|
||||||
fb = SosFilterBank(1, 1)
|
fb = SosFilterBank(1, 1)
|
||||||
hpf = highpass(samplerate, ch.highpass, Q=np.sqrt(2))
|
hpf = highpass(samplerate, ch.highpass, Q=np.sqrt(2) / 2)
|
||||||
fb.setFilter(0, hpf[None, :])
|
fb.setFilter(0, hpf[None, :])
|
||||||
self.hpfs[i] = fb
|
self.hpfs[i] = fb
|
||||||
|
|
||||||
@ -164,7 +160,6 @@ class AudioStream:
|
|||||||
)
|
)
|
||||||
self.running = True
|
self.running = True
|
||||||
|
|
||||||
|
|
||||||
def streamCallback(self, indata, outdata, nframes):
|
def streamCallback(self, indata, outdata, nframes):
|
||||||
"""
|
"""
|
||||||
This is called (from a separate thread) for each block
|
This is called (from a separate thread) for each block
|
||||||
@ -191,12 +186,11 @@ class AudioStream:
|
|||||||
# be an empty filter
|
# be an empty filter
|
||||||
if self.hpfs[i] is not None:
|
if self.hpfs[i] is not None:
|
||||||
indata_float = indata[:, [i]].astype(np.float)
|
indata_float = indata[:, [i]].astype(np.float)
|
||||||
filtered_ch_float = self.hpfs[i].filter_(
|
filtered_ch_float = self.hpfs[i].filter_(indata_float)
|
||||||
indata_float
|
|
||||||
)
|
|
||||||
|
|
||||||
indata_filtered[:, i] = filtered_ch_float.astype(
|
indata_filtered[:, i] = filtered_ch_float.astype(
|
||||||
self.streammetadata.dtype)[:, 0]
|
self.streammetadata.dtype
|
||||||
|
)[:, 0]
|
||||||
else:
|
else:
|
||||||
# One-to-one copy
|
# One-to-one copy
|
||||||
indata_filtered[:, i] = indata[:, i]
|
indata_filtered[:, i] = indata[:, i]
|
||||||
@ -261,7 +255,7 @@ class AvStreamProcess(mp.Process):
|
|||||||
"""
|
"""
|
||||||
The actual function running in a different process.
|
The actual function running in a different process.
|
||||||
"""
|
"""
|
||||||
# First things first, ignore interrupt signals
|
# First things first, ignore interrupt signals for THIS process
|
||||||
# https://stackoverflow.com/questions/21104997/keyboard-interrupt-with-pythons-multiprocessing
|
# https://stackoverflow.com/questions/21104997/keyboard-interrupt-with-pythons-multiprocessing
|
||||||
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
||||||
|
|
||||||
@ -296,8 +290,7 @@ class AvStreamProcess(mp.Process):
|
|||||||
StreamMsg.streamMetaData, avtype, stream.streammetadata
|
StreamMsg.streamMetaData, avtype, stream.streammetadata
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.sendAllQueues(
|
self.sendAllQueues(StreamMsg.streamMetaData, avtype, None)
|
||||||
StreamMsg.streamMetaData, avtype, None)
|
|
||||||
|
|
||||||
elif msg == StreamMsg.startStream:
|
elif msg == StreamMsg.startStream:
|
||||||
avtype, daqconfig = data
|
avtype, daqconfig = data
|
||||||
@ -319,12 +312,9 @@ class AvStreamProcess(mp.Process):
|
|||||||
while not self.outq.empty():
|
while not self.outq.empty():
|
||||||
self.outq.get()
|
self.outq.get()
|
||||||
try:
|
try:
|
||||||
stream = AudioStream(avtype, self.devices,
|
stream = AudioStream(avtype, self.devices, daqconfig, self.streamCallback)
|
||||||
daqconfig, self.streamCallback)
|
|
||||||
self.streams[avtype] = stream
|
self.streams[avtype] = stream
|
||||||
self.sendAllQueues(
|
self.sendAllQueues(StreamMsg.streamStarted, avtype, stream.streammetadata)
|
||||||
StreamMsg.streamStarted, avtype, stream.streammetadata
|
|
||||||
)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.sendAllQueues(
|
self.sendAllQueues(
|
||||||
@ -332,7 +322,6 @@ class AvStreamProcess(mp.Process):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def stopStream(self, avtype: AvType):
|
def stopStream(self, avtype: AvType):
|
||||||
"""
|
"""
|
||||||
Stop an existing stream, and sets the attribute in the list of streams
|
Stop an existing stream, and sets the attribute in the list of streams
|
||||||
@ -345,8 +334,7 @@ class AvStreamProcess(mp.Process):
|
|||||||
if stream is not None:
|
if stream is not None:
|
||||||
try:
|
try:
|
||||||
stream.stop()
|
stream.stop()
|
||||||
self.sendAllQueues(
|
self.sendAllQueues(StreamMsg.streamStopped, stream.avtype)
|
||||||
StreamMsg.streamStopped, stream.avtype)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.sendAllQueues(
|
self.sendAllQueues(
|
||||||
StreamMsg.streamError,
|
StreamMsg.streamError,
|
||||||
@ -487,9 +475,7 @@ class StreamManager:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Open a stream for audio in/output and video input. For audio output,
|
"""Open a stream for audio in/output and video input. For audio output,"""
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Initialize streamstatus
|
# Initialize streamstatus
|
||||||
self.streamstatus = {t: StreamStatus() for t in list(AvType)}
|
self.streamstatus = {t: StreamStatus() for t in list(AvType)}
|
||||||
@ -525,67 +511,12 @@ class StreamManager:
|
|||||||
self.our_msgqueue = self.addMsgQueueListener()
|
self.our_msgqueue = self.addMsgQueueListener()
|
||||||
|
|
||||||
# Create the stream process
|
# Create the stream process
|
||||||
self.streamProcess = AvStreamProcess(child_pipe,
|
self.streamProcess = AvStreamProcess(
|
||||||
self.msg_qlist,
|
child_pipe, self.msg_qlist, self.indata_qlist, self.outq
|
||||||
self.indata_qlist, self.outq)
|
)
|
||||||
self.streamProcess.start()
|
self.streamProcess.start()
|
||||||
|
|
||||||
def handleMessages(self):
|
def scanDaqDevices(self):
|
||||||
"""
|
|
||||||
Handle messages that are still on the pipe.
|
|
||||||
"""
|
|
||||||
# logging.debug('StreamManager::handleMessages()')
|
|
||||||
msgs = []
|
|
||||||
while not self.our_msgqueue.empty():
|
|
||||||
msg, data = self.our_msgqueue.get()
|
|
||||||
logging.debug(f'StreamManager obtained message {msg}')
|
|
||||||
if msg == StreamMsg.streamStarted:
|
|
||||||
avtype, streammetadata = data
|
|
||||||
# logging.debug(f'{avtype}, {streammetadata}')
|
|
||||||
self.streamstatus[avtype].lastStatus = msg
|
|
||||||
self.streamstatus[avtype].errorTxt = None
|
|
||||||
self.streamstatus[avtype].streammetadata = streammetadata
|
|
||||||
|
|
||||||
elif msg == StreamMsg.streamStopped:
|
|
||||||
(avtype,) = data
|
|
||||||
self.streamstatus[avtype].lastStatus = msg
|
|
||||||
self.streamstatus[avtype].errorTxt = None
|
|
||||||
self.streamstatus[avtype].streammetadata = None
|
|
||||||
|
|
||||||
elif msg == StreamMsg.streamError:
|
|
||||||
avtype, errorTxt = data
|
|
||||||
if avtype is not None:
|
|
||||||
self.streamstatus[avtype].lastStatus = msg
|
|
||||||
self.streamstatus[avtype].errorTxt = errorTxt
|
|
||||||
logging.debug(f'Message: {errorTxt}')
|
|
||||||
|
|
||||||
elif msg == StreamMsg.streamTemporaryError:
|
|
||||||
avtype, errorTxt = data
|
|
||||||
if avtype is not None:
|
|
||||||
logging.debug(f'Message: {errorTxt}')
|
|
||||||
|
|
||||||
elif msg == StreamMsg.streamFatalError:
|
|
||||||
avtype, errorTxt = data
|
|
||||||
logging.critical(f"Streamprocess fatal error: {errorTxt}")
|
|
||||||
self.cleanup()
|
|
||||||
|
|
||||||
elif msg == StreamMsg.streamMetaData:
|
|
||||||
avtype, metadata = data
|
|
||||||
self.streamstatus[avtype].streammetadata = metadata
|
|
||||||
|
|
||||||
elif msg == StreamMsg.deviceList:
|
|
||||||
devices, = data
|
|
||||||
# logging.debug(devices)
|
|
||||||
self.devices = devices
|
|
||||||
msgs.append((msg, data))
|
|
||||||
|
|
||||||
return msgs
|
|
||||||
|
|
||||||
def getDeviceList(self):
|
|
||||||
self.handleMessages()
|
|
||||||
return self.devices
|
|
||||||
|
|
||||||
def rescanDaqDevices(self):
|
|
||||||
"""
|
"""
|
||||||
Output the message to the stream process to rescan the list of devices
|
Output the message to the stream process to rescan the list of devices
|
||||||
"""
|
"""
|
||||||
@ -595,7 +526,6 @@ class StreamManager:
|
|||||||
"""
|
"""
|
||||||
Sends a request for the stream status over the pipe, for given AvType
|
Sends a request for the stream status over the pipe, for given AvType
|
||||||
"""
|
"""
|
||||||
self.handleMessages()
|
|
||||||
self.sendPipe(StreamMsg.getStreamMetaData, avtype)
|
self.sendPipe(StreamMsg.getStreamMetaData, avtype)
|
||||||
|
|
||||||
def getOutputQueue(self):
|
def getOutputQueue(self):
|
||||||
@ -604,11 +534,8 @@ class StreamManager:
|
|||||||
|
|
||||||
Note, should (of course) only be used by one signal generator at the time!
|
Note, should (of course) only be used by one signal generator at the time!
|
||||||
"""
|
"""
|
||||||
self.handleMessages()
|
|
||||||
return self.outq
|
return self.outq
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def addMsgQueueListener(self):
|
def addMsgQueueListener(self):
|
||||||
"""
|
"""
|
||||||
Add a listener queue to the list of message queues, and return the
|
Add a listener queue to the list of message queues, and return the
|
||||||
@ -652,7 +579,7 @@ class StreamManager:
|
|||||||
del self.indata_qlist[idx]
|
del self.indata_qlist[idx]
|
||||||
del self.indata_qlist_local[idx]
|
del self.indata_qlist_local[idx]
|
||||||
|
|
||||||
def startStream(self, avtype: AvType, daqconfig: DaqConfiguration, wait=False):
|
def startStream(self, avtype: AvType, daqconfig: DaqConfiguration):
|
||||||
"""
|
"""
|
||||||
Start the stream, which means the callbacks are called with stream
|
Start the stream, which means the callbacks are called with stream
|
||||||
data (audio/video)
|
data (audio/video)
|
||||||
@ -663,19 +590,10 @@ class StreamManager:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
logging.debug("Starting stream...")
|
logging.debug("Starting stream...")
|
||||||
self.handleMessages()
|
|
||||||
self.sendPipe(StreamMsg.startStream, avtype, daqconfig)
|
self.sendPipe(StreamMsg.startStream, avtype, daqconfig)
|
||||||
if wait:
|
|
||||||
# Wait for a message to come into the pipe
|
|
||||||
while True:
|
|
||||||
if self.pipe.poll():
|
|
||||||
self.handleMessages()
|
|
||||||
if self.streamstatus[avtype].lastStatus != StreamMsg.streamStopped:
|
|
||||||
break
|
|
||||||
|
|
||||||
def stopStream(self, avtype: AvType):
|
def stopStream(self, avtype: AvType):
|
||||||
logging.debug(f'StreamManager::stopStream({avtype})')
|
logging.debug(f"StreamManager::stopStream({avtype})")
|
||||||
self.handleMessages()
|
|
||||||
self.sendPipe(StreamMsg.stopStream, avtype)
|
self.sendPipe(StreamMsg.stopStream, avtype)
|
||||||
|
|
||||||
def stopAllStreams(self):
|
def stopAllStreams(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user