summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGalen Guyer <galen@galenguyer.com>2022-11-22 01:10:50 -0500
committerGalen Guyer <galen@galenguyer.com>2022-11-22 01:10:50 -0500
commit95e6b7489c1f937921061a1872705e456546fc83 (patch)
tree4cd4466d5551758b945a8f1b0de87cda48cef535
Python UDP audio streaming in real time
-rw-r--r--.gitignore1
-rw-r--r--udp-audio.py88
2 files changed, 89 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f7275bb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+venv/
diff --git a/udp-audio.py b/udp-audio.py
new file mode 100644
index 0000000..d6d86a0
--- /dev/null
+++ b/udp-audio.py
@@ -0,0 +1,88 @@
+import socket
+import struct
+import pyaudio
+import time
+
+from threading import Thread
+import numpy as np
+import scipy.signal
+from matplotlib import pyplot as plt
+
+TGID_in_stream = True # When set to True, we expect a 4 byte long int with the TGID prior to the audio in each packet
+TGID_to_play = 0 # When TGID_in_stream is set to True, we'll only play audio if the received TGID matches this value
+UDP_PORT = 9123 # UDP port to listen on
+AUDIO_OUTPUT_DEVICE_INDEX = 4 # Audio device to play received audio on
+
+# Set up a UDP server
+UDPSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+# UDPSock.settimeout(1)
+
+listen_addr = ("", UDP_PORT)
+UDPSock.bind(listen_addr)
+
+p = pyaudio.PyAudio()
+
+for i in range(p.get_device_count()):
+ print(p.get_device_info_by_index(i))
+
+CHUNK=1024
+FORMAT = pyaudio.paInt16
+CHANNELS = 1
+IN_RATE = 8_000
+OUT_RATE = 48_000
+stream = p.open(
+ format=FORMAT,
+ channels=CHANNELS,
+ rate=OUT_RATE,
+ input=False,
+ output=True,
+ frames_per_buffer=CHUNK,
+ output_device_index=AUDIO_OUTPUT_DEVICE_INDEX,
+)
+
+FRAMES = []
+
+def receive_audio():
+ global FRAMES
+ global TGID_in_stream
+ global TGID_to_play
+ while True:
+ try:
+ data, addr = UDPSock.recvfrom((CHUNK * CHANNELS * 2) + (4 if TGID_in_stream else 0))
+ if TGID_in_stream:
+ tgid = int.from_bytes(data[0:4], "little")
+ if TGID_to_play == 0:
+ TGID_to_play = [tgid]
+ if TGID_to_play == 0 or tgid in TGID_to_play:
+ audio_data = data[4:]
+ if len(audio_data) < 128:
+ continue
+ print(f"TGID: {tgid}, audio_data: {len(audio_data)}")
+ signal = np.frombuffer(audio_data, dtype=np.int16)
+ res = scipy.signal.resample(signal, (len(signal) * OUT_RATE) // IN_RATE).astype(np.int16)
+ FRAMES.append(res)
+ else:
+ stream.write(data)
+ except socket.timeout:
+ pass
+
+def play_audio():
+ global FRAMES
+ while True:
+ while len(FRAMES) == 0:
+ time.sleep(1)
+ frames = FRAMES[:]
+ FRAMES.clear()
+ print(f"Playing {len(frames)} frames")
+ for frame in frames:
+ stream.write(frame.tobytes())
+
+
+stream_t = Thread(target=receive_audio)
+play_t = Thread(target=play_audio)
+stream_t.daemon = True
+play_t.daemon = True
+stream_t.start()
+play_t.start()
+stream_t.join()
+play_t.join()