Skip to content

Audio streaming gets disconnected after 39 seconds with EC2 TURN server #255

@jarvis0

Description

@jarvis0

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

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions