package rtsp import ( "encoding/json" "errors" "github.com/AlexxIT/go2rtc/pkg/core" ) func (c *Conn) GetTrack(media *core.Media, codec *core.Codec) (*core.Receiver, error) { core.Assert(media.Direction == core.DirectionRecvonly) for _, track := range c.Receivers { if track.Codec == codec { return track, nil } } c.stateMu.Lock() defer c.stateMu.Unlock() 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 } c.state = StateSetup case core.ModePassiveConsumer: // Backchannel channel = byte(len(c.Senders)) * 2 default: return nil, errors.New("rtsp: wrong mode for GetTrack") } track := core.NewReceiver(media, codec) track.ID = channel c.Receivers = append(c.Receivers, track) return track, nil } func (c *Conn) Start() (err error) { core.Assert(c.mode == core.ModeActiveProducer || c.mode == core.ModePassiveProducer) for { ok := false c.stateMu.Lock() switch c.state { case StateNone: err = nil case StateConn: err = errors.New("start from CONN state") case StateSetup: switch c.mode { case core.ModeActiveProducer: err = c.Play() case core.ModePassiveProducer: err = nil default: err = errors.New("start from wrong mode: " + c.mode.String()) } if err == nil { c.state = StatePlay ok = true } } c.stateMu.Unlock() if !ok { return } // Handler can return different states: // 1. None after PLAY should exit without error // 2. Play after PLAY should exit from Start with error // 3. Setup after PLAY should Play once again err = c.Handle() } } func (c *Conn) Stop() (err error) { for _, receiver := range c.Receivers { receiver.Close() } for _, sender := range c.Senders { sender.Close() } c.stateMu.Lock() if c.state != StateNone { c.state = StateNone err = c.Close() } c.stateMu.Unlock() return } func (c *Conn) MarshalJSON() ([]byte, error) { return json.Marshal(c.Connection) } func (c *Conn) Reconnect() error { c.Fire("RTSP reconnect") // close current session _ = c.Close() // start new session if err := c.Dial(); err != nil { return err } if err := c.Describe(); err != nil { return err } // restore previous medias for _, receiver := range c.Receivers { if _, err := c.SetupMedia(receiver.Media); err != nil { return err } } for _, sender := range c.Senders { if _, err := c.SetupMedia(sender.Media); err != nil { return err } } return nil }