4
votes

I wrote a little program which records voice from the microphone and sends it over network and plays it there. I'm using PyAudio for this task. It works almost fine but on both computers i get errors from ALSA that an underrun occurred. I googled a lot about it and now I know what an underrun even is. But I still don't know how to fix the problem. Most of the time the sound is just fine. But it sounds a little bit strange if underruns occur. Is there anything I should take care of in my code? It feels like I'm doing an simple error and I miss it.

My system: python: python3.3, OS: Linux Mint Debian Edition UP7, PyAudio v0.2.7

3
If you don't want increase the buffer size: how else would you prevent the buffers from emptying?CL.
I don't know. Because that i'm asking.Kritzefitz
I now googled a bit more about this. I found that my translation of "increase" was wrong. (English isn't my native language) I thought it means making the buffer smaller. But now i'm even more confused, how does it help to make the buffer bigger if there isn't enough data coming in?Kritzefitz

3 Answers

4
votes

Have you considered syncing sound? You didn't provide the code, so my guess is that you need to have a timer in separate thread, that will execute every CHUNK_SIZE/RATE milliseconds code that looks like this:

silence = chr(0)*self.chunk*self.channels*2 
out_stream = ... # is the output stream opened in pyaudio

def play(data):
    # if data has not arrived, play the silence
    # yes, we will sacrifice a sound frame for output buffer consistency
    if data == '':
        data = silence
    out_stream.write(data) 

Assuming this code will execute regularly, this way we will always supply some audio data to output audio stream.

2
votes

It's possible to prevent the underruns by filling silence in if needed. That looks like that:

#...
data = s.recv(CHUNK * WIDTH) # Receive data from peer
stream.write(data) # Play sound
free = stream.get_write_available() # How much space is left in the buffer?
if free > CHUNK # Is there a lot of space in the buffer?
    tofill = free - CHUNK
    stream.write(SILENCE * tofill) # Fill it with silence
#...
0
votes

The solution for me was to buffer the first 10 packets/frames of the recorded sound. Look at the snippet below

BUFFER = 10
while len(queue) < BUFFER:
    continue

while running:
    recorded_frame = queue.pop(0)
    audio.write(recorded_frame)