Pure Go implementation of the WebRTC API

Overview

Pion WebRTC
Pion WebRTC

A pure Go implementation of the WebRTC API

Pion webrtc Sourcegraph Widget Slack Widget Twitter Widget
Build Status PkgGoDev Coverage Status Go Report Card Codacy Badge License: MIT


New Release

Pion WebRTC v3.0.0 has been released! See the release notes to learn about new features and breaking changes.

If you aren't able to upgrade yet check the tags for the latest v2 release.

We would love your feedback! Please create GitHub issues or join the Slack channel to follow development and speak with the maintainers.


Usage

Go Modules are mandatory for using Pion WebRTC. So make sure you set export GO111MODULE=on, and explicitly specify /v2 or /v3 when importing.

example applications contains code samples of common things people build with Pion WebRTC.

example-webrtc-applications contains more full featured examples that use 3rd party libraries.

awesome-pion contains projects that have used Pion, and serve as real world examples of usage.

GoDoc is an auto generated API reference. All our Public APIs are commented.

FAQ has answers to common questions. If you have a question not covered please ask in Slack we are always looking to expand it.

Now go build something awesome! Here are some ideas to get your creative juices flowing:

  • Send a video file to multiple browser in real time for perfectly synchronized movie watching.
  • Send a webcam on an embedded device to your browser with no additional server required!
  • Securely send data between two servers, without using pub/sub.
  • Record your webcam and do special effects server side.
  • Build a conferencing application that processes audio/video and make decisions off of it.
  • Remotely control a robots and stream its cameras in realtime.

Want to learn more about WebRTC?

Check out WebRTC for the Curious. A book about WebRTC in depth, not just about the APIs. Learn the full details of ICE, SCTP, DTLS, SRTP, and how they work together to make up the WebRTC stack.

This is also a great resource if you are trying to debug. Learn the tools of the trade and how to approach WebRTC issues.

This book is vendor agnostic and will not have any Pion specific information.

Features

PeerConnection API

  • Go implementation of webrtc-pc and webrtc-stats
  • DataChannels
  • Send/Receive audio and video
  • Renegotiation
  • Plan-B and Unified Plan
  • SettingEngine for Pion specific extensions

Connectivity

  • Full ICE Agent
  • ICE Restart
  • Trickle ICE
  • STUN
  • TURN (UDP, TCP, DTLS and TLS)
  • mDNS candidates

DataChannels

  • Ordered/Unordered
  • Lossy/Lossless

Media

  • API with direct RTP/RTCP access
  • Opus, PCM, H264, VP8 and VP9 packetizer
  • API also allows developer to pass their own packetizer
  • IVF, Ogg, H264 and Matroska provided for easy sending and saving
  • getUserMedia implementation (Requires Cgo)
  • Easy integration with x264, libvpx, GStreamer and ffmpeg.
  • Simulcast
  • SVC
  • NACK
  • Full loss recovery and congestion control is not complete, see pion/interceptor for progress
    • See ion for how an implementor can do it today

Security

  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 and TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA for DTLS v1.2
  • SRTP_AEAD_AES_256_GCM and SRTP_AES128_CM_HMAC_SHA1_80 for SRTP
  • Hardware acceleration available for GCM suites

Pure Go

  • No Cgo usage
  • Wide platform support
    • Windows, macOS, Linux, FreeBSD
    • iOS, Android
    • WASM see examples
    • 386, amd64, arm, mips, ppc64
  • Easy to build Numbers generated on Intel(R) Core(TM) i5-2520M CPU @ 2.50GHz
    • Time to build examples/play-from-disk - 0.66s user 0.20s system 306% cpu 0.279 total
    • Time to run entire test suite - 25.60s user 9.40s system 45% cpu 1:16.69 total
  • Tools to measure performance provided

Roadmap

The library is in active development, please refer to the roadmap to track our major milestones. We also maintain a list of Big Ideas these are things we want to build but don't have a clear plan or the resources yet. If you are looking to get involved this is a great place to get started! We would also love to hear your ideas! Even if you can't implement it yourself, it could inspire others.

Community

Pion has an active community on the Slack.

Follow the Pion Twitter for project updates and important WebRTC news.

We are always looking to support your projects. Please reach out if you have something to build! If you need commercial support or don't want to use public methods you can contact us at [email protected]

Contributing

Check out the contributing wiki to join the group of amazing people making this project possible:

License

MIT License - see LICENSE for full text

