Repository navigation
Communication RTSP Client
This page shows how to receive and play audio from an RTSP server - an IP camera, a media server like mediamtx or live555, or another microcontroller running the RTSP Server of this library.
Contents
| Client | Header | Library | Transport | Notes |
|---|---|---|---|---|
RTSPClient (RTSPClientWiFi, RTSPClientEthernet) |
AudioTools/Communication/RTSP.h |
part of this library | UDP | small, decodes via registered decoders, audio only |
AudioClientRTSP |
AudioTools/Communication/RTSPClient555.h |
arduino-live555 | TCP or UDP | based on the proven live555 implementation, bigger |
Start with RTSPClient. Use AudioClientRTSP if a server doesn't work with it, or if you need RTP over TCP.
RTSPClient<TcpClient, UdpSocket> opens the RTSP session (OPTIONS, DESCRIBE, SETUP, PLAY), binds a local UDP port and receives the RTP packets. The SDP of the server tells it the format. The payload of each RTP packet is passed to an internal MultiDecoder, which selects the decoder that matches the format and writes the decoded PCM to your output - via a resampler, which can compensate small clock differences between server and client (see setResampleFactor()). During the session it sends an OPTIONS keep-alive.
The template parameters bind it to a network stack:
using RTSPClientWiFi = RTSPClient<WiFiClient, WiFiUDP>; // RTSPClientWiFi.h, included by RTSP.h on ESP32
using RTSPClientEthernet = RTSPClient<EthernetClient, EthernetUDP>; // RTSPClientEthernet.hFor Ethernet include AudioTools/Communication/RTSP/RTSPClientEthernet.h in addition to RTSP.h.
From audio-client-audiokit.ino: plays MP3 or IMA ADPCM from an RTSP server on an AudioKit.
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecADPCM.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h" // https://github.com/pschatzmann/codec-helix
#include "AudioTools/AudioLibs/AudioBoardStream.h"
#include "AudioTools/Communication/RTSP.h" // brings RTSPClientWiFi
IPAddress srv(192, 168, 1, 39); // RTSP server
const uint16_t rtspPort = 8554;
const char* rtspPath = "stream"; // path of the stream on the server
AudioBoardStream i2s(AudioKitEs8388V1);
RTSPClientWiFi client(i2s);
MP3DecoderHelix mp3; // for audio/mpeg
ADPCMDecoder adpcm(AV_CODEC_ID_ADPCM_IMA_WAV, 512); // for audio/adpcm
void setup() {
Serial.begin(115200);
// connect WiFi
WiFi.begin("ssid", "password");
while (WiFi.status() != WL_CONNECTED) delay(500);
WiFi.setSleep(false);
auto cfg = i2s.defaultConfig(TX_MODE);
i2s.begin(cfg);
client.addDecoder(mp3);
client.addDecoder(adpcm);
client.setHeaderTimeoutMs(8000); // for slow servers
if (!client.begin(srv, rtspPort, rtspPath)) {
Serial.println("Failed to start RTSP client");
stop();
}
}
void loop() {
client.copy(); // decodes the next RTP payload
}begin(address, port, path) connects to rtsp://<address>:<port>/<path>/; leave the path out if the server provides its stream at the root. Call copy() as often as possible in loop().
The format is determined from the first a=rtpmap line of the server's SDP - from the static RTP payload type if there is one, else from the encoding name:
| SDP | MIME | Decoder |
|---|---|---|
| L16 (payload type 10, 11) | audio/L16 |
built in (network byte order to PCM) |
| L8 | audio/L8 |
built in |
| PCMU (0), PCMA (8) |
audio/PCMU, audio/PCMA
|
G.711 decoder, register with addDecoder()
|
| GSM (3) | audio/gsm |
GSM decoder |
| G722 (9) | audio/g722 |
G.722 decoder |
| DVI4 (5, 6, 16, 17) | audio/adpcm |
IMA ADPCM decoder |
| MPA (14) | audio/mpeg |
MP3 decoder - see below |
| MPEG4-GENERIC | audio/aac |
not supported out of the box: the AU headers of RFC 3640 are not removed, and the frames come without ADTS header |
| OPUS | audio/opus |
Opus decoder |
Register the decoders you need with addDecoder(decoder), which uses the decoder's own mime(), or with addDecoder("audio/...", decoder) if it doesn't match. See Encoding and Decoding of Audio for the decoders and the libraries they need. mime() and payloadType() tell you what the server announced, audioInfo() the format of raw PCM.
MP3 (payload type 14): RFC 2250 puts a 4 byte header in front of the MP3 data in each packet. Servers that send it (e.g. ffmpeg, and this library's server with setUseRfc2250Header(true)) need client.setPayloadOffset(4), so that the client skips these bytes; servers that send raw MP3 frames (the default of this library's server, which VLC expects) need no offset. If it plays with distortions, check this first.
| Method | Description |
|---|---|
setOutput(out) |
defines where the decoded audio is written to (also possible in the constructor) |
addDecoder(decoder), addDecoder(mime, decoder)
|
registers a decoder for a format |
begin(address, port, path) |
starts the session; returns false if the server can't be reached or rejects it |
copy() |
passes the next received RTP payload to the decoder - call it in loop()
|
available() |
bytes received and not yet decoded |
setActive(bool) |
pauses (RTSP PAUSE) and resumes (PLAY) the stream |
end() |
ends the session (TEARDOWN) |
mime(), payloadType(), audioInfo()
|
what the server announced |
setResampleFactor(factor) |
> 1.0 plays faster, < 1.0 slower: compensates clock differences that would otherwise let the buffers run over or empty |
setPayloadOffset(bytes) |
bytes to skip after the RTP header (e.g. 4 for RFC 2250 MP3) |
setHeaderTimeoutMs(ms) |
timeout for the server's responses (default 3000) |
setConnectRetries(n), setConnectRetryDelayMs(ms)
|
connection retries (default 2, 500 ms) |
setIdleDelay(ms) |
delay in copy()/available() when there is no data, to avoid a busy loop |
-
UDP only: RTP is received over UDP. Lost packets are lost - over a weak WiFi connection you hear gaps. If that's a problem, use
AudioClientRTSPwith TCP. - Audio only: there are no video decoders in this pipeline, and an MPEG transport stream with video and audio (MP2T, like Streaming Video and Audio via RTSP produces) is not supported.
-
One track: the client uses the first
a=rtpmapline of the SDP. A server that announces only a static payload type without ana=rtpmapline is not recognized (mime()returns nullptr).
AudioClientRTSP wraps the RTSP client of live555 - install arduino-live555. It writes the received payload to any Print, e.g. an EncodedAudioStream that decodes it, and can receive RTP over TCP or UDP. From audio-client-555-audiokit.ino:
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include "AudioTools/AudioLibs/AudioBoardStream.h"
#include "AudioTools/Communication/RTSPClient555.h" // https://github.com/pschatzmann/arduino-live555
AudioBoardStream i2s(AudioKitEs8388V1);
EncodedAudioStream out_mp3(&i2s, new MP3DecoderHelix());
AudioClientRTSP rtsp(1024); // receive buffer size
void setup() {
auto cfg = i2s.defaultConfig(TX_MODE);
i2s.begin(cfg);
out_mp3.begin();
rtsp.setLogin("ssid", "password"); // optional: connects WiFi
rtsp.begin("rtsp://192.168.1.38:8554/test.mp3", out_mp3);
}
void loop() {
rtsp.loop();
}The constructor takes the receive buffer size - make sure that one encoded frame fits -, whether to use TCP (setTCP()/setUDP()) and whether begin() should block (setBlocking()); in the non-blocking default call loop() in your loop(). The live555 library itself also provides an RTSPSimpleClient, used in audio-client-555-i2s.ino.
A desktop RTSP server is the easiest way to test a client. With mediamtx running, publish a file with ffmpeg:
ffmpeg -re -stream_loop -1 -i test.mp3 -c:a copy -f rtsp rtsp://localhost:8554/stream
ffmpeg -re -stream_loop -1 -i test.wav -c:a pcm_s16be -ar 16000 -ac 1 -f rtsp rtsp://localhost:8554/stream
and connect the client to <ip of the PC>, port 8554, path stream. Or use a second board with one of the RTSP server examples of this library. Check the stream with ffplay rtsp://<server>:8554/stream first: if ffplay can't play it, the client won't either.
-
begin()fails: check the address, port and path - many servers only accept their exact stream path. IncreasesetHeaderTimeoutMs()for slow servers. -
No sound, but no error: no decoder matches the announced format - print
client.mime()and register a decoder for it. If it is nullptr, the SDP has noa=rtpmapline the client understands. -
MP3 sounds distorted: the RFC 2250 header - see
setPayloadOffset()above. -
Gaps in the sound: UDP packets got lost - check the WiFi connection, switch off WiFi power save (
WiFi.setSleep(false)), or useAudioClientRTSPwith TCP. -
The playback slowly runs ahead or falls behind, with buffer over- or underflows: the clocks of server and client differ - compensate with
setResampleFactor(), e.g. 1.001 or 0.999.