diff --git a/internal/rtsp/rtsp.go b/internal/rtsp/rtsp.go index 230bdece..377061e5 100644 --- a/internal/rtsp/rtsp.go +++ b/internal/rtsp/rtsp.go @@ -8,6 +8,7 @@ import ( "github.com/AlexxIT/go2rtc/internal/app" "github.com/AlexxIT/go2rtc/internal/streams" + "github.com/AlexxIT/go2rtc/pkg/aac" "github.com/AlexxIT/go2rtc/pkg/core" "github.com/AlexxIT/go2rtc/pkg/rtsp" "github.com/AlexxIT/go2rtc/pkg/tcp" @@ -184,6 +185,23 @@ 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}, + {Name: core.CodecAAC, ClockRate: 16000, FmtpLine: aac.FMTP + "1408"}, + }, + }) + } + 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..323d9197 100644 --- a/pkg/rtsp/producer.go +++ b/pkg/rtsp/producer.go @@ -16,27 +16,43 @@ func (c *Conn) GetTrack(media *core.Media, codec *core.Codec) (*core.Receiver, e } } - c.stateMu.Lock() - defer c.stateMu.Unlock() + switch c.mode { + case core.ModeActiveProducer: + c.stateMu.Lock() + defer c.stateMu.Unlock() - if c.state == StatePlay { - if err := c.Reconnect(); err != nil { + if c.state == StatePlay { + if err := c.Reconnect(); err != nil { + return nil, err + } + } + + 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 - c.state = StateSetup + track := core.NewReceiver(media, codec) + track.ID = channel + c.Receivers = append(c.Receivers, track) - track := core.NewReceiver(media, codec) - track.ID = channel - c.Receivers = append(c.Receivers, track) + return track, nil + case core.ModePassiveConsumer: + // Backchannel + c.stateMu.Lock() + defer c.stateMu.Unlock() - return track, nil + channel := byte(len(c.Senders)) * 2 + track := core.NewReceiver(media, codec) + track.ID = channel + c.Receivers = append(c.Receivers, track) + + return track, nil + default: + return nil, errors.New("rtsp: wrong mode for GetTrack") + } } func (c *Conn) Start() (err error) { diff --git a/pkg/rtsp/server.go b/pkg/rtsp/server.go index 7953b0dc..1cddbec5 100644 --- a/pkg/rtsp/server.go +++ b/pkg/rtsp/server.go @@ -129,6 +129,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 @@ -154,11 +164,20 @@ 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 - tr = fmt.Sprintf("RTP/AVP/TCP;unicast;interleaved=%d-%d", i*2, i*2+1) - res.Header.Set("Transport", tr) + trackID := reqTrackID(req) + + if trackID >= 0 { + if trackID < len(c.Senders) { + c.Senders[trackID].Media.ID = MethodSetup + tr = fmt.Sprintf("RTP/AVP/TCP;unicast;interleaved=%d-%d", trackID*2, trackID*2+1) + res.Header.Set("Transport", tr) + } else if trackID >= len(c.Senders) && trackID < len(c.Senders)+len(c.Receivers) { + c.Receivers[trackID-len(c.Senders)].Media.ID = MethodSetup + tr = fmt.Sprintf("RTP/AVP/TCP;unicast;interleaved=%d-%d", trackID*2, trackID*2+1) + res.Header.Set("Transport", tr) + } else { + res.Status = "400 Bad Request" + } } else { res.Status = "400 Bad Request" }