Settings

Theme

Go Donut: Convert Live Streaming to WebRTC

github.com

128 points by dreampeppers99 a year ago · 26 comments

Reader

iod a year ago

Another library that I would recommend people look into for live streaming to WebRTC, as an alternative to Pion used in this project, is Janus WebRTC Server. I use it for ingesting RTP streams I generate from usb webcams and then playing it with very low latency in the browser. It even has a feature where you can stream multiple streams simultaneously. It also has a simple http api for adding, updating, and removing streams on demand.

Here is the library's streaming demo:

https://janus.conf.meetecho.com/demos/streaming.html

  • rgovostes a year ago

    Janus is used by the PiKVM project for WebRTC streaming. I found it arcane to configure and never got it to work over Tailscale (https://janus.discourse.group/t/failing-to-establish-webrtc-...).

    • iod a year ago

      I went to your discourse link. As Lorenzo was trying to say, you will want to get a better idea what is going on with ICE candidate gathering. In firefox there is an about:config setting that might help with this:

        media.peerconnection.ice.obfuscate_host_addresses = false
      
      which will show the actual deobfuscated candidates host addresses. Here is a tool you can run on your client to see the stun candidates received.

      https://webrtc.github.io/samples/src/content/peerconnection/...

      If you do not get any valid candidates, then it is most likely a misconfiguration of your browser, vpn, firewall or network. Unfortunately this is most likely not a Janus thing, but I would need more information to know for sure.

  • tamimio a year ago

    > I use it for ingesting RTP streams I generate from usb webcams and then playing it with very low latency in the browser.

    Do you have any write up about this? I did try Janus years ago, it wasn’t great, slow, and buggy, but I don’t know about its current state now.

    • iod a year ago

      I used the demo streaming.html code linked above as-is and host it statically on Nginx alongside Janus on a cloud VPS. As far as config, there is just the one file: /etc/janus/janus.plugin.streaming.jcfg , but you can leave it blank and just use the html api¹ if you don't want to mess with that file as the API has an option:

        "permanent":true
      
      that automatically generates/updates the config for you. You can substitute srtp (secure) for regular rtp for testing, but I prefer to use the secure variant since it goes out to a public VPS and doesn't really incur any overhead for my source devices.

      ¹ https://janus.conf.meetecho.com/docs/streaming#streamapi

      I wrote a little helper shell code using wget, openssl, dd, jq, and jo to make it easy to talk JSON to the API, for the one-off configs I do. Here is an example of what I use which demonstrates simulcast and srtp ingestion for both h264 and vp8 video streams as well as opus audio. Just fill in the [ ]'s with your specifics. I then use ffmpeg to generate all the streams and pipe to the appropriate ports for each simulcast level and target. If you use gstreamer beware srtp key format is different.

        #!/bin/sh
        server="https://[YOUR_JANUS_SERVER_HOST]/janus"
        token(){ dd if=/dev/urandom bs=6 count=1 status=none|openssl base64;}
        post_jo(){ first="$1";shift;wget --quiet --output-document - --post-data "$(jo -- "$@")" "$server$first";}
        tx(){ post_jo "$@" transaction="$(token)";}
        data_id(){ jq ".data.id//(null|halt_error(1))";}
        message()( set -e
          id="$(tx / janus=create|data_id)" # create janus session and store id
          hn="$(tx "/$id" janus=attach plugin=janus.plugin.streaming|data_id)" # create plugin session and store id
          tx "/$id/$hn" janus=message body="$(jo -- "$@")"
          tx "/$id" janus=destroy >/dev/null
        )
      
        # example usage:
      
        # list all streams
        message request=list|jq .plugindata.data.list
      
        # remove stream with id 666
        message request=destroy id=666 secret=adminpwd permanent=true|jq 
      
        # create new stream
        message request=create id=666 secret=adminpwd permanent=true name=[YOUR_STREAM_NAME] type=rtp media=["$(
          jo type=video mid=v1 codec=h264 pt=96 simulcast=true svc=false port=5010 port2=5020 port3=5030 \
            fmtp=level-asymmetry-allowed=1\;packetization-mode=1\;profile-level-id=42c01f
          )","$(
          jo type=video mid=v2 codec=vp8 pt=96 simulcast=true svc=false port=5012 port2=5022 port3=5032
          )","$(
          jo type=audio mid=a codec=opus pt=97 port=5000
          )"] srtpsuite=80 srtpcrypto=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz|jq # your srtp token needs to match your source
      
        # show new stream info to verify configuration
        message request=info id=666 secret=adminpwd|jq
      
        # on streaming source device
        ffmpeg [YOUR_INPUT_CONFIG HERE] -f rtp -srtp_out_suite SRTP_AES128_CM_HMAC_SHA1_80 -srtp_out_params zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz srtp://[YOUR_JANUS_SERVER_HOST]/:[PORT]
      
        # for gstreamer, showing alternative key format
        gst-launch-1.0 [YOUR_INPUT_CONFIG HERE] ! rtpav1pay ! srtpenc key=cf3cf3cf3cf3cf3cf3cf3cf3cf3cf3cf3cf3cf3cf3cf3cf3cf3cf3cf3cf3 ! udpsink host=[YOUR_JANUS_SERVER_HOST] port=[PORT]
majorchord a year ago

My issue with this (and WebRTC in general) is that most residential users (at least in the US, probably many other countries) are behind some type of symmetrical NAT or CGNAT, often without the ability to forward ports or have working NAT traversal, which makes WebRTC unusable without a TURN server as it relies on communicating between peers via DTLS over UDP.

The problem with needing a TURN server is that you practically need to host it yourself, because there are no fast and reliable public ones, probably due to abuse. WebTorrent also has the same problem since it also uses WebRTC, and as such, 99% of applications that use either technology simply do not work at all for me or anyone else I've asked to try these services.

  • Sean-Der a year ago

    You shouldn’t need TURN for Client/Server like Donut. The Donut server runs on a world addressable host. So luckily no TURN woes here!

    In practice ~20% of users need TURN https://medium.com/@fippo/what-kind-of-turn-server-is-being-...

    • majorchord a year ago

      Donut still uses WebRTC though, which like I said, I still need TURN for and I can prove it. I still have a really hard time believing that only 20% of "users" (what users where? everyone in the world?) need it, as like I said, almost every residential US user needs it at the least.

      • ongy a year ago

        If the server is not behind NAT, the only reason you might require TURN is a restrictive egress firewall blocking UDP to arbitrary ports.

        It'll be a host<>prflx connection pair. Though if the host can be reached that way, I'm unsure what the benefit of WebRTC is.

Hypnosis6173 a year ago

I searched a solution to this 2 year ago, great to see such an easy to use implementation now.

rgovostes a year ago

RTSPtoWeb (https://github.com/deepch/RTSPtoWeb) is a similar application for re-encapsulating video packets from RTSP to WebRTC, also written in Go.

ongy a year ago

What's the purpose of this?

Mostly a tech-demo, or primarily to plug a p2p layer onto existing servers?

  • Sean-Der a year ago

    This allows you to view video from protocols the browser doesn’t support with very little added latency.

    Things like RTMP/SRT/RIST/RTSP….

  • VWWHFSfQ a year ago

    Back when I was doing live-streaming the primary reason I wanted it was to eliminate (or reduce) the need for a CDN to deliver chunks to the end-user viewers. I fantasized about a protocol adapter like this that would act has the "host" peer that would stream the video from e.g. RTMP source, which would then translate to WebRTC for all the viewer peers in a P2P fashion.

    I don't know if this actually works like that, but it's fun to think about this being the missing link I wanted all those years ago.

  • majorchord a year ago

    It looks to me like an early WIP clone of those "watch movies together with friends online" services.

  • manorwar8 a year ago

    it might be useful as a preview for media ingestion

nixosbestos a year ago

Wait is there a CLI mode? What if I want a simple rtmp/srt -> webrtc bridge on a "headless" device?

Sean-Der a year ago

This is a great project. I really want to add a little JS lib so it could be all done client side

<donut server=‘’ src=‘rtmp://….’ />

src could be any protocol you want.

tamimio a year ago

Does it work with USB cameras? It would be great if it can just interface with /dev/video0 for example.

  • Sean-Der a year ago

    Check out https://github.com/pion/mediadevices it’s an attempt to make that way easier

    • tamimio a year ago

      Thanks for sharing that! How I usually do it involves manual work by using gatreamer with usb source and into rtp or even sink it to udp port, I will check this out!

      > Capture camera stream, encode it in H264/VP8/VP9, and send it to a RTP server

      It says here few encodings but below it’s only h264 package, for others I would have to write my own package I assume? Also, any AV1 support if hw allow it?

alexdoesh a year ago

Do we have any reverse bridge available, that you can use for in-browser or edge conversion from WebRTC to RTMP/HSL?

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection