DTLS handshake fails with "no SRTP profile negotiated" when streaming from ffmpeg (schannel) to aiortc WHIP server
10:28 25 Nov 2025

I'm trying to test low-latency video streaming using ffmpeg's WHIP protocol to stream to an aiortc-based Python server. The ICE connection completes successfully, but the DTLS handshake fails with "no SRTP profile negotiated".

My ffmpeg build (nightly 20251120) is compiled with --enable-schannel instead of --enable-openssl, I don't know if this is the source of the failed handshake.

Server code:

from aiohttp import web
from aiortc import RTCPeerConnection, RTCSessionDescription, RTCConfiguration, RTCIceServer
import logging

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

whip_sessions = {}

async def whip_endpoint(request):
    global whip_sessions
    sdp = await request.text()
    config = RTCConfiguration(
        iceServers=[RTCIceServer(urls=["stun:stun.l.google.com:19302"])]
    )
    pc = RTCPeerConnection(configuration=config)

    session_id = id(pc)
    whip_sessions[session_id] = {
        'pc': pc,
        'video_track': None
    }

    @pc.on('track')
    async def on_track(track):
        global whip_sessions
        if track.kind == 'video':
            whip_sessions[session_id]['video_track'] = track
            logger.info('subscribed to video stream')

    await pc.setRemoteDescription(
        RTCSessionDescription(sdp=sdp, type='offer')
    )
    answer = await pc.createAnswer()
    await pc.setLocalDescription(answer)

    return web.Response(
        content_type='application/sdp',
        text=pc.localDescription.sdp,
        status=201,
        headers={
            'Location': f'/whip/{session_id}'
        }
    )

async def whip_delete(request):
    global whip_sessions
    session_id = int(request.match_info['id'])
    session = whip_sessions.get(session_id)
    if session:
        await session['pc'].close()
        whip_sessions.pop(session_id, None)
        logger.info(f"Session {session_id} terminated")
        return web.Response(status=200)
    else:
        logger.warning(f"Session {session_id} not found")
        return web.Response(status=404, text='Session not found')


if __name__ == '__main__':
    app = web.Application()
    app.router.add_post('/whip', whip_endpoint)
    app.router.add_delete('/whip/{id}', whip_delete)
    web.run_app(app, host='127.0.0.1', port=8080)

ffmpeg command:

ffmpeg -re -f lavfi -i testsrc=size=640x360:rate=30 -f lavfi -i sine=frequency=440:sample_rate=48000 \
  -c:v libx264 -preset ultrafast -tune zerolatency -b:v 500k -g 30 -pix_fmt yuv420p \
  -c:a libopus -b:a 128k -ac 2 \
  -f whip http://localhost:8080/whip

debug output:

INFO:aioice.ice:Connection(0) ICE completed
DEBUG:aiortc.rtcicetransport:RTCIceTransport(controlled) - checking -> completed
DEBUG:aiortc.rtcpeerconnection:RTCPeerConnection() iceConnectionState checking -> completed DEBUG:aiortc.rtcdtlstransport:RTCDtlsTransport(client) - State.NEW -> State.CONNECTING 
DEBUG:aiortc.rtcdtlstransport:RTCDtlsTransport(client) x DTLS handling timeout 
DEBUG:aiortc.rtcdtlstransport:RTCDtlsTransport(client) x DTLS handshake failed (no SRTP profile negotiated) DEBUG:aiortc.rtcdtlstransport:RTCDtlsTransport(client) - State.CONNECTING -> State.FAILED 
DEBUG:aiortc.rtcpeerconnection:RTCPeerConnection() connectionState connecting -> failed

Has anyone successfully streamed from ffmpeg to aiortc using WHIP?

python ffmpeg webrtc aiortc