mirror of
https://github.com/Monibuca/engine.git
synced 2025-10-05 16:46:58 +08:00
修复内置鉴权,音频轨道因IDR锁环并发问题,增加Internal配置,mp4重放能力
This commit is contained in:
@@ -29,6 +29,8 @@
|
|||||||
- 获取engine信息 `/api/sysInfo` 返回值{Version:xxx,StartTime:xxx,IP:[xxx.xxx.xxx.xxx]}
|
- 获取engine信息 `/api/sysInfo` 返回值{Version:xxx,StartTime:xxx,IP:[xxx.xxx.xxx.xxx]}
|
||||||
- 获取系统基本情况 `/api/summary` 返回值Summary数据
|
- 获取系统基本情况 `/api/summary` 返回值Summary数据
|
||||||
- 获取所有插件信息 `/api/plugins` 返回值Plugin数据
|
- 获取所有插件信息 `/api/plugins` 返回值Plugin数据
|
||||||
|
- 读取mp4文件再次发布为视频流 `/api/replay/mp4?streamPath=xxx&dump=filepath` filepath是文件路径
|
||||||
|
- 读取ts文件再次发布为视频流 `/api/replay/ts?streamPath=xxx&dump=filepath` filepath是文件路径
|
||||||
- 获取指定的配置信息 `/api/getconfig?name=xxx` 返回xxx插件的配置信息,如果不带参数或参数为空则返回全局配置
|
- 获取指定的配置信息 `/api/getconfig?name=xxx` 返回xxx插件的配置信息,如果不带参数或参数为空则返回全局配置
|
||||||
- 修改并保存配置信息 `/api/modifyconfig?name=xxx&yaml=1` 修改xxx插件的配置信息,在请求的body中传入修改后的配置yaml字符串
|
- 修改并保存配置信息 `/api/modifyconfig?name=xxx&yaml=1` 修改xxx插件的配置信息,在请求的body中传入修改后的配置yaml字符串
|
||||||
- 热更新配置信息 `/api/updateconfig?name=xxx` 热更新xxx插件的配置信息,如果不带参数或参数为空则热更新全局配置
|
- 热更新配置信息 `/api/updateconfig?name=xxx` 热更新xxx插件的配置信息,如果不带参数或参数为空则热更新全局配置
|
||||||
|
@@ -62,6 +62,7 @@ type Subscribe struct {
|
|||||||
Key string // 订阅鉴权key
|
Key string // 订阅鉴权key
|
||||||
SecretArgName string `default:"secret"` // 订阅鉴权参数名
|
SecretArgName string `default:"secret"` // 订阅鉴权参数名
|
||||||
ExpireArgName string `default:"expire"` // 订阅鉴权失效时间参数名
|
ExpireArgName string `default:"expire"` // 订阅鉴权失效时间参数名
|
||||||
|
Internal bool `default:"false"` // 是否内部订阅
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Subscribe) GetSubscribeConfig() *Subscribe {
|
func (c *Subscribe) GetSubscribeConfig() *Subscribe {
|
||||||
|
2
go.mod
2
go.mod
@@ -41,7 +41,7 @@ require (
|
|||||||
github.com/quic-go/qtls-go1-20 v0.1.0 // indirect
|
github.com/quic-go/qtls-go1-20 v0.1.0 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||||
github.com/tklauser/numcpus v0.6.0 // indirect
|
github.com/tklauser/numcpus v0.6.0 // indirect
|
||||||
github.com/yapingcat/gomedia v0.0.0-20230222121919-c67df405bf33
|
github.com/yapingcat/gomedia v0.0.0-20230426092936-387031404274
|
||||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||||
golang.org/x/crypto v0.4.0 // indirect
|
golang.org/x/crypto v0.4.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
|
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
|
||||||
|
2
go.sum
2
go.sum
@@ -150,6 +150,8 @@ github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYm
|
|||||||
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
|
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
|
||||||
github.com/yapingcat/gomedia v0.0.0-20230222121919-c67df405bf33 h1:uyZY++dluUg7iTSsNzuOVln/mC2U2KXwgKLfKLCJ74Y=
|
github.com/yapingcat/gomedia v0.0.0-20230222121919-c67df405bf33 h1:uyZY++dluUg7iTSsNzuOVln/mC2U2KXwgKLfKLCJ74Y=
|
||||||
github.com/yapingcat/gomedia v0.0.0-20230222121919-c67df405bf33/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc=
|
github.com/yapingcat/gomedia v0.0.0-20230222121919-c67df405bf33/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc=
|
||||||
|
github.com/yapingcat/gomedia v0.0.0-20230426092936-387031404274 h1:cj4I+bvWX9I+Hg6tnZ7DAiOVxzhyLhdvYVKp+WpM/2c=
|
||||||
|
github.com/yapingcat/gomedia v0.0.0-20230426092936-387031404274/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
19
http.go
19
http.go
@@ -22,6 +22,11 @@ type GlobalConfig struct {
|
|||||||
config.Engine
|
config.Engine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ShouldYaml(r *http.Request) bool {
|
||||||
|
format := r.URL.Query().Get("format")
|
||||||
|
return r.URL.Query().Get("yaml") != "" || format == "yaml"
|
||||||
|
}
|
||||||
|
|
||||||
func (conf *GlobalConfig) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
func (conf *GlobalConfig) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||||
rw.Write([]byte("Monibuca API Server\n"))
|
rw.Write([]byte("Monibuca API Server\n"))
|
||||||
for _, api := range apiList {
|
for _, api := range apiList {
|
||||||
@@ -34,11 +39,11 @@ func fetchSummary() *Summary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (conf *GlobalConfig) API_summary(rw http.ResponseWriter, r *http.Request) {
|
func (conf *GlobalConfig) API_summary(rw http.ResponseWriter, r *http.Request) {
|
||||||
format := r.URL.Query().Get("format")
|
y := ShouldYaml(r)
|
||||||
if r.Header.Get("Accept") == "text/event-stream" {
|
if r.Header.Get("Accept") == "text/event-stream" {
|
||||||
summary.Add()
|
summary.Add()
|
||||||
defer summary.Done()
|
defer summary.Done()
|
||||||
if format == "yaml" {
|
if y {
|
||||||
util.ReturnYaml(fetchSummary, time.Second, rw, r)
|
util.ReturnYaml(fetchSummary, time.Second, rw, r)
|
||||||
} else {
|
} else {
|
||||||
util.ReturnJson(fetchSummary, time.Second, rw, r)
|
util.ReturnJson(fetchSummary, time.Second, rw, r)
|
||||||
@@ -47,7 +52,7 @@ func (conf *GlobalConfig) API_summary(rw http.ResponseWriter, r *http.Request) {
|
|||||||
if !summary.Running() {
|
if !summary.Running() {
|
||||||
summary.collect()
|
summary.collect()
|
||||||
}
|
}
|
||||||
if format == "yaml" {
|
if y {
|
||||||
if err := yaml.NewEncoder(rw).Encode(&summary); err != nil {
|
if err := yaml.NewEncoder(rw).Encode(&summary); err != nil {
|
||||||
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
@@ -71,7 +76,11 @@ func (conf *GlobalConfig) API_plugins(rw http.ResponseWriter, r *http.Request) {
|
|||||||
func (conf *GlobalConfig) API_stream(rw http.ResponseWriter, r *http.Request) {
|
func (conf *GlobalConfig) API_stream(rw http.ResponseWriter, r *http.Request) {
|
||||||
if streamPath := r.URL.Query().Get("streamPath"); streamPath != "" {
|
if streamPath := r.URL.Query().Get("streamPath"); streamPath != "" {
|
||||||
if s := Streams.Get(streamPath); s != nil {
|
if s := Streams.Get(streamPath); s != nil {
|
||||||
|
if ShouldYaml(r) {
|
||||||
|
util.ReturnYaml(func() *Stream { return s }, time.Second, rw, r)
|
||||||
|
} else {
|
||||||
util.ReturnJson(func() *Stream { return s }, time.Second, rw, r)
|
util.ReturnJson(func() *Stream { return s }, time.Second, rw, r)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
http.Error(rw, NO_SUCH_STREAM, http.StatusNotFound)
|
http.Error(rw, NO_SUCH_STREAM, http.StatusNotFound)
|
||||||
}
|
}
|
||||||
@@ -113,7 +122,7 @@ func (conf *GlobalConfig) API_getConfig(w http.ResponseWriter, r *http.Request)
|
|||||||
} else {
|
} else {
|
||||||
p = Engine
|
p = Engine
|
||||||
}
|
}
|
||||||
if q.Get("yaml") != "" {
|
if ShouldYaml(r) {
|
||||||
mm, err := yaml.Marshal(p.RawConfig)
|
mm, err := yaml.Marshal(p.RawConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mm = []byte("")
|
mm = []byte("")
|
||||||
@@ -145,7 +154,7 @@ func (conf *GlobalConfig) API_modifyConfig(w http.ResponseWriter, r *http.Reques
|
|||||||
} else {
|
} else {
|
||||||
p = Engine
|
p = Engine
|
||||||
}
|
}
|
||||||
if q.Has("yaml") {
|
if ShouldYaml(r) {
|
||||||
err = yaml.NewDecoder(r.Body).Decode(&p.Modified)
|
err = yaml.NewDecoder(r.Body).Decode(&p.Modified)
|
||||||
} else {
|
} else {
|
||||||
err = json.NewDecoder(r.Body).Decode(&p.Modified)
|
err = json.NewDecoder(r.Body).Decode(&p.Modified)
|
||||||
|
30
io.go
30
io.go
@@ -129,6 +129,20 @@ var (
|
|||||||
OnAuthPub func(p *util.Promise[IPublisher]) error
|
OnAuthPub func(p *util.Promise[IPublisher]) error
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (io *IO) auth(key string, secret string, expire string) bool {
|
||||||
|
if unixTime, err := strconv.ParseInt(expire, 16, 64); err != nil || time.Now().Unix() > unixTime {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
trueSecret := md5.Sum([]byte(key + io.Stream.Path + expire))
|
||||||
|
for i := 0; i < 16; i++ {
|
||||||
|
hex, err := strconv.ParseInt(secret[i<<1:(i<<1)+2], 16, 16)
|
||||||
|
if trueSecret[i] != byte(hex) || err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// receive 用于接收发布或者订阅
|
// receive 用于接收发布或者订阅
|
||||||
func (io *IO) receive(streamPath string, specific IIO) error {
|
func (io *IO) receive(streamPath string, specific IIO) error {
|
||||||
streamPath = strings.Trim(streamPath, "/")
|
streamPath = strings.Trim(streamPath, "/")
|
||||||
@@ -206,13 +220,7 @@ func (io *IO) receive(streamPath string, specific IIO) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if conf.Key != "" {
|
} else if conf.Key != "" {
|
||||||
secret := io.Args.Get(conf.SecretArgName)
|
if !io.auth(conf.Key, io.Args.Get(conf.SecretArgName), io.Args.Get(conf.ExpireArgName)) {
|
||||||
t := io.Args.Get(conf.ExpireArgName)
|
|
||||||
if unixTime, err := strconv.ParseInt(t, 16, 64); err != nil || time.Now().Unix() > unixTime {
|
|
||||||
return ErrAuth
|
|
||||||
}
|
|
||||||
trueSecret := md5.Sum([]byte(conf.Key + s.StreamName + t))
|
|
||||||
if string(trueSecret[:]) != secret {
|
|
||||||
return ErrAuth
|
return ErrAuth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,13 +255,7 @@ func (io *IO) receive(streamPath string, specific IIO) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if conf := specific.(ISubscriber).GetSubscriber().Config; conf.Key != "" {
|
} else if conf := specific.(ISubscriber).GetSubscriber().Config; conf.Key != "" {
|
||||||
secret := io.Args.Get(conf.SecretArgName)
|
if !io.auth(conf.Key, io.Args.Get(conf.SecretArgName), io.Args.Get(conf.ExpireArgName)) {
|
||||||
t := io.Args.Get(conf.ExpireArgName)
|
|
||||||
if unixTime, err := strconv.ParseInt(t, 16, 64); err != nil || time.Now().Unix() > unixTime {
|
|
||||||
return ErrAuth
|
|
||||||
}
|
|
||||||
trueSecret := md5.Sum([]byte(conf.Key + s.StreamName + t))
|
|
||||||
if string(trueSecret[:]) != secret {
|
|
||||||
return ErrAuth
|
return ErrAuth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -48,6 +48,7 @@ reamins: 剩余
|
|||||||
"first frame read": 第一帧已读取
|
"first frame read": 第一帧已读取
|
||||||
"fu have no start": rtp的FU起始包丢了
|
"fu have no start": rtp的FU起始包丢了
|
||||||
"disabled by env": 被环境变量禁用
|
"disabled by env": 被环境变量禁用
|
||||||
|
"event cost too much time": 事件处理耗时过长
|
||||||
firstTs: 第一帧时间戳
|
firstTs: 第一帧时间戳
|
||||||
firstSeq: 第一帧序列号
|
firstSeq: 第一帧序列号
|
||||||
skipSeq: 跳过序列号
|
skipSeq: 跳过序列号
|
||||||
|
@@ -50,11 +50,11 @@ func (p *MP4Publisher) ReadMP4Data(source io.ReadSeeker) error {
|
|||||||
}
|
}
|
||||||
switch pkg.Cid {
|
switch pkg.Cid {
|
||||||
case mp4.MP4_CODEC_H264, mp4.MP4_CODEC_H265:
|
case mp4.MP4_CODEC_H264, mp4.MP4_CODEC_H265:
|
||||||
p.VideoTrack.WriteAnnexB(uint32(pkg.Pts), uint32(pkg.Dts), pkg.Data)
|
p.VideoTrack.WriteAnnexB(uint32(pkg.Pts*90), uint32(pkg.Dts*90), pkg.Data)
|
||||||
case mp4.MP4_CODEC_AAC:
|
case mp4.MP4_CODEC_AAC:
|
||||||
p.AudioTrack.WriteADTS(uint32(pkg.Pts), pkg.Data)
|
p.AudioTrack.WriteADTS(uint32(pkg.Pts*90), pkg.Data)
|
||||||
case mp4.MP4_CODEC_G711A, mp4.MP4_CODEC_G711U:
|
case mp4.MP4_CODEC_G711A, mp4.MP4_CODEC_G711U:
|
||||||
p.AudioTrack.WriteRaw(uint32(pkg.Pts), pkg.Data)
|
p.AudioTrack.WriteRaw(uint32(pkg.Pts*90), pkg.Data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -416,9 +416,6 @@ func (s *Stream) run() {
|
|||||||
s.Subscribers.Broadcast(event)
|
s.Subscribers.Broadcast(event)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if s.State != STATE_PUBLISHING {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if s.Tracks.Len() == 0 || (s.Publisher != nil && s.Publisher.IsClosed()) {
|
if s.Tracks.Len() == 0 || (s.Publisher != nil && s.Publisher.IsClosed()) {
|
||||||
s.action(ACTION_PUBLISHLOST)
|
s.action(ACTION_PUBLISHLOST)
|
||||||
} else {
|
} else {
|
||||||
@@ -530,6 +527,8 @@ func (s *Stream) run() {
|
|||||||
if _, ok := v.Value.(*track.Audio); ok && !s.GetPublisherConfig().PubVideo {
|
if _, ok := v.Value.(*track.Audio); ok && !s.GetPublisherConfig().PubVideo {
|
||||||
s.Subscribers.AbortWait()
|
s.Subscribers.AbortWait()
|
||||||
}
|
}
|
||||||
|
// 这里重置的目的是当PublishTimeout设置很大的情况下,需要及时取消订阅者的等待
|
||||||
|
s.timeout.Reset(time.Second * 5)
|
||||||
} else {
|
} else {
|
||||||
v.Reject(ErrBadTrackName)
|
v.Reject(ErrBadTrackName)
|
||||||
}
|
}
|
||||||
|
@@ -115,7 +115,6 @@ type TrackPlayer struct {
|
|||||||
// Subscriber 订阅者实体定义
|
// Subscriber 订阅者实体定义
|
||||||
type Subscriber struct {
|
type Subscriber struct {
|
||||||
IO
|
IO
|
||||||
IsInternal bool //是否内部订阅,不放入订阅列表
|
|
||||||
Config *config.Subscribe
|
Config *config.Subscribe
|
||||||
TrackPlayer `json:"-" yaml:"-"`
|
TrackPlayer `json:"-" yaml:"-"`
|
||||||
}
|
}
|
||||||
@@ -384,7 +383,7 @@ func (s *Subscriber) PlayBlock(subType byte) {
|
|||||||
func (s *Subscriber) onStop() {
|
func (s *Subscriber) onStop() {
|
||||||
if !s.Stream.IsClosed() {
|
if !s.Stream.IsClosed() {
|
||||||
s.Info("stop")
|
s.Info("stop")
|
||||||
if !s.IsInternal {
|
if !s.Config.Internal {
|
||||||
s.Stream.Receive(s.Spesific)
|
s.Stream.Receive(s.Spesific)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -105,7 +105,7 @@ func (s *Subscribers) Delete(suber ISubscriber) {
|
|||||||
|
|
||||||
func (s *Subscribers) Add(suber ISubscriber, wait *waitTracks) {
|
func (s *Subscribers) Add(suber ISubscriber, wait *waitTracks) {
|
||||||
io := suber.GetSubscriber()
|
io := suber.GetSubscriber()
|
||||||
if io.IsInternal {
|
if io.Config.Internal {
|
||||||
s.internal[suber] = wait
|
s.internal[suber] = wait
|
||||||
io.Info("innersuber +1", zap.Int("remains", len(s.internal)))
|
io.Info("innersuber +1", zap.Int("remains", len(s.internal)))
|
||||||
} else {
|
} else {
|
||||||
|
@@ -85,8 +85,8 @@ func (a *Audio) CompleteRTP(value *AVFrame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *Audio) Narrow() {
|
func (a *Audio) Narrow() {
|
||||||
if a.HistoryRing == nil && a.IDRing != nil {
|
// if a.HistoryRing == nil && a.IDRing != nil {
|
||||||
a.narrow(int(a.Value.Sequence - a.IDRing.Value.Sequence))
|
// a.narrow(int(a.Value.Sequence - a.IDRing.Value.Sequence))
|
||||||
}
|
// }
|
||||||
a.AddIDR()
|
a.AddIDR()
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user