Search code examples
python-3.xlinuxwindowssocketspyaudio

how am I supposed to live stream with pyaudio


I can't seem to get my code to work. I would like to be able to live stream sound with python to another computer, and my code just quits on windows. How would I be able to fix this?

dev box: Linux Mint 20 64-bit
test computer: Windows 10

I am using pyaudio to record sound and while it is recording, send it to another computer. I am getting no audio output and both windows & linux will just randomly stall the application.

Linux errors:

starting
IP address: 192.168.0.11
Port:       65535
Send IP:    192.168.0.10
Send Port:  65535

threads starting
--- starting stream ---
sending data to: 192.168.0.10:65534
--- starting receive ---
--- THREAD RECEIVE:
    got connection from: 192.168.0.10
---
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe
ALSA lib pcm.c:2642:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side
ALSA lib pcm_route.c:869:(find_matching_chmap) Found no matching channel map
ALSA lib pcm_route.c:869:(find_matching_chmap) Found no matching channel map
ALSA lib pcm_route.c:869:(find_matching_chmap) Found no matching channel map
ALSA lib pcm_route.c:869:(find_matching_chmap) Found no matching channel map
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
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
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "/home/henrik/PycharmProjects/AudioChat/main.py", line 51, in play
    data = ps.recv(64 * 2 * 2)  # var #1: chunk; var #2: channels; var #3: just to have a safe overhead
OSError: [Errno 107] Transport endpoint is not connected

Alsa errors I think are fine, don't they just point to no mic?

windows errors:

starting
IP address: 192.168.0.10
Port:       65534
Send IP:    192.168.0.11
Send Port:  65535

threads starting
--- starting stream ---
sending data to: 192.168.0.11:65535
--- starting receive ---
Exception in thread Thread-1:
Traceback (most recent call last):
  File "E:\installers&apps\Python38\lib\threading.py", line 932, in _bootstrap_inner
    self.run()
  File "E:\installers&apps\Python38\lib\threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "E:\main.py", line 35, in record
    rs.send(data)  # send the sound to the send_to_ip
ConnectionAbortedError: [WinError 10053] An established connection was aborted by the software in your host machine

from the errors it seems that the code connected to Linux, but connection was aborted, while Linux tried connecting to windows and timed out. Linux also thinks that the connection was aborted. why would that be?

my code:

#!/usr/bin/python3
# Python Audio Server for realtime audio.

import threading, socket, pyaudio, time  # import all needed codes
from tkinter import *


def startThreads(send_ip, send_to_ip, kill_event):  # function to start threads
    print("IP address:\t"+send_ip[0]+"\nPort:\t\t"+str(send_ip[1]))  # print ip address and port
    print("Send IP:\t"+send_to_ip[0]+"\nSend Port:\t"+str(send_ip[1])+"\n")  # print the second address set
    print("threads starting")
    r_thread = threading.Thread(target=record, args=(send_to_ip, kill_event))  # create threads
    p_thread = threading.Thread(target=play, args=(send_ip, kill_event))
    r_thread.start()  # start threads
    p_thread.start()


def record(send_to_ip, kill_event):  # the r_thread function
    print("--- starting stream ---")
    print("sending data to: "+send_to_ip[0]+":"+str(send_to_ip[1]))  # print ip address and port yet again
    rs = socket.socket()  # start socket
    rs.connect((send_to_ip[0], int(send_to_ip[1])))
    # todo: figure out why linux times out connecting to windows & windows aborts connecting to linux
    # I believe below code will work?
    rp = pyaudio.PyAudio()  # start pyaudio
    chunk = 64  # pyaudio config
    sample_format = pyaudio.paInt16
    channels = 2
    fs = 44100
    rtime = 3600
    while not kill_event.wait(0):
        rstream = rp.open(format=sample_format, channels=channels, rate=fs, frames_per_buffer=chunk, input=True)  # start recording
        for i in range(0, int(fs / chunk * rtime)):  # record sounds
            data = rstream.read(chunk)  # read sound data
            rs.send(data)  # send the sound to the send_to_ip
        rstream.stop_stream()  # stop recording, then loop
        rstream.close()
    rp.terminate()


def play(send_ip, kill_event):  # the p_thread function
    print("--- starting receive ---")  # working client code
    ps = socket.socket()
    ps.bind((send_ip[0], int(send_ip[1])))  # todo: figure out why linux times out connecting to windows & windows aborts connecting to linux
    ps.listen(1)
    connection, addr = ps.accept()
    print("--- THREAD RECEIVE:\n\tgot connection from: "+addr[0]+"\n---")
    pp = pyaudio.PyAudio()  # start pyaudio
    stream = pp.open(format=pyaudio.paInt16, channels=2, rate=44100, frames_per_buffer=64, output=True)  # open play sound
    while not kill_event.wait(0):
        data = ps.recv(64 * 2 * 2)  # var #1: chunk; var #2: channels; var #3: just to have a safe overhead
        stream.write(data, 64)


if __name__ == "__main__":
    print("starting")
    kill_event = threading.Event()
    UI = Tk()  # creating UI
    UI.title("Audio Connect")  # set window title
    UI.configure(bg="#FFF")  # set window color
    UI.resizable(False, False)  # stop window from being able to resize

    #  this block of code is the title and IP field
    TitleLabel = Label(UI, text="Audio Connect", bg="white").grid(column=0, columnspan=2, padx=1, pady=1)  # the title label
    Label(UI, text="IP: ", bg="white", bd=1).grid(row=1, column=0, padx=1, pady=1)  # IP fields
    IPField = Entry(UI, bd=1)  # IP entry
    IPField.grid(row=1, column=1, padx=1, pady=1)  # write the ip entry to the screen

    # this block of code is the Port field
    Label(UI, text="PORT: ", bg="white", bd=1).grid(row=2, column=0, padx=1, pady=1)  # port fields
    PortField = Entry(UI, text="65535", bd=1)  # port entry
    PortField.grid(row=2, column=1, padx=1, pady=1)  # draw the port entry

    # this is the connect to section, IP
    Label(UI, text="Send To IP: ", bg="white", bd=1).grid(row=3, column=0, padx=1, pady=1)
    SendIP = Entry(UI, bd=1)
    SendIP.grid(row=3, column=1, padx=1, pady=1)

    # connect to port
    Label(UI, text="Port: ", bg="white", bd=1).grid(row=4, column=0, padx=1, pady=1)
    SendPort = Entry(UI, bd=1)
    SendPort.grid(row=4, column=1, padx=1, pady=1)

    # this block of code is the connect button and the scripts for that
    lambdafunc = lambda: startThreads((IPField.get(), int(PortField.get())), (SendIP.get(), SendPort.get()), kill_event)  # the function to run when ConnectButton is pressed
    ConnectButton = Button(UI, text="connect", bg="white", bd=1, relief="solid", command=lambdafunc)\
        .grid(row=5, column=0, columnspan=2, sticky="EW", padx=1, pady=1)

    UI.mainloop()

    kill_event.set()
    time.sleep(1)
    exit(0)

Feel free to play around with it! Also, am I sending the audio correctly?

summary: trying to send audio from one computer to another:
windows connects to linux. Connection gets aborted????
linux tries connecting to windows... connection timed out???


Solution

  • There wasn't any problem with the connection getting aborted, but rather a problem with how I was receiving sound.

    In my play thread, in the while loop, I changed my first line of code from data = ps.recv(64 * 2 *2) I needed to put data = connection.recv(64 * 2 * 2) instead. That fixed my problem, and now I just need to learn some more audio coding, because now I get "alsa underrun" errors.