Search code examples
pythonloggingstderrpyaudio

How do I silence PyAudio's noisy output?


I've installed PyAudio and it's working exactly as I want it to, both for playing and recording audio. However, every time I initialise a PyAudio object, it barfs a whole bunch of warnings and error into STDERR and it's making it difficult to sort through my own application's logs. Here's a sample out of an ipython session:

In [1]: from pyaudio import PyAudio

In [2]: PyAudio()
ALSA lib pcm.c:2660:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear
ALSA lib pcm.c:2660:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe
ALSA lib pcm.c:2660:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'cards.USB-Audio.pcm.hdmi.0:CARD=0,AES0=4,AES1=130,AES2=0,AES3=2'
ALSA lib conf.c:4745:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5233:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2660:(snd_pcm_open_noupdate) Unknown PCM hdmi
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'cards.USB-Audio.pcm.hdmi.0:CARD=0,AES0=4,AES1=130,AES2=0,AES3=2'
ALSA lib conf.c:4745:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5233:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2660:(snd_pcm_open_noupdate) Unknown PCM hdmi
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'cards.USB-Audio.pcm.modem.0:CARD=0'
ALSA lib conf.c:4745:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5233:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2660:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline:CARD=0,DEV=0
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'cards.USB-Audio.pcm.modem.0:CARD=0'
ALSA lib conf.c:4745:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5233:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2660:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline:CARD=0,DEV=0
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'cards.USB-Audio.pcm.modem.0:CARD=0'
ALSA lib conf.c:4745:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5233:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2660:(snd_pcm_open_noupdate) Unknown PCM phoneline
ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'cards.USB-Audio.pcm.modem.0:CARD=0'
ALSA lib conf.c:4745:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:5233:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2660:(snd_pcm_open_noupdate) Unknown PCM phoneline
connect(2) call to /dev/shm/jack-1000/default/jack_0 failed (err=No such file or directory)
attempt to connect to server failed
connect(2) call to /dev/shm/jack-1000/default/jack_0 failed (err=No such file or directory)
attempt to connect to server failed
ALSA lib pcm_oss.c:377:(_snd_pcm_oss_open) Unknown field port
ALSA lib pcm_oss.c:377:(_snd_pcm_oss_open) Unknown field port
ALSA lib pcm_usb_stream.c:486:(_snd_pcm_usb_stream_open) Invalid type for card
ALSA lib pcm_usb_stream.c:486:(_snd_pcm_usb_stream_open) Invalid type for card
connect(2) call to /dev/shm/jack-1000/default/jack_0 failed (err=No such file or directory)
attempt to connect to server failed

Out[2]: <pyaudio.PyAudio at 0x7f7066350850>

I poked through the source code and couldn't find where it's spewing this out, and as far as I can tell this isn't happening via Python's logging facility because this prints []:

import logging
print([logging.getLogger(name) for name in logging.root.manager.loggerDict])

It doesn't appear to be telling me anything I need to know so I'd like it to just... stop. Any help would be appreciated.


Solution

  • The problem was that PyAudio loads a bunch of non-Python stuff whenever it's envoked, and it's that's stuff that's printing to STDOUT so it has to be silenced directly. The cleanest way to do this is to wrap it in a context manager that silences STDOUT for the shortest amount of time possible:

    import os
    
    from pyaudio import PyAudio
    
    
    class pyaudio:
        """
        PyAudio is noisy af every time you initialise it, which makes reading the
        log output rather difficult.  The output appears to be being made by the
        C internals, so I can't even redirect the logs with Python's logging
        facility.  Therefore the nuclear option was selected: swallow all stderr
        and stdout for the duration of PyAudio's use.
    
        Lifted and adapted from StackOverflow:
          https://stackoverflow.com/questions/11130156/
        """
    
        def __init__(self):
    
            # Open a pair of null files
            self.null_fds = [os.open(os.devnull, os.O_RDWR) for x in range(2)]
    
            # Save the actual stdout (1) and stderr (2) file descriptors.
            self.save_fds = [os.dup(1), os.dup(2)]
    
            self.pyaudio = None
    
        def __enter__(self) -> PyAudio:
    
            # Assign the null pointers to stdout and stderr.
            os.dup2(self.null_fds[0], 1)
            os.dup2(self.null_fds[1], 2)
    
            self.pyaudio = PyAudio()
    
            return self.pyaudio
    
        def __exit__(self, *_):
    
            self.pyaudio.terminate()
    
            # Re-assign the real stdout/stderr back to (1) and (2)
            os.dup2(self.save_fds[0], 1)
            os.dup2(self.save_fds[1], 2)
    
            # Close all file descriptors
            for fd in self.null_fds + self.save_fds:
                os.close(fd)
    

    Using the above looks like this:

    with pyaudio() as audio:
        ...