Stream Handle#

class nistreamer.streamer.NIStreamer.StreamHandle(streamer)#

Handle providing full stream control within with context.

The handle is obtained by initializing stream context (see init_stream()):

>>> strmr = NIStreamer()
>>> # ... add cards/channels, add instructions, compile ...
>>>
>>> # This is how you initialize stream context:
>>> with strmr.init_stream() as stream_handle:
>>>     # ... This is context body ...
>>>
>>>     # Use handle to control stream:
>>>     stream_handle.launch(instream_reps=10)
>>>
>>>     # Always wait for stream to finish:
>>>     stream_handle.wait_until_finished()
>>>
>>> # Stream will be closed automatically when leaving context
launch(instream_reps=1)#

Launch sequence generation.

This call is non-blocking - returns immediately after generation starts. You must always call wait_until_finished() after launching to ensure generation is complete before making any further stream actions.

Parameters:

instream_reps – number of in-stream repetitions. Plays once by default.

Raises:

RuntimeError – if attempting to launch stream while it is already running.

Notes

In-stream looping is very different from basic repeating by re-launching (see run()) - all iterations happen as a single continuous stream without any gaps (but it is still interruptible between repetitions).

The limitation is that in-stream looping requires at least a minimal sequence duration of chunksize_ms(). Shorter sequences can still be played with instream_reps=1 only or be repeated by re-launching. Alternatively, one can concatenate several repetitions into a single sequence to reach sufficient duration for in-stream looping to work.

See also

You must always call wait_until_finished() after launching stream.

reps_written_count()#

Number of fully computed and transferred in-stream repetitions so far.

Return type:

int

Notes

This value DOES NOT show the current play position and cannot serve as a reliable sync mechanism.

Samples are computed and written to cards before they are actually played. So this value - the number of fully written repetitions - can be greater than the actual number of fully played cycles. The two can differ significantly, especially for very short sequences.

Instead, this value is meant to be a coarse progress indicator for long-running in-stream loops (see example below).

Examples

>>> strmr = NIStreamer()
>>> # ... add cards/channels, add instructions, compile ...
>>>
>>> # Timed wait + reps_written_count to implement live progress printing:
>>> with strmr.init_stream() as handle:
>>>     handle.launch(instream_reps=1000)
>>>     while True:
>>>         finished = handle.wait_until_finished(timeout=1)
>>>         print(handle.reps_written_count())
>>>         if finished:
>>>             break
>>>
request_stop()#

Request to stop in-stream loop without completing all repetitions.

Streamer will complete the current repetition in progress and then stop. You should call wait_until_finished() after requesting stop to wait until the in-progress iteration is finished.

Notes

Practically, you do not need to use this function in most cases - simply leaving with context will automatically request stop and wait until stream finishes before returning:

>>> import time
>>> strmr = NIStreamer()
>>> # ... add cards/channels, add instructions, compile ...
>>>
>>> # This will stop in-stream loop as well:
>>> with strmr.init_stream() as handle:
>>>     handle.launch(instream_reps=1000000)
>>>     time.sleep(10)
>>>
>>> # This will stop the loop whenever `KeyboardInterrupt` is emitted:
>>> with strmr.init_stream() as handle:
>>>     handle.launch(instream_reps=1000000)
>>>     handle.wait_until_finished()

This function is only exposed for advanced cases where you need to break out of in-stream loop (e.g. due to some external condition) and then launch the stream again without incurring re-init overhead:

>>> import time
>>> strmr = NIStreamer()
>>> # ... add cards/channels, add instructions, compile ...
>>>
>>> with strmr.init_stream() as handle:
>>>     handle.launch(instream_reps=1000000)
>>>     time.sleep(10)
>>>
>>>     # Now have to break the loop due to some condition:
>>>     handle.request_stop()
>>>     handle.wait_until_finished()
>>>
>>>     # Then launch again:
>>>     handle.launch(instream_reps=10)
>>>     handle.wait_until_finished()
>>>
wait_until_finished(timeout=None)#

Block to wait until generation is finished.

Parameters:

timeout (Optional[float]) – wait time limit in seconds. None - wait indefinitely (default).

Return type:

Optional[bool]

Returns:

In timed mode, Ture means generation finished, False means still running when timeout elapsed. Basic mode returns None.

Raises:

RuntimeError – if there is any stream error (underflow, overvoltage, sync signal loss)

Notes

There are two modes depending on timeout value:

  • Basic (timeout=None, default). Blocks and waits indefinitely until run is finished. Can be interrupted with KeyboardInterrupt. Returns None when finished.

  • Timed (timeout: float). Blocks and returns True if run is finished or False if timeout elapses before.

Examples

>>> strmr = NIStreamer()
>>> # ... add cards/channels, add instructions, compile ...
>>>
>>> # Basic wait:
>>> with strmr.init_stream() as handle:
>>>     handle.launch(instream_reps=10)
>>>     handle.wait_until_finished()
>>>
>>> # Timed wait - using to implement live progress printing:
>>> with strmr.init_stream() as handle:
>>>     handle.launch(instream_reps=10)
>>>     while True:
>>>         finished = handle.wait_until_finished(timeout=1)
>>>         print(handle.reps_written_count())
>>>         if finished:
>>>             break
>>>