Issues
  • Support 1:1 NAT option

    Support 1:1 NAT option

    Summary

    Motivation

    Pion could be used in C/S topology, one end is a client and the other end is a server (just like Janus G/W does). But in this case, the server must have a routable (public) IP address. Many server environments may not have access to public IP address to bind to the local interface.

    Janus provides the following option. Pion could provide something equivalent.

        -1, --nat-1-1=ip              Public IP to put in all host candidates,
                                      assuming a 1:1 NAT is in place (e.g., Amazon
                                      EC2 instances, default=none)
    

    Describe alternatives you've considered

    Use STUN server for the server-side nodes.

    opened by enobufs 37
  • Move transceiver selection inside SetRemoteDescription and CreateOffer

    Move transceiver selection inside SetRemoteDescription and CreateOffer

    Description

    This tries to better match the JSEP spec and will fix at least two issues: #1171 and #1178

    • Move transceiver selection/creation in SetRemoteDescription and CreateOffer
    • In SetRemoteDescription also create new Transceivers of type recvonly when no satisfying transceiver is available
    • In CreateOffer generate unique mid in number format avoiding possible collisions with remote provide mids and to also already handle a future implementation of m= section rejection and reuse
    • Now generateMatchedSDP will just find the transceivers with the required mid since they are already selected previously.

    More details in these extract from JSEP:

    JSEP 5.10 (Applying a Remote Description) says:

    For each m= section, the following steps MUST be performed
    
    [...]
    
    If the m= section is not associated with any RtpTransceiver
    (possibly because it was dissociated in the previous step),
    either find an RtpTransceiver or create one according to the
    following steps:
    

    JSEP 5.2 (Constructing an Offer) says:

    [...]
    
    An m= section is generated for each RtpTransceiver
    that has been added to the PeerConnection, excluding any stopped
    RtpTransceivers;
    

    Note that we are currently directly associating a mid to a transceiver in CreateOffer, instead the spec says to also keep a m= section index mapping to a transceiver and set the transceiver mid only when applying the local description. This is needed to support rollback of proposed offer/answer but currently we don't have support and tests for rollback situations.

    Reference issue

    Fixes #1171 Fixes #1178

    opened by sgotti 24
  • PeerConnection OnTrack callback never invoked

    PeerConnection OnTrack callback never invoked

    Your environment.

    • Version: v2.1.8
    • Browser: None
    • Other Information - I am trying to create a softphone using SIP and this library. The remote SIP & RTC service have no problem, because I have done a softphone using Node.js: https://github.com/ringcentral/ringcentral-softphone-js . I am trying to make a GoLang version, but I am stuck.

    What did you do?

    I have written the following code: https://github.com/ringcentral/ringcentral-softphone-go/blob/master/softphone.go#L137-L220

    Just for your reference, here is the Node.js version of the GoLang code: https://github.com/ringcentral/ringcentral-softphone-js/blob/ce833c613d5e4bb959235e37addefd10cc9cb81e/index.js#L140-L177 . The Node.js code works like a charm.

    What did you expect?

    I expect that the peerConnection.OnTrack callback function will be invoked so that I can get the input audio

    What happened?

    peerConnection.OnTrack never invoked and I am stuck.

    Some questions:

    Could it because I specify the wrong codec? If so, I expect some error message like: no codec to handle the remote track. remote SDP sample:

    v=0
    o=- 5305405169010475891 908790132696250821 IN IP4 104.245.57.182
    s=SmcSip
    c=IN IP4 104.245.57.182
    t=0 0
    m=audio 20040 RTP/SAVPF 109 111 18 0 8 9 96 101
    a=rtpmap:109 OPUS/16000
    a=fmtp:109 useinbandfec=1
    a=rtcp-fb:109 ccm tmmbr
    a=rtpmap:111 OPUS/48000/2
    a=fmtp:111 useinbandfec=1
    a=rtcp-fb:111 ccm tmmbr
    a=rtpmap:18 g729/8000
    a=fmtp:18 annexb=no
    a=rtpmap:0 pcmu/8000
    a=rtpmap:8 pcma/8000
    a=rtpmap:9 g722/8000
    a=rtpmap:96 ilbc/8000
    a=fmtp:96 mode=20
    a=rtpmap:101 telephone-event/8000
    a=fmtp:101 0-15
    a=sendrecv
    a=rtcp:20041
    a=rtcp-mux
    a=setup:actpass
    a=fingerprint:sha-1 E2:F8:90:C6:37:7E:82:17:3C:63:CF:55:68:4E:1D:16:17:2C:D9:4D
    a=ice-ufrag:atwbXWRm
    a=ice-pwd:32SCWdSoU7BgkXxet5g5mlId5E
    a=candidate:muEZ8Bb5Zhy8XFSL 1 UDP 2130706431 104.245.57.182 20040 typ host
    a=candidate:muEZ8Bb5Zhy8XFSL 2 UDP 2130706430 104.245.57.182 20041 typ host
    

    How can I port the Node.JS code to GoLang? Because I know Node.js version works like charm. And the code even works in browser (with browser WebRTC). So if pion/webrtc is compatible with browser WebRTC, I should be able to get this GoLang version work.

    Could it becuase of this https://github.com/pion/webrtc/issues/879? I temporarily worked around the issue: https://github.com/ringcentral/ringcentral-softphone-go/blob/master/softphone.go#L133

    opened by tylerlong 23
  • Exchange messages using Windows environment

    Exchange messages using Windows environment

    Hi, we are trying to sending message using windows environment.

    We have 1 server instance run on the Windows from NAT network and other one client instance run on the Windows from NAT network on other PC.

    As the result we cant exhange messages and we cant see any errors.

    Can you help as run this solution using Windows enviroment, because is it important for us?

    If you need we can gve you as information you want.

    Thanks.

    PS we are using this example: https://github.com/pions/webrtc/tree/master/examples/pion-to-pion

    bug backlog 
    opened by netwer 23
  • How to replace gstreamer from the examples gstreamer-receive and gstreamer-send

    How to replace gstreamer from the examples gstreamer-receive and gstreamer-send

    How could I replace gstreamer with something more lightweight c lib

    or pure go lib if I only want to work with audio (non-GUI app)?

    Any ideas?

    Thanks in advance :)

    triaged 
    opened by joeky888 23
  • Regression: connection failed

    Regression: connection failed

    The latest working commit c87c3ca45386f2889887ac70633d71841793bc3c Current master doesn't establish connection at all, I think issue related because of latest ICE changes. Tested with chrome browser. Network map: client -> NAT -> server with real ip

    bug blocked 
    opened by bdandy 23
  • media: support sending MediaStreams with multiple tracks

    media: support sending MediaStreams with multiple tracks

    Currently the media stream labels are hardcoded in the SDP offer and answer generation. The RTCPeerConnection.AddTrack should be extended to support adding media stream labels.

    TODO

    • [ ] Add a variadic streams argument to the AddTrack method as specified in the RTP Media API
    • [ ] Store the media stream ids on the RTCTrack object as specified here
    • [ ] Add the media streams to the SDP offer and answer. Some of the required logic already exists. However, the stream label is currently hardcoded to the track label. The procedure is specified in the JSEP spec
    help wanted good first issue difficulty:easy 
    opened by Sean-Der 23
  • Send offer twice in very short time, second offer doesn't reflect well

    Send offer twice in very short time, second offer doesn't reflect well

    Your environment.

    What did you do?

    Send offer twice in very short time(within 100ms). In the first offer, I just add datachannel in SDP In the second offer, I add two tracks(audio, video)

    But the second offer doesn't reflects well and see error log in PeerConnection as below Incoming unhandled RTP ssrc(123412341234), OnTrack will not be fired. incoming SSRC failed Simulcast probing

    This issue is raised because REMOTE DESCRIPTION is changed during processing the first offer's startRTP(). (startSCTP() takes long time for init) So I think before completing startRTP() of the first offer, it should prevent to change REMOTE DESCRIPTION or filter the simulcastStream by undeclaredMediaProcessor().

    And there is no way to check it startRTP() is in progress. Adding some function for checking it in PeerConnection might be helpful for user.

    • I call PeerConnection's functions sequentially as below.
    SetRemoteDescription(offer) -> answer, err := CreateAnswer(nil) -> SetLocalDescription(answer) 
    

    What did you expect?

    The second offer should reflect well.

    What happened?

    The second offer doesn't reflect well

    opened by Rollooo 21
  • interceptor POC

    interceptor POC

    Updated interceptor design based on TrackLocal:

    Changes:

    1. Interceptor now have Bind methods similar to track, which are called for every track (local/remote) for rtp, and once per peerconnection for rtcp.
    2. Added interceptors separately to API, instead of under setting engine. Did this because interceptors must be created per peerconnection, and InterceptorFactory seemed confusing. Also API was already a depedency of Receiver/Sender, so this was was much simpler. Similarly to MediaEngine, Interceptors now must be configured for each PeerConnection and added to API. Default interceptors can later be added in NewAPI method.
    3. Instead of using interfaces with single a single function (eg: RTPWriter with a single WriteRTP function), I use function types. This makes implementing an interceptor simpler, because there is no need to create a separate struct for each interface (inline functions can be used instead).
    type WriteRTP func(p *rtp.Packet, attributes map[interface{}]interface{}) (int, error)
    type ReadRTP func() (*rtp.Packet, map[interface{}]interface{}, error)
    type WriteRTCP func(pkts []rtcp.Packet, attributes map[interface{}]interface{}) (int, error)
    type ReadRTCP func() ([]rtcp.Packet, map[interface{}]interface{}, error)
    
    type Interceptor interface {
    	BindReadRTCP(read ReadRTCP) ReadRTCP     // TODO: call this
    	BindWriteRTCP(write WriteRTCP) WriteRTCP // TODO: call this
    
    	BindLocalTrack(ctx *TrackLocalContext, write WriteRTP) WriteRTP
    	UnbindLocalTrack(ctx *TrackLocalContext)
    
    	BindRemoteTrack(ctx *TrackRemoteContext, read ReadRTP) ReadRTP
    	UnbindRemoteTrack(ctx *TrackRemoteContext)
    
    	io.Closer
    }
    

    Questions:

    1. Please see interceptor_peerconnection.go and interceptor_track_remote.go. They are quite ugly. I'm open to any suggestions.
    2. ReadRTCP is currently present on both RTPSender and RTPReceiver, while WriteRTCP is on PeerConnection. I think it would make much more sense to move ReadRTCP to PeerConnection as well. The current solution using DestinationSSRC() method is very opionated and causes some rtcp packets to be duplicated (in case they belong to multiple ssrc, or they are in a batch with another rtcp packet that belong to a different rtcp, see session_rtcp.go/destinationSSRC). In fact in our project we went to great length to undo this behaviour and get a single ReadRTCP method, without packet duplications. Is there any plan to modify this behaviour? (It would make calling BindReadRTCP in the Interceptor much easier).

    Any suggestions are welcome.

    @Sean-Der @at-wat please check

    opened by masterada 21
  • Single port mode

    Single port mode

    Summary

    Currently every candidate created will open up a new UDP connection. This makes it hard to configure some loadbalancers/firewalls that do not support configuring port ranges, and can also impact performance if there are thousands of forwarded ports. I would like to suggest a single port mode option that allows listening on a single UDP port instead. This consists of 2 parts:

    1. Server reflexive candidates should not open a separate port, but use the same port as the corresponding host candidate. Some examples in the rfc suggests this kind of behaviour, although it's never stated explicitly

    RFC: https://tools.ietf.org/html/rfc8445#appendix-B.2

    The initiating agent obtains a host candidate on its IP address on network C (10.0.1.100:2498) and a host candidate on its IP address on network A (192.168.1.100:3344). It performs a STUN query to its configured STUN server from 192.168.1.100:3344.

    1. The rfc contains some notes about the possiblity of using a single ICE candidate for multiple ICE sessions. I think it would be possible to gather local candidates once, and share them through the whole lifetime of the server. The packets can be sorted based on the source address returned by PacketConn.ReadFrom .

    RFC: https://tools.ietf.org/html/rfc8445#section-8.3.1

    (a candidate may be used by multiple ICE sessions, e.g., in forking scenarios)

    Motivation

    To make loadbalancer/firewall configurations simpler by only listening on a single UDP port. Will be also useful once TCP support is implemented, because the server can listen on tcp port 80 (some hotel/public wifis only allow outgoing requests to TCP port 80 and 443).

    Implementation ideas

    I can think of two ways to implement this, and I would be happy to do either of them (or anything else if someine has a better idea):

    • make candidate gathering pluggable (with a Candidate interface), and write a plugin for single port mode
    • make a configuration option for single port mode, and modify the candidate struct to handle multiple connections (and multiple agents).

    Questions

    • What do you think of the idea in general?
    • Would you like (1.) to be part of the core functionality?
    • Would you like (2.) to be part of the core functionality?
    • Would you mind if I made the gathering part of the agent pluggable in order to support this?
    opened by masterada 21
  • community: related projects

    community: related projects

    This ticket tracks projects related to pions. These can be projects using pions or projects we want to/are contributing WebRTC support to.

    Media API

    DataChannel

    Unknown

    Other language implementations

    Organize TODO

    • https://github.com/Antonito/gfile
    • https://github.com/pion/asciirtc
    • https://github.com/maxmcd/webtty
    • https://github.com/rtctunnel/rtctunnel
    • https://github.com/nobonobo/ssh-p2p
    • https://github.com/mxseba/rtc-ssh
    • https://github.com/poi5305/go-yuv2webRTC
    • https://github.com/rian-hotate/tetoris
    • https://github.com/schollz/webrtc-transfer
    • https://github.com/machinesworking/myhome
    • https://github.com/wwl33695/myrtc
    • https://github.com/takutakahashi/wg-connect
    • https://github.com/open-domophone/soft-omega2
    • https://github.com/mtojek/filegate
    • https://github.com/porjo/babelcast
    • https://github.com/porjo/mumblet
    • https://github.com/cretz/myscreen.live
    • https://github.com/deepch/RTSPtoWebRTC
    • https://github.com/hoernschen/goat
    • https://github.com/discordianfish/infisk8-server
    • https://github.com/edwintcloud/classmate
    • https://github.com/nacgarg/stereo
    • https://github.com/mtharp/gunk
    • https://github.com/bashawhm/TheHarmonicInternetNoiseGiver
    • https://github.com/s8sg/satellite

    This issue can be used for tracking. Please use the Golang Slack #pion channel or mailing list for discussions.

    triaged 
    opened by backkem 21
  • Unable to receive simulcast tracks

    Unable to receive simulcast tracks

    Your environment.

    • Version: v3.1.43
    • Browser:

    What did you do?

    • [Succeed]Deployed a pion SFU server (with webRTC v3.1.43)
    • [Succeed]On Mac, create a peerConnection (using pion-go-sdk), join (use webRTC json protocol)
    • Try to publish a track, with two simulcast tracks (the same streamID, trackID and different RID - h, q, f).
    • See error Incoming unhandled RTP ssrc(XXXXXXX), OnTrack will not be fired. incoming SSRC failed Simulcast probing on SFU server (3 times, one for each track), and in a web viewer subscriber side can't see the tracks.
    • If only publish one track, everything works fine.

    Track type: video track: h264/90000

    What did you expect?

    Simulcast tracks pass down to subscriber side and won't show the failure warning

    What happened?

    I tried with the latest version, but still see the error. Suspecting maybe race condition (but the failure is consistent) or not support simulcast features?

    opened by sweetbasil-bill 0
  • Which Go compiler versions should Pion support?

    Which Go compiler versions should Pion support?

    This issue was 'inspired' by https://github.com/pion/transport/pull/200 created by @jech which has the effect of broadening the range of Go compiler versions that Pion can be built with. I felt the question of Go compiler support is best answered with substantial community input as it impacts past and future contributors to Pion, as well as third-party software that uses Pion as a dependency.

    The core question is: which versions of the Go toolchain should Pion support? Right now there is no clear answer (i.e. nothing is stated explicitly in the docs), and the Pion codebase itself offers a number of contradictory answers:

    1. Pion's CI system tests builds only against 1.17 and 1.18. This is consistent with Go's own support for the current major version, plus the last version, of the toolchain. This means that, in practice, committed changes are only guaranteed to work on 1.17 and 1.18.
    2. go.mod in the main repo targets go 1.13. Some of the other packages e.g. pion/transport target go 1.12 in the go.mod.
    3. Recent changes e.g. inclusion of optimised assembly for crypto functions currently use syntax only available in 1.16 onwards.

    The point was raised that the Go toolchain advances faster than some Linux distros are updated, so it is possible/likely that people are developing primary with Go toolchain releases that are now unsupported/EOL.

    Some possible options:

    1. We synchronize Pion's support for the Go toolchain with Go's own support schedule, i.e. current version + last major version only. This is effectively what's done by Pion's current CI system, and so this 'change' is simply to state that 1.17 and 1.18 are the only supported Go toolchain releases. We can choose to enforce this in go.mod or not do so, and state that Pion may compile under earlier versions of Go but we do not test or support such usage.
    2. We make a decision to broaden support to e.g. current + last + last-but-one + last-but-two. If we do this we should change Pion's CI process to also build and test under 1.16 and 1.15. This might reveal breakages either due to Go features in use in the codebase that were not supported in 1.15/1.16, or due to compiler bugs whose fixes were not marked for backport. This might be fine, or might open a 'can of worms' - it is hard to tell.

    What are people's views on this?

    opened by adriancable 4
  • How to deal packet loss?

    How to deal packet loss?

    I use pion webrtc to develop a media server and the video quality is low(I use simulcast) and video loss frame frequently.I send rtcp from server to client using below code in example/simulcast:

    // Start reading from all the streams and sending them to the related output track
    rid := track.RID()
    go func() {
        ticker := time.NewTicker(3 * time.Second)
        for range ticker.C {
    	fmt.Printf("Sending pli for stream with rid: %q, ssrc: %d\n", track.RID(), track.SSRC())
    	if writeErr := peerConnection.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{MediaSSRC: uint32(track.SSRC())}}); writeErr != nil {
    		fmt.Println(writeErr)
    	}
        }
    }()
    

    but the video quality still low and the packet still loss(increment by I doing nothing) How can I sovle it and I have two question. 1.Is there some perfect example or project to deal with packet loss. 2.How can I deal Rtcp packet from sender(client).If I must handle rtcp packets in code or the pion can handle it automaticly Thank you

    opened by ChenMoGe2 0
  • Communication with webrtc native using data channel is slow

    Communication with webrtc native using data channel is slow

    We use webrtc native on ios and android platforms. Below are the issue we found. For this, we had to use webrtc native in our go project.

    pion/webrtc/v3 v3.1.43 webrtc native latest (I don't know how to get the version) WSL2(Utuntu-20.04)

    speed unstable

    iperf3 client -> pion/webrtc (go) -> webrtc native (c++) -> iperf3 server

    image

    go code
    package main
    
    import (
    	"encoding/base64"
    	"encoding/json"
    	"errors"
    	"flag"
    	"fmt"
    	"io"
    	"net"
    
    	"github.com/pion/webrtc/v3"
    )
    
    /*
    iperf3 -s
    go run ./build/ -listen=:5555
    iperf3 -c 127.0.0.1 -p 5555 -b 500M
    */
    func main() {
    	listenAddress := flag.String("listen", ":0", "address to listen on")
    	flag.Parse()
    
    	// 创建 peerConnection
    	config := webrtc.Configuration{}
    	var err error
    	peerConnection, err := webrtc.NewPeerConnection(config)
    	if err != nil {
    		panic(err)
    	}
    
    	// 注册 peerConnection 回调
    	peerConnection.OnICEConnectionStateChange(func(is webrtc.ICEConnectionState) {
    		fmt.Println("peerConnection.OnICEConnectionStateChange: ", is.String())
    	})
    	peerConnection.OnNegotiationNeeded(func() {
    		fmt.Println("peerConnection.OnNegotiationNeeded")
    
    		offer, err := peerConnection.CreateOffer(nil)
    		if err != nil {
    			panic(err)
    		}
    		err = peerConnection.SetLocalDescription(offer)
    		if err != nil {
    			panic(err)
    		}
    	})
    	peerConnection.OnICECandidate(func(i *webrtc.ICECandidate) {
    		// 跳过,直到最后一次
    		if i != nil {
    			return
    		}
    
    		// 发送 offer
    		offer := peerConnection.LocalDescription()
    		offerBytes, err := json.Marshal(offer)
    		if err != nil {
    			panic(err)
    		}
    		offerBase64 := base64.StdEncoding.EncodeToString(offerBytes)
    		fmt.Println(offerBase64)
    
    		// 接收 answer
    		fmt.Println("please enter answer")
    		var answerBase64 string
    		fmt.Scanln(&answerBase64)
    		answerBytes, err := base64.StdEncoding.DecodeString(answerBase64)
    		if err != nil {
    			panic(err)
    		}
    		var answer webrtc.SessionDescription
    		err = json.Unmarshal(answerBytes, &answer)
    		if err != nil {
    			panic(err)
    		}
    		err = peerConnection.SetRemoteDescription(answer)
    		if err != nil {
    			panic(err)
    		}
    	})
    
    	// 监听端口
    	listener, err := net.Listen("tcp", *listenAddress)
    	if err != nil {
    		panic(err)
    	}
    
    	for {
    		conn, err := listener.Accept()
    		if err != nil {
    			panic(err)
    		}
    
    		// 创建 dataChannel
    		dataChan, err := peerConnection.CreateDataChannel(conn.RemoteAddr().String(), nil)
    		if err != nil {
    			panic(err)
    		}
    		dataChan.OnClose(func() {
    			fmt.Println("dataChan.OnClose")
    		})
    		dataChan.OnOpen(func() {
    			fmt.Printf("Data channel '%s'-'%d' open.\n", dataChan.Label(), dataChan.ID())
    
    			// 转发数据
    			buf := make([]byte, 8*1024)
    			for {
    				nread, err := conn.Read(buf)
    				if nread > 0 {
    					err = dataChan.Send(buf[:nread])
    					if err != nil {
    						panic(err)
    					}
    				}
    				if err != nil {
    					if errors.Is(err, io.EOF) {
    						return
    					}
    					panic(err)
    				}
    			}
    		})
    		dataChan.OnMessage(func(msg webrtc.DataChannelMessage) {
    			// 转发数据
    			_, err = conn.Write(msg.Data)
    			if err != nil {
    				panic(err)
    			}
    		})
    	}
    }
    
    c++ code
    #include <iostream>
    
    #include <api/create_peerconnection_factory.h>
    #include <boost/asio.hpp>
    #include <boost/beast/core/detail/base64.hpp>
    #include <boost/property_tree/json_parser.hpp>
    #include <boost/property_tree/ptree.hpp>
    
    using namespace std;
    using namespace webrtc;
    using namespace rtc;
    using namespace boost::beast::detail;
    using namespace boost::property_tree;
    using namespace boost::asio;
    using namespace boost::asio::ip;
    
    class DummySetSessionDescriptionObserver
        : public SetSessionDescriptionObserver {
      public:
        static DummySetSessionDescriptionObserver *Create() {
            return new RefCountedObject<DummySetSessionDescriptionObserver>();
        }
        virtual void OnSuccess() {}
        virtual void OnFailure(RTCError error) { assert(false); }
    };
    
    class DataChannelObserver : public webrtc::DataChannelObserver {
      public:
        DataChannelObserver(scoped_refptr<DataChannelInterface> dataChannel,
                            io_context &ioc)
            : dataChannel(dataChannel), ioc(ioc) {}
    
      protected:
        void OnStateChange() {
            cout << "OnStateChange: " << dataChannel->state() << endl;
    
            if (dataChannel->state() == DataChannelInterface::kOpen) {
                tcp::socket tcpSocket(ioc);
                tcpSocket.async_connect(
                    tcp::endpoint(ip::make_address("127.0.0.1"), 5201),
                    [this](boost::system::error_code ec) {
                        if (ec) {
                            cout << ec.message() << endl;
                            return;
                        }
                        doRead();
                    });
                this->tcpSocket =
                    shared_ptr<tcp::socket>(new tcp::socket(move(tcpSocket)));
            } else if (dataChannel->state() == DataChannelInterface::kClosed) {
                delete (this);
            }
        }
    
        void OnMessage(const DataBuffer &buffer) {
            async_write(*tcpSocket,
                               boost::asio::buffer(buffer.data.data(), buffer.size()),
                               [this](boost::system::error_code ec, size_t bytesTransferred) {
                                   if (ec) {
                                       cout << ec.message() << endl;
                                       return;
                                   }
                               });
        }
    
      private:
        scoped_refptr<DataChannelInterface> dataChannel;
        io_context &ioc;
        shared_ptr<tcp::socket> tcpSocket;
        vector<char> tcpSocketReadBuf = vector<char>(8 * 1024);
    
        void doRead() {
            tcpSocket->async_read_some(
                buffer(tcpSocketReadBuf.data(),
                       tcpSocketReadBuf.size()),
                [this](boost::system::error_code ec, size_t nread) {
                    if (ec) {
                        cout << ec.message() << endl;
                        return;
                    }
                    dataChannel->Send(DataBuffer(CopyOnWriteBuffer(tcpSocketReadBuf.data(), nread), true));
                    doRead();
                });
        }
    };
    
    class Client : public PeerConnectionObserver,
                   public CreateSessionDescriptionObserver {
      public:
        scoped_refptr<PeerConnectionInterface> peerConnection;
        io_context &ioc;
        unique_ptr<Thread> signalingThread;
    
        Client(io_context &ioc) : ioc(ioc) {
            // 创建 peerConnection
            signalingThread = Thread::Create();
            signalingThread->Start();
            PeerConnectionFactoryDependencies dependencies;
            dependencies.signaling_thread = signalingThread.get();
            auto peerConnectionFactory =
                CreateModularPeerConnectionFactory(move(dependencies));
            PeerConnectionInterface::RTCConfiguration configuration;
            PeerConnectionDependencies connectionDependencies(this);
            auto peerConnectionOrError =
                peerConnectionFactory->CreatePeerConnectionOrError(
                    configuration, move(connectionDependencies));
            if (!peerConnectionOrError.ok()) {
                cout << "!peerConnectionOrError.ok()" << endl;
                exit(1);
            }
            peerConnection = peerConnectionOrError.MoveValue();
        }
    
        void start() {
            // 读取 offer
            cout << "please enter offer" << endl;
            string offerBase64;
            getline(cin, offerBase64);
            string offerStr(base64::decoded_size(offerBase64.size()), ' ');
            auto decodePair = base64::decode((void *)offerStr.data(),
                                             offerBase64.c_str(), offerBase64.size());
            offerStr.resize(decodePair.first);
            stringstream offerStream;
            offerStream << offerStr;
            ptree pt;
            read_json(offerStream, pt);
            auto sdpStr = pt.get<string>("sdp");
            auto sdp = CreateSessionDescription(SdpType::kOffer, sdpStr);
            peerConnection->SetRemoteDescription(
                DummySetSessionDescriptionObserver::Create(), sdp.release());
            PeerConnectionInterface::RTCOfferAnswerOptions options;
            peerConnection->CreateAnswer(this, options);
        }
    
      protected:
        /*
        PeerConnectionObserver
        */
    
        void OnSignalingChange(PeerConnectionInterface::SignalingState new_state) {
            cout << "OnSignalingChange: "
                 << PeerConnectionInterface::AsString(new_state) << endl;
        }
    
        void OnDataChannel(scoped_refptr<DataChannelInterface> data_channel) {
            cout << "OnDataChannel: " << data_channel->label() << endl;
            auto dataChannelObserver = new ::DataChannelObserver(data_channel, ioc);
            data_channel->RegisterObserver(dataChannelObserver);
        }
    
        void OnNegotiationNeededEvent(uint32_t event_id) {
            cout << "OnNegotiationNeededEvent: " << event_id << endl;
        }
    
        void
        OnIceConnectionChange(PeerConnectionInterface::IceConnectionState new_state) {
            cout << "OnIceConnectionChange: "
                 << PeerConnectionInterface::AsString(new_state) << endl;
        }
    
        void
        OnConnectionChange(PeerConnectionInterface::PeerConnectionState new_state) {
            cout << "OnConnectionChange: "
                 << PeerConnectionInterface::AsString(new_state) << endl;
        }
    
        void
        OnIceGatheringChange(PeerConnectionInterface::IceGatheringState new_state) {
            cout << "OnIceGatheringChange: "
                 << PeerConnectionInterface::AsString(new_state) << endl;
        }
    
        void OnIceCandidate(const IceCandidateInterface *candidate) {
            cout << "OnIceCandidate" << endl;
        }
    
        /*
        CreateSessionDescriptionObserver
        */
    
        void OnSuccess(SessionDescriptionInterface *desc) {
            cout << "OnSuccess" << endl;
    
            if (desc->GetType() == SdpType::kAnswer) {
                peerConnection->SetLocalDescription(
                    DummySetSessionDescriptionObserver::Create(), desc);
                desc = const_cast<SessionDescriptionInterface *>(
                    peerConnection->local_description());
                string sdpStr;
                desc->ToString(&sdpStr);
                stringstream answerStream;
                ptree pt;
                pt.add("type", "answer");
                pt.add("sdp", sdpStr);
                write_json(answerStream, pt, false);
                string answerBase64(base64::encoded_size(answerStream.str().size()), ' ');
                auto nwrite = base64::encode(answerBase64.data(),
                                             (void *)answerStream.str().c_str(),
                                             answerStream.str().size());
                answerBase64.resize(nwrite);
                cout << answerBase64 << endl;
            }
        }
    
        void OnFailure(RTCError error) {
            cout << "OnFailure: " << error.message() << endl;
        }
    };
    
    /*
    clear
    g++ -o server -g -ggdb \
        server.cpp \
        -I/usr/local/include/webrtc \
        -I/usr/local/include/webrtc/third_party/abseil-cpp \
        -std=c++17 \
        -DWEBRTC_POSIX \
        /home/test/webrtc-checkout/src/out/Release-gcc/obj/libwebrtc.a \
        -ldl -lpthread -lX11
    g++ -o server -O2 -s \
        server.cpp \
        -I/usr/local/include/webrtc \
        -I/usr/local/include/webrtc/third_party/abseil-cpp \
        -std=c++17 \
        -DWEBRTC_POSIX \
        /home/test/webrtc-checkout/src/out/Release-gcc/obj/libwebrtc.a \
        -ldl -lpthread -lX11
    ./server
    
    */
    int main(int argc, char const *argv[]) {
        io_context ioc(4);
        scoped_refptr<Client> client{new RefCountedObject<Client>(ioc)};
        client->start();
    
        boost::asio::executor_work_guard<decltype(ioc.get_executor())> work{ioc.get_executor()};
        ioc.run();
    
        return 0;
    }
    

    speed fast

    iperf3 client -> pion/webrtc (go) -> pion/webrtc (go) -> iperf3 server

    I tested it but the code is missing.

    speed fast

    iperf3 client -> webrtc native (c++) -> webrtc native (c++) -> iperf3 server

    image

    c++ code
    #include <iostream>
    
    #include <api/create_peerconnection_factory.h>
    #include <boost/asio.hpp>
    #include <boost/beast/core/detail/base64.hpp>
    #include <boost/property_tree/json_parser.hpp>
    #include <boost/property_tree/ptree.hpp>
    
    using namespace std;
    using namespace webrtc;
    using namespace rtc;
    using namespace boost::beast::detail;
    using namespace boost::property_tree;
    using namespace boost::asio;
    using namespace boost::asio::ip;
    
    class DummySetSessionDescriptionObserver
        : public SetSessionDescriptionObserver {
      public:
        static DummySetSessionDescriptionObserver *Create() {
            return new RefCountedObject<DummySetSessionDescriptionObserver>();
        }
        virtual void OnSuccess() {}
        virtual void OnFailure(RTCError error) { assert(false); }
    };
    
    class DataChannelObserver : public webrtc::DataChannelObserver {
      public:
        string label;
        DataChannelObserver(scoped_refptr<DataChannelInterface> dataChannel,
                            io_context &ioc,
                            shared_ptr<tcp::socket> tcpSocket,
                            string label)
            : dataChannel(dataChannel), ioc(ioc), tcpSocket(tcpSocket), label(label) {}
    
      protected:
        void OnStateChange() {
            cout << "OnStateChange: " << label << ": " << DataChannelInterface::DataStateString(dataChannel->state()) << endl;
    
            if (dataChannel->state() == DataChannelInterface::kOpen) {
                if (tcpSocket == nullptr) {
                    tcp::socket tcpSocket(ioc);
                    tcpSocket.async_connect(
                        tcp::endpoint(ip::make_address("127.0.0.1"), 5201),
                        [this](boost::system::error_code ec) {
                            if (ec) {
                                cout << ec.message() << endl;
                                return;
                            }
                            doRead();
                        });
                    this->tcpSocket =
                        shared_ptr<tcp::socket>(new tcp::socket(move(tcpSocket)));
                } else {
                    doRead();
                }
            } else if (dataChannel->state() == DataChannelInterface::kClosed) {
                delete (this);
            }
        }
    
        void OnMessage(const DataBuffer &buffer) {
            async_write(*tcpSocket,
                        boost::asio::buffer(buffer.data.data(), buffer.size()),
                        [this](boost::system::error_code ec, size_t bytesTransferred) {
                            if (ec) {
                                cout << ec.message() << endl;
                                return;
                            }
                        });
        }
    
      private:
        scoped_refptr<DataChannelInterface> dataChannel;
        io_context &ioc;
        shared_ptr<tcp::socket> tcpSocket;
        vector<char> tcpSocketReadBuf = vector<char>(8 * 1024);
    
        void doRead() {
            tcpSocket->async_read_some(
                buffer(tcpSocketReadBuf.data(),
                       tcpSocketReadBuf.size()),
                [this](boost::system::error_code ec, size_t nread) {
                    if (ec) {
                        cout << ec.message() << endl;
                        return;
                    }
                    dataChannel->Send(DataBuffer(CopyOnWriteBuffer(tcpSocketReadBuf.data(), nread), true));
                    doRead();
                });
        }
    };
    
    class Client : public PeerConnectionObserver,
                   public CreateSessionDescriptionObserver {
      public:
        scoped_refptr<PeerConnectionInterface> peerConnection;
        io_context &ioc;
        unique_ptr<Thread> signalingThread;
        Client *otherClient = nullptr;
        tcp::acceptor *acceptor;
    
        Client(io_context &ioc) : ioc(ioc) {
            // 创建 peerConnection
            signalingThread = Thread::Create();
            signalingThread->Start();
            PeerConnectionFactoryDependencies dependencies;
            dependencies.signaling_thread = signalingThread.get();
            auto peerConnectionFactory =
                CreateModularPeerConnectionFactory(move(dependencies));
            PeerConnectionInterface::RTCConfiguration configuration;
            PeerConnectionDependencies connectionDependencies(this);
            auto peerConnectionOrError =
                peerConnectionFactory->CreatePeerConnectionOrError(
                    configuration, move(connectionDependencies));
            if (!peerConnectionOrError.ok()) {
                cout << "!peerConnectionOrError.ok()" << endl;
                exit(1);
            }
            peerConnection = peerConnectionOrError.MoveValue();
        }
    
        void doListen() {
            acceptor = new tcp::acceptor(ioc, tcp::endpoint(tcp::v4(), 5555));
            doAccept();
        }
    
        void doAccept() {
            acceptor->async_accept([this](boost::system::error_code ec, tcp::socket socket) {
                cout << "acceptor->async_accept" << endl;
    
                if (ec) {
                    cout << ec.message() << endl;
                    return;
                }
    
                signalingThread->Invoke<void>(RTC_FROM_HERE, [this, &socket]() {
                    stringstream srcAddr;
                    srcAddr << socket.remote_endpoint();
                    auto dataChannelOrError = peerConnection->CreateDataChannelOrError(srcAddr.str(), nullptr);
                    if (!dataChannelOrError.ok()) {
                        cout << "!dataChannelOrError.ok()" << endl;
                        exit(1);
                    }
                    auto dataChannel = dataChannelOrError.MoveValue();
                    auto dataChannelObserver = new ::DataChannelObserver(dataChannel, ioc, shared_ptr<tcp::socket>(new tcp::socket(move(socket))), "doAccept");
                    dataChannel->RegisterObserver(dataChannelObserver);
                });
    
                doAccept();
            });
        }
    
        void SetOtherClient(Client *client) {
            otherClient = client;
        }
    
      protected:
        /*
        PeerConnectionObserver
        */
    
        void OnSignalingChange(PeerConnectionInterface::SignalingState new_state) {
            cout << "OnSignalingChange: "
                 << PeerConnectionInterface::AsString(new_state) << endl;
        }
    
        void OnDataChannel(scoped_refptr<DataChannelInterface> data_channel) {
            cout << "OnDataChannel: " << data_channel->label() << endl;
            auto dataChannelObserver = new ::DataChannelObserver(data_channel, ioc, nullptr, "OnDataChannel");
            data_channel->RegisterObserver(dataChannelObserver);
        }
    
        void OnNegotiationNeededEvent(uint32_t event_id) {
            cout << "OnNegotiationNeededEvent: " << event_id << endl;
    
            PeerConnectionInterface::RTCOfferAnswerOptions options;
            peerConnection->CreateOffer(this, options);
        }
    
        void
        OnIceConnectionChange(PeerConnectionInterface::IceConnectionState new_state) {
            cout << "OnIceConnectionChange: "
                 << PeerConnectionInterface::AsString(new_state) << endl;
        }
    
        void
        OnConnectionChange(PeerConnectionInterface::PeerConnectionState new_state) {
            cout << "OnConnectionChange: "
                 << PeerConnectionInterface::AsString(new_state) << endl;
        }
    
        void
        OnIceGatheringChange(PeerConnectionInterface::IceGatheringState new_state) {
            cout << "OnIceGatheringChange: "
                 << PeerConnectionInterface::AsString(new_state) << endl;
        }
    
        void OnIceCandidate(const IceCandidateInterface *candidate) {
            cout << "OnIceCandidate" << endl;
        }
    
        /*
        CreateSessionDescriptionObserver
        */
    
        void OnSuccess(SessionDescriptionInterface *desc) {
            cout << "OnSuccess" << endl;
    
            peerConnection->SetLocalDescription(DummySetSessionDescriptionObserver::Create(), desc);
            auto localSDP = const_cast<SessionDescriptionInterface *>(peerConnection->local_description());
            otherClient->peerConnection->SetRemoteDescription(DummySetSessionDescriptionObserver::Create(), localSDP);
    
            if (desc->GetType() == SdpType::kOffer) {
                PeerConnectionInterface::RTCOfferAnswerOptions options;
                otherClient->peerConnection->CreateAnswer(otherClient, options);
            }
        }
    
        void OnFailure(RTCError error) {
            cout << "OnFailure: " << error.message() << endl;
        }
    };
    
    /*
    clear
    g++ -o double_side -g -ggdb \
        double_side.cpp \
        -I/usr/local/include/webrtc \
        -I/usr/local/include/webrtc/third_party/abseil-cpp \
        -std=c++17 \
        -DWEBRTC_POSIX \
        /home/test/webrtc-checkout/src/out/Debug-gcc/obj/libwebrtc.a \
        -ldl -lpthread -lX11
    g++ -o double_side -O2 -s \
        double_side.cpp \
        -I/usr/local/include/webrtc \
        -I/usr/local/include/webrtc/third_party/abseil-cpp \
        -std=c++17 \
        -DWEBRTC_POSIX \
        /home/test/webrtc-checkout/src/out/Release-gcc/obj/libwebrtc.a \
        -ldl -lpthread -lX11
    ./double_side
    
    */
    int main(int argc, char const *argv[]) {
        io_context ioc(1);
        scoped_refptr<Client> client1{new RefCountedObject<Client>(ioc)};
        scoped_refptr<Client> client2{new RefCountedObject<Client>(ioc)};
        client1->SetOtherClient(client2.get());
        client2->SetOtherClient(client1.get());
        client2->doListen();
    
        boost::asio::executor_work_guard<decltype(ioc.get_executor())> work{ioc.get_executor()};
        ioc.run();
    
        return 0;
    }
    
    opened by FH0 0
  • Firefox error setting ice candidate attribute

    Firefox error setting ice candidate attribute

    Your environment.

    • Version: https://unpkg.com/[email protected] github.com/pion/webrtc/v3 v3.0.0-beta.4.0.20200902134452-789ff0975342
    • Browser: Firefox 102.0.1

    What happened?

    Chrome works fine, firefox has the following error

    error1. SDP Parse error image

    31: Warning: problem parsing rtcp-fb ccm type 31: Warning: could not parse ccm type for rtcp-fb attribute 39: c= connection line not specified for every media level, validation failed.

    v=0 o=- 5690260156074151900 1657504137 IN IP4 0.0.0.0 s=- t=0 0 a=fingerprint:sha-256 48:BD:21:3C:A7:A5:F3:CF:2C:E1:EE:1B:32:EE:C8:57:B9:D6:BF:90:B6:FE:40:E2:00:A1:3B:5D:25:B7:3F:00 a=group:BUNDLE 0 2 m=application 9 DTLS/SCTP 5000 c=IN IP4 0.0.0.0 a=setup:actpass a=mid:0 a=sendrecv a=sctpmap:5000 webrtc-datachannel 1024 a=ice-ufrag:QHUzwHZxAuyvZWfk a=ice-pwd:OWzLWqPZnBaiagLlNSXYxjpNFgaJAYet a=candidate:foundation 1 udp 2130706431 x.x.x.x 5200 typ host generation 0 a=candidate:foundation 2 udp 2130706431 x.x.x.x 5200 typ host generation 0 a=candidate:foundation 1 udp 1694498815 x.x.x.x 19159 typ srflx raddr 0.0.0.0 rport 5048 generation 0 a=candidate:foundation 2 udp 1694498815 x.x.x.x 19159 typ srflx raddr 0.0.0.0 rport 5048 generation 0 a=end-of-candidates m=audio 0 UDP/TLS/RTP/SAVPF 0 m=video 9 UDP/TLS/RTP/SAVPF 102 c=IN IP4 0.0.0.0 a=setup:actpass a=mid:2 a=ice-ufrag:QHUzwHZxAuyvZWfk a=ice-pwd:OWzLWqPZnBaiagLlNSXYxjpNFgaJAYet a=rtcp-mux a=rtcp-rsize a=rtpmap:102 H264/90000 a=rtcp-fb:102 goog-remb a=rtcp-fb:102 ccm a=rtcp-fb:102 nack a=rtcp-fb:102 nack pli a=recvonly a=candidate:foundation 1 udp 2130706431 x.x.x.x 5200 typ host generation 0 a=candidate:foundation 2 udp 2130706431 x.x.x.x 5200 typ host generation 0 a=candidate:foundation 1 udp 1694498815 x.x.x.x 19159 typ srflx raddr 0.0.0.0 rport 5048 generation 0 a=candidate:foundation 2 udp 1694498815 x.x.x.x 19159 typ srflx raddr 0.0.0.0 rport 5048 generation 0 a=end-of-candidates

    error2.AddICECandidate image

    error setting ice candidate attribute not long enough to be ICE candidate (0)

    opened by Ztai2018 0
Releases(v3.1.0)
  • v3.1.0(Sep 19, 2021)

    Pion WebRTC v3.1.0 is now available. Pion WebRTC is a Go implementation of WebRTC. If you haven't used it before check out awesome-pion or example-webrtc-applications for what people are doing. We maintain a feature list and other helpful resources in our README.md

    This release includes 170 commits from 36 authors. This release was primarily focused on improve media quality/experience and making it easier to scale with Pion.

    New Features

    Serve many PeerConnections with one UDP port

    You can now serve all your PeerConnections with a single UDP port. This makes deploying and scaling in environment like Kubernetes easier. Most WebRTC implementations (including Pion) will listen on a random UDP port for each remote peer.

    To use this you create a ICEUDPMux and then share across all your PeerConnections via the SettingEngine. Your code will look like the following.

    // Listen on UDP Port 8443
    udpListener, _ := net.ListenUDP("udp", &net.UDPAddr{
        IP:   net.IP{0, 0, 0, 0},
        Port: 8443,
    })
    
    // Configure a SettingEngine to use our UDPMux. By default a PeerConnection has
    // no global state. The API+SettingEngine allows the user to share state between them.
    // In this case we are sharing our listening port across many.
    settingEngine := webrtc.SettingEngine{}
    settingEngine.SetICEUDPMux(webrtc.NewICEUDPMux(nil, udpListener))
    
    // Create a new API using our SettingEngine
    api = webrtc.NewAPI(webrtc.WithSettingEngine(settingEngine))
    
    // Create a new PeerConnection
    peerConnection_, := api.NewPeerConnection(webrtc.Configuration{})
    

    This was implemented in d0a525.

    FireFox Simulcast Support

    We now support SSRC based Simulcast, before we only supported reading RID/MID from the RTP Extension Header as defined in ietf-mmusic-sdp-simulcast.

    This was implemented in d570b7.

    Sender/Receiver Report

    Sender/Receiver Reports are now enabled by default via pion/interceptor This means that remote peers will now get metadata from Pion and be able to do things like Bandwidth Estimation.

    No code changes are needed to use them, but if you wish to disable them create a PeerConnection without passing a InterceptorRegisty that RegisterDefaultInterceptors has been called on. This can be useful if performance is critical or you want to ship your own implementation.

    // Register the default Codec configuration
    m := &webrtc.MediaEngine{}
    m.RegisterDefaultCodecs()
    
    // Create a new API using our MediaEngine
    api = webrtc.NewAPI(webrtc.WithMediaEngine(m))
    
    // Create a new PeerConnection
    peerConnection_, := api.NewPeerConnection(webrtc.Configuration{})
    

    This was implemented in bc3016

    Transport Wide Congestion Control Feedback

    Transport Wide Congestion Control Feedback is now enabled by default via pion/interceptor This allows remote peers to perform even better Congestion Control over Receiver Reports.

    No code changes are needed to use them, but if you wish to disable them create a PeerConnection without passing a InterceptorRegisty that RegisterDefaultInterceptors has been called on. This can be useful if performance is critical or you want to ship your own implementation.

    // Register the default Codec configuration
    m := &webrtc.MediaEngine{}
    m.RegisterDefaultCodecs()
    
    // Create a new API using our MediaEngine
    api = webrtc.NewAPI(webrtc.WithMediaEngine(m))
    
    // Create a new PeerConnection
    peerConnection_, := api.NewPeerConnection(webrtc.Configuration{})
    

    This was implemented in c8a26a

    H265 Support

    You can now packetize/depacketize H265. This allows you to read from a video file and send it over RTP, or the reverse.

    This was implemented in 6cf5e9

    Source code(tar.gz)
    Source code(zip)
  • v3.0.0(Dec 31, 2020)

    The Pion team is very excited to announce the v3.0.0 release of Pion WebRTC. Pion WebRTC is a Go implementation of WebRTC. If you haven't used it before check out awesome-pion or example-webrtc-applications for what people are doing. We maintain a feature list and other helpful resources in our README.md

    This release includes 264 commits from 43 authors. We reduced sharp edges in the media API, add performance gains in media and datachannel paths and brought ourselves more in alignment with the browser API.

    We do have quite a few breaking changes. Please read them carefully, most of these things can't be caught at compile time. Reading this document could save a lot of time debugging. Each change will have a linked commit. Looking at examples/ in the linked commit should show what code you need to change in your application.

    Breaking Changes

    Trickle ICE is now enabled by default

    Before /v3 Pion WebRTC would gather all candidates before a CreateOffer or CreateAnswer generated a SDP. This would cause a few issues in real world applications. You can read about the benefits of Trickle ICE here

    • Longer call connection times since we blocked for STUN/TURN even if not needed
    • This didn't comply with the WebRTC spec
    • Made it harder for users to filter/process ICE Candidates

    Now you should exchange ICE Candidates that are pushed via the OnICECandidate callback.

    Before

      peerConnection, _ := webrtc.NewPeerConnection(webrtc.Configuration{})
    
      offer, _ := peerConnection.CreateOffer()
      peerConnection.SetLocalDescription(offer)
    
      // Send `offer` to remote peer
      websocket.Write(offer)
    

    After

      peerConnection, _ := webrtc.NewPeerConnection(webrtc.Configuration{})
    
      // Set ICE Candidate handler. As soon as a PeerConnection has gathered a candidate
      // send it to the other peer
      peerConnection.OnICECandidate(func(i *webrtc.ICECandidate) {
        // Send ICE Candidate via Websocket/HTTP/$X to remote peer
      })
    
      // Listen for ICE Candidates from the remote peer
      peerConnection.AddICECandidate(remoteCandidate)
    
      // You still signal like before, but `CreateOffer` will be much faster
      offer, _ := peerConnection.CreateOffer()
      peerConnection.SetLocalDescription(offer)
    
      // Send `offer` to remote peer
      websocket.Write(offer)
    

    If you are unable to migrate we have provided a helper function to simulate the pre-v3 behavior.

    Helper function to simulate non-trickle ICE

      peerConnection, _ := webrtc.NewPeerConnection(webrtc.Configuration{})
    
      offer, _ := peerConnection.CreateOffer()
    
      // Create channel that is blocked until ICE Gathering is complete
      gatherComplete := webrtc.GatheringCompletePromise(peerConnection)
      peerConnection.SetLocalDescription(offer)
      <-gatherComplete
    
      // Send `LocalDescription` to remote peer
      // This is the offer but populated with all the ICE Candidates
      websocket.Write(*peerConnection.LocalDescription())
    

    This was changed with bb3aa9

    A data channel is no longer implicitly created with a PeerConnection

    Before /v3 Pion WebRTC would always insert a application Media Section. This means that an offer would work even if you didn't create a DataChannel or Transceiver, in /v3 you MUST create a DataChannel or track first. To better illustrate these are two SDPs, each from a different version of Pion WebRTC

    /v2 SDP with no CreateDataChannel

    v=0
    o=- 8334017457074456852 1596089329 IN IP4 0.0.0.0
    s=-
    t=0 0
    a=fingerprint:sha-256 91:B0:3A:6E:9E:43:9A:9D:1B:71:17:7D:FB:D0:5C:81:12:6E:61:D5:6C:BF:92:E8:8D:04:F5:92:EF:62:36:C9
    a=group:BUNDLE 0
    m=application 9 DTLS/SCTP 5000
    c=IN IP4 0.0.0.0
    a=setup:actpass
    a=mid:0
    a=sendrecv
    a=sctpmap:5000 webrtc-datachannel 1024
    a=ice-ufrag:yBlrlyMmuDdCfawp
    a=ice-pwd:RzlouYCNYDNpPLJLdddFtUkMVpKVLYWz
    a=candidate:foundation 1 udp 2130706431 192.168.1.8 51147 typ host generation 0
    a=candidate:foundation 2 udp 2130706431 192.168.1.8 51147 typ host generation 0
    a=end-of-candidates
    

    /v3 SDP with no CreateDataChannel

    v=0
    o=- 8628031010413059766 1596089396 IN IP4 0.0.0.0
    s=-
    t=0 0
    a=fingerprint:sha-256 64:79:7C:73:6B:8A:CF:34:9D:D0:9C:6B:31:07:44:0A:CD:56:F0:74:62:72:D4:23:D5:BC:B2:C9:46:55:C5:A3
    a=group:BUNDLE
    

    To simulate the old functionality, call CreateDataChannel after creating your PeerConnection and before calling anything else.

    This was changed with abd6a3

    Track is now an interface

    The design of the Track API in /v3 has been updated to accommodate more use cases and reduce the sharp edges in the API. Before we used one structure to represent incoming and outgoing media. This didn't match with how WebRTC actually works. In WebRTC a track isn't bi-directional. Having Read and Write on the same structure was confusing.

    Split Track into TrackLocal and TrackRemote

    Now we have TrackLocal and TrackRemote. TrackLocal is used to send media, TrackRemote is used to receive media.

    TrackRemote has a similar API to /v2. It has Read and ReadRTP and code will continue to work with just a name change Track -> TrackRemote

    TrackLocal is now an interface, and will require more work to port. For existing code you will want to use one of the TrackLocal implementations. NewLocalTrackStaticSample or NewLocalTrackStaticRTP depending on what type of data you were sending before.

    Code that looks like

      videoTrack, err := peerConnection.NewTrack(payloadType, randutil.NewMathRandomGenerator().Uint32(), "video", "pion")
    

    Needs to become like one of the following

      videoTrack, err := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video", "pion")
    
      videoTrack, err := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: "video/vp8"}, "video", "pion")
    

    Users no longer have to manage SSRC/PayloadType

    When creating a Track you don't need to know these values. When writing packets you don't need to pull these values either. Internally we make sure that everything is properly set. This means that mediaengine.PopulateFromSDP has been removed, and you can delete any code that does this.

    Other packages can satisfy LocalTrack

    pion/mediadevices now can provide an API that feels like getUserMedia in the browser. Before it wasn't able to generate anything that pion/webrtc could directly call AddTrack on.

    A user could also implement LocalTrack and and add custom behavior.

    MediaEngine API has changed

    We now use data structures from the W3C to configure available codecs and header extensions. You can also define your own MimeTypes, allowing you to send any codec you wish! pion/webrtc can support for a new codec with just calls to the public API.

    Before

      m.RegisterCodec(webrtc.NewRTPOpusCodec(webrtc.DefaultPayloadTypeOpus, 48000))
      m.RegisterCodec(webrtc.NewRTPVP8Codec(webrtc.DefaultPayloadTypeVP8, 90000))
    

    After

      if err := m.RegisterCodec(webrtc.RTPCodecParameters{
        RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: "video/VP8", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil},
        PayloadType:        96,
      }, webrtc.RTPCodecTypeVideo); err != nil {
        panic(err)
      }
      if err := m.RegisterCodec(webrtc.RTPCodecParameters{
        RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: "audio/opus", ClockRate: 48000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil},
        PayloadType:        111,
      }, webrtc.RTPCodecTypeAudio); err != nil {
        panic(err)
      }
    

    This was changed with 7edfb7

    New Features

    ICE Restarts

    You can now initiate and accept an ICE Restart! This means that if a PeerConnection goes to Disconnected or Failed because of network interruption it is no longer fatal.

    To use you just need to pass ICERestart: true in your OfferOptions. The answering PeerConnection will then restart also. This is supported in FireFox/Chrome and Mobile WebRTC Clients.

      peerConn, _ := NewPeerConnection(Configuration{})
    
      // PeerConnection goes to ICEConnectionStateFailed
    
      offer, _ := peerConn.CreateOffer(&OfferOptions{ICERestart: true})
    

    This was implemented in f29414

    ICE TCP

    Pion WebRTC now can act as a passive ICE TCP candidates. This means that a remote ICE Agent that supports TCP active can connect to Pion without using UDP. Before the only way to achieve ICE Connectivity in UDP-less networks was by using a TURN server.

    You should still deploy and use a TURN server for NAT traversal.

    Since this isn't part of the standard WebRTC API it requires SettingEngine usage. You can see how to use it in examples/ice-tcp

    This was implemented in 2236dd

    OnNegotationNeeded

    onnegotationneeded is now available. You can define a callback and be notified whenever session negotiation needs to done.

    OnNegotationNeeded in pion/webrtc will behave differently that in the browser because we are operating in a multi-threaded environment. Make sure to have proper locking around your signaling/Session Description handling.

    This was implemented in c5819d

    Simulcast

    You can now send Simulcast feeds to Pion WebRTC! It uses MID/RID identification as defined in ietf-mmusic-sdp-simulcast. An example has been provided at examples/simulcast.

    This was implemented in 6ee528

    SRTP AEAD_AES_128_GCM

    pion/srtp added support for the SRTP Cipher AEAD_AES_128_GCM. Thanks to hardware acceleration you can see up to a 400% performance improvement. You can run benchmarks in pion/srtp to see if your hardware supports it.

    This cipher is on by default, so no change is required. During negotiation Pion WebRTC will prefer this cipher, but fall back to others if not available.

    This was implemented in f871f4

    Interceptor

    v3.0.0 introduces a new Pion specific concept known as a interceptor. A Interceptor is a pluggable RTP/RTCP processor. Via a public API users can easily add and customize operations that are run on inbound/outbound RTP. Interceptors are an interface this means A user could provide their own implementation. Or you can use one of the interceptors Pion will have in-tree.

    We designed this with the following vision.

    • Useful defaults. Nontechnical users should be able to build things without tuning.
    • Don't block unique use cases. We shouldn't paint ourself in a corner. We want to support interesting WebRTC users
    • Allow users to bring their own logic. We should encourage easy changing. Innovation in this area is important.
    • Allow users to learn. Don't put this stuff deep in the code base. Should be easy to jump into so people can learn.

    In this release we only are providing a NACK Generator/Responder interceptor. We will be implementing more and you can import the latest at anytime! This means you can update your pion/interceptor version without having to upgrade pion/webrtc!

    We plan on implementing the following. Check the README in pion/interceptor for the most up to date information.

    WebRTC for the Curious

    The Pion developers started a free book on how WebRTC actually works. It is available at https://webrtcforthecurious.com and is hosted from GitHub. It is A book about WebRTC in depth, not just about the APIs. Learn the full details of ICE, SCTP, DTLS, SRTP, and how they work together to make up the WebRTC stack.

    This is also a great resource if you are trying to debug. Learn the tools of the trade and how to approach WebRTC issues.

    This book is vendor agnostic and will not have any Pion specific information.

    Projects that have been migrated

    See https://github.com/pion/webrtc/issues/1615 for a list of projects that have been migrated to v3.0.0 already. If you are confused about what API changes you need these may be helpful

    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta.15(Dec 6, 2020)

  • v3.0.0-beta.11(Nov 4, 2020)

  • v3.0.0-beta.10(Oct 23, 2020)

  • v2.2.0(Feb 17, 2020)

    After 5 months of work (and lots of distraction) the Pion team is excited to announce the release of v2.2.0! This release includes.

    New Features

    DataChannel Performance Improvements

    Thanks to hard work by @enobufs Datachannels have gotten a huge performance improvement. In some cases you will see a 16x improvement in throughput. You can read more about his fantastic work here

    Extend SettingEngine to support SFU use cases

    Pion WebRTC is seeing lots of usage in building SFUs. To support this the SettingEngine has been extended to add even more options. You now have the following flags you can configure

    • SetEphemeralUDPPortRange You can limit the range of UDP ports used to support restrictive networks
    • SetInterfaceFilter You can exclude some interfaces from being used.
    • SetNAT1To1IPs Allows you to set a static IP to replace all host candidates. Useful if you are behind a DNAT, and don't want to make a STUN request for each PeerConnection.
    • SetNetworkTypes You can blacklist TCP, UDP, IPv4 or IPv6. Useful if you know certain configurations will never work.
    • SetLite Enables ICE lite, a minimal version of the ICE protocol. Reduces complexity in situations where full ICE isn't needed like a publicly routeable SFU.

    Thank you @seppo0010, @AeroNotix, @enobufs and @trivigy for your work on this

    TCP TURN Support

    Pion WebRTC now supports creating allocations via UDP, TCP and TLS. Implemented by @enobufs

    PCM Support

    Pion WebRTC now supports sending and receiving PCM.

    Renegotiation

    You can now Add/Remove tracks at anytime, and renegotiate! We have add a new minimal example called play-from-disk-renegotation that demonstrates this behavior. This example allows you to play a video back from disk multiple times, and you can stop the individual instances at any time!

    Add IVFReader

    We now have a Go implementation of an .ivf Demuxer. This allows users to easily playback files from disk. Pion also provides an IVFWriter, so you could easily save a file to disk and play it back later. Implemented by @justinokamoto

    VP9 Support

    You can now send and receive VP9. Implemented by @at-wat

    Next Release

    The next release will contain lots of bugfixes and other improvements, but the general goals for the next 6 months are.

    Better Stats

    Pion WebRTC is seeing lots of usage for load testing and measuring WebRTC servers. We are going to work on implement as many webrtc-stats as possible, after that we are going to explore building a framework on top of the PeerConnection API that makes load testing easier. We also want to make it easier to measure things in production, have an application that is easy to build deploy to production that can measure how your service is behaving will help a lot of users.

    Better Media

    Pion WebRTC lacks a in-tree JitterBuffer and Congestion Control. Users like ion right now have to implement it themselves. In the future Pion WebRTC will allow users to pass their own implementations (because they know their needs best), but provide some default implementations.

    Better Performance

    We are going to start measuring allocations, create real benchmarks and working on getting them better. We then need to add these benchmarks to CI and make sure they never regress.

    Source code(tar.gz)
    Source code(zip)
  • v2.1.0(Jul 31, 2019)

    The Pion team is excited to announce the v2.1.0 release of Pion WebRTC. This release represents 3 months of feature development and testing across a variety of Pion projects. The headline features are:

    TURN Support

    Thanks to @enobufs Pion WebRTC now has full TURN support. This has been tested against multiple Open Source and hosted TURN providers.

    Stats

    @hugoArregui has added support for webrtc-stats. This initial implementation collects stats related to the PeerConnection, DataChannels, ICECandidates and ICECandidatePairs. The status and remaining work is being tracked in #610

    mDNS Host Candidates

    WebRTC has added mDNS candidates to help with privacy when using WebRTC, you can read the RFC here. We are able to parse and connect to these candidates. Currently we don't generate them, but in the future we will make this controllable by the user.

    vnet

    Pion WebRTC now implements a virtual network layer. You can read more about it here. This feature allows people to construct networks that only exist in software. This will allow users to simulate real world network conditions simulating NATs, packet loss, bandwidth and jitter without every actually sending a packet. Thanks to this feature written by @enobufs we have fixed multiple bugs in pion/turn and pion/ice already!

    Trickle ICE

    Trickle ICE is now available! This is controlled by the SettingEngine. We will make this the default in Pion v3 since it is a breaking change, and is not apparent to the user via an API change. Thank you @trivigy and @hugo for all your work on this.

    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Dec 23, 2018)

    This is the third public release of pion-WebRTC, thanks for trying it out!

    We hope you have as much fun using it and we did making it. Thank you so much to everyone that contributed, the code and bug reports of the community are what makes it all possible.


    This release adding the following features

    • Raw RTP Input You can now supply RTP packets directly. Instead of parsing and rebuilding packets you can just forward. This should improve performance for this use case, and will make code simpler. Implemented by Michael MacDonald

    • Allow adding Trickle-ICE candidates ICE candidates can now be added at any time, making pion-WebRTC compatible with WebRTC implementations that use trickle ICE like Chromium and FireFox. Implement by Michael MacDonald

    • Implement RTCP Reception The API now provides code to emit and handle RTCP packets, allowing you to build applications that interact and emit RTCP packets. Implemented by Woodrow Douglass

    • Transport refactor The internals of pion-WebRTC have been completely rewritten. This allows us to move subsystems to their own packages, cleaner code and fixed bugs along the way! Soon we should be able to provide ICE, SRTP, SCTP and more libraries for general use. We also now can explore alternative APIs like ORTC. Implemented by Michiel De Backker

    • Go native DTLS We are now 100% Go, removing our last C dependency (OpenSSL) We also now are able to provide a DTLS implementation to the greater community and are really excited about all the opportunities it opens up. Implemented by Michiel De Backker and Sean DuBois

    • Improve SRTP code and add auth tag checking Fixed a bug where wrong SRTP keys were used, in some cases video would fail to decode. Also expanded the SRTP code to do tag checking Implemented by Tobias Fridén

    • Add go-fuzz support to RTCP, and discovered crash in RTP code Implemented by Max Hawkins


    We ship with the following demos you can base your application off of.

    • data-channels Shows how to use DataChannels and send/receive data to your browser
    • gstreamer-receive Shows how to receive video and play or process it via GStreamer
    • gstreamer-send Shows how to generate video via GStreamer and send it to your browser
    • janus-gateway/streaming Shows how to use connect to a Janus streaming mountpoint and save to an ivf container
    • janus-gateway/video-room Shows how to use connect to a Janus video-room and publish video
    • pion-to-pion Shows to communicate between two Pion instance using DataChannels, no browser required!
    • save-to-disk Shows how to receive VP8 from your browser and save to an ivf container
    • sfu Shows how to broadcast a video to many peers, while only requiring the broadcaster to upload once

    To see what features are planned in the future, please see our roadmap

    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Oct 2, 2018)

    This is the second public release of pion-WebRTC, thanks for trying it out! Hopefully you have as much fun using it and we did making it

    This release adding the following features

    • Full ICE. pion-WebRTC is able to be controlling or controlled and can connect to itself.
    • DataChannels. pion-WebRTC can now send and receive messages via SCTP DataChannels.
    • RTCP. pion-WebRTC now is able to send and receive RTCP, making it a great building block for building things like an SFU.

    We also ship with the following demos you can base your application off of.

    • data-channels Shows how to use DataChannels and send/receive data to your browser
    • gstreamer-receive Shows how to receive video and play or process it via GStreamer
    • gstreamer-send Shows how to generate video via GStreamer and send it to your browser
    • janus-gateway Shows how to use connect to a Janus streaming mountpoint and save to an ivf container
    • pion-to-pion Shows to communicate between two Pion instance using DataChannels, no browser required!
    • save-to-disk Shows how to receive VP8 from your browser and save to an ivf container
    • sfu Shows how to broadcast a video to many peers, while only requiring the broadcaster to upload once

    To see what features are planned in the future, please see our roadmap

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Jul 4, 2018)

    This is the first public release of pion-WebRTC. Thank you for checking it out!

    pion-WebRTC is not finished, but ships with the following features

    • Send and receiving audio and video
    • Go Native SRTP
    • DTLS via OpenSSL (we still require Cgo just for this, but will be rewritten soon)
    • ICE-lite (requires that pion-WebRTC is run on a public IP, or communicates with in a LAN)

    We also ship with the following demos you can base your application off of.

    • gstreamer-send Shows how to generate video via GStreamer and send it to your browser
    • gstreamer-receive Shows how to receive video and play or process it via GStreamer
    • save-to-disk Shows how to receive VP8 from your browser and save to an ivf container

    To see what features are planned in the future, please see our roadmap

    Source code(tar.gz)
    Source code(zip)
