mirror of
https://github.com/AlexxIT/go2rtc.git
synced 2025-10-07 09:11:28 +08:00
151 lines
2.7 KiB
Go
151 lines
2.7 KiB
Go
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()
|
|
|
|
if c.state == StatePlay {
|
|
if err := c.Reconnect(); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
channel, err := c.SetupMedia(media)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c.state = StateSetup
|
|
|
|
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) {
|
|
info := &core.Info{
|
|
Type: "RTSP " + c.mode.String(),
|
|
SDP: c.sdp,
|
|
UserAgent: c.UserAgent,
|
|
Medias: c.Medias,
|
|
Receivers: c.receivers,
|
|
Senders: c.senders,
|
|
Recv: c.recv,
|
|
Send: c.send,
|
|
}
|
|
|
|
if c.URL != nil {
|
|
info.URL = c.URL.String()
|
|
}
|
|
if c.conn != nil {
|
|
info.RemoteAddr = c.conn.RemoteAddr().String()
|
|
}
|
|
|
|
return json.Marshal(info)
|
|
}
|
|
|
|
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
|
|
}
|