3

I am trying to do something like a walkie talkie. 1 device is my laptop and the other being the raspberry pi.

What I have working. I am able to record the microphone, transmit it over a socket and save the recording audio into a wav file.

Only issue I am having is playing the audio live while being sent by the socket. It seems to always breaking in sound. It gets like maybe a 1/4 second of audio then just breaks and then hear another random sound it tried to play, but doesn't.

When I take these scripts and run them both on the same machine there is no issue. So, my thought is there is something going wrong when sending it over or it isn't reading it quick enough or trying to do too much at a time.

Could be how much data that is being transfer that is the issue in which it is failing to play the sound properly.

I have been able to save the wav file and play it with aplay and can confirm the speakers do work and that audio data is at least being transmitted.


Edit:

I tried the suggested UDP method, but kept getting desync audio. Completely inaudible. Just sounded like pieces of audio just were completely gone, which makes sense, but no clue how I can stitch the sound together to even sound close to the original sound.

I was able to sort of getting it to work with TCP. On the client side I end up randomly getting [Errno -9981] Input overflowed at some point which then closes the stream. [Errno -9988] Stream closed.

Not much has change on the code. CHUNK sizes requires playing with sometimes.

I can hear my voice, but after couple of seconds the stream closes due to the errors and I tried having a handle for it, but still goes about closing the stream.

The server tends to spit out this in the terminal

Increasing the CHUNK helps with the underrun issue, however the stream still closes on its own.

Server.py (PI)

import Queue
import socket
import wave

import pyaudio

CHUNK = 8192
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
WAVE_OUTPUT_FILENAME = "server_output.wav"
WIDTH = 2

HOST = '192.168.2.90'     # Symbolic name meaning all available interfaces
PORT = 50007              # Arbitrary non-privileged port

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr

p = pyaudio.PyAudio()
stream = p.open(format=p.get_format_from_width(WIDTH),
                channels=CHANNELS,
                rate=RATE,
                output=True,
                frames_per_buffer=CHUNK)
q = Queue.Queue()

frames = []

stream.start_stream()


def main():
    data = conn.recv(CHUNK)

    while data != '':
        q.put(data)
        if not q.empty():
            stream.write(q.get())

        # stream.write(data)
        data = conn.recv(CHUNK)
        frames.append(data)

    wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(b''.join(frames))
    wf.close()

    stream.stop_stream()
    stream.close()
    p.terminate()
    conn.close()

if __name__ == '__main__':
    main()

Client.py

import socket

import pyaudio

CHUNK = 8192
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
RECORD_SECONDS = 5

HOST = '192.168.2.90'    # The remote host
PORT = 50007             # The same port as used by the server

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

p = pyaudio.PyAudio()

stream = p.open(format=FORMAT,
                channels=CHANNELS,
                rate=RATE,
                input=True,
                frames_per_buffer=CHUNK)

stream.start_stream()


def main():
    print("*_>recording")

    for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
        try:
            data = stream.read(CHUNK)
        except Exception as e:
            print e
            data = '\x00' * CHUNK

        print len(data)
        s.sendall(data)

    print("*_>done recording")

    stream.stop_stream()
    stream.close()
    p.terminate()
    s.close()

    print("*_>closed")

if __name__ == '__main__':
    main()
3
  • i don't sure about your python code. but i am sure if you use gstreamer tcpserversink if is very easy to play live audio over tcp.
    – rajesh6115
    Jan 31, 2017 at 16:21
  • 2
    That's what UDP is used for. TCP does error checking and retries
    – PaulF8080
    Feb 1, 2017 at 9:24
  • +1 - TCP is not an ideal mechanism for streaming media, where it doesn't particularly matter if you drop a frame or two along the way and really just want the packets slung as quickly as is possible.
    – goobering
    Feb 1, 2017 at 13:44

1 Answer 1

0

So after some research I found a post suggesting the RPI2 may not be fast enough.

I found a quick RPI3 and it works. Or at least with a large enough CHUNK size to process within the appropriate time for ALSA to play the audio.

The other suggestion was to somehow improve how fast the bytes get sent to ALSA, but really seems simply just to get to RPI3.

No really satisfying answer, but was able to get it working.

2
  • Any chance of adding a link to your research. I think I may have the exact same problem. Intermittent stream closure by the rPi. nb: in my use case I just used a try: except: around my read line to catch the stream closure and simply reopened the stream when needed. I get a break in the audio every few seconds but that was fine for me. Mine is an RPI1b. I'd prefer to be sure about your answer in my case and find a better solution though.
    – Mr Purple
    Sep 10, 2018 at 21:33
  • Please accept your answer. Only this will finally finish the question after years now and it will never pop up again.
    – Ingo
    Dec 1, 2019 at 10:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.