Fix buggy SDP parsing
This commit is contained in:
+30
-5
@@ -4,8 +4,10 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||||
"github.com/pion/rtcp"
|
"github.com/pion/rtcp"
|
||||||
|
"github.com/pion/sdp/v3"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,8 +23,8 @@ s=-
|
|||||||
t=0 0`
|
t=0 0`
|
||||||
|
|
||||||
func UnmarshalSDP(rawSDP []byte) ([]*streamer.Media, error) {
|
func UnmarshalSDP(rawSDP []byte) ([]*streamer.Media, error) {
|
||||||
medias, err := streamer.UnmarshalSDP(rawSDP)
|
sd := &sdp.SessionDescription{}
|
||||||
if err != nil {
|
if err := sd.Unmarshal(rawSDP); err != nil {
|
||||||
// fix multiple `s=` https://github.com/AlexxIT/WebRTC/issues/417
|
// fix multiple `s=` https://github.com/AlexxIT/WebRTC/issues/417
|
||||||
re, _ := regexp.Compile("\ns=[^\n]+")
|
re, _ := regexp.Compile("\ns=[^\n]+")
|
||||||
rawSDP = re.ReplaceAll(rawSDP, nil)
|
rawSDP = re.ReplaceAll(rawSDP, nil)
|
||||||
@@ -30,16 +32,28 @@ func UnmarshalSDP(rawSDP []byte) ([]*streamer.Media, error) {
|
|||||||
// fix SDP header for some cameras
|
// fix SDP header for some cameras
|
||||||
if i := bytes.Index(rawSDP, []byte("\nm=")); i > 0 {
|
if i := bytes.Index(rawSDP, []byte("\nm=")); i > 0 {
|
||||||
rawSDP = append([]byte(sdpHeader), rawSDP[i:]...)
|
rawSDP = append([]byte(sdpHeader), rawSDP[i:]...)
|
||||||
medias, err = streamer.UnmarshalSDP(rawSDP)
|
sd = &sdp.SessionDescription{}
|
||||||
|
err = sd.Unmarshal(rawSDP)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix bug in ONVIF spec
|
medias := streamer.UnmarshalMedias(sd.MediaDescriptions)
|
||||||
// https://www.onvif.org/specs/stream/ONVIF-Streaming-Spec-v241.pdf
|
|
||||||
for _, media := range medias {
|
for _, media := range medias {
|
||||||
|
// Check buggy SDP with fmtp for H264 on another track
|
||||||
|
// https://github.com/AlexxIT/WebRTC/issues/419
|
||||||
|
for _, codec := range media.Codecs {
|
||||||
|
if codec.Name == streamer.CodecH264 && codec.FmtpLine == "" {
|
||||||
|
codec.FmtpLine = findFmtpLine(codec.PayloadType, sd.MediaDescriptions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix bug in ONVIF spec
|
||||||
|
// https://www.onvif.org/specs/stream/ONVIF-Streaming-Spec-v241.pdf
|
||||||
switch media.Direction {
|
switch media.Direction {
|
||||||
case streamer.DirectionRecvonly, "":
|
case streamer.DirectionRecvonly, "":
|
||||||
media.Direction = streamer.DirectionSendonly
|
media.Direction = streamer.DirectionSendonly
|
||||||
@@ -51,6 +65,17 @@ func UnmarshalSDP(rawSDP []byte) ([]*streamer.Media, error) {
|
|||||||
return medias, nil
|
return medias, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findFmtpLine(payloadType uint8, descriptions []*sdp.MediaDescription) string {
|
||||||
|
s := strconv.Itoa(int(payloadType))
|
||||||
|
for _, md := range descriptions {
|
||||||
|
codec := streamer.UnmarshalCodec(md, s)
|
||||||
|
if codec.FmtpLine != "" {
|
||||||
|
return codec.FmtpLine
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// urlParse fix bugs:
|
// urlParse fix bugs:
|
||||||
// 1. Content-Base: rtsp://::ffff:192.168.1.123/onvif/profile.1/
|
// 1. Content-Base: rtsp://::ffff:192.168.1.123/onvif/profile.1/
|
||||||
// 2. Content-Base: rtsp://rtsp://turret2-cam.lan:554/stream1/
|
// 2. Content-Base: rtsp://rtsp://turret2-cam.lan:554/stream1/
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ func TestURLParse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMultipleSinSDP(t *testing.T) {
|
func TestMultipleSinSDP(t *testing.T) {
|
||||||
|
// https://github.com/AlexxIT/WebRTC/issues/417
|
||||||
s := `v=0
|
s := `v=0
|
||||||
o=- 91674849066 1 IN IP4 192.168.1.123
|
o=- 91674849066 1 IN IP4 192.168.1.123
|
||||||
s=RtspServer
|
s=RtspServer
|
||||||
@@ -50,3 +51,25 @@ a=control:track1
|
|||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.NotNil(t, medias)
|
assert.NotNil(t, medias)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFindFmtp(t *testing.T) {
|
||||||
|
// https://github.com/AlexxIT/WebRTC/issues/419
|
||||||
|
s := `v=0
|
||||||
|
o=- 1675628282 1675628283 IN IP4 192.168.1.123
|
||||||
|
s=streamed by the RTSP server
|
||||||
|
t=0 0
|
||||||
|
m=video 0 RTP/AVP 96
|
||||||
|
a=rtpmap:96 H264/90000
|
||||||
|
a=control:track0
|
||||||
|
m=audio 0 RTP/AVP 8
|
||||||
|
a=rtpmap:0 pcma/8000/1
|
||||||
|
a=control:track1
|
||||||
|
a=framerate:25
|
||||||
|
a=range:npt=now-
|
||||||
|
a=fmtp:96 packetization-mode=1;profile-level-id=64001F;sprop-parameter-sets=Z0IAH5WoFAFuQA==,aM48gA==
|
||||||
|
`
|
||||||
|
medias, err := UnmarshalSDP([]byte(s))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.NotNil(t, medias)
|
||||||
|
assert.NotEqual(t, "", medias[0].Codecs[0].FmtpLine)
|
||||||
|
}
|
||||||
|
|||||||
@@ -166,14 +166,8 @@ func (c *Codec) Match(codec *Codec) bool {
|
|||||||
(c.Channels == codec.Channels || codec.Channels == 0)
|
(c.Channels == codec.Channels || codec.Channels == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnmarshalSDP(rawSDP []byte) ([]*Media, error) {
|
func UnmarshalMedias(descriptions []*sdp.MediaDescription) (medias []*Media) {
|
||||||
sd := &sdp.SessionDescription{}
|
for _, md := range descriptions {
|
||||||
if err := sd.Unmarshal(rawSDP); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var medias []*Media
|
|
||||||
for _, md := range sd.MediaDescriptions {
|
|
||||||
media := UnmarshalMedia(md)
|
media := UnmarshalMedia(md)
|
||||||
|
|
||||||
if media.Direction == DirectionSendRecv {
|
if media.Direction == DirectionSendRecv {
|
||||||
@@ -187,7 +181,7 @@ func UnmarshalSDP(rawSDP []byte) ([]*Media, error) {
|
|||||||
medias = append(medias, media)
|
medias = append(medias, media)
|
||||||
}
|
}
|
||||||
|
|
||||||
return medias, nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func MarshalSDP(name string, medias []*Media) ([]byte, error) {
|
func MarshalSDP(name string, medias []*Media) ([]byte, error) {
|
||||||
|
|||||||
+6
-2
@@ -2,6 +2,7 @@ package webrtc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||||
|
"github.com/pion/sdp/v3"
|
||||||
"github.com/pion/webrtc/v3"
|
"github.com/pion/webrtc/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -90,12 +91,15 @@ func (c *Conn) SetOffer(offer string) (err error) {
|
|||||||
if err = c.Conn.SetRemoteDescription(sdOffer); err != nil {
|
if err = c.Conn.SetRemoteDescription(sdOffer); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rawSDP := []byte(c.Conn.RemoteDescription().SDP)
|
rawSDP := []byte(c.Conn.RemoteDescription().SDP)
|
||||||
medias, err := streamer.UnmarshalSDP(rawSDP)
|
sd := &sdp.SessionDescription{}
|
||||||
if err != nil {
|
if err = sd.Unmarshal(rawSDP); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
medias := streamer.UnmarshalMedias(sd.MediaDescriptions)
|
||||||
|
|
||||||
// sort medias, so video will always be before audio
|
// sort medias, so video will always be before audio
|
||||||
// and ignore application media from Hass default lovelace card
|
// and ignore application media from Hass default lovelace card
|
||||||
for _, media := range medias {
|
for _, media := range medias {
|
||||||
|
|||||||
Reference in New Issue
Block a user