bastibe/PySoundCard

Setting callback after Stream initialisation

Closed this issue · 4 comments

We are trying to set the callback after the Stream initialisation, something like below, which doesn't work:

import time
import numpy as np
from pysoundcard import Stream, continue_flag

def callback(in_data, out_data, time_info, status):
    out_data[:] = 0.1 * np.random.rand(*out_data.shape) - 1
    return continue_flag

# This works:
stream = Stream(
    samplerate=44100,
    blocksize=1024,
    callback=callback
)

# This doesnt work:
stream = Stream(
    samplerate=44100,
    blocksize=1024,
)
stream.callback = callback

stream.start()
time.sleep(5)
stream.stop()

This could be useful, for example, to allow the user to setup the audio properties, before handing us the stream to setup the callback and read/write.

Perhaps using properties to set the callback, and only then create the callback_wrapper, could solve this?

class Stream(object):
    def __init__(self, callback=None):
        # We don't need to care about callback_wrapper here anymore
        self.callback = callback

    @property
    def callback(self):
        return self._callback

    @callback.setter
    def callback(self, value):
        self._callback = callback_wrapper(value, something...)

Then from outside you can do

stream.callback = my_callback_function

at any time (before stream.start) to set the callback.

The problem is that the underlying library requires to run either in callback mode or in read/write-function mode. This has to be decided when the Stream is created, and can't be changed later. There's nothing I can do about this on the Python side to change this. Sorry.

Okay, thank you - I didn't realise that! Is it possible to, or worth considering, creating the stream only when the stream is started, if that is the first point where it would be required? I guess this would allow Stream properties to be set and updated, up until the point where the stream actually starts and properties must be fixed?

This would be possible, yes. It would have the disadvantage that the Stream object would report errors only when first used, and those errors would potentially refer to incorrect property values that were set at a different time. I prefer the current behavior where errors are created at the time where the incorrect values were set.

That said, it is probably pretty easy to create a wrapper for the Stream object, that only initializes the object when actually used. This is something you can probably easily do in your own code base. If you want to share it, I could link to it in the README, or even incorporate it in PySoundCard.

Okay, thank you, I understand. We've got a workaround for the moment, but I'll let you know if we end up writing anything worth sharing/incorporating. Cheers