Updated API for recording using context manager. Easy for Recording, both in GUI and in CLI

This commit is contained in:
Anne de Jong 2019-12-23 12:25:37 +01:00
parent b88ec2904c
commit 705f77858d
3 changed files with 100 additions and 45 deletions

View File

@ -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):

View File

@ -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()

View File

@ -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()