diff --git a/internal/network/manager.go b/internal/network/manager.go index 482e6715..d072a19e 100644 --- a/internal/network/manager.go +++ b/internal/network/manager.go @@ -159,6 +159,22 @@ func (m *Manager) SendRTP(packet *rtp.Packet) { } } +// SendRTCP finds a connected port and sends the passed RTCP packet +func (m *Manager) SendRTCP(pkt []byte) { + m.portsLock.Lock() + defer m.portsLock.Unlock() + + local, remote := m.IceAgent.SelectedPair() + if local == nil || remote == nil { + return + } + for _, p := range m.ports { + if p.listeningAddr.Equal(local) { + p.sendRTCP(pkt, remote) + } + } +} + // SendDataChannelMessage sends a DataChannel message to a connected peer func (m *Manager) SendDataChannelMessage(payload datachannel.Payload, streamIdentifier uint16) error { var data []byte diff --git a/internal/network/port-send.go b/internal/network/port-send.go index d7dc7b2d..469745b8 100644 --- a/internal/network/port-send.go +++ b/internal/network/port-send.go @@ -11,7 +11,8 @@ func (p *port) sendRTP(packet *rtp.Packet, dst net.Addr) { p.m.srtpOutboundContextLock.Lock() defer p.m.srtpOutboundContextLock.Unlock() if p.m.srtpOutboundContext == nil { - fmt.Printf("Tried to send RTP packet but no SRTP Context to handle it \n") + // TODO log-level + // fmt.Printf("Tried to send RTP packet but no SRTP Context to handle it \n") return } @@ -40,3 +41,22 @@ func (p *port) sendSCTP(buf []byte, dst fmt.Stringer) { fmt.Println(err) } } + +func (p *port) sendRTCP(buf []byte, dst net.Addr) { + p.m.srtpOutboundContextLock.Lock() + defer p.m.srtpOutboundContextLock.Unlock() + if p.m.srtpOutboundContext == nil { + fmt.Printf("Tried to send RTCP packet but no SRTP Context to handle it \n") + return + } + + encrypted, err := p.m.srtpOutboundContext.EncryptRTCP(buf) + if err != nil { + fmt.Println(err) + return + } + + if _, err := p.conn.WriteTo(encrypted, nil, dst); err != nil { + fmt.Printf("Failed to send packet: %s \n", err.Error()) + } +} diff --git a/pkg/rtcp/header.go b/pkg/rtcp/header.go index c4faf568..7be25f4d 100644 --- a/pkg/rtcp/header.go +++ b/pkg/rtcp/header.go @@ -9,11 +9,13 @@ type PacketType uint8 // RTCP packet types registered with IANA. See: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-4 const ( - TypeSenderReport PacketType = 200 // RFC 3550, 6.4.1 - TypeReceiverReport PacketType = 201 // RFC 3550, 6.4.2 - TypeSourceDescription PacketType = 202 // RFC 3550, 6.5 - TypeGoodbye PacketType = 203 // RFC 3550, 6.6 - TypeApplicationDefined PacketType = 204 // RFC 3550, 6.7 (unimplemented) + TypeSenderReport PacketType = 200 // RFC 3550, 6.4.1 + TypeReceiverReport PacketType = 201 // RFC 3550, 6.4.2 + TypeSourceDescription PacketType = 202 // RFC 3550, 6.5 + TypeGoodbye PacketType = 203 // RFC 3550, 6.6 + TypeApplicationDefined PacketType = 204 // RFC 3550, 6.7 (unimplemented) + TypePayloadSpecificFeedback PacketType = 206 // RFC 4585, 6.3 + ) func (p PacketType) String() string { @@ -28,6 +30,8 @@ func (p PacketType) String() string { return "BYE" case TypeApplicationDefined: return "APP" + case TypePayloadSpecificFeedback: + return "PSFB" default: return string(p) } @@ -41,7 +45,7 @@ type Header struct { // some additional padding octets at the end which are not part of // the control information but are included in the length field. Padding bool - // The number of reception reports or sources contained in this packet (depending on the Type) + // The number of reception reports, sources contained or FMT in this packet (depending on the Type) Count uint8 // The RTCP packet type for this packet Type PacketType diff --git a/pkg/rtcp/packet.go b/pkg/rtcp/packet.go new file mode 100644 index 00000000..4a97a447 --- /dev/null +++ b/pkg/rtcp/packet.go @@ -0,0 +1,7 @@ +package rtcp + +// Packet represents an RTCP packet, a protocol used for out-of-band statistics and control information for an RTP session +type Packet interface { + Marshal() ([]byte, error) + Unmarshal(rawPacket []byte) error +} diff --git a/rtcpeerconnection.go b/rtcpeerconnection.go index b8707456..f9c10be1 100644 --- a/rtcpeerconnection.go +++ b/rtcpeerconnection.go @@ -18,6 +18,7 @@ import ( "github.com/pions/webrtc/pkg/ice" "github.com/pions/webrtc/pkg/media" "github.com/pions/webrtc/pkg/rtcerr" + "github.com/pions/webrtc/pkg/rtcp" "github.com/pions/webrtc/pkg/rtp" "github.com/pkg/errors" ) @@ -719,6 +720,17 @@ func (pc *RTCPeerConnection) SetIdentityProvider(provider string) error { return errors.Errorf("TODO SetIdentityProvider") } +// SendRTCP sends a user provided RTCP packet to the connected peer +// If no peer is connected the packet is discarded +func (pc *RTCPeerConnection) SendRTCP(pkt rtcp.Packet) error { + raw, err := pkt.Marshal() + if err != nil { + return err + } + pc.networkManager.SendRTCP(raw) + return nil +} + // Close ends the RTCPeerConnection func (pc *RTCPeerConnection) Close() error { pc.networkManager.Close()