Owner
Pion
The Open Source, Cross Platform Stack for Real-time Media and Data Communication.
Pion
Pure Go implementation of the WebRTC API

Pure Go implementation of the WebRTC API

Pion 9.7k Aug 8, 2022
Pure Go implementation of the WebRTC API

Pion WebRTC A pure Go implementation of the WebRTC API New Release Pion WebRTC v3.0.0 has been released! See the release notes to learn about new feat

Pion 9.7k Aug 9, 2022
This project is designed to be an open source implementation for streaming desktop games using WebRTC

The aim of this project is develop a WebRTC screenshare designed for streaming video games and accepting remote inputs. There will be ansible instruct

Akilan Selvacoumar 18 Jul 25, 2022
A RTP -> WebRTC broadcast server for Project Lightspeed.

Project Lightspeed WebRTC A RTP -> WebRTC server based on Pion written in Go. This server accepts RTP packets on port 65535 and broadcasts them via We

Garrett GRVY Graves 70 Jun 23, 2022
gRPC over WebRTC

gRPC over WebRTC Just a proof of concept, please be kind. How to Start all the things Client, create-react-app + grpc-web signaling + webrtc extension

Jean-Sebastien Mouret 254 Jul 25, 2022
Demonstration of a browser connecting to Pion WebRTC without a signaling server.

