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?