Files
monibuca/plugin/rtsp/pkg/client.go
2025-09-26 15:57:26 +08:00

151 lines
3.2 KiB
Go

package rtsp
import (
task "github.com/langhuihui/gotask"
"m7s.live/v5/pkg/config"
"m7s.live/v5"
pkg "m7s.live/v5/pkg"
)
// Plugin-specific progress step names for RTSP
const (
StepDescribe pkg.StepName = "describe"
StepSetup pkg.StepName = "setup"
StepPlay pkg.StepName = "play"
)
// Fixed steps for RTSP pull workflow
var rtspPullSteps = []pkg.StepDef{
{Name: pkg.StepPublish, Description: "Publishing stream"},
{Name: pkg.StepConnection, Description: "Connecting to RTSP server"},
{Name: StepDescribe, Description: "Sending DESCRIBE request"},
{Name: StepSetup, Description: "Setting up media tracks"},
{Name: StepPlay, Description: "Starting media playback"},
{Name: pkg.StepStreaming, Description: "Receiving and processing media data"},
}
const (
DIRECTION_PULL = "pull"
DIRECTION_PUSH = "push"
)
type Client struct {
Stream
pullCtx m7s.PullJob
pushCtx m7s.PushJob
direction string
}
func (c *Client) Start() (err error) {
if c.direction == DIRECTION_PULL { // no progress tracking
c.pullCtx.SetProgressStepsDefs(rtspPullSteps)
if err = c.pullCtx.Publish(); err != nil {
c.pullCtx.Fail(err.Error())
return
}
if err = c.NetConnection.Connect(c.pullCtx.RemoteURL); err != nil {
c.pullCtx.Fail(err.Error())
return
}
} else {
err = c.NetConnection.Connect(c.pushCtx.RemoteURL)
}
return
}
func (c *Client) GetPullJob() *m7s.PullJob {
return &c.pullCtx
}
func (c *Client) GetPushJob() *m7s.PushJob {
return &c.pushCtx
}
func NewPuller(_ config.Pull) m7s.IPuller {
client := &Client{
direction: DIRECTION_PULL,
}
client.NetConnection = &NetConnection{}
client.SetDescription(task.OwnerTypeKey, "RTSPPuller")
return client
}
func NewPusher() m7s.IPusher {
client := &Client{
direction: DIRECTION_PUSH,
}
client.NetConnection = &NetConnection{}
client.SetDescription(task.OwnerTypeKey, "RTSPPusher")
return client
}
func (c *Client) Run() (err error) {
if err = c.Options(); err != nil {
return
}
if c.direction == DIRECTION_PULL {
c.pullCtx.GoToStepConst(StepDescribe)
var medias []*Media
if medias, err = c.Describe(); err != nil {
return
}
receiver := &Receiver{Publisher: c.pullCtx.Publisher, Stream: c.Stream}
if err = receiver.SetMedia(medias); err != nil {
return
}
c.pullCtx.GoToStepConst(StepSetup)
for i, media := range medias {
switch media.Kind {
case "audio", "video":
_, err = c.SetupMedia(media, "play", i)
if err != nil {
return
}
default:
c.Warn("media kind not support", "kind", media.Kind)
}
}
c.pullCtx.GoToStepConst(StepPlay)
if err = c.Play(); err != nil {
return
}
c.pullCtx.GoToStepConst(pkg.StepStreaming)
return receiver.Receive()
} else {
err = c.pushCtx.Subscribe()
if err != nil {
return
}
sender := &Sender{Subscriber: c.pushCtx.Subscriber, Stream: c.Stream}
var medias []*Media
medias, err = sender.GetMedia()
err = c.Announce(medias)
if err != nil {
return
}
for i, media := range medias {
switch media.Kind {
case "audio", "video":
_, err = c.SetupMedia(media, "record", i)
if err != nil {
return
}
default:
c.Warn("media kind not support", "kind", media.Kind)
}
}
if err = c.Record(); err != nil {
return
}
return sender.Send()
}
}