Offline Browser Sync WebRTC without a signaling server! This repo demonstrates how you can connect two WebRTC proccesses without signaling. No configu

Pion 138 Jul 12, 2022
A yet to be voice call application in terminal. with the power of go and webRTC (pion).

Kenny I'm just trying to make a cli operated voice call chat application using go with help of webRTC and PortAudio. It might stay a Work In Progress

Mohammad Fatemi 37 Apr 30, 2022
A yet to be voice call application in terminal. with the power of go and webRTC (pion).

A yet to be voice call application in terminal. with the power of go and webRTC (pion).

Mohammad Fatemi 37 Apr 30, 2022
A toy MMO example built using Ebiten and WebRTC DataChannels (UDP)

Ebiten WebRTC Toy MMO ⚠️ This is a piece of incomplete hobby work and not robust. Please read the "Why does this project exist?" section. What is this

Jae Bentvelzen 14 Jul 31, 2022
LiveKit - Open source, distributed video/audio rooms over WebRTC

LiveKit is an open source project that provides scalable, multi-user conferencing over WebRTC. It's designed to give you everything you need to build real time video/audio capabilities in your applications.

LiveKit 3.7k Aug 12, 2022
Scalable WebRTC Signaling Server with ayame-like protocol.

ayu ayu is WebRTC Signaling Server with ayame-like protocol. Scalable: ayu uses Redis to store room states, so it can be used on serverless platforms

