mirror of
https://github.com/pion/webrtc.git
synced 2025-10-30 10:16:36 +08:00
*Avoid a type switch in srtp.go
*Add support for transport layer nack and
slice loss indication messages
*Add String() functions for several RTCP
packets to aid in debugging
*Add support for transparent profile
extensions to ReceiverReport messages
Relates to #119
142 lines
3.4 KiB
Go
142 lines
3.4 KiB
Go
package network
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/pions/webrtc/internal/srtp"
|
|
"github.com/pions/webrtc/pkg/rtcp"
|
|
"github.com/pions/webrtc/pkg/rtp"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
const (
|
|
srtpMasterKeyLen = 16
|
|
srtpMasterKeySaltLen = 14
|
|
)
|
|
|
|
// TODO: Migrate to srtp.Conn
|
|
|
|
// CreateContextSRTP takes the exported keying material from DTLS and creates Client/Server contexts
|
|
func (m *Manager) CreateContextSRTP(keyingMaterial []byte) error {
|
|
offset := 0
|
|
|
|
clientWriteKey := append([]byte{}, keyingMaterial[offset:offset+srtpMasterKeyLen]...)
|
|
offset += srtpMasterKeyLen
|
|
|
|
serverWriteKey := append([]byte{}, keyingMaterial[offset:offset+srtpMasterKeyLen]...)
|
|
offset += srtpMasterKeyLen
|
|
|
|
clientWriteKey = append(clientWriteKey, keyingMaterial[offset:offset+srtpMasterKeySaltLen]...)
|
|
offset += srtpMasterKeySaltLen
|
|
|
|
serverWriteKey = append(serverWriteKey, keyingMaterial[offset:offset+srtpMasterKeySaltLen]...)
|
|
|
|
var err error
|
|
m.srtpInboundContextLock.Lock()
|
|
m.srtpInboundContext, err = srtp.CreateContext(serverWriteKey[0:16], serverWriteKey[16:] /* Profile */, "")
|
|
m.srtpInboundContextLock.Unlock()
|
|
if err != nil {
|
|
return errors.New("failed to build inbound SRTP context")
|
|
}
|
|
|
|
m.srtpOutboundContextLock.Lock()
|
|
m.srtpOutboundContext, err = srtp.CreateContext(clientWriteKey[0:16], clientWriteKey[16:] /* Profile */, "")
|
|
m.srtpOutboundContextLock.Unlock()
|
|
if err != nil {
|
|
return errors.New("failed to build outbound SRTP context")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func handleRTCP(getBufferTransports func(uint32) *TransportPair, buffer []byte) {
|
|
//decrypted packets can also be compound packets, so we have to nest our reader loop here.
|
|
compoundPacket := rtcp.NewReader(bytes.NewReader(buffer))
|
|
for {
|
|
_, rawrtcp, err := compoundPacket.ReadPacket()
|
|
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
|
|
var report rtcp.Packet
|
|
report, _, err = rtcp.Unmarshal(rawrtcp)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return
|
|
}
|
|
|
|
f := func(ssrc uint32) {
|
|
bufferTransport := getBufferTransports(ssrc)
|
|
if bufferTransport != nil && bufferTransport.RTCP != nil {
|
|
select {
|
|
case bufferTransport.RTCP <- report:
|
|
default:
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, ssrc := range report.DestinationSSRC() {
|
|
f(ssrc)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (m *Manager) handleSRTP(buffer []byte) {
|
|
m.srtpInboundContextLock.Lock()
|
|
defer m.srtpInboundContextLock.Unlock()
|
|
if m.srtpInboundContext == nil {
|
|
fmt.Printf("Got RTP packet but no SRTP Context to handle it \n")
|
|
return
|
|
}
|
|
|
|
if len(buffer) > 4 {
|
|
var rtcpPacketType uint8
|
|
|
|
r := bytes.NewReader([]byte{buffer[1]})
|
|
if err := binary.Read(r, binary.BigEndian, &rtcpPacketType); err != nil {
|
|
fmt.Println("Failed to check packet for RTCP")
|
|
return
|
|
}
|
|
|
|
if rtcpPacketType >= 192 && rtcpPacketType <= 223 {
|
|
decrypted, err := m.srtpInboundContext.DecryptRTCP(buffer)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
fmt.Println(decrypted)
|
|
return
|
|
}
|
|
|
|
handleRTCP(m.getBufferTransports, decrypted)
|
|
return
|
|
}
|
|
}
|
|
|
|
packet := &rtp.Packet{}
|
|
if err := packet.Unmarshal(buffer); err != nil {
|
|
fmt.Println("Failed to unmarshal RTP packet")
|
|
return
|
|
}
|
|
|
|
if ok := m.srtpInboundContext.DecryptRTP(packet); !ok {
|
|
fmt.Println("Failed to decrypt packet")
|
|
return
|
|
}
|
|
|
|
bufferTransport := m.getOrCreateBufferTransports(packet.SSRC, packet.PayloadType)
|
|
if bufferTransport != nil && bufferTransport.RTP != nil {
|
|
select {
|
|
case bufferTransport.RTP <- packet:
|
|
default:
|
|
}
|
|
}
|
|
|
|
}
|