spatialaudio / python-sounddevice

:sound: Play and Record Sound with Python :snake:
https://python-sounddevice.readthedocs.io/
MIT License
1.02k stars 149 forks source link

Error opening OutputStream: Unanticipated host error [PaErrorCode -9999] #460

Closed nscotto closed 1 year ago

nscotto commented 1 year ago

I am having this issue on a macOS 13.2.1 with M1 chip:

❯ python play_file.py MR1106_BlueLitMoon_Full/01_Kick.wav
||PaMacCore (AUHAL)|| AUHAL component not found.PortAudioError: Error opening OutputStream: Unanticipated host error [PaErrorCode -9999]: '' [<host API not found> error 0]

play_file.py:

import argparse
import threading

import sounddevice as sd
import soundfile as sf

def int_or_str(text):
    """Helper function for argument parsing."""
    try:
        return int(text)
    except ValueError:
        return text

parser = argparse.ArgumentParser(add_help=False)
parser.add_argument(
    '-l', '--list-devices', action='store_true',
    help='show list of audio devices and exit')
args, remaining = parser.parse_known_args()
if args.list_devices:
    print(sd.query_devices())
    parser.exit(0)
parser = argparse.ArgumentParser(
    description=__doc__,
    formatter_class=argparse.RawDescriptionHelpFormatter,
    parents=[parser])
parser.add_argument(
    'filename', metavar='FILENAME',
    help='audio file to be played back')
parser.add_argument(
    '-d', '--device', type=int_or_str,
    help='output device (numeric ID or substring)')
args = parser.parse_args(remaining)

event = threading.Event()

try:
    data, fs = sf.read(args.filename, always_2d=True)

    current_frame = 0

    def callback(outdata, frames, time, status):
        global current_frame
        if status:
            print(status)
        chunksize = min(len(data) - current_frame, frames)
        outdata[:chunksize] = data[current_frame:current_frame + chunksize]
        if chunksize < frames:
            outdata[chunksize:] = 0
            raise sd.CallbackStop()
        current_frame += chunksize

    stream = sd.OutputStream(
        samplerate=fs, device=args.device, channels=data.shape[1],
        callback=callback, finished_callback=event.set)
    with stream:
        event.wait()  # Wait until playback is finished
except KeyboardInterrupt:
    parser.exit('\nInterrupted by user')
except Exception as e:
    parser.exit(type(e).__name__ + ': ' + str(e))

also I have:

>>> sd._libname
'/opt/homebrew/Caskroom/miniforge/base/envs/audio/bin/../lib/libportaudio.dylib

so issue

mgeier commented 1 year ago

So it looks like you are using libportaudio.dylib installed by conda.

You could try uninstalling that and see what happens.

If then the one from brew is used, you can try uninstalling that as well.

Then the one that's bundled with the sounddevice module should be used.

mgeier commented 1 year ago

BTW, did you try other examples? Does this error appear always or only in some situations? Did you try selecting other devices? How does your list of devices look like?

nscotto commented 1 year ago

I tried selecting other devices but got the same results. Here's my list of devices currently, I also had a soundcard plugged previously:

❯ python play_file.py -l
  0 MacBook Pro Microphone, Core Audio (1 in, 0 out)
  1 MacBook Pro Speakers, Core Audio (0 in, 2 out)
> 2 WH-1000XM4, Core Audio (1 in, 0 out)
< 3 WH-1000XM4, Core Audio (0 in, 2 out)
  4 Microsoft Teams Audio, Core Audio (2 in, 2 out)

Thanks for pointing at conda, I've tried:

❯ conda uninstall python-sounddevice
❯ pip install sounddevice
❯ python play_file.py MR1106_BlueLitMoon_Full/01_Kick.wav
# audio playing...
❯ pip uninstall sounddevice
❯ brew uninstall portaudio
❯ conda install -c conda-forge python-sounddevice
❯ python play_file.py MR1106_BlueLitMoon_Full/01_Kick.wav
||PaMacCore (AUHAL)|| AUHAL component not found.PortAudioError: Error opening OutputStream: Unanticipated host error [PaErrorCode -9999]: '' [<host API not found> error 0]

Good I can make it work with brew and pip :)

However it means that there is a problem with the portaudio shipped with conda on my system.

mgeier commented 1 year ago

It's great that you found a way to make it work!

I would be curious though ... could you please check sd._libname in the case where it works?

I'm not sure if you are now using PortAudio from brew or the bundled one from the sounddevice module.

It might also be interesting to do brew uninstall portaudio and then pip install sounddevice.