castaneai 23 Jul 14, 2022
Example of using Pion WebRTC to play H264 + Ogg from disk

This repo demonstrates how you can use Pion WebRTC to play H264 and Ogg from disk. These same APIs can be used to pull from other sources. You can use

Sean DuBois 7 Sep 18, 2021
Stream video from ffmpeg to webrtc

ffmpeg-to-webrtc demonstrates how to send video from ffmpeg to your browser using pion.

Artur Shellunts 861 Jul 26, 2022
rtsp to webrtc proxy with websocket signaling, currently limited to single h264 stream per endpoint

rtp-to-webrtc rtp-to-webrtc demonstrates how to consume a RTP stream video UDP, and then send to a WebRTC client. With this example we have pre-made G

Game On 5 Aug 6, 2022
Demonstration of using Pion WebRTC with a shared socket

pion-webrtc-shared-socket This example demonstrates how Pion WebRTC can use an already listening UDP socket. On startup we listen on UDP Socket 8000.

Sean DuBois 6 Apr 4, 2022
WebRTC media servers stress testing tool (currently only Janus)

GHODRAT WebRTC media servers stress testing tool (currently only Janus) Architecture Janus media-server under load Deployment ghodrat # update or crea

Snapp Cab Incubators 32 Jul 25, 2022
This project is the eloboration of pion/webrtc.

This project is the eloboration of pion/webrtc. The idea is to make the (pion/webrtc) sfu-ws example be able to handle multiple rooms

null 0 Nov 29, 2021
Go Webrtc Signaling Server

Go Webrtc Signaling Server This package is used to listen for Remote SDP (Sessio

Ali Error 1 Dec 28, 2021
Peerconnection_explainer - PeerConnection-Explainer parses WebRTC Offers/Answers then provides summaries and suggestions

PeerConnection Explainer PeerConnection Explainer decodes WebRTC... so you don't have too! PeerConnection Explainer parses WebRTC Offers/Answers then

Pion 34 Jul 31, 2022
Overlay networks based on WebRTC.

weron Overlay networks based on WebRTC. ⚠️ weron has not yet been audited! While we try to make weron as secure as possible, it has not yet undergone

Felicitas Pojtinger 1.2k Aug 10, 2022
Pure Go implementation of the NaCL set of API's

go-nacl This is a pure Go implementation of the API's available in NaCL: https://nacl.cr.yp.to. Compared with the implementation in golang.org/x/crypt

Kevin Burke 526 Aug 5, 2022
Pure Go implementation of the NaCL set of API's

go-nacl This is a pure Go implementation of the API's available in NaCL: https://nacl.cr.yp.to. Compared with the implementation in golang.org/x/crypt

Kevin Burke 526 Aug 5, 2022
Pure Go termbox implementation

IMPORTANT This library is somewhat not maintained anymore. But I'm glad that it did what I wanted the most. It moved people away from "ncurses" mindse

null 4.4k Aug 12, 2022
The pure golang implementation of nanomsg (version 1, frozen)

mangos NOTE: This is the legacy version of mangos (v1). Users are encouraged to use mangos v2 instead if possible. No further development is taking pl

nanomsg 1.5k Jun 22, 2022
Pure Go implementation of D. J. Bernstein's cdb constant database library.

Pure Go implementation of D. J. Bernstein's cdb constant database library.

John Barham 222 Jun 12, 2022
A QUIC implementation in pure go

A QUIC implementation in pure Go quic-go is an implementation of the QUIC protocol in Go. It implements the IETF QUIC draft-29 and draft-32. Version c

Lucas Clemente 7.1k Aug 13, 2022
A Windows named pipe implementation written in pure Go.

npipe Package npipe provides a pure Go wrapper around Windows named pipes. Windows named pipe documentation: http://msdn.microsoft.com/en-us/library/w

Nate Finch 250 Aug 3, 2022
mangos is a pure Golang implementation of nanomsg's "Scalablilty Protocols"

mangos Mangos™ is an implementation in pure Go of the SP (“Scalability Protocols”) messaging system. These are colloquially known as a “nanomsg”. ❗ Th

nanomsg 534 Aug 6, 2022
Package git provides an incomplete pure Go implementation of Git core methods.

git Package git provides an incomplete pure Go implementation of Git core methods. Example Code: store := git.TempStore() defer os.RemoveAll(string(st

Daniel Skinner 27 Mar 1, 2022