mirror of
https://github.com/aler9/gortsplib
synced 2025-09-26 19:21:20 +08:00
add Transport.Profile, media.Profile (#873)
this will allow to support AVPF in the future.
This commit is contained in:
85
client.go
85
client.go
@@ -202,9 +202,9 @@ func prepareForAnnounce(
|
||||
) error {
|
||||
for i, m := range desc.Medias {
|
||||
m.Control = "trackID=" + strconv.FormatInt(int64(i), 10)
|
||||
m.Secure = secure
|
||||
|
||||
if secure {
|
||||
m.Profile = headers.TransportProfileSAVP
|
||||
announceDataMedia := announceData[m]
|
||||
|
||||
ssrcs := make([]uint32, len(m.Formats))
|
||||
@@ -232,6 +232,8 @@ func prepareForAnnounce(
|
||||
}
|
||||
|
||||
m.KeyMgmtMikey = mikeyMsg
|
||||
} else {
|
||||
m.Profile = headers.TransportProfileAVP
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,8 +514,8 @@ type Client struct {
|
||||
lastDescribeDesc *description.Session
|
||||
baseURL *base.URL
|
||||
announceData map[*description.Media]*clientAnnounceDataMedia // record
|
||||
effectiveTransport *Transport
|
||||
effectiveSecure bool
|
||||
setuppedTransport *Transport
|
||||
setuppedProfile headers.TransportProfile
|
||||
backChannelSetupped bool
|
||||
stdChannelSetupped bool
|
||||
setuppedMedias map[*description.Media]*clientMedia
|
||||
@@ -973,7 +975,7 @@ func (c *Client) reset() {
|
||||
c.optionsSent = false
|
||||
c.useGetParameter = false
|
||||
c.baseURL = nil
|
||||
c.effectiveTransport = nil
|
||||
c.setuppedTransport = nil
|
||||
c.backChannelSetupped = false
|
||||
c.stdChannelSetupped = false
|
||||
c.setuppedMedias = nil
|
||||
@@ -1004,7 +1006,7 @@ func (c *Client) trySwitchingProtocol() error {
|
||||
c.reset()
|
||||
|
||||
v := TransportTCP
|
||||
c.effectiveTransport = &v
|
||||
c.setuppedTransport = &v
|
||||
|
||||
// some Hikvision cameras require a describe before a setup
|
||||
_, _, err := c.doDescribe(c.lastDescribeURL)
|
||||
@@ -1040,18 +1042,18 @@ func (c *Client) startTransportRoutines() {
|
||||
cm.start()
|
||||
}
|
||||
|
||||
if *c.effectiveTransport == TransportTCP {
|
||||
if *c.setuppedTransport == TransportTCP {
|
||||
c.tcpFrame = &base.InterleavedFrame{}
|
||||
c.tcpBuffer = make([]byte, c.MaxPacketSize+4)
|
||||
}
|
||||
|
||||
// always enable keepalives unless we are recording with TCP
|
||||
if c.state == clientStatePlay || *c.effectiveTransport != TransportTCP {
|
||||
if c.state == clientStatePlay || *c.setuppedTransport != TransportTCP {
|
||||
c.keepAliveTimer = time.NewTimer(c.keepAlivePeriod)
|
||||
}
|
||||
|
||||
if c.state == clientStatePlay && c.stdChannelSetupped {
|
||||
switch *c.effectiveTransport {
|
||||
switch *c.setuppedTransport {
|
||||
case TransportUDP:
|
||||
c.checkTimeoutTimer = time.NewTimer(c.InitialUDPReadTimeout)
|
||||
c.checkTimeoutInitial = true
|
||||
@@ -1066,7 +1068,7 @@ func (c *Client) startTransportRoutines() {
|
||||
}
|
||||
}
|
||||
|
||||
if *c.effectiveTransport == TransportTCP {
|
||||
if *c.setuppedTransport == TransportTCP {
|
||||
c.reader.setAllowInterleavedFrames(true)
|
||||
}
|
||||
}
|
||||
@@ -1281,8 +1283,8 @@ func (c *Client) isInTCPTimeout() bool {
|
||||
}
|
||||
|
||||
func (c *Client) doCheckTimeout() error {
|
||||
if *c.effectiveTransport == TransportUDP ||
|
||||
*c.effectiveTransport == TransportUDPMulticast {
|
||||
if *c.setuppedTransport == TransportUDP ||
|
||||
*c.setuppedTransport == TransportUDPMulticast {
|
||||
if c.checkTimeoutInitial && !c.backChannelSetupped && c.Transport == nil {
|
||||
c.checkTimeoutInitial = false
|
||||
|
||||
@@ -1586,20 +1588,30 @@ func (c *Client) doSetup(
|
||||
|
||||
switch {
|
||||
// use transport from previous SETUP calls
|
||||
case c.effectiveTransport != nil:
|
||||
transport = *c.effectiveTransport
|
||||
th.Secure = c.effectiveSecure
|
||||
case c.setuppedTransport != nil:
|
||||
transport = *c.setuppedTransport
|
||||
th.Profile = c.setuppedProfile
|
||||
|
||||
// use transport from config, secure flag from server
|
||||
case c.Transport != nil:
|
||||
transport = *c.Transport
|
||||
th.Secure = medi.Secure && c.Scheme == "rtsps"
|
||||
if isSecure(medi.Profile) && c.Scheme == "rtsps" {
|
||||
th.Profile = headers.TransportProfileSAVP
|
||||
} else {
|
||||
th.Profile = headers.TransportProfileAVP
|
||||
}
|
||||
|
||||
// try UDP if unencrypted or secure is supported by server, otherwise try TCP
|
||||
// try
|
||||
// - UDP if unencrypted or secure is supported by server
|
||||
// - otherwise, TCP
|
||||
default:
|
||||
th.Secure = medi.Secure && c.Scheme == "rtsps"
|
||||
if isSecure(medi.Profile) && c.Scheme == "rtsps" {
|
||||
th.Profile = headers.TransportProfileSAVP
|
||||
} else {
|
||||
th.Profile = headers.TransportProfileAVP
|
||||
}
|
||||
|
||||
if th.Secure || c.Scheme == "rtsp" {
|
||||
if th.Profile == headers.TransportProfileSAVP || c.Scheme == "rtsp" {
|
||||
transport = TransportUDP
|
||||
} else {
|
||||
transport = TransportTCP
|
||||
@@ -1609,7 +1621,7 @@ func (c *Client) doSetup(
|
||||
cm := &clientMedia{
|
||||
c: c,
|
||||
media: medi,
|
||||
secure: th.Secure,
|
||||
secure: isSecure(th.Profile),
|
||||
}
|
||||
err = cm.initialize()
|
||||
if err != nil {
|
||||
@@ -1618,7 +1630,7 @@ func (c *Client) doSetup(
|
||||
|
||||
switch transport {
|
||||
case TransportUDP, TransportUDPMulticast:
|
||||
if c.Scheme == "rtsps" && !th.Secure {
|
||||
if c.Scheme == "rtsps" && !isSecure(th.Profile) {
|
||||
cm.close()
|
||||
return nil, fmt.Errorf("unable to setup secure UDP")
|
||||
}
|
||||
@@ -1683,7 +1695,7 @@ func (c *Client) doSetup(
|
||||
header["Require"] = base.HeaderValue{"www.onvif.org/ver20/backchannel"}
|
||||
}
|
||||
|
||||
if th.Secure {
|
||||
if isSecure(th.Profile) {
|
||||
ssrcs := make([]uint32, len(cm.formats))
|
||||
n := 0
|
||||
for _, cf := range cm.formats {
|
||||
@@ -1726,11 +1738,11 @@ func (c *Client) doSetup(
|
||||
|
||||
// switch transport automatically
|
||||
if res.StatusCode == base.StatusUnsupportedTransport &&
|
||||
c.effectiveTransport == nil && c.Transport == nil {
|
||||
c.setuppedTransport == nil && c.Transport == nil {
|
||||
c.OnTransportSwitch(liberrors.ErrClientSwitchToTCP2{})
|
||||
v := TransportTCP
|
||||
c.effectiveTransport = &v
|
||||
c.effectiveSecure = th.Secure
|
||||
c.setuppedTransport = &v
|
||||
c.setuppedProfile = th.Profile
|
||||
|
||||
return c.doSetup(baseURL, medi, 0, 0)
|
||||
}
|
||||
@@ -1751,7 +1763,7 @@ func (c *Client) doSetup(
|
||||
cm.close()
|
||||
|
||||
// switch transport automatically
|
||||
if c.effectiveTransport == nil && c.Transport == nil {
|
||||
if c.setuppedTransport == nil && c.Transport == nil {
|
||||
c.OnTransportSwitch(liberrors.ErrClientSwitchToTCP2{})
|
||||
|
||||
c.baseURL = baseURL
|
||||
@@ -1759,8 +1771,8 @@ func (c *Client) doSetup(
|
||||
c.reset()
|
||||
|
||||
v := TransportTCP
|
||||
c.effectiveTransport = &v
|
||||
c.effectiveSecure = th.Secure
|
||||
c.setuppedTransport = &v
|
||||
c.setuppedProfile = th.Profile
|
||||
|
||||
// some Hikvision cameras require a describe before a setup
|
||||
_, _, err = c.doDescribe(c.lastDescribeURL)
|
||||
@@ -1906,12 +1918,12 @@ func (c *Client) doSetup(
|
||||
cm.tcpChannel = thRes.InterleavedIDs[0]
|
||||
}
|
||||
|
||||
if cm.secure {
|
||||
if !thRes.Secure {
|
||||
cm.close()
|
||||
return nil, fmt.Errorf("transport was not setupped securely")
|
||||
}
|
||||
if thRes.Profile != th.Profile {
|
||||
cm.close()
|
||||
return nil, fmt.Errorf("returned profile does not match requested profile")
|
||||
}
|
||||
|
||||
if cm.secure {
|
||||
var mikeyMsg *mikey.Message
|
||||
|
||||
// extract key-mgmt from (in order of priority):
|
||||
@@ -1943,9 +1955,6 @@ func (c *Client) doSetup(
|
||||
cm.close()
|
||||
return nil, err
|
||||
}
|
||||
} else if thRes.Secure {
|
||||
cm.close()
|
||||
return nil, fmt.Errorf("received unexpected secure profile")
|
||||
}
|
||||
|
||||
if c.setuppedMedias == nil {
|
||||
@@ -1955,8 +1964,8 @@ func (c *Client) doSetup(
|
||||
c.setuppedMedias[medi] = cm
|
||||
|
||||
c.baseURL = baseURL
|
||||
c.effectiveTransport = &transport
|
||||
c.effectiveSecure = th.Secure
|
||||
c.setuppedTransport = &transport
|
||||
c.setuppedProfile = th.Profile
|
||||
|
||||
if medi.IsBackChannel {
|
||||
c.backChannelSetupped = true
|
||||
@@ -2057,7 +2066,7 @@ func (c *Client) doPlay(ra *headers.Range) (*base.Response, error) {
|
||||
// when protocol is UDP,
|
||||
// open the firewall by sending empty packets to the remote part.
|
||||
// do this before sending the PLAY request.
|
||||
if *c.effectiveTransport == TransportUDP {
|
||||
if *c.setuppedTransport == TransportUDP {
|
||||
for _, cm := range c.setuppedMedias {
|
||||
if !cm.media.IsBackChannel && cm.udpRTPListener.writeAddr != nil {
|
||||
buf, _ := (&rtp.Packet{Header: rtp.Header{Version: 2}}).Marshal()
|
||||
|
@@ -399,11 +399,11 @@ func TestClientPlay(t *testing.T) {
|
||||
h := base.Header{}
|
||||
|
||||
th := headers.Transport{
|
||||
Secure: inTH.Secure,
|
||||
Profile: inTH.Profile,
|
||||
}
|
||||
|
||||
if ca.secure == "secure" {
|
||||
require.True(t, inTH.Secure)
|
||||
require.Equal(t, headers.TransportProfileSAVP, inTH.Profile)
|
||||
|
||||
var keyMgmt headers.KeyMgmt
|
||||
err2 = keyMgmt.Unmarshal(req.Header["KeyMgmt"])
|
||||
|
@@ -213,7 +213,7 @@ func TestClientRecord(t *testing.T) {
|
||||
require.NoError(t, err2)
|
||||
|
||||
if ca.secure == "secure" {
|
||||
require.True(t, desc2.Medias[0].Secure)
|
||||
require.Equal(t, headers.TransportProfileSAVP, desc2.Medias[0].Profile)
|
||||
|
||||
_, err = mikeyToContext(desc2.Medias[0].KeyMgmtMikey)
|
||||
require.NoError(t, err)
|
||||
@@ -257,16 +257,14 @@ func TestClientRecord(t *testing.T) {
|
||||
|
||||
th := headers.Transport{
|
||||
Delivery: deliveryPtr(headers.TransportDeliveryUnicast),
|
||||
Secure: inTH.Secure,
|
||||
Profile: inTH.Profile,
|
||||
}
|
||||
|
||||
var srtpInCtx *wrappedSRTPContext
|
||||
var srtpOutCtx *wrappedSRTPContext
|
||||
|
||||
if ca.secure == "secure" {
|
||||
th.Secure = true
|
||||
|
||||
require.True(t, th.Secure)
|
||||
require.Equal(t, inTH.Profile, headers.TransportProfileSAVP)
|
||||
|
||||
var keyMgmt headers.KeyMgmt
|
||||
err = keyMgmt.Unmarshal(req.Header["KeyMgmt"])
|
||||
|
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/base"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/format"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/headers"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/mikey"
|
||||
)
|
||||
|
||||
@@ -78,15 +79,20 @@ type Media struct {
|
||||
// Whether this media is a back channel.
|
||||
IsBackChannel bool
|
||||
|
||||
// Control attribute.
|
||||
Control string
|
||||
|
||||
// Whether the transport is secure.
|
||||
//
|
||||
// Deprecated: replaced by Profile
|
||||
Secure bool
|
||||
|
||||
// RTP Profile.
|
||||
Profile headers.TransportProfile
|
||||
|
||||
// key-mgmt attribute.
|
||||
KeyMgmtMikey *mikey.Message
|
||||
|
||||
// Control attribute.
|
||||
Control string
|
||||
|
||||
// Formats contained into the media.
|
||||
Formats []format.Format
|
||||
}
|
||||
@@ -101,8 +107,14 @@ func (m *Media) Unmarshal(md *psdp.MediaDescription) error {
|
||||
}
|
||||
|
||||
m.IsBackChannel = isBackChannel(md.Attributes)
|
||||
m.Control = getAttribute(md.Attributes, "control")
|
||||
m.Secure = slices.Contains(md.MediaName.Protos, "SAVP")
|
||||
|
||||
if slices.Contains(md.MediaName.Protos, "SAVP") {
|
||||
m.Secure = true
|
||||
m.Profile = headers.TransportProfileSAVP
|
||||
} else {
|
||||
m.Secure = false
|
||||
m.Profile = headers.TransportProfileAVP
|
||||
}
|
||||
|
||||
if enc := getAttribute(md.Attributes, "key-mgmt"); enc != "" {
|
||||
if !strings.HasPrefix(enc, "mikey ") {
|
||||
@@ -121,6 +133,8 @@ func (m *Media) Unmarshal(md *psdp.MediaDescription) error {
|
||||
}
|
||||
}
|
||||
|
||||
m.Control = getAttribute(md.Attributes, "control")
|
||||
|
||||
m.Formats = nil
|
||||
|
||||
for _, payloadType := range md.MediaName.Formats {
|
||||
@@ -152,11 +166,16 @@ func (m Media) Marshal() *psdp.MediaDescription {
|
||||
|
||||
// Marshal2 encodes the media in SDP format.
|
||||
func (m Media) Marshal2() (*psdp.MediaDescription, error) {
|
||||
if m.Secure {
|
||||
m.Profile = headers.TransportProfileSAVP
|
||||
}
|
||||
|
||||
var protos []string
|
||||
if !m.Secure {
|
||||
protos = []string{"RTP", "AVP"}
|
||||
} else {
|
||||
|
||||
if m.Profile == headers.TransportProfileSAVP {
|
||||
protos = []string{"RTP", "SAVP"}
|
||||
} else {
|
||||
protos = []string{"RTP", "AVP"}
|
||||
}
|
||||
|
||||
md := &psdp.MediaDescription{
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/format"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/headers"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/mikey"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/sdp"
|
||||
)
|
||||
@@ -726,6 +727,7 @@ var casesSession = []struct {
|
||||
Type: "video",
|
||||
Control: "trackID=0",
|
||||
Secure: true,
|
||||
Profile: headers.TransportProfileSAVP,
|
||||
Formats: []format.Format{&format.H264{
|
||||
PayloadTyp: 96,
|
||||
}},
|
||||
@@ -762,6 +764,7 @@ var casesSession = []struct {
|
||||
Type: "video",
|
||||
Control: "trackID=0",
|
||||
Secure: true,
|
||||
Profile: headers.TransportProfileSAVP,
|
||||
KeyMgmtMikey: &mikey.Message{ //nolint:dupl
|
||||
Header: mikey.Header{
|
||||
Version: 1,
|
||||
|
@@ -38,6 +38,15 @@ func parsePorts(val string) (*[2]int, error) {
|
||||
return &[2]int{0, 0}, fmt.Errorf("invalid ports (%v)", val)
|
||||
}
|
||||
|
||||
// TransportProfile is a transport profile.
|
||||
type TransportProfile int
|
||||
|
||||
// transport profiles.
|
||||
const (
|
||||
TransportProfileAVP TransportProfile = iota
|
||||
TransportProfileSAVP
|
||||
)
|
||||
|
||||
// TransportProtocol is a transport protocol.
|
||||
type TransportProtocol int
|
||||
|
||||
@@ -116,13 +125,18 @@ func (m TransportMode) String() string {
|
||||
|
||||
// Transport is a Transport header.
|
||||
type Transport struct {
|
||||
// protocol of the stream.
|
||||
Protocol TransportProtocol
|
||||
|
||||
// Whether the secure variant is active.
|
||||
//
|
||||
// Deprecated: replaced by Profile.
|
||||
Secure bool
|
||||
|
||||
// (optional) delivery method of the stream.
|
||||
// profile.
|
||||
Profile TransportProfile
|
||||
|
||||
// protocol.
|
||||
Protocol TransportProtocol
|
||||
|
||||
// (optional) delivery method.
|
||||
Delivery *TransportDelivery
|
||||
|
||||
// (optional) Source IP.
|
||||
@@ -146,7 +160,7 @@ type Transport struct {
|
||||
// (optional) server ports.
|
||||
ServerPorts *[2]int
|
||||
|
||||
// (optional) SSRC of the packets of the stream.
|
||||
// (optional) SSRC of packets.
|
||||
SSRC *uint32
|
||||
|
||||
// (optional) mode.
|
||||
@@ -175,21 +189,25 @@ func (h *Transport) Unmarshal(v base.HeaderValue) error {
|
||||
|
||||
switch k {
|
||||
case "RTP/AVP", "RTP/AVP/UDP":
|
||||
h.Profile = TransportProfileAVP
|
||||
h.Protocol = TransportProtocolUDP
|
||||
profileFound = true
|
||||
|
||||
case "RTP/AVP/TCP":
|
||||
h.Profile = TransportProfileAVP
|
||||
h.Protocol = TransportProtocolTCP
|
||||
profileFound = true
|
||||
|
||||
case "RTP/SAVP", "RTP/SAVP/UDP":
|
||||
h.Protocol = TransportProtocolUDP
|
||||
h.Secure = true
|
||||
h.Profile = TransportProfileSAVP
|
||||
profileFound = true
|
||||
|
||||
case "RTP/SAVP/TCP":
|
||||
h.Protocol = TransportProtocolTCP
|
||||
h.Secure = true
|
||||
h.Profile = TransportProfileSAVP
|
||||
h.Protocol = TransportProtocolTCP
|
||||
profileFound = true
|
||||
|
||||
case "unicast":
|
||||
@@ -299,16 +317,20 @@ func (h *Transport) Unmarshal(v base.HeaderValue) error {
|
||||
func (h Transport) Marshal() base.HeaderValue {
|
||||
var rets []string
|
||||
|
||||
if h.Secure {
|
||||
h.Profile = TransportProfileSAVP
|
||||
}
|
||||
|
||||
var profile string
|
||||
|
||||
switch {
|
||||
case h.Protocol == TransportProtocolUDP && !h.Secure:
|
||||
case h.Protocol == TransportProtocolUDP && h.Profile == TransportProfileAVP:
|
||||
profile = "RTP/AVP"
|
||||
case h.Protocol == TransportProtocolTCP && !h.Secure:
|
||||
case h.Protocol == TransportProtocolTCP && h.Profile == TransportProfileAVP:
|
||||
profile = "RTP/AVP/TCP"
|
||||
case h.Protocol == TransportProtocolUDP && h.Secure:
|
||||
case h.Protocol == TransportProtocolUDP && h.Profile == TransportProfileSAVP:
|
||||
profile = "RTP/SAVP"
|
||||
case h.Protocol == TransportProtocolTCP && h.Secure:
|
||||
case h.Protocol == TransportProtocolTCP && h.Profile == TransportProfileSAVP:
|
||||
profile = "RTP/SAVP/TCP"
|
||||
}
|
||||
|
||||
|
@@ -175,6 +175,7 @@ var casesTransport = []struct {
|
||||
Transport{
|
||||
Protocol: TransportProtocolUDP,
|
||||
Secure: true,
|
||||
Profile: TransportProfileSAVP,
|
||||
Delivery: deliveryPtr(TransportDeliveryUnicast),
|
||||
ClientPorts: &[2]int{3456, 3457},
|
||||
Mode: transportModePtr(TransportModePlay),
|
||||
@@ -187,6 +188,7 @@ var casesTransport = []struct {
|
||||
Transport{
|
||||
Protocol: TransportProtocolTCP,
|
||||
Secure: true,
|
||||
Profile: TransportProfileSAVP,
|
||||
InterleavedIDs: &[2]int{0, 1},
|
||||
},
|
||||
},
|
||||
|
@@ -777,7 +777,7 @@ func TestServerPlay(t *testing.T) {
|
||||
desc := doDescribe(t, conn, false)
|
||||
|
||||
if ca.secure == "secure" {
|
||||
require.True(t, desc.Medias[0].Secure)
|
||||
require.Equal(t, headers.TransportProfileSAVP, desc.Medias[0].Profile)
|
||||
require.NotEmpty(t, desc.Medias[0].KeyMgmtMikey)
|
||||
}
|
||||
|
||||
@@ -811,7 +811,7 @@ func TestServerPlay(t *testing.T) {
|
||||
var srtpOutCtx *wrappedSRTPContext
|
||||
|
||||
if ca.secure == "secure" {
|
||||
inTH.Secure = true
|
||||
inTH.Profile = headers.TransportProfileSAVP
|
||||
|
||||
key := make([]byte, srtpKeyLength)
|
||||
_, err = rand.Read(key)
|
||||
@@ -854,7 +854,7 @@ func TestServerPlay(t *testing.T) {
|
||||
var srtpInCtx *wrappedSRTPContext
|
||||
|
||||
if ca.secure == "secure" {
|
||||
require.True(t, th.Secure)
|
||||
require.Equal(t, headers.TransportProfileSAVP, th.Profile)
|
||||
|
||||
var keyMgmt headers.KeyMgmt
|
||||
err = keyMgmt.Unmarshal(res.Header["KeyMgmt"])
|
||||
|
@@ -752,7 +752,7 @@ func TestServerRecord(t *testing.T) {
|
||||
}
|
||||
|
||||
if ca.secure == "secure" {
|
||||
inTH.Secure = true
|
||||
inTH.Profile = headers.TransportProfileSAVP
|
||||
|
||||
key := make([]byte, srtpKeyLength)
|
||||
_, err = rand.Read(key)
|
||||
@@ -800,7 +800,7 @@ func TestServerRecord(t *testing.T) {
|
||||
}
|
||||
|
||||
if ca.secure == "secure" {
|
||||
require.True(t, th.Secure)
|
||||
require.Equal(t, headers.TransportProfileSAVP, th.Profile)
|
||||
|
||||
var keyMgmt headers.KeyMgmt
|
||||
err = keyMgmt.Unmarshal(res.Header["KeyMgmt"])
|
||||
|
@@ -31,6 +31,10 @@ import (
|
||||
|
||||
type readFunc func([]byte) bool
|
||||
|
||||
func isSecure(profile headers.TransportProfile) bool {
|
||||
return profile == headers.TransportProfileSAVP
|
||||
}
|
||||
|
||||
func stringsReverseIndex(s, substr string) int {
|
||||
for i := len(s) - 1 - len(substr); i >= 0; i-- {
|
||||
if s[i:i+len(substr)] == substr {
|
||||
@@ -181,12 +185,12 @@ func isTransportSupported(s *Server, tr *headers.Transport) bool {
|
||||
}
|
||||
|
||||
// prevent using unsecure UDP with RTSPS
|
||||
if tr.Protocol == headers.TransportProtocolUDP && !tr.Secure && s.TLSConfig != nil {
|
||||
if tr.Protocol == headers.TransportProtocolUDP && !isSecure(tr.Profile) && s.TLSConfig != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// prevent using secure profiles with plain RTSP, since keys are in plain
|
||||
if tr.Secure && s.TLSConfig == nil {
|
||||
if isSecure(tr.Profile) && s.TLSConfig == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -420,7 +424,7 @@ type ServerSession struct {
|
||||
setuppedMediasOrdered []*serverSessionMedia
|
||||
tcpCallbackByChannel map[int]readFunc
|
||||
setuppedTransport *Transport
|
||||
setuppedSecure bool
|
||||
setuppedProfile headers.TransportProfile
|
||||
setuppedStream *ServerStream // play
|
||||
setuppedPath string
|
||||
setuppedQuery string
|
||||
@@ -503,7 +507,7 @@ func (ss *ServerSession) SetuppedTransport() *Transport {
|
||||
// If this is false, it does not mean that the stream is not secure, since
|
||||
// there are some combinations that are secure nonetheless, like RTSPS+TCP+unsecure.
|
||||
func (ss *ServerSession) SetuppedSecure() bool {
|
||||
return ss.setuppedSecure
|
||||
return isSecure(ss.setuppedProfile)
|
||||
}
|
||||
|
||||
// SetuppedStream returns the stream associated with the session.
|
||||
@@ -1126,7 +1130,7 @@ func (ss *ServerSession) handleRequestInner(sc *ServerConn, req *base.Request) (
|
||||
|
||||
var srtpInCtx *wrappedSRTPContext
|
||||
|
||||
if inTH.Secure {
|
||||
if isSecure(inTH.Profile) {
|
||||
var keyMgmt headers.KeyMgmt
|
||||
err = keyMgmt.Unmarshal(req.Header["KeyMgmt"])
|
||||
if err != nil {
|
||||
@@ -1143,7 +1147,7 @@ func (ss *ServerSession) handleRequestInner(sc *ServerConn, req *base.Request) (
|
||||
}
|
||||
}
|
||||
|
||||
if ss.setuppedTransport != nil && (*ss.setuppedTransport != transport || ss.setuppedSecure != inTH.Secure) {
|
||||
if ss.setuppedTransport != nil && (*ss.setuppedTransport != transport || ss.setuppedProfile != inTH.Profile) {
|
||||
return &base.Response{
|
||||
StatusCode: base.StatusBadRequest,
|
||||
}, liberrors.ErrServerMediasDifferentTransports{}
|
||||
@@ -1247,7 +1251,7 @@ func (ss *ServerSession) handleRequestInner(sc *ServerConn, req *base.Request) (
|
||||
}
|
||||
|
||||
ss.setuppedTransport = &transport
|
||||
ss.setuppedSecure = inTH.Secure
|
||||
ss.setuppedProfile = inTH.Profile
|
||||
|
||||
if ss.state == ServerSessionStateInitial {
|
||||
err = stream.readerAdd(ss,
|
||||
@@ -1266,7 +1270,7 @@ func (ss *ServerSession) handleRequestInner(sc *ServerConn, req *base.Request) (
|
||||
}
|
||||
|
||||
th := headers.Transport{
|
||||
Secure: inTH.Secure,
|
||||
Profile: inTH.Profile,
|
||||
}
|
||||
|
||||
if ss.state == ServerSessionStatePrePlay {
|
||||
@@ -1355,7 +1359,7 @@ func (ss *ServerSession) handleRequestInner(sc *ServerConn, req *base.Request) (
|
||||
|
||||
res.Header["Transport"] = th.Marshal()
|
||||
|
||||
if inTH.Secure {
|
||||
if isSecure(inTH.Profile) {
|
||||
ssrcs := make([]uint32, len(sm.formats))
|
||||
n := 0
|
||||
for _, sf := range sm.formats {
|
||||
|
@@ -159,7 +159,7 @@ func (sf *serverSessionFormat) writePacketRTP(pkt *rtp.Packet) error {
|
||||
pkt.SSRC = sf.localSSRC
|
||||
|
||||
maxPlainPacketSize := sf.sm.ss.s.MaxPacketSize
|
||||
if sf.sm.ss.setuppedSecure {
|
||||
if isSecure(sf.sm.ss.setuppedProfile) {
|
||||
maxPlainPacketSize -= srtpOverhead
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ func (sf *serverSessionFormat) writePacketRTP(pkt *rtp.Packet) error {
|
||||
plain = plain[:n]
|
||||
|
||||
var encr []byte
|
||||
if sf.sm.ss.setuppedSecure {
|
||||
if isSecure(sf.sm.ss.setuppedProfile) {
|
||||
encr = make([]byte, sf.sm.ss.s.MaxPacketSize)
|
||||
encr, err = sf.sm.srtpOutCtx.encryptRTP(encr, plain, &pkt.Header)
|
||||
if err != nil {
|
||||
@@ -179,7 +179,7 @@ func (sf *serverSessionFormat) writePacketRTP(pkt *rtp.Packet) error {
|
||||
}
|
||||
}
|
||||
|
||||
if sf.sm.ss.setuppedSecure {
|
||||
if isSecure(sf.sm.ss.setuppedProfile) {
|
||||
return sf.writePacketRTPEncoded(encr)
|
||||
}
|
||||
return sf.writePacketRTPEncoded(plain)
|
||||
|
@@ -459,7 +459,7 @@ func (sm *serverSessionMedia) writePacketRTCP(pkt rtcp.Packet) error {
|
||||
}
|
||||
|
||||
maxPlainPacketSize := sm.ss.s.MaxPacketSize
|
||||
if sm.ss.setuppedSecure {
|
||||
if isSecure(sm.ss.setuppedProfile) {
|
||||
maxPlainPacketSize -= srtcpOverhead
|
||||
}
|
||||
|
||||
@@ -468,7 +468,7 @@ func (sm *serverSessionMedia) writePacketRTCP(pkt rtcp.Packet) error {
|
||||
}
|
||||
|
||||
var encr []byte
|
||||
if sm.ss.setuppedSecure {
|
||||
if isSecure(sm.ss.setuppedProfile) {
|
||||
encr = make([]byte, sm.ss.s.MaxPacketSize)
|
||||
encr, err = sm.srtpOutCtx.encryptRTCP(encr, plain, nil)
|
||||
if err != nil {
|
||||
@@ -476,7 +476,7 @@ func (sm *serverSessionMedia) writePacketRTCP(pkt rtcp.Packet) error {
|
||||
}
|
||||
}
|
||||
|
||||
if sm.ss.setuppedSecure {
|
||||
if isSecure(sm.ss.setuppedProfile) {
|
||||
return sm.writePacketRTCPEncoded(encr)
|
||||
}
|
||||
return sm.writePacketRTCPEncoded(plain)
|
||||
|
@@ -120,7 +120,7 @@ func (sf *serverStreamFormat) writePacketRTP(pkt *rtp.Packet, ntp time.Time) err
|
||||
if rsm, ok := r.setuppedMedias[sf.sm.media]; ok {
|
||||
rsf := rsm.formats[pkt.PayloadType]
|
||||
|
||||
if r.setuppedSecure {
|
||||
if isSecure(r.setuppedProfile) {
|
||||
err = rsf.writePacketRTPEncoded(encr)
|
||||
if err != nil {
|
||||
r.onStreamWriteError(err)
|
||||
|
@@ -110,7 +110,7 @@ func (sm *serverStreamMedia) writePacketRTCP(pkt rtcp.Packet) error {
|
||||
// send unicast
|
||||
for r := range sm.st.activeUnicastReaders {
|
||||
if sm, ok := r.setuppedMedias[sm.media]; ok {
|
||||
if r.setuppedSecure {
|
||||
if isSecure(r.setuppedProfile) {
|
||||
err = sm.writePacketRTCPEncoded(encr)
|
||||
if err != nil {
|
||||
r.onStreamWriteError(err)
|
||||
|
Reference in New Issue
Block a user