Updated API for recording using context manager. Easy for Recording, both in GUI and in CLI
This commit is contained in:
parent
b88ec2904c
commit
705f77858d
@ -55,6 +55,7 @@ class AvStream:
|
||||
self.daqconfig = daqconfig
|
||||
self._device = device
|
||||
self.avtype = avtype
|
||||
self.duplex_mode = daqconfig.duplex_mode
|
||||
|
||||
# Determine highest input channel number
|
||||
channelconfigs = daqconfig.en_input_channels
|
||||
@ -125,7 +126,9 @@ class AvStream:
|
||||
"""
|
||||
Returns the current number of installed callbacks
|
||||
"""
|
||||
return len(self._callbacks)
|
||||
return len(self._callbacks[AvType.audio_input]) + \
|
||||
len(self._callbacks[AvType.audio_output]) + \
|
||||
len(self._callbacks[AvType.video])
|
||||
|
||||
def addCallback(self, cb: callable, cbtype: AvType):
|
||||
"""
|
||||
@ -196,9 +199,15 @@ class AvStream:
|
||||
output_signal = None
|
||||
with self._callbacklock:
|
||||
for cb in self._callbacks[AvType.audio_input]:
|
||||
cb(indata, self._aframectr())
|
||||
try:
|
||||
cb(indata, self._aframectr())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
for cb in self._callbacks[AvType.audio_output]:
|
||||
output_data = cb(indata, self._aframectr())
|
||||
try:
|
||||
output_signal = cb(indata, self._aframectr())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return output_signal, 0 if self._running else 1
|
||||
|
||||
def stop(self):
|
||||
|
@ -8,12 +8,19 @@ from .lasp_atomic import Atomic
|
||||
from threading import Condition
|
||||
from .lasp_avstream import AvType, AvStream
|
||||
import h5py
|
||||
import dataclasses
|
||||
import os
|
||||
import time
|
||||
|
||||
@dataclasses.dataclass
|
||||
class RecordStatus:
|
||||
curT: float
|
||||
done: bool
|
||||
|
||||
class Recording:
|
||||
|
||||
def __init__(self, fn, stream, rectime=None):
|
||||
def __init__(self, fn, stream, rectime=None, wait = True,
|
||||
progressCallback=None):
|
||||
"""
|
||||
|
||||
Args:
|
||||
@ -39,67 +46,100 @@ class Recording:
|
||||
self._aframeno = Atomic(0)
|
||||
self._vframeno = 0
|
||||
|
||||
def start(self):
|
||||
stream = self._stream
|
||||
self._progressCallback = progressCallback
|
||||
self._wait = wait
|
||||
|
||||
with h5py.File(self._fn, 'w') as f:
|
||||
self._ad = f.create_dataset('audio',
|
||||
(1, stream.blocksize, stream.nchannels),
|
||||
dtype=stream.numpy_dtype,
|
||||
maxshape=(None, stream.blocksize,
|
||||
stream.nchannels),
|
||||
self._f = h5py.File(self._fn, 'w')
|
||||
self._deleteFile = False
|
||||
|
||||
def setDelete(self, val: bool):
|
||||
self._deleteFile = val
|
||||
|
||||
def __enter__(self):
|
||||
"""
|
||||
|
||||
with self._recording(wait=False):
|
||||
event_loop_here()
|
||||
|
||||
or:
|
||||
|
||||
with Recording(wait=True):
|
||||
pass
|
||||
"""
|
||||
|
||||
stream = self._stream
|
||||
f = self._f
|
||||
|
||||
self._ad = f.create_dataset('audio',
|
||||
(1, stream.blocksize, stream.nchannels),
|
||||
dtype=stream.numpy_dtype,
|
||||
maxshape=(None, stream.blocksize,
|
||||
stream.nchannels),
|
||||
compression='gzip'
|
||||
)
|
||||
if stream.hasVideo():
|
||||
video_x, video_y = stream.video_x, stream.video_y
|
||||
self._vd = f.create_dataset('video',
|
||||
(1, video_y, video_x, 3),
|
||||
dtype='uint8',
|
||||
maxshape=(
|
||||
None, video_y, video_x, 3),
|
||||
compression='gzip'
|
||||
)
|
||||
if stream.hasVideo():
|
||||
video_x, video_y = stream.video_x, stream.video_y
|
||||
self._vd = f.create_dataset('video',
|
||||
(1, video_y, video_x, 3),
|
||||
dtype='uint8',
|
||||
maxshape=(
|
||||
None, video_y, video_x, 3),
|
||||
compression='gzip'
|
||||
)
|
||||
|
||||
f.attrs['samplerate'] = stream.samplerate
|
||||
f.attrs['nchannels'] = stream.nchannels
|
||||
f.attrs['blocksize'] = stream.blocksize
|
||||
f.attrs['sensitivity'] = stream.sensitivity
|
||||
f.attrs['time'] = time.time()
|
||||
self._running <<= True
|
||||
# Videothread is going to start
|
||||
f.attrs['samplerate'] = stream.samplerate
|
||||
f.attrs['nchannels'] = stream.nchannels
|
||||
f.attrs['blocksize'] = stream.blocksize
|
||||
f.attrs['sensitivity'] = stream.sensitivity
|
||||
f.attrs['time'] = time.time()
|
||||
self._running <<= True
|
||||
|
||||
if not stream.isRunning():
|
||||
stream.start()
|
||||
if not stream.isRunning():
|
||||
stream.start()
|
||||
|
||||
print('Starting record....')
|
||||
stream.addCallback(self._aCallback, AvType.audio_input)
|
||||
if stream.hasVideo():
|
||||
stream.addCallback(self._aCallback, AvType.audio_input)
|
||||
if stream.hasVideo():
|
||||
stream.addCallback(self._aCallback, AvType.audio_input)
|
||||
|
||||
if self._wait:
|
||||
with self._running_cond:
|
||||
print('Stop recording with CTRL-C')
|
||||
try:
|
||||
print('Starting record....')
|
||||
while self._running:
|
||||
self._running_cond.wait()
|
||||
except KeyboardInterrupt:
|
||||
print("Keyboard interrupt on record")
|
||||
self._running <<= False
|
||||
|
||||
stream.removeCallback(self._aCallback, AvType.audio_input)
|
||||
|
||||
if stream.hasVideo():
|
||||
stream.removeCallback(self._vCallback, AvType.video_input)
|
||||
f['video_frame_positions'] = self._video_frame_positions
|
||||
|
||||
print('\nEnding record')
|
||||
|
||||
def stop(self):
|
||||
def __exit__(self, type, value, traceback):
|
||||
self._running <<= False
|
||||
with self._running_cond:
|
||||
self._running_cond.notify()
|
||||
stream = self._stream
|
||||
stream.removeCallback(self._aCallback, AvType.audio_input)
|
||||
if stream.hasVideo():
|
||||
stream.removeCallback(self._vCallback, AvType.video_input)
|
||||
f['video_frame_positions'] = self._video_frame_positions
|
||||
|
||||
self._f.close()
|
||||
print('\nEnding record')
|
||||
if self._deleteFile:
|
||||
try:
|
||||
os.remove(self._fn)
|
||||
except Exception as e:
|
||||
print(f'Error deleting file: {self._fn}')
|
||||
|
||||
|
||||
|
||||
def _aCallback(self, frames, aframe):
|
||||
|
||||
curT = self._aframeno()*self.blocksize/self.samplerate
|
||||
recstatus = RecordStatus(
|
||||
curT = curT,
|
||||
done = False)
|
||||
if self._progressCallback is not None:
|
||||
self._progressCallback(recstatus)
|
||||
|
||||
curT_rounded_to_seconds = int(curT)
|
||||
if curT_rounded_to_seconds > self._curT_rounded_to_seconds:
|
||||
self._curT_rounded_to_seconds = curT_rounded_to_seconds
|
||||
@ -112,7 +152,10 @@ class Recording:
|
||||
self._running <<= False
|
||||
with self._running_cond:
|
||||
self._running_cond.notify()
|
||||
return
|
||||
if self._progressCallback is not None:
|
||||
recstatus.done = True
|
||||
self._progressCallback(recstatus)
|
||||
return
|
||||
|
||||
self._ad.resize(self._aframeno()+1, axis=0)
|
||||
self._ad[self._aframeno(), :, :] = frames
|
||||
@ -129,4 +172,6 @@ class Recording:
|
||||
if __name__ == '__main__':
|
||||
stream = AvStream()
|
||||
rec = Recording('test', stream, 5)
|
||||
with rec(wait=True):
|
||||
sleep
|
||||
rec.start()
|
||||
|
@ -47,7 +47,8 @@ stream = AvStream(input_device,
|
||||
config)
|
||||
|
||||
rec = Recording(args.filename, stream, args.duration)
|
||||
rec.start()
|
||||
with rec:
|
||||
pass
|
||||
|
||||
print('Stopping stream...')
|
||||
stream.stop()
|
||||
|
Loading…
Reference in New Issue
Block a user