diff --git a/internal/rtsp/rtsp.go b/internal/rtsp/rtsp.go index c680dd07..9b18982f 100644 --- a/internal/rtsp/rtsp.go +++ b/internal/rtsp/rtsp.go @@ -186,6 +186,22 @@ func tcpHandler(conn *rtsp.Conn) { } } + if query.Get("backchannel") == "1" { + conn.Medias = append(conn.Medias, &core.Media{ + Kind: core.KindAudio, + Direction: core.DirectionRecvonly, + Codecs: []*core.Codec{ + {Name: core.CodecOpus, ClockRate: 48000, Channels: 2}, + {Name: core.CodecPCM, ClockRate: 16000}, + {Name: core.CodecPCMA, ClockRate: 16000}, + {Name: core.CodecPCMU, ClockRate: 16000}, + {Name: core.CodecPCM, ClockRate: 8000}, + {Name: core.CodecPCMA, ClockRate: 8000}, + {Name: core.CodecPCMU, ClockRate: 8000}, + }, + }) + } + if s := query.Get("pkt_size"); s != "" { conn.PacketSize = uint16(core.Atoi(s)) } diff --git a/pkg/core/media.go b/pkg/core/media.go index 72ab58c6..a700bb62 100644 --- a/pkg/core/media.go +++ b/pkg/core/media.go @@ -141,6 +141,10 @@ func MarshalSDP(name string, medias []*Media) ([]byte, error) { } md.WithCodec(codec.PayloadType, name, codec.ClockRate, codec.Channels, codec.FmtpLine) + if media.Direction != "" { + md.WithPropertyAttribute(media.Direction) + } + if media.ID != "" { md.WithValueAttribute("control", media.ID) } diff --git a/pkg/rtsp/producer.go b/pkg/rtsp/producer.go index de115808..3d818b62 100644 --- a/pkg/rtsp/producer.go +++ b/pkg/rtsp/producer.go @@ -19,19 +19,30 @@ func (c *Conn) GetTrack(media *core.Media, codec *core.Codec) (*core.Receiver, e c.stateMu.Lock() defer c.stateMu.Unlock() - if c.state == StatePlay { - if err := c.Reconnect(); err != nil { + var channel byte + + switch c.mode { + case core.ModeActiveProducer: + if c.state == StatePlay { + if err := c.Reconnect(); err != nil { + return nil, err + } + } + + var err error + channel, err = c.SetupMedia(media) + if err != nil { return nil, err } - } - channel, err := c.SetupMedia(media) - if err != nil { - return nil, err + c.state = StateSetup + case core.ModePassiveConsumer: + // Backchannel + channel = byte(len(c.Senders)) * 2 + default: + return nil, errors.New("rtsp: wrong mode for GetTrack") } - c.state = StateSetup - track := core.NewReceiver(media, codec) track.ID = channel c.Receivers = append(c.Receivers, track) diff --git a/pkg/rtsp/server.go b/pkg/rtsp/server.go index 1a3b288b..343bdc66 100644 --- a/pkg/rtsp/server.go +++ b/pkg/rtsp/server.go @@ -136,6 +136,16 @@ func (c *Conn) Accept() error { medias = append(medias, media) } + for i, track := range c.Receivers { + media := &core.Media{ + Kind: core.GetKind(track.Codec.Name), + Direction: core.DirectionSendonly, + Codecs: []*core.Codec{track.Codec}, + ID: "trackID=" + strconv.Itoa(i+len(c.Senders)), + } + medias = append(medias, media) + } + res.Body, err = core.MarshalSDP(c.SessionName, medias) if err != nil { return err @@ -160,9 +170,12 @@ func (c *Conn) Accept() error { c.state = StateSetup if c.mode == core.ModePassiveConsumer { - if i := reqTrackID(req); i >= 0 && i < len(c.Senders) { - // mark sender as SETUP - c.Senders[i].Media.ID = MethodSetup + if i := reqTrackID(req); i >= 0 && i < len(c.Senders)+len(c.Receivers) { + if i < len(c.Senders) { + c.Senders[i].Media.ID = MethodSetup + } else { + c.Receivers[i-len(c.Senders)].Media.ID = MethodSetup + } tr = fmt.Sprintf("RTP/AVP/TCP;unicast;interleaved=%d-%d", i*2, i*2+1) res.Header.Set("Transport", tr) } else {