4Read data from stream and record sound and video at the same time
6import dataclasses, logging, os, time, h5py, threading
9from .lasp_atomic
import Atomic
10from .lasp_cpp
import (LASP_VERSION_MAJOR, LASP_VERSION_MINOR, InDataHandler,
22 Class used to perform a recording. Recording data can come in from a
23 different thread, that is supposed to call the `inCallback` method, with
24 audio data as an argument.
31 rectime: float =
None,
33 progressCallback=
None,
34 startDelay: float = 0,
37 Start a recording. Blocks if wait is set to True.
40 fn: Filename to record to. Extension is automatically added if not
42 stream: AvStream instance to record from. Should have input
44 rectime: Recording time [s], None for infinite, in seconds. If set
45 to None, or np.inf, the recording continues indefintely.
46 progressCallback: callable that is called with an instance of
47 RecordStatus instance as argument.
48 startDelay: Optional delay added before the recording is *actually*
59 raise RuntimeError(
"Invalid start delay value. Should be >= 0")
87 self.
f = h5py.File(self.
fn,
"w",
'stdio')
89 except Exception
as e:
90 logging.error(f
'Error creating measurement file {e}')
98 streamstatus = streammgr.getStreamStatus(StreamMgr.StreamType.input)
99 if not streamstatus.runningOK():
101 "Stream is not running properly. Please first start the stream"
106 logging.debug(
"Starting record....")
111 logging.debug(
"Stop recording with CTRL-C")
113 while not self.
stop():
115 except KeyboardInterrupt:
116 logging.debug(
"Keyboard interrupt on record")
122 Function called with initial stream data.
125 in_ch = daq.enabledInChannels()
126 blocksize = daq.framesPerBlock()
129 self.
fs = daq.samplerate()
133 f.attrs[
"LASP_VERSION_MAJOR"] = LASP_VERSION_MAJOR
134 f.attrs[
"LASP_VERSION_MINOR"] = LASP_VERSION_MINOR
137 f.attrs[
"samplerate"] = daq.samplerate()
138 f.attrs[
"nchannels"] = daq.neninchannels()
139 f.attrs[
"blocksize"] = blocksize
140 f.attrs[
"sensitivity"] = [ch.sensitivity
for ch
in in_ch]
141 f.attrs[
"channelNames"] = [ch.name
for ch
in in_ch]
146 f.attrs[
"time"] = time.time() + self.
startDelay
150 f.attrs[
"qtys_enum_idx"] = [ch.qty.value
for ch
in in_ch]
159 Set up the dataset in which to store the audio data. This will create
160 the attribute `self.ad`
163 adata: Numpy array with data from DAQ
169 dtype = np.dtype(adata.dtype)
171 self.
ad = self.
f.create_dataset(
187 This method is called when a block of audio data from the stream is
188 available. It should return either True or False.
190 When returning False, it will stop the stream.
194 logging.debug(
'Stop flag set, early return in inCallback')
208 Set the delete flag. If set, measurement file is deleted at the end of
209 the recording. Typically used for cleaning up after canceling a
217 This method should be called to finish and a close a recording file,
218 remove the queue from the stream, etc.
221 logging.debug(
"Recording::finish()")
243 except Exception
as e:
244 logging.error(f
"Error closing file: {e}")
246 logging.debug(
"Recording ended")
250 def __deleteFile(self):
252 Cleanup the recording file.
256 except Exception
as e:
257 logging.error(f
"Error deleting file: {self.fn}: {str(e)}")
259 def __addTimeData(self, indata):
261 Called by handleQueue() and adds new time data to the storage file.
287 curT_rounded_to_seconds = int(curT)
290 print(f
"{curT_rounded_to_seconds}", end=
"", flush=
True)
292 print(
".", end=
"", flush=
True)
297 recstatus.done =
True
303 self.
ad.resize(ablockno, axis=0)
304 self.
ad[ablockno - 1, :, :] = indata
Implementation of atomic operations on integers and booleans.
Class used to perform a recording.
firstFrames(self, adata)
Set up the dataset in which to store the audio data.
inCallback(self, adata)
This method is called when a block of audio data from the stream is available.
resetCallback(self, daq)
Function called with initial stream data.
__init__(self, str fn, StreamMgr streammgr, float rectime=None, bool wait=True, progressCallback=None, float startDelay=0)
Start a recording.
__addTimeData(self, indata)
finish(self)
This method should be called to finish and a close a recording file, remove the queue from the stream...
setDelete(self, bool val)
Set the delete flag.