Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
jarvis0 opened this issue Apr 21, 2025 · 0 comments
Open

Comments

@jarvis0
Copy link

jarvis0 commented Apr 21, 2025

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant