263 lines
5.3 KiB
Go
263 lines
5.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"net"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/aler9/gortsplib"
|
|
"github.com/pion/rtcp"
|
|
"github.com/pion/sdp"
|
|
)
|
|
|
|
func parseIpCidrList(in []string) ([]interface{}, error) {
|
|
if len(in) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
var ret []interface{}
|
|
for _, t := range in {
|
|
_, ipnet, err := net.ParseCIDR(t)
|
|
if err == nil {
|
|
ret = append(ret, ipnet)
|
|
continue
|
|
}
|
|
|
|
ip := net.ParseIP(t)
|
|
if ip != nil {
|
|
ret = append(ret, ip)
|
|
continue
|
|
}
|
|
|
|
return nil, fmt.Errorf("unable to parse ip/network '%s'", t)
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
func ipEqualOrInRange(ip net.IP, ips []interface{}) bool {
|
|
for _, item := range ips {
|
|
switch titem := item.(type) {
|
|
case net.IP:
|
|
if titem.Equal(ip) {
|
|
return true
|
|
}
|
|
|
|
case *net.IPNet:
|
|
if titem.Contains(ip) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type doubleBuffer struct {
|
|
buf1 []byte
|
|
buf2 []byte
|
|
curBuf bool
|
|
}
|
|
|
|
func newDoubleBuffer(size int) *doubleBuffer {
|
|
return &doubleBuffer{
|
|
buf1: make([]byte, size),
|
|
buf2: make([]byte, size),
|
|
}
|
|
}
|
|
|
|
func (db *doubleBuffer) swap() []byte {
|
|
var ret []byte
|
|
if !db.curBuf {
|
|
ret = db.buf1
|
|
} else {
|
|
ret = db.buf2
|
|
}
|
|
db.curBuf = !db.curBuf
|
|
return ret
|
|
}
|
|
|
|
type rtcpReceiverEvent interface {
|
|
isRtpReceiverEvent()
|
|
}
|
|
|
|
type rtcpReceiverEventFrameRtp struct {
|
|
sequenceNumber uint16
|
|
}
|
|
|
|
func (rtcpReceiverEventFrameRtp) isRtpReceiverEvent() {}
|
|
|
|
type rtcpReceiverEventFrameRtcp struct {
|
|
ssrc uint32
|
|
ntpTimeMiddle uint32
|
|
}
|
|
|
|
func (rtcpReceiverEventFrameRtcp) isRtpReceiverEvent() {}
|
|
|
|
type rtcpReceiverEventLastFrameTime struct {
|
|
res chan time.Time
|
|
}
|
|
|
|
func (rtcpReceiverEventLastFrameTime) isRtpReceiverEvent() {}
|
|
|
|
type rtcpReceiverEventReport struct {
|
|
res chan []byte
|
|
}
|
|
|
|
func (rtcpReceiverEventReport) isRtpReceiverEvent() {}
|
|
|
|
type rtcpReceiverEventTerminate struct{}
|
|
|
|
func (rtcpReceiverEventTerminate) isRtpReceiverEvent() {}
|
|
|
|
type rtcpReceiver struct {
|
|
events chan rtcpReceiverEvent
|
|
done chan struct{}
|
|
}
|
|
|
|
func newRtcpReceiver() *rtcpReceiver {
|
|
rr := &rtcpReceiver{
|
|
events: make(chan rtcpReceiverEvent),
|
|
done: make(chan struct{}),
|
|
}
|
|
go rr.run()
|
|
return rr
|
|
}
|
|
|
|
func (rr *rtcpReceiver) run() {
|
|
lastFrameTime := time.Now()
|
|
publisherSSRC := uint32(0)
|
|
receiverSSRC := rand.Uint32()
|
|
sequenceNumberCycles := uint16(0)
|
|
lastSequenceNumber := uint16(0)
|
|
lastSenderReport := uint32(0)
|
|
|
|
outer:
|
|
for rawEvt := range rr.events {
|
|
switch evt := rawEvt.(type) {
|
|
case rtcpReceiverEventFrameRtp:
|
|
if evt.sequenceNumber < lastSequenceNumber {
|
|
sequenceNumberCycles += 1
|
|
}
|
|
lastSequenceNumber = evt.sequenceNumber
|
|
lastFrameTime = time.Now()
|
|
|
|
case rtcpReceiverEventFrameRtcp:
|
|
publisherSSRC = evt.ssrc
|
|
lastSenderReport = evt.ntpTimeMiddle
|
|
|
|
case rtcpReceiverEventLastFrameTime:
|
|
evt.res <- lastFrameTime
|
|
|
|
case rtcpReceiverEventReport:
|
|
rr := &rtcp.ReceiverReport{
|
|
SSRC: receiverSSRC,
|
|
Reports: []rtcp.ReceptionReport{
|
|
{
|
|
SSRC: publisherSSRC,
|
|
LastSequenceNumber: uint32(sequenceNumberCycles)<<8 | uint32(lastSequenceNumber),
|
|
LastSenderReport: lastSenderReport,
|
|
},
|
|
},
|
|
}
|
|
frame, _ := rr.Marshal()
|
|
evt.res <- frame
|
|
|
|
case rtcpReceiverEventTerminate:
|
|
break outer
|
|
}
|
|
}
|
|
|
|
close(rr.events)
|
|
|
|
close(rr.done)
|
|
}
|
|
|
|
func (rr *rtcpReceiver) close() {
|
|
rr.events <- rtcpReceiverEventTerminate{}
|
|
<-rr.done
|
|
}
|
|
|
|
func (rr *rtcpReceiver) onFrame(streamType gortsplib.StreamType, buf []byte) {
|
|
if streamType == gortsplib.StreamTypeRtp {
|
|
// extract sequence number of first frame
|
|
if len(buf) >= 3 {
|
|
sequenceNumber := uint16(uint16(buf[2])<<8 | uint16(buf[1]))
|
|
rr.events <- rtcpReceiverEventFrameRtp{sequenceNumber}
|
|
}
|
|
|
|
} else {
|
|
frames, err := rtcp.Unmarshal(buf)
|
|
if err == nil {
|
|
for _, frame := range frames {
|
|
if senderReport, ok := (frame).(*rtcp.SenderReport); ok {
|
|
rr.events <- rtcpReceiverEventFrameRtcp{
|
|
senderReport.SSRC,
|
|
uint32(senderReport.NTPTime >> 16),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (rr *rtcpReceiver) lastFrameTime() time.Time {
|
|
res := make(chan time.Time)
|
|
rr.events <- rtcpReceiverEventLastFrameTime{res}
|
|
return <-res
|
|
}
|
|
|
|
func (rr *rtcpReceiver) report() []byte {
|
|
res := make(chan []byte)
|
|
rr.events <- rtcpReceiverEventReport{res}
|
|
return <-res
|
|
}
|
|
|
|
func sdpForServer(sin *sdp.SessionDescription) (*sdp.SessionDescription, []byte) {
|
|
sout := &sdp.SessionDescription{
|
|
SessionName: "Stream",
|
|
Origin: sdp.Origin{
|
|
Username: "-",
|
|
NetworkType: "IN",
|
|
AddressType: "IP4",
|
|
UnicastAddress: "127.0.0.1",
|
|
},
|
|
TimeDescriptions: []sdp.TimeDescription{
|
|
{Timing: sdp.Timing{0, 0}},
|
|
},
|
|
}
|
|
|
|
for i, min := range sin.MediaDescriptions {
|
|
mout := &sdp.MediaDescription{
|
|
MediaName: sdp.MediaName{
|
|
Media: min.MediaName.Media,
|
|
Protos: []string{"RTP", "AVP"}, // override protocol
|
|
Formats: min.MediaName.Formats,
|
|
},
|
|
Bandwidth: min.Bandwidth,
|
|
Attributes: func() []sdp.Attribute {
|
|
var ret []sdp.Attribute
|
|
|
|
for _, attr := range min.Attributes {
|
|
if attr.Key == "rtpmap" || attr.Key == "fmtp" {
|
|
ret = append(ret, attr)
|
|
}
|
|
}
|
|
|
|
// control attribute is mandatory, and is the path that is appended
|
|
// to the stream path in SETUP
|
|
ret = append(ret, sdp.Attribute{
|
|
Key: "control",
|
|
Value: "trackID=" + strconv.FormatInt(int64(i), 10),
|
|
})
|
|
|
|
return ret
|
|
}(),
|
|
}
|
|
sout.MediaDescriptions = append(sout.MediaDescriptions, mout)
|
|
}
|
|
|
|
bytsout := []byte(sout.Marshal())
|
|
return sout, bytsout
|
|
}
|