-
-
Notifications
You must be signed in to change notification settings - Fork 132
Open
Description
Hi, I'm building an app where some audio is streamed and reproduced on Streamlit (no audio input from client). The audio is being produced by another server behind NAT.
It works fine when tested locally with a STUB server but when I deploy the solution on EC2, I get disconnected after 39 seconds sharp. I'm using a TURN Server (coturn) and for simplicity I'm streaming silence only.
Client config
webrtc_streamer(
key="audio-streaming",
mode=WebRtcMode.RECVONLY,
rtc_configuration={
"iceServers": [
{
"urls": [
f"turn:{TURN_SERVER_IP}:3478?transport=tcp",
f"turn:{TURN_SERVER_IP}:3478?transport=udp",
],
"username": TURN_SERVER_USER,
"credential": TURN_SERVER_PASSWORD,
},
],
"iceTransportPolicy": "relay",
"iceCandidatePoolSize": 20,
"bundlePolicy": "max-bundle",
},
media_stream_constraints={"audio": False, "video": False},
source_audio_track=AudioStreamTrack(),
async_processing=True,
sendback_audio=False,
sendback_video=False,
Source audio track
class AudioStreamTrack(MediaStreamTrack):
"""
A dummy audio track which reads silence.
"""
kind = "audio"
_start: float
_timestamp: int
async def recv(self) -> Frame:
"""
Receive the next :class:`~av.audio.frame.AudioFrame`.
The base implementation just reads silence, subclass
:class:`AudioStreamTrack` to provide a useful implementation.
"""
if self.readyState != "live":
raise MediaStreamError
sample_rate = 8000
samples = int(AUDIO_PTIME * sample_rate)
if hasattr(self, "_timestamp"):
self._timestamp += samples
wait = self._start + (self._timestamp / sample_rate) - time.time()
await asyncio.sleep(wait)
else:
self._start = time.time()
self._timestamp = 0
frame = AudioFrame(format="s16", layout="mono", samples=samples)
for p in frame.planes:
p.update(bytes(p.buffer_size))
frame.pts = self._timestamp
frame.sample_rate = sample_rate
frame.time_base = fractions.Fraction(1, sample_rate)
return frame
Coturn server config (tested on https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ and works fine)
#!/bin/bash
# Install coturn
amazon-linux-extras install epel -y
yum install -y coturn
# Create a basic configuration that's guaranteed to work
cat > /etc/turnserver.conf << EOL
# Basic settings
listening-port=3478
fingerprint
lt-cred-mech
# NAT traversal settings
listening-ip=0.0.0.0
external-ip=$TURN_SERVER_IP
# CRITICAL: NAT-specific settings
# Allow connections from private networks
allow-loopback-peers
# Explicitly enable both TCP and UDP
no-tcp-relay=0
no-udp-relay=0
# NAT handling improvements
mobility
# No RFC5780 - can cause issues with NAT
no-rfc5780
# Auth
user=testuser:testpassword
realm=$TURN_SERVER_IP
# Logging
log-file=/var/log/coturn/turnserver.log
verbose
EOL
# Create log file with right permissions
touch /var/log/coturn/turnserver.log
chmod 666 /var/log/coturn/turnserver.log
# Enable and start coturn
systemctl enable coturn
systemctl start coturn
Error log
2025-04-21T18:45:40.952Z
INFO:aioice.ice:Connection(2) Check CandidatePair(('169.254.172.4', 33078) -> ('10.0.61.10', 57550)) State.FROZEN -> State.IN_PROGRESS
2025-04-21T18:45:40.972Z
INFO:aioice.ice:Connection(2) Check CandidatePair(('10.0.190.186', 56196) -> ('10.0.61.10', 57550)) State.FROZEN -> State.IN_PROGRESS
2025-04-21T18:45:40.992Z
INFO:aioice.ice:Connection(2) Check CandidatePair(('169.254.172.4', 33078) -> ('10.0.61.10', 64407)) State.FROZEN -> State.IN_PROGRESS
2025-04-21T18:45:41.013Z
INFO:aioice.ice:Connection(2) Check CandidatePair(('10.0.190.186', 56196) -> ('10.0.61.10', 64407)) State.FROZEN -> State.IN_PROGRESS
2025-04-21T18:45:41.033Z
INFO:aioice.ice:Connection(2) Check CandidatePair(('10.0.61.10', 64065) -> ('10.0.61.10', 57550)) State.FROZEN -> State.IN_PROGRESS
2025-04-21T18:45:41.034Z
INFO:aioice.turn:TURN channel bound 16384 ('10.0.61.10', 57550)
2025-04-21T18:45:41.054Z
INFO:aioice.ice:Connection(2) Check CandidatePair(('10.0.61.10', 64065) -> ('10.0.61.10', 64407)) State.FROZEN -> State.IN_PROGRESS
2025-04-21T18:45:41.055Z
INFO:aioice.turn:TURN channel bound 16385 ('10.0.61.10', 64407)
2025-04-21T18:45:41.525Z
INFO:aioice.ice:Connection(2) Check CandidatePair(('10.0.190.186', 56196) -> ('10.0.61.10', 57550)) State.IN_PROGRESS -> State.SUCCEEDED
2025-04-21T18:45:41.525Z
INFO:aioice.ice:Connection(2) ICE completed
2025-04-21T18:45:41.668Z
INFO | UI | Commentator | Starting commentary...
2025-04-21T18:45:41.670Z
INFO | UI | Commentator | Showing commentary control buttons...
2025-04-21T18:45:53.820Z
WARNING:asyncio:socket.send() raised exception.
2025-04-21T18:45:53.839Z
WARNING:asyncio:socket.send() raised exception.
2025-04-21T18:46:21.095Z
INFO | UI | Commentator | Starting commentary...
2025-04-21T18:46:21.096Z
INFO | UI | Commentator | Showing commentary control buttons...
2025-04-21T18:46:21.282Z
INFO:aioice.turn:TURN allocation deleted ('10.0.61.10', 64065)
2025-04-21T18:46:25.820Z
INFO:aioice.ice:Connection(0) Check CandidatePair(('10.0.61.10', 52193) -> ('10.0.61.10', 64437)) State.IN_PROGRESS -> State.FAILED
2025-04-21T18:46:25.840Z
INFO:aioice.ice:Connection(0) Check CandidatePair(('10.0.61.10', 52193) -> ('10.0.61.10', 55977)) State.IN_PROGRESS -> State.FAILED
Tried many configs countless times with no success and about to give up this framework.
Metadata
Metadata
Assignees
Labels
No labels