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