145 lines
2.9 KiB
Go
145 lines
2.9 KiB
Go
package core
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/bluenviron/gortsplib/v3/pkg/formats"
|
|
"github.com/bluenviron/gortsplib/v3/pkg/media"
|
|
"github.com/pion/rtcp"
|
|
"github.com/pion/webrtc/v3"
|
|
)
|
|
|
|
const (
|
|
keyFrameInterval = 2 * time.Second
|
|
)
|
|
|
|
type webRTCIncomingTrack struct {
|
|
track *webrtc.TrackRemote
|
|
receiver *webrtc.RTPReceiver
|
|
writeRTCP func([]rtcp.Packet) error
|
|
|
|
mediaType media.Type
|
|
format formats.Format
|
|
media *media.Media
|
|
}
|
|
|
|
func newWebRTCIncomingTrack(
|
|
track *webrtc.TrackRemote,
|
|
receiver *webrtc.RTPReceiver,
|
|
writeRTCP func([]rtcp.Packet) error,
|
|
) (*webRTCIncomingTrack, error) {
|
|
t := &webRTCIncomingTrack{
|
|
track: track,
|
|
receiver: receiver,
|
|
writeRTCP: writeRTCP,
|
|
}
|
|
|
|
switch strings.ToLower(track.Codec().MimeType) {
|
|
case strings.ToLower(webrtc.MimeTypeAV1):
|
|
t.mediaType = media.TypeVideo
|
|
t.format = &formats.AV1{
|
|
PayloadTyp: uint8(track.PayloadType()),
|
|
}
|
|
|
|
case strings.ToLower(webrtc.MimeTypeVP9):
|
|
t.mediaType = media.TypeVideo
|
|
t.format = &formats.VP9{
|
|
PayloadTyp: uint8(track.PayloadType()),
|
|
}
|
|
|
|
case strings.ToLower(webrtc.MimeTypeVP8):
|
|
t.mediaType = media.TypeVideo
|
|
t.format = &formats.VP8{
|
|
PayloadTyp: uint8(track.PayloadType()),
|
|
}
|
|
|
|
case strings.ToLower(webrtc.MimeTypeH264):
|
|
t.mediaType = media.TypeVideo
|
|
t.format = &formats.H264{
|
|
PayloadTyp: uint8(track.PayloadType()),
|
|
PacketizationMode: 1,
|
|
}
|
|
|
|
case strings.ToLower(webrtc.MimeTypeOpus):
|
|
t.mediaType = media.TypeAudio
|
|
t.format = &formats.Opus{
|
|
PayloadTyp: uint8(track.PayloadType()),
|
|
}
|
|
|
|
case strings.ToLower(webrtc.MimeTypeG722):
|
|
t.mediaType = media.TypeAudio
|
|
t.format = &formats.G722{}
|
|
|
|
case strings.ToLower(webrtc.MimeTypePCMU):
|
|
t.mediaType = media.TypeAudio
|
|
t.format = &formats.G711{
|
|
MULaw: true,
|
|
}
|
|
|
|
case strings.ToLower(webrtc.MimeTypePCMA):
|
|
t.mediaType = media.TypeAudio
|
|
t.format = &formats.G711{
|
|
MULaw: false,
|
|
}
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unsupported codec: %v", track.Codec())
|
|
}
|
|
|
|
t.media = &media.Media{
|
|
Type: t.mediaType,
|
|
Formats: []formats.Format{t.format},
|
|
}
|
|
|
|
return t, nil
|
|
}
|
|
|
|
func (t *webRTCIncomingTrack) start(stream *stream) {
|
|
go func() {
|
|
for {
|
|
pkt, _, err := t.track.ReadRTP()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// sometimes Chrome sends empty RTP packets. ignore them.
|
|
if len(pkt.Payload) == 0 {
|
|
continue
|
|
}
|
|
|
|
stream.writeRTPPacket(t.media, t.format, pkt, time.Now())
|
|
}
|
|
}()
|
|
|
|
// read incoming RTCP packets to make interceptors work
|
|
go func() {
|
|
buf := make([]byte, 1500)
|
|
for {
|
|
_, _, err := t.receiver.Read(buf)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
if t.mediaType == media.TypeVideo {
|
|
go func() {
|
|
keyframeTicker := time.NewTicker(keyFrameInterval)
|
|
defer keyframeTicker.Stop()
|
|
|
|
for range keyframeTicker.C {
|
|
err := t.writeRTCP([]rtcp.Packet{
|
|
&rtcp.PictureLossIndication{
|
|
MediaSSRC: uint32(t.track.SSRC()),
|
|
},
|
|
})
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
}
|