Python Sounddevice.play() on Threads
<p>I am having some problems to play the sounddevice on a Thread. I import the sounddevice as sd at the beginning. Then during running I want to play a tone on a thread using the ASIO sound card. All the configurations I need to do on the thread works well. However, when I want to play the tone I got the following Error: </p>

<p><strong>sounddevice.PortAudioError: Error opening OutputStream: Unanticipated host API 2 error 0: u'Failed to load ASIO driver'</strong></p>

<p>If I initialize the import at the thread everytime I need it, it work. But of course I do not want to do that. Any Idea hot to solve it? </p>

<p>Thanks!</p>

<p>Here a simple code example:</p>

<pre><code>from threading import Thread
import numpy as np
import sounddevice as sd

class Test(Thread):

    def __init__(self):
        Thread.__init__(self)
        #-- Configuration of the Tone to be played
        self.fs = 44100       # sampling rate, in Hz, 44100 or 48000
        duration = 1.05  # in seconds, may be float
        f = 200.0        # sine frequency, Hz, may be float
        self.tone_data = (np.sin(2*np.pi*np.arange(self.fs*duration)*f/self.fs)).astype(np.float32)

    def run(self):                       

        #-- Configuration of the ASIO sound card
        #import sounddevice as sd
        sd.default.channels = 2
        sd.default.device = 14
        print sd.query_devices(sd.default.device)['name']
        #sd.default.latency = ('low','low')
        #asio_out = sd.AsioSettings(channel_selectors=[1, 2])
        #sd.default.extra_settings = asio_out        
        sd.default.samplerate = self.fs                
        sd.play(self.tone_data)
        sd.wait()        

w = Test()        
w.start()
</code></pre>

<p>This seems to be a platform-specific problem. I just tried it with ALSA/Linux and it works fine. With ASIO, you probably have to do the library initialization (which happens during <code>import</code> time) in the same thread you are using later to create the stream (which <code>play()</code> does for you)?</p>

<blockquote>
  <p>If I initialize the import at the thread everytime I need it, it work. But of course I do not want to do that.</p>
</blockquote>

<p>Why do you not want to do that? Are you aware that the use of <code>import</code> in Python is cached automatically? The second time you use <code>import</code>, only a <code>dict</code> lookup is done and nothing else.</p>

<p>But you are right, the repeated <code>import</code> still <em>looks</em> a bit strange.
Did you try to do the <code>import</code> only once in <code>Test.__init__()</code>? There you could also do all the <code>sd.default</code> stuff.</p>

<p>If you still have problems during the initialization (or if you insist on having all imports at the top), you can try to use the undocumented <code>_initialize()</code> and <code>_terminate()</code> functions, see <a href="https://github.com/spatialaudio/python-sounddevice/issues/3" rel="nofollow">issue #3</a>.</p>

<p>If you want to use multiple <code>Thread</code> instances, you'll get problems with the <code>play()</code> function, which is meant for single-threaded use. But it probably makes more sense anyway to have only one Python thread that does the audio I/O. See also <a href="https://app.assembla.com/spaces/portaudio/wiki/Tips_Threading" rel="nofollow">PortAudio Tips â Threading</a>.</p>

<p>BTW, you don't need <code>(...).astype(np.float32)</code>, this conversion is done automatically for you.</p>

<p>And while I'm at it, your line <code>sd.query_devices(sd.default.device)['name']</code> will break if the default input and output devices are different.</p>

python multithreading python-sounddevice