From 5b761da38835e62d556ff65dfb836a65eb7c8a8d Mon Sep 17 00:00:00 2001 From: Michael Franzl Date: Fri, 12 Jan 2018 13:39:34 +0100 Subject: [PATCH] greatly extended README and slight API change --- README.md | 94 ++++++++++++++++++++++++++++++++++++++-------- janus_rtpforward.c | 2 +- 2 files changed, 79 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 1eee14b..7f1dff3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Janus rtpforward plugin -This plugin receives RTP and RTCP packets from a WebRTC connection (Janus Session) and forwards/sends them to UDP ports for further processing or display by an external receiver/decoder, e.g. a GStreamer pipeline. - +This plugin for the [Janus WebRTC gateway](https://github.com/meetecho/janus-gateway) takes RTP and RTCP packets from a WebRTC connection (Janus Session) and forwards/sends them to UDP ports for further processing or display by an external receiver/decoder (e.g. a GStreamer pipeline). UDP broadcast and multicast is implicitly supported by setting the `sendipv4` to broadcast or multicast IP addresses. + Four destination UDP addresses/ports are used: 1. Audio RTP @@ -9,7 +9,7 @@ Four destination UDP addresses/ports are used: 3. Video RTP 4. Video RTCP -There are no config files. All ports/addresses can be configured via the plugin API before a WebRTC session is set up. To configure the plugin, send the following JSON to the plugin: +There are no configuration files. All ports/addresses can be configured via the plugin API on a per-session basis. To configure a plugin session, send the following JSON: "request": "configure", "sendipv4": "127.0.0.1", @@ -28,14 +28,14 @@ To send to the browser a Full Intraframe request packet (FIR), send the followin "request": "fir" -To send to the browser a Receiver Estimated Maximum Bitrate packet (REMB), send the following API request (note that depending on the video codec used, Firefox can currently go only as low as 200000, and Chrome can go as low as 50000): +To send to the browser a Receiver Estimated Maximum Bitrate packet (REMB), send the following API request (note that depending on the video codec used, Firefox can currently go only as low as 200000, whereas Chrome can go as low as 50000): "request": "remb", "bitrate": To experiment how a RTP/RTCP receiver can tolerate packet loss, there are three API requests: -`drop_probability` configures the random drop of a number of packages in parts per 1000: +`drop_probability` configures the uniformly random drop of a number of packages in parts per 1000: "request": "drop_probability", "drop_permille": @@ -56,25 +56,87 @@ These packet loss simulations are perhaps too simple. They are no replacement fo This plugin only accepts VP8 and OPUS in RECVONLY mode. This is hardcoded via arguments to the `janus_sdp_generate_answer()` function, but can be changed easily (see comments there). -# GStreamer example -The following example GStreamer pipeline will output the WebRTC audio and video emitted by this plugin, if the port numbers, the payload numbers, and encoding names match. The payload numbers are negotiated dynamically in the SDP exchange, and may differ from browser to browser, and even from session to session. You need to inspect the SDP to find them. +# Use cases + +Note: The following two use cases use the UDP multicast IP address 225.0.0.37 (which is in a group of multicast addresses not routed, i.e. only working on the same machine). This enables multiple subscribers to the same RTP stream, for maximum flexibility. + +## GStreamer display -You probably also need to send a PLI to the browser to request a keyframe. The pipeline starts displaying only after a keyframe has been received. +The following example GStreamer pipeline will output the WebRTC audio and video emitted by this plugin (if the port numbers, the payload numbers, and encoding names match). The payload numbers are negotiated dynamically in the SDP exchange, and may differ from browser to browser, and even from session to session. You need to inspect each SDP exchange to find them on a per-session basis. Such a pipeline is thus best launched programmatically. + +You probably also need to send a PLI to the browser to request a keyframe if the GStreamer pipeline is launched mid-stream. The following pipeline will start running only after a keyframe has been received. + +Hardware clocks of low-end consumer audio and video electronics (e.g. USB webcam, USB headset) may drift up to 1 second per 24 hours. To compensate, this pipeline uses one `rtpbin` element, which synchronizes audio and video ("lip-sync") according to timestamps in all RTP and RTCP packets. + +Note that you can lauch the same pipeline several times when you're multicasting. ````shell -gst-launch-1.0 -v rtpbin name=rtpbin latency=50 \ - udpsrc port=60000 caps="application/x-rtp, media=audio, payload=111, encoding-name=OPUS, clock-rate=48000" ! rtpbin.recv_rtp_sink_0 \ - udpsrc port=60001 caps="application/x-rtcp" ! rtpbin.recv_rtcp_sink_0 \ - udpsrc port=60002 caps="application/x-rtp, media=video, payload=96, encoding-name=VP8, clock-rate=90000" ! rtpbin.recv_rtp_sink_1 \ - udpsrc port=60003 caps="application/x-rtcp" ! rtpbin.recv_rtcp_sink_1 \ - rtpbin. ! rtpvp8depay ! vp8dec ! autovideosink \ - rtpbin. ! rtpopusdepay ! queue ! opusdec ! pulsesink +gst-launch-1.0 -v \ +rtpbin name=rtpbin latency=100 \ +udpsrc address=225.0.0.37 auto-multicast=true port=60000 caps="application/x-rtp, media=audio, payload=111, encoding-name=OPUS, clock-rate=48000" ! rtpbin.recv_rtp_sink_0 \ +udpsrc address=225.0.0.37 auto-multicast=true port=60001 caps="application/x-rtcp" ! rtpbin.recv_rtcp_sink_0 \ +udpsrc address=225.0.0.37 auto-multicast=true port=60002 caps="application/x-rtp, media=video, payload=96, encoding-name=VP8, clock-rate=90000" ! rtpbin.recv_rtp_sink_1 \ +udpsrc address=225.0.0.37 auto-multicast=true port=60003 caps="application/x-rtcp" ! rtpbin.recv_rtcp_sink_1 \ +rtpbin. ! rtpvp8depay ! vp8dec ! autovideosink \ +rtpbin. ! rtpopusdepay ! queue ! opusdec ! pulsesink ```` + +## GStreamer dumping to file + +The following GStreamer pipeline simply dumps the synchronized (by `rtpbin`) and already compressed media (by the client browser, conveniently!) into a Matroska container (note that the video will only start after a keyframe): + + +````shell +gst-launch-1.0 -v -e \ +matroskamux name=mux streamable=1 ! filesink location=/tmp/dump.mkv \ +rtpbin name=rtpbin latency=100 \ +udpsrc address=225.0.0.37 auto-multicast=true port=60000 caps="application/x-rtp, media=audio, payload=111, encoding-name=OPUS, clock-rate=48000" ! rtpbin.recv_rtp_sink_0 \ +udpsrc address=225.0.0.37 auto-multicast=true port=60001 caps="application/x-rtcp" ! rtpbin.recv_rtcp_sink_0 \ +udpsrc address=225.0.0.37 auto-multicast=true port=60002 caps="application/x-rtp, media=video, payload=96, encoding-name=VP8, clock-rate=90000" ! rtpbin.recv_rtp_sink_1 \ +udpsrc address=225.0.0.37 auto-multicast=true port=60003 caps="application/x-rtcp" ! rtpbin.recv_rtcp_sink_1 \ +rtpbin. ! rtpopusdepay ! mux.audio_0 \ +rtpbin. ! rtpvp8depay ! mux.video_0 +```` + + +## Combining janus-rtpforward-plugin and janus-streaming-plugin + +Combining this plugin with the janus-streaming plugin (supplied with Janus) allows a novel implementation of an echo test and opens up interesting possibilities for other use-cases. If you configure one rtpforward session like so... + + "request": "configure", + "sendipv4": "225.0.0.37", + "sendport_audio_rtp": 60000, + "sendport_audio_rtcp": 60001, + "sendport_video_rtp": 60002, + "sendport_video_rtcp": 60003 + +... and then configure the janus-streaming plugin like so (in its configuration file) ... + +```` +[multicast-from-janus-rtpforward-plugin] +type = rtp +id = 1 +description = Opus/VP8 live multicast stream coming from janus-rtpforward-plugin +audio = yes +video = yes +audioport = 60000 +audiomcast = 225.0.0.37 +audiopt = 111 +audiortpmap = opus/48000/2 +videoport = 60002 +videomcast = 225.0.0.37 +videopt = 100 +videortpmap = VP8/90000 +```` + +... then all subscribers to this mountpoint (id=1) will receive realtime A/V from the first rtpforward session. + + # Acknowledgements -Thanks go to mquander for the excellent "Simplest possible plugin for Janus". https://github.com/mquander/janus-helloworld-plugin +Thanks go to the authors of [janus-gateway](https://github.com/meetecho/janus-gateway) and mquander for the excellent "Simplest possible plugin for Janus" ([janus-helloworld-plugin](https://github.com/mquander/janus-helloworld-plugin)). # Compiling and installing diff --git a/janus_rtpforward.c b/janus_rtpforward.c index e583660..b391536 100644 --- a/janus_rtpforward.c +++ b/janus_rtpforward.c @@ -39,7 +39,7 @@ #include "utils.h" #define RTPFORWARD_VERSION 1 -#define RTPFORWARD_VERSION_STRING "0.2.0" +#define RTPFORWARD_VERSION_STRING "0.2.1" #define RTPFORWARD_DESCRIPTION "Forwards RTP and RTCP to an external UDP receiver/decoder" #define RTPFORWARD_NAME "rtpforward" #define RTPFORWARD_AUTHOR "Michael Karl Franzl"