Skip to content
Sean DuBois edited this page Sep 30, 2018 · 17 revisions

Issues with Current API

Concurrency/Race issues -- Golang provides an excellent API for sharing data between threads (channels) and we aren't taking advantage of them at all. There is a big mental burden (and chance of error) by locking/unlocking in the networkManager.

Maintainability -- people find the current design confusing. Would prefer more clear boundaries between components. This would also look like the ECMAScript WebRTC API. However, they have zero relation. This is internal to pion-WebRTC and has no effect on a user.

Callback heavy -- Everytime we want to add new features we add a new callback, and it is making things cumbersome

Current API

NetworkManager

Manages all network traffic. To send a packet call a method on the networkManager.

Responding to an inbound packet is done via callbacks. When you create a networkManager we have multiple distinct callbacks for events (RTP, SCTP, ICE etc..)

ICE

Handles ICE status. NetworkManager pushes packets on it, and uses callbacks when it wants to send traffic.

DTLS

Handles encryption for SCTP packets, and DTLS handshake. NetworkManager pushes packets on it, and uses callbacks when it wants to send traffic.

SCTP

Protocol used by DataChannels. NetworkManager pushes packets on it, and uses callbacks when it wants to send traffic.

SRTP

Used for Encrypting/Decrypting audio/video data. This is used by the NetworkManager directly, it isn't async so provides simple Encrypt/Decrypt blocking APIs

Proposed API

The new API is designed to take advantage of Go channels, and tries copy the pattern of 'Transport Chaining' see in WebRTC documentation.

A new package will be created internal/transport, this package will contain chainable transports that all inherit from a generic interface. Transports that that implement it will also add their own generic APIs, but MUST be MT safe.

type Transport interface {
  // Stop tears down the transport, cleaning up any state.
  Stop()

  // Start the transport, passing any linked Transports
  Start(Transport...) error

  // Send pushes data to the transport and takes ownership
  Send(interface{}) error

  // Recv pulls data from the transport, puller takes ownership
  Recv() (interface{}, error)
}

With the following instances

  • internal/Transport.ICE
  • internal/Transport.DTLS
  • internal/Transport.SCTP
  • internal/Transport.SRTP

Example usage

package webrtc

type RTCPeerConnection struct {
    iceTransport  *Transport.ICE
    dtlsTransport *Transport.DTLS
    sctpTransport *Transport.SCTP
    srtpTransport *Transport.SRTP
}

// Not a real API call, just an example starting transports for an RTCPeerConnection
func (r *RTCPeerConnection) Start() {
    dtlsTransport.Start(iceTransport, srtpTransport, sctpTransport)
    iceTransport.Start(dtlsTransport, srtpTransport)
    srtpTransport.Start(iceTransport)
    sctpTransport.Start(dtlsTransport)

    go func() {
      rtpPacket, err := srtpTransport.Recv()
      // Distribute packet to user, we will also do the same for SCTP (distributing message to proper DataChannel
    }()


// Not a real API call, just an example of sending a packet
func (r *RTCPeerConnection) SendRTPPacket(p *rtp.Packet) {
    r.srtpTransport.Send(p)
}

Notes

This design isn't concerned with someday exporting parts of pion-WebRTC. I don't see much value in that, one of the mistakes of the TURN server was exporting STUN. It would have been better that we exported it after we started the WebRTC project, then we would have known the API we wanted.

Instead we designed it for a theoretical user, which ended up being much different then we expected.

Feedback