mirror of
https://github.com/langhuihui/monibuca.git
synced 2025-10-22 15:39:37 +08:00
feat: webrtc->rtmp h264
This commit is contained in:
106
api.go
106
api.go
@@ -40,18 +40,77 @@ func (s *Server) SysInfo(context.Context, *emptypb.Empty) (res *pb.SysInfoRespon
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) StreamInfo(ctx context.Context, req *pb.StreamSnapRequest) (res *pb.StreamInfoResponse, err error) {
|
func (s *Server) StreamInfo(ctx context.Context, req *pb.StreamSnapRequest) (res *pb.StreamInfoResponse, err error) {
|
||||||
// s.Call(func() {
|
s.Call(func() {
|
||||||
// if pub, ok := s.Streams.Get(req.StreamPath); ok {
|
if pub, ok := s.Streams.Get(req.StreamPath); ok {
|
||||||
// res = &pb.StreamInfoResponse{
|
tmp, _ := json.Marshal(pub.MetaData)
|
||||||
// }
|
res = &pb.StreamInfoResponse{
|
||||||
// } else {
|
Meta: string(tmp),
|
||||||
// err = pkg.ErrNotFound
|
}
|
||||||
// }
|
if t := pub.AudioTrack.AVTrack; t != nil {
|
||||||
// })
|
res.AudioTrack = &pb.AudioTrackInfo{
|
||||||
|
Meta: t.GetInfo(),
|
||||||
|
Bps: uint32(t.BPS),
|
||||||
|
Delta: pub.AudioTrack.Delta.String(),
|
||||||
|
}
|
||||||
|
if t.ICodecCtx != nil {
|
||||||
|
res.AudioTrack.SampleRate = uint32(t.ICodecCtx.(pkg.IAudioCodecCtx).GetSampleRate())
|
||||||
|
res.AudioTrack.Channels = uint32(t.ICodecCtx.(pkg.IAudioCodecCtx).GetChannels())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if t := pub.VideoTrack.AVTrack; t != nil {
|
||||||
|
res.VideoTrack = &pb.VideoTrackInfo{
|
||||||
|
Meta: t.GetInfo(),
|
||||||
|
Bps: uint32(t.BPS),
|
||||||
|
Delta: pub.VideoTrack.Delta.String(),
|
||||||
|
Gop: uint32(pub.GOP),
|
||||||
|
}
|
||||||
|
if t.ICodecCtx != nil {
|
||||||
|
res.VideoTrack.Width = uint32(t.ICodecCtx.(pkg.IVideoCodecCtx).GetWidth())
|
||||||
|
res.VideoTrack.Height = uint32(t.ICodecCtx.(pkg.IVideoCodecCtx).GetHeight())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = pkg.ErrNotFound
|
||||||
|
}
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (s *Server) GetSubscribers(ctx context.Context, req *pb.SubscribersRequest) (res *pb.SubscribersResponse, err error) {
|
||||||
func (s *Server) AudioTrackSnap(ctx context.Context, req *pb.StreamSnapRequest) (res *pb.AudioTrackSnapShotResponse, err error) {
|
s.Call(func() {
|
||||||
|
var subscribers []*pb.SubscriberSnapShot
|
||||||
|
for _, subscriber := range s.Subscribers.Items {
|
||||||
|
meta, _ := json.Marshal(subscriber.MetaData)
|
||||||
|
snap := &pb.SubscriberSnapShot{
|
||||||
|
Id: uint32(subscriber.ID),
|
||||||
|
StartTime: timestamppb.New(subscriber.StartTime),
|
||||||
|
Meta: string(meta),
|
||||||
|
}
|
||||||
|
if ar := subscriber.AudioReader; ar != nil {
|
||||||
|
snap.AudioReader = &pb.RingReaderSnapShot{
|
||||||
|
Sequence: uint32(ar.Value.Sequence),
|
||||||
|
Timestamp: ar.AbsTime,
|
||||||
|
Delay: ar.Delay,
|
||||||
|
State: int32(ar.State),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if vr := subscriber.VideoReader; vr != nil {
|
||||||
|
snap.VideoReader = &pb.RingReaderSnapShot{
|
||||||
|
Sequence: uint32(vr.Value.Sequence),
|
||||||
|
Timestamp: vr.AbsTime,
|
||||||
|
Delay: vr.Delay,
|
||||||
|
State: int32(vr.State),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subscribers = append(subscribers, snap)
|
||||||
|
}
|
||||||
|
res = &pb.SubscribersResponse{
|
||||||
|
List: subscribers,
|
||||||
|
Total: int32(s.Subscribers.Length),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (s *Server) AudioTrackSnap(ctx context.Context, req *pb.StreamSnapRequest) (res *pb.TrackSnapShotResponse, err error) {
|
||||||
// s.Call(func() {
|
// s.Call(func() {
|
||||||
// if pub, ok := s.Streams.Get(req.StreamPath); ok {
|
// if pub, ok := s.Streams.Get(req.StreamPath); ok {
|
||||||
// res = pub.AudioSnapShot()
|
// res = pub.AudioSnapShot()
|
||||||
@@ -62,16 +121,21 @@ func (s *Server) AudioTrackSnap(ctx context.Context, req *pb.StreamSnapRequest)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) VideoTrackSnap(ctx context.Context, req *pb.StreamSnapRequest) (res *pb.VideoTrackSnapShotResponse, err error) {
|
func (s *Server) VideoTrackSnap(ctx context.Context, req *pb.StreamSnapRequest) (res *pb.TrackSnapShotResponse, err error) {
|
||||||
s.Call(func() {
|
s.Call(func() {
|
||||||
if pub, ok := s.Streams.Get(req.StreamPath); ok {
|
if pub, ok := s.Streams.Get(req.StreamPath); ok {
|
||||||
res = &pb.VideoTrackSnapShotResponse{}
|
res = &pb.TrackSnapShotResponse{}
|
||||||
if !pub.VideoTrack.IsEmpty() {
|
if !pub.VideoTrack.IsEmpty() {
|
||||||
vcc := pub.VideoTrack.AVTrack.ICodecCtx.(pkg.IVideoCodecCtx)
|
// vcc := pub.VideoTrack.AVTrack.ICodecCtx.(pkg.IVideoCodecCtx)
|
||||||
res.Width = uint32(vcc.GetWidth())
|
res.Reader = make(map[uint32]uint32)
|
||||||
res.Height = uint32(vcc.GetHeight())
|
for sub := range pub.Subscribers {
|
||||||
res.Info = pub.VideoTrack.GetInfo()
|
if sub.VideoReader == nil {
|
||||||
pub.VideoTrack.Ring.Next().Do(func(v *pkg.AVFrame) {
|
continue
|
||||||
|
}
|
||||||
|
res.Reader[uint32(sub.ID)] = sub.VideoReader.Value.Sequence
|
||||||
|
}
|
||||||
|
pub.VideoTrack.Ring.Do(func(v *pkg.AVFrame) {
|
||||||
|
if v.TryRLock() {
|
||||||
var snap pb.TrackSnapShot
|
var snap pb.TrackSnapShot
|
||||||
snap.Sequence = v.Sequence
|
snap.Sequence = v.Sequence
|
||||||
snap.Timestamp = uint32(v.Timestamp / time.Millisecond)
|
snap.Timestamp = uint32(v.Timestamp / time.Millisecond)
|
||||||
@@ -86,6 +150,8 @@ func (s *Server) VideoTrackSnap(ctx context.Context, req *pb.StreamSnapRequest)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
res.Ring = append(res.Ring, &snap)
|
res.Ring = append(res.Ring, &snap)
|
||||||
|
v.RUnlock()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -111,7 +177,7 @@ func (s *Server) Shutdown(ctx context.Context, req *pb.RequestWithId) (res *empt
|
|||||||
return empty, err
|
return empty, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) StopSubscribe(ctx context.Context, req *pb.StopSubscribeRequest) (res *pb.StopSubscribeResponse, err error) {
|
func (s *Server) StopSubscribe(ctx context.Context, req *pb.RequestWithId) (res *pb.SuccessResponse, err error) {
|
||||||
s.Call(func() {
|
s.Call(func() {
|
||||||
if subscriber, ok := s.Subscribers.Get(int(req.Id)); ok {
|
if subscriber, ok := s.Subscribers.Get(int(req.Id)); ok {
|
||||||
subscriber.Stop(errors.New("stop by api"))
|
subscriber.Stop(errors.New("stop by api"))
|
||||||
@@ -119,7 +185,7 @@ func (s *Server) StopSubscribe(ctx context.Context, req *pb.StopSubscribeRequest
|
|||||||
err = pkg.ErrNotFound
|
err = pkg.ErrNotFound
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return &pb.StopSubscribeResponse{
|
return &pb.SuccessResponse{
|
||||||
Success: err == nil,
|
Success: err == nil,
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
@@ -265,7 +331,7 @@ func (s *Server) GetConfig(_ context.Context, req *pb.GetConfigRequest) (res *pb
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) ModifyConfig(_ context.Context, req *pb.ModifyConfigRequest) (res *pb.ModifyConfigResponse, err error) {
|
func (s *Server) ModifyConfig(_ context.Context, req *pb.ModifyConfigRequest) (res *pb.SuccessResponse, err error) {
|
||||||
var conf *config.Config
|
var conf *config.Config
|
||||||
if req.Name == "global" {
|
if req.Name == "global" {
|
||||||
conf = &s.Config
|
conf = &s.Config
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
global:
|
global:
|
||||||
# loglevel: debug
|
# loglevel: debug
|
||||||
|
tcp:
|
||||||
|
listenaddr: :50051
|
||||||
|
console:
|
||||||
|
secret: de2c0bb9fd47684adc07a426e139239b
|
||||||
|
webrtc:
|
||||||
|
publish:
|
||||||
|
pubaudio: false
|
||||||
rtmp:
|
rtmp:
|
||||||
chunksize: 2048
|
chunksize: 2048
|
||||||
subscribe:
|
subscribe:
|
||||||
|
@@ -3,7 +3,9 @@ global:
|
|||||||
http:
|
http:
|
||||||
listenaddr: :8081
|
listenaddr: :8081
|
||||||
listenaddrtls: :8555
|
listenaddrtls: :8555
|
||||||
|
disableall: true
|
||||||
rtmp:
|
rtmp:
|
||||||
|
enable: true
|
||||||
chunksize: 2048
|
chunksize: 2048
|
||||||
tcp:
|
tcp:
|
||||||
listenaddr:
|
listenaddr:
|
||||||
|
0
example/multiple/fatal/latest.log
Normal file
0
example/multiple/fatal/latest.log
Normal file
@@ -7,13 +7,15 @@ import (
|
|||||||
"m7s.live/m7s/v5"
|
"m7s.live/m7s/v5"
|
||||||
_ "m7s.live/m7s/v5/plugin/debug"
|
_ "m7s.live/m7s/v5/plugin/debug"
|
||||||
_ "m7s.live/m7s/v5/plugin/hdl"
|
_ "m7s.live/m7s/v5/plugin/hdl"
|
||||||
|
_ "m7s.live/m7s/v5/plugin/webrtc"
|
||||||
_ "m7s.live/m7s/v5/plugin/rtmp"
|
_ "m7s.live/m7s/v5/plugin/rtmp"
|
||||||
|
_ "m7s.live/m7s/v5/plugin/console"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
// ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(time.Second*100))
|
// ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(time.Second*100))
|
||||||
go m7s.Run(ctx, "config1.yaml")
|
go m7s.Run(ctx, "config1.yaml")
|
||||||
time.Sleep(time.Second * 10)
|
time.Sleep(time.Second * 20)
|
||||||
m7s.NewServer().Run(ctx, "config2.yaml")
|
m7s.NewServer().Run(ctx, "config2.yaml")
|
||||||
}
|
}
|
||||||
|
1309
pb/global.pb.go
1309
pb/global.pb.go
File diff suppressed because it is too large
Load Diff
@@ -260,6 +260,76 @@ func local_request_Global_StreamInfo_0(ctx context.Context, marshaler runtime.Ma
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
filter_Global_GetSubscribers_0 = &utilities.DoubleArray{Encoding: map[string]int{"streamPath": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
||||||
|
)
|
||||||
|
|
||||||
|
func request_Global_GetSubscribers_0(ctx context.Context, marshaler runtime.Marshaler, client GlobalClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq SubscribersRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
var (
|
||||||
|
val string
|
||||||
|
ok bool
|
||||||
|
err error
|
||||||
|
_ = err
|
||||||
|
)
|
||||||
|
|
||||||
|
val, ok = pathParams["streamPath"]
|
||||||
|
if !ok {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "streamPath")
|
||||||
|
}
|
||||||
|
|
||||||
|
protoReq.StreamPath, err = runtime.String(val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "streamPath", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := req.ParseForm(); err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Global_GetSubscribers_0); err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := client.GetSubscribers(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func local_request_Global_GetSubscribers_0(ctx context.Context, marshaler runtime.Marshaler, server GlobalServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq SubscribersRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
var (
|
||||||
|
val string
|
||||||
|
ok bool
|
||||||
|
err error
|
||||||
|
_ = err
|
||||||
|
)
|
||||||
|
|
||||||
|
val, ok = pathParams["streamPath"]
|
||||||
|
if !ok {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "streamPath")
|
||||||
|
}
|
||||||
|
|
||||||
|
protoReq.StreamPath, err = runtime.String(val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "streamPath", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := req.ParseForm(); err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Global_GetSubscribers_0); err != nil {
|
||||||
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := server.GetSubscribers(ctx, &protoReq)
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func request_Global_AudioTrackSnap_0(ctx context.Context, marshaler runtime.Marshaler, client GlobalClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
func request_Global_AudioTrackSnap_0(ctx context.Context, marshaler runtime.Marshaler, client GlobalClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
var protoReq StreamSnapRequest
|
var protoReq StreamSnapRequest
|
||||||
var metadata runtime.ServerMetadata
|
var metadata runtime.ServerMetadata
|
||||||
@@ -365,7 +435,7 @@ func local_request_Global_VideoTrackSnap_0(ctx context.Context, marshaler runtim
|
|||||||
}
|
}
|
||||||
|
|
||||||
func request_Global_StopSubscribe_0(ctx context.Context, marshaler runtime.Marshaler, client GlobalClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
func request_Global_StopSubscribe_0(ctx context.Context, marshaler runtime.Marshaler, client GlobalClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
var protoReq StopSubscribeRequest
|
var protoReq RequestWithId
|
||||||
var metadata runtime.ServerMetadata
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
||||||
@@ -395,7 +465,7 @@ func request_Global_StopSubscribe_0(ctx context.Context, marshaler runtime.Marsh
|
|||||||
}
|
}
|
||||||
|
|
||||||
func local_request_Global_StopSubscribe_0(ctx context.Context, marshaler runtime.Marshaler, server GlobalServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
func local_request_Global_StopSubscribe_0(ctx context.Context, marshaler runtime.Marshaler, server GlobalServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
var protoReq StopSubscribeRequest
|
var protoReq RequestWithId
|
||||||
var metadata runtime.ServerMetadata
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
|
||||||
@@ -744,6 +814,31 @@ func RegisterGlobalHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
mux.Handle("GET", pattern_Global_GetSubscribers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
var stream runtime.ServerTransportStream
|
||||||
|
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/m7s.Global/GetSubscribers", runtime.WithHTTPPathPattern("/api/subscribers/{streamPath=**}"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := local_request_Global_GetSubscribers_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||||
|
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_Global_GetSubscribers_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Global_AudioTrackSnap_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Global_AudioTrackSnap_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -1067,6 +1162,28 @@ func RegisterGlobalHandlerClient(ctx context.Context, mux *runtime.ServeMux, cli
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
mux.Handle("GET", pattern_Global_GetSubscribers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
|
defer cancel()
|
||||||
|
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/m7s.Global/GetSubscribers", runtime.WithHTTPPathPattern("/api/subscribers/{streamPath=**}"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_Global_GetSubscribers_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||||
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_Global_GetSubscribers_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_Global_AudioTrackSnap_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", pattern_Global_AudioTrackSnap_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
ctx, cancel := context.WithCancel(req.Context())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -1215,6 +1332,8 @@ var (
|
|||||||
|
|
||||||
pattern_Global_StreamInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 3, 0, 4, 1, 5, 3}, []string{"api", "stream", "info", "streamPath"}, ""))
|
pattern_Global_StreamInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 3, 0, 4, 1, 5, 3}, []string{"api", "stream", "info", "streamPath"}, ""))
|
||||||
|
|
||||||
|
pattern_Global_GetSubscribers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 3, 0, 4, 1, 5, 2}, []string{"api", "subscribers", "streamPath"}, ""))
|
||||||
|
|
||||||
pattern_Global_AudioTrackSnap_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 3, 0, 4, 1, 5, 3}, []string{"api", "audiotrack", "snap", "streamPath"}, ""))
|
pattern_Global_AudioTrackSnap_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 3, 0, 4, 1, 5, 3}, []string{"api", "audiotrack", "snap", "streamPath"}, ""))
|
||||||
|
|
||||||
pattern_Global_VideoTrackSnap_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 3, 0, 4, 1, 5, 3}, []string{"api", "videotrack", "snap", "streamPath"}, ""))
|
pattern_Global_VideoTrackSnap_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 3, 0, 4, 1, 5, 3}, []string{"api", "videotrack", "snap", "streamPath"}, ""))
|
||||||
@@ -1241,6 +1360,8 @@ var (
|
|||||||
|
|
||||||
forward_Global_StreamInfo_0 = runtime.ForwardResponseMessage
|
forward_Global_StreamInfo_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
|
forward_Global_GetSubscribers_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_Global_AudioTrackSnap_0 = runtime.ForwardResponseMessage
|
forward_Global_AudioTrackSnap_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_Global_VideoTrackSnap_0 = runtime.ForwardResponseMessage
|
forward_Global_VideoTrackSnap_0 = runtime.ForwardResponseMessage
|
||||||
|
@@ -37,17 +37,22 @@ service Global {
|
|||||||
get: "/api/stream/info/{streamPath=**}"
|
get: "/api/stream/info/{streamPath=**}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc AudioTrackSnap (StreamSnapRequest) returns (AudioTrackSnapShotResponse) {
|
rpc GetSubscribers(SubscribersRequest) returns (SubscribersResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
get: "/api/subscribers/{streamPath=**}"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
rpc AudioTrackSnap (StreamSnapRequest) returns (TrackSnapShotResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/api/audiotrack/snap/{streamPath=**}"
|
get: "/api/audiotrack/snap/{streamPath=**}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc VideoTrackSnap (StreamSnapRequest) returns (VideoTrackSnapShotResponse) {
|
rpc VideoTrackSnap (StreamSnapRequest) returns (TrackSnapShotResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/api/videotrack/snap/{streamPath=**}"
|
get: "/api/videotrack/snap/{streamPath=**}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc StopSubscribe (StopSubscribeRequest) returns (StopSubscribeResponse) {
|
rpc StopSubscribe (RequestWithId) returns (SuccessResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post: "/api/stop/subscribe/{id}"
|
post: "/api/stop/subscribe/{id}"
|
||||||
body: "*"
|
body: "*"
|
||||||
@@ -63,7 +68,7 @@ service Global {
|
|||||||
get: "/api/config/formily/{name}"
|
get: "/api/config/formily/{name}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
rpc ModifyConfig (ModifyConfigRequest) returns (ModifyConfigResponse) {
|
rpc ModifyConfig (ModifyConfigRequest) returns (SuccessResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post: "/api/config/modify/{name}"
|
post: "/api/config/modify/{name}"
|
||||||
body: "yaml"
|
body: "yaml"
|
||||||
@@ -98,10 +103,6 @@ message ModifyConfigRequest {
|
|||||||
string yaml = 2;
|
string yaml = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ModifyConfigResponse {
|
|
||||||
bool success = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message NetWorkInfo {
|
message NetWorkInfo {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
uint64 receive = 2;
|
uint64 receive = 2;
|
||||||
@@ -160,7 +161,9 @@ message StreamSnapRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message StreamInfoResponse {
|
message StreamInfoResponse {
|
||||||
|
string meta = 1;
|
||||||
|
AudioTrackInfo audioTrack = 2;
|
||||||
|
VideoTrackInfo videoTrack = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Wrap {
|
message Wrap {
|
||||||
@@ -177,28 +180,60 @@ message TrackSnapShot {
|
|||||||
repeated Wrap wrap = 5;
|
repeated Wrap wrap = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AudioTrackSnapShotResponse {
|
message AudioTrackInfo {
|
||||||
|
string delta = 1;
|
||||||
|
string meta = 2;
|
||||||
|
uint32 bps = 3;
|
||||||
|
uint32 sampleRate = 4;
|
||||||
|
uint32 channels = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TrackSnapShotResponse {
|
||||||
repeated TrackSnapShot ring = 1;
|
repeated TrackSnapShot ring = 1;
|
||||||
uint32 sampleRate = 2;
|
map<uint32, uint32> reader = 2;
|
||||||
uint32 channels = 3;
|
|
||||||
string info = 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message VideoTrackSnapShotResponse {
|
message VideoTrackInfo {
|
||||||
repeated TrackSnapShot ring = 1;
|
string delta = 1;
|
||||||
uint32 width = 2;
|
string meta = 2;
|
||||||
uint32 height = 3;
|
uint32 bps = 3;
|
||||||
string info = 4;
|
uint32 width = 4;
|
||||||
|
uint32 height = 5;
|
||||||
|
uint32 gop = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message StopSubscribeRequest {
|
message SuccessResponse {
|
||||||
uint32 id = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message StopSubscribeResponse {
|
|
||||||
bool success = 1;
|
bool success = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RequestWithId {
|
message RequestWithId {
|
||||||
uint32 id = 1;
|
uint32 id = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message SubscribersRequest {
|
||||||
|
string streamPath = 1;
|
||||||
|
int32 pageNum = 2;
|
||||||
|
int32 pageSize = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RingReaderSnapShot {
|
||||||
|
uint32 sequence = 1;
|
||||||
|
uint32 timestamp = 2;
|
||||||
|
uint32 delay = 3;
|
||||||
|
int32 state = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SubscriberSnapShot {
|
||||||
|
uint32 id = 1;
|
||||||
|
google.protobuf.Timestamp startTime = 2;
|
||||||
|
RingReaderSnapShot audioReader = 3;
|
||||||
|
RingReaderSnapShot videoReader = 4;
|
||||||
|
string meta = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SubscribersResponse {
|
||||||
|
int32 total = 1;
|
||||||
|
int32 pageNum = 2;
|
||||||
|
int32 pageSize = 3;
|
||||||
|
repeated SubscriberSnapShot list = 4;
|
||||||
|
}
|
@@ -29,12 +29,13 @@ type GlobalClient interface {
|
|||||||
Restart(ctx context.Context, in *RequestWithId, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
Restart(ctx context.Context, in *RequestWithId, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||||
StreamList(ctx context.Context, in *StreamListRequest, opts ...grpc.CallOption) (*StreamListResponse, error)
|
StreamList(ctx context.Context, in *StreamListRequest, opts ...grpc.CallOption) (*StreamListResponse, error)
|
||||||
StreamInfo(ctx context.Context, in *StreamSnapRequest, opts ...grpc.CallOption) (*StreamInfoResponse, error)
|
StreamInfo(ctx context.Context, in *StreamSnapRequest, opts ...grpc.CallOption) (*StreamInfoResponse, error)
|
||||||
AudioTrackSnap(ctx context.Context, in *StreamSnapRequest, opts ...grpc.CallOption) (*AudioTrackSnapShotResponse, error)
|
GetSubscribers(ctx context.Context, in *SubscribersRequest, opts ...grpc.CallOption) (*SubscribersResponse, error)
|
||||||
VideoTrackSnap(ctx context.Context, in *StreamSnapRequest, opts ...grpc.CallOption) (*VideoTrackSnapShotResponse, error)
|
AudioTrackSnap(ctx context.Context, in *StreamSnapRequest, opts ...grpc.CallOption) (*TrackSnapShotResponse, error)
|
||||||
StopSubscribe(ctx context.Context, in *StopSubscribeRequest, opts ...grpc.CallOption) (*StopSubscribeResponse, error)
|
VideoTrackSnap(ctx context.Context, in *StreamSnapRequest, opts ...grpc.CallOption) (*TrackSnapShotResponse, error)
|
||||||
|
StopSubscribe(ctx context.Context, in *RequestWithId, opts ...grpc.CallOption) (*SuccessResponse, error)
|
||||||
GetConfig(ctx context.Context, in *GetConfigRequest, opts ...grpc.CallOption) (*GetConfigResponse, error)
|
GetConfig(ctx context.Context, in *GetConfigRequest, opts ...grpc.CallOption) (*GetConfigResponse, error)
|
||||||
GetFormily(ctx context.Context, in *GetConfigRequest, opts ...grpc.CallOption) (*GetConfigResponse, error)
|
GetFormily(ctx context.Context, in *GetConfigRequest, opts ...grpc.CallOption) (*GetConfigResponse, error)
|
||||||
ModifyConfig(ctx context.Context, in *ModifyConfigRequest, opts ...grpc.CallOption) (*ModifyConfigResponse, error)
|
ModifyConfig(ctx context.Context, in *ModifyConfigRequest, opts ...grpc.CallOption) (*SuccessResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type globalClient struct {
|
type globalClient struct {
|
||||||
@@ -99,8 +100,17 @@ func (c *globalClient) StreamInfo(ctx context.Context, in *StreamSnapRequest, op
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *globalClient) AudioTrackSnap(ctx context.Context, in *StreamSnapRequest, opts ...grpc.CallOption) (*AudioTrackSnapShotResponse, error) {
|
func (c *globalClient) GetSubscribers(ctx context.Context, in *SubscribersRequest, opts ...grpc.CallOption) (*SubscribersResponse, error) {
|
||||||
out := new(AudioTrackSnapShotResponse)
|
out := new(SubscribersResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/m7s.Global/GetSubscribers", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *globalClient) AudioTrackSnap(ctx context.Context, in *StreamSnapRequest, opts ...grpc.CallOption) (*TrackSnapShotResponse, error) {
|
||||||
|
out := new(TrackSnapShotResponse)
|
||||||
err := c.cc.Invoke(ctx, "/m7s.Global/AudioTrackSnap", in, out, opts...)
|
err := c.cc.Invoke(ctx, "/m7s.Global/AudioTrackSnap", in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -108,8 +118,8 @@ func (c *globalClient) AudioTrackSnap(ctx context.Context, in *StreamSnapRequest
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *globalClient) VideoTrackSnap(ctx context.Context, in *StreamSnapRequest, opts ...grpc.CallOption) (*VideoTrackSnapShotResponse, error) {
|
func (c *globalClient) VideoTrackSnap(ctx context.Context, in *StreamSnapRequest, opts ...grpc.CallOption) (*TrackSnapShotResponse, error) {
|
||||||
out := new(VideoTrackSnapShotResponse)
|
out := new(TrackSnapShotResponse)
|
||||||
err := c.cc.Invoke(ctx, "/m7s.Global/VideoTrackSnap", in, out, opts...)
|
err := c.cc.Invoke(ctx, "/m7s.Global/VideoTrackSnap", in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -117,8 +127,8 @@ func (c *globalClient) VideoTrackSnap(ctx context.Context, in *StreamSnapRequest
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *globalClient) StopSubscribe(ctx context.Context, in *StopSubscribeRequest, opts ...grpc.CallOption) (*StopSubscribeResponse, error) {
|
func (c *globalClient) StopSubscribe(ctx context.Context, in *RequestWithId, opts ...grpc.CallOption) (*SuccessResponse, error) {
|
||||||
out := new(StopSubscribeResponse)
|
out := new(SuccessResponse)
|
||||||
err := c.cc.Invoke(ctx, "/m7s.Global/StopSubscribe", in, out, opts...)
|
err := c.cc.Invoke(ctx, "/m7s.Global/StopSubscribe", in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -144,8 +154,8 @@ func (c *globalClient) GetFormily(ctx context.Context, in *GetConfigRequest, opt
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *globalClient) ModifyConfig(ctx context.Context, in *ModifyConfigRequest, opts ...grpc.CallOption) (*ModifyConfigResponse, error) {
|
func (c *globalClient) ModifyConfig(ctx context.Context, in *ModifyConfigRequest, opts ...grpc.CallOption) (*SuccessResponse, error) {
|
||||||
out := new(ModifyConfigResponse)
|
out := new(SuccessResponse)
|
||||||
err := c.cc.Invoke(ctx, "/m7s.Global/ModifyConfig", in, out, opts...)
|
err := c.cc.Invoke(ctx, "/m7s.Global/ModifyConfig", in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -163,12 +173,13 @@ type GlobalServer interface {
|
|||||||
Restart(context.Context, *RequestWithId) (*emptypb.Empty, error)
|
Restart(context.Context, *RequestWithId) (*emptypb.Empty, error)
|
||||||
StreamList(context.Context, *StreamListRequest) (*StreamListResponse, error)
|
StreamList(context.Context, *StreamListRequest) (*StreamListResponse, error)
|
||||||
StreamInfo(context.Context, *StreamSnapRequest) (*StreamInfoResponse, error)
|
StreamInfo(context.Context, *StreamSnapRequest) (*StreamInfoResponse, error)
|
||||||
AudioTrackSnap(context.Context, *StreamSnapRequest) (*AudioTrackSnapShotResponse, error)
|
GetSubscribers(context.Context, *SubscribersRequest) (*SubscribersResponse, error)
|
||||||
VideoTrackSnap(context.Context, *StreamSnapRequest) (*VideoTrackSnapShotResponse, error)
|
AudioTrackSnap(context.Context, *StreamSnapRequest) (*TrackSnapShotResponse, error)
|
||||||
StopSubscribe(context.Context, *StopSubscribeRequest) (*StopSubscribeResponse, error)
|
VideoTrackSnap(context.Context, *StreamSnapRequest) (*TrackSnapShotResponse, error)
|
||||||
|
StopSubscribe(context.Context, *RequestWithId) (*SuccessResponse, error)
|
||||||
GetConfig(context.Context, *GetConfigRequest) (*GetConfigResponse, error)
|
GetConfig(context.Context, *GetConfigRequest) (*GetConfigResponse, error)
|
||||||
GetFormily(context.Context, *GetConfigRequest) (*GetConfigResponse, error)
|
GetFormily(context.Context, *GetConfigRequest) (*GetConfigResponse, error)
|
||||||
ModifyConfig(context.Context, *ModifyConfigRequest) (*ModifyConfigResponse, error)
|
ModifyConfig(context.Context, *ModifyConfigRequest) (*SuccessResponse, error)
|
||||||
mustEmbedUnimplementedGlobalServer()
|
mustEmbedUnimplementedGlobalServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,13 +205,16 @@ func (UnimplementedGlobalServer) StreamList(context.Context, *StreamListRequest)
|
|||||||
func (UnimplementedGlobalServer) StreamInfo(context.Context, *StreamSnapRequest) (*StreamInfoResponse, error) {
|
func (UnimplementedGlobalServer) StreamInfo(context.Context, *StreamSnapRequest) (*StreamInfoResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method StreamInfo not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method StreamInfo not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedGlobalServer) AudioTrackSnap(context.Context, *StreamSnapRequest) (*AudioTrackSnapShotResponse, error) {
|
func (UnimplementedGlobalServer) GetSubscribers(context.Context, *SubscribersRequest) (*SubscribersResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method GetSubscribers not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedGlobalServer) AudioTrackSnap(context.Context, *StreamSnapRequest) (*TrackSnapShotResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method AudioTrackSnap not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method AudioTrackSnap not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedGlobalServer) VideoTrackSnap(context.Context, *StreamSnapRequest) (*VideoTrackSnapShotResponse, error) {
|
func (UnimplementedGlobalServer) VideoTrackSnap(context.Context, *StreamSnapRequest) (*TrackSnapShotResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method VideoTrackSnap not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method VideoTrackSnap not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedGlobalServer) StopSubscribe(context.Context, *StopSubscribeRequest) (*StopSubscribeResponse, error) {
|
func (UnimplementedGlobalServer) StopSubscribe(context.Context, *RequestWithId) (*SuccessResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method StopSubscribe not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method StopSubscribe not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedGlobalServer) GetConfig(context.Context, *GetConfigRequest) (*GetConfigResponse, error) {
|
func (UnimplementedGlobalServer) GetConfig(context.Context, *GetConfigRequest) (*GetConfigResponse, error) {
|
||||||
@@ -209,7 +223,7 @@ func (UnimplementedGlobalServer) GetConfig(context.Context, *GetConfigRequest) (
|
|||||||
func (UnimplementedGlobalServer) GetFormily(context.Context, *GetConfigRequest) (*GetConfigResponse, error) {
|
func (UnimplementedGlobalServer) GetFormily(context.Context, *GetConfigRequest) (*GetConfigResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetFormily not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetFormily not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedGlobalServer) ModifyConfig(context.Context, *ModifyConfigRequest) (*ModifyConfigResponse, error) {
|
func (UnimplementedGlobalServer) ModifyConfig(context.Context, *ModifyConfigRequest) (*SuccessResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method ModifyConfig not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method ModifyConfig not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedGlobalServer) mustEmbedUnimplementedGlobalServer() {}
|
func (UnimplementedGlobalServer) mustEmbedUnimplementedGlobalServer() {}
|
||||||
@@ -333,6 +347,24 @@ func _Global_StreamInfo_Handler(srv interface{}, ctx context.Context, dec func(i
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _Global_GetSubscribers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(SubscribersRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(GlobalServer).GetSubscribers(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/m7s.Global/GetSubscribers",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(GlobalServer).GetSubscribers(ctx, req.(*SubscribersRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
func _Global_AudioTrackSnap_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _Global_AudioTrackSnap_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(StreamSnapRequest)
|
in := new(StreamSnapRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
@@ -370,7 +402,7 @@ func _Global_VideoTrackSnap_Handler(srv interface{}, ctx context.Context, dec fu
|
|||||||
}
|
}
|
||||||
|
|
||||||
func _Global_StopSubscribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _Global_StopSubscribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(StopSubscribeRequest)
|
in := new(RequestWithId)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -382,7 +414,7 @@ func _Global_StopSubscribe_Handler(srv interface{}, ctx context.Context, dec fun
|
|||||||
FullMethod: "/m7s.Global/StopSubscribe",
|
FullMethod: "/m7s.Global/StopSubscribe",
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(GlobalServer).StopSubscribe(ctx, req.(*StopSubscribeRequest))
|
return srv.(GlobalServer).StopSubscribe(ctx, req.(*RequestWithId))
|
||||||
}
|
}
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
@@ -472,6 +504,10 @@ var Global_ServiceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "StreamInfo",
|
MethodName: "StreamInfo",
|
||||||
Handler: _Global_StreamInfo_Handler,
|
Handler: _Global_StreamInfo_Handler,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
MethodName: "GetSubscribers",
|
||||||
|
Handler: _Global_GetSubscribers_Handler,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
MethodName: "AudioTrackSnap",
|
MethodName: "AudioTrackSnap",
|
||||||
Handler: _Global_AudioTrackSnap_Handler,
|
Handler: _Global_AudioTrackSnap_Handler,
|
||||||
|
@@ -32,8 +32,7 @@ type Publish struct {
|
|||||||
IdleTimeout time.Duration `desc:"空闲(无订阅)超时"` // 空闲(无订阅)超时
|
IdleTimeout time.Duration `desc:"空闲(无订阅)超时"` // 空闲(无订阅)超时
|
||||||
PauseTimeout time.Duration `default:"30s" desc:"暂停超时时间"` // 暂停超时
|
PauseTimeout time.Duration `default:"30s" desc:"暂停超时时间"` // 暂停超时
|
||||||
BufferTime time.Duration `desc:"缓冲长度(单位:秒),0代表取最近关键帧"` // 缓冲长度(单位:秒),0代表取最近关键帧
|
BufferTime time.Duration `desc:"缓冲长度(单位:秒),0代表取最近关键帧"` // 缓冲长度(单位:秒),0代表取最近关键帧
|
||||||
SpeedLimit time.Duration `default:"500ms" desc:"速度限制最大等待时间,0则不等待"` //速度限制最大等待时间
|
Speed float64 `default:"0" desc:"倍速"` // 倍速,0 为不限速
|
||||||
Speed float64 `default:"1" desc:"倍速"` // 倍速
|
|
||||||
Key string `desc:"发布鉴权key"` // 发布鉴权key
|
Key string `desc:"发布鉴权key"` // 发布鉴权key
|
||||||
SecretArgName string `default:"secret" desc:"发布鉴权参数名"` // 发布鉴权参数名
|
SecretArgName string `default:"secret" desc:"发布鉴权参数名"` // 发布鉴权参数名
|
||||||
ExpireArgName string `default:"expire" desc:"发布鉴权失效时间参数名"` // 发布鉴权失效时间参数名
|
ExpireArgName string `default:"expire" desc:"发布鉴权失效时间参数名"` // 发布鉴权失效时间参数名
|
||||||
|
@@ -29,7 +29,7 @@ func NewBufReader(reader io.Reader) (r *BufReader) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *BufReader) eat() error {
|
func (r *BufReader) eat() error {
|
||||||
buf := r.buf.Malloc(r.BufLen)
|
buf := r.buf.NextN(r.BufLen)
|
||||||
if n, err := r.reader.Read(buf); err != nil {
|
if n, err := r.reader.Read(buf); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if n < r.BufLen {
|
} else if n < r.BufLen {
|
||||||
|
@@ -190,6 +190,11 @@ func (buffers *Buffers) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
return buf.WriteTo(w)
|
return buf.WriteTo(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (buffers *Buffers) ReadN(n int) (r net.Buffers, actual int) {
|
||||||
|
actual = buffers.WriteNTo(n, &r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (buffers *Buffers) WriteNTo(n int, result *net.Buffers) (actual int) {
|
func (buffers *Buffers) WriteNTo(n int, result *net.Buffers) (actual int) {
|
||||||
for actual = n; buffers.Length > 0 && n > 0; buffers.skipBuf() {
|
for actual = n; buffers.Length > 0 && n > 0; buffers.skipBuf() {
|
||||||
if buffers.curBufLen > n {
|
if buffers.curBufLen > n {
|
||||||
|
@@ -91,6 +91,9 @@ func NewScalableMemoryAllocator(size int) (ret *ScalableMemoryAllocator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sma *ScalableMemoryAllocator) Malloc(size int) (memory []byte) {
|
func (sma *ScalableMemoryAllocator) Malloc(size int) (memory []byte) {
|
||||||
|
if sma == nil {
|
||||||
|
return make([]byte, size)
|
||||||
|
}
|
||||||
memory, _, _, _ = sma.Malloc2(size)
|
memory, _, _, _ = sma.Malloc2(size)
|
||||||
return memory
|
return memory
|
||||||
}
|
}
|
||||||
@@ -112,6 +115,9 @@ func (sma *ScalableMemoryAllocator) GetScalableMemoryAllocator() *ScalableMemory
|
|||||||
return sma
|
return sma
|
||||||
}
|
}
|
||||||
func (sma *ScalableMemoryAllocator) Free(mem []byte) bool {
|
func (sma *ScalableMemoryAllocator) Free(mem []byte) bool {
|
||||||
|
if sma == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
ptr := uintptr(unsafe.Pointer(&mem[:1][0]))
|
ptr := uintptr(unsafe.Pointer(&mem[:1][0]))
|
||||||
for _, child := range *sma {
|
for _, child := range *sma {
|
||||||
if start := int(int64(ptr) - child.start); child.Free2(start, start+len(mem)) {
|
if start := int(int64(ptr) - child.start); child.Free2(start, start+len(mem)) {
|
||||||
@@ -144,6 +150,20 @@ func (r *RecyclableMemory) Malloc(size int) (memory []byte) {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *RecyclableMemory) Pop() []int {
|
||||||
|
l := len(r.mem)
|
||||||
|
if l == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ret := r.mem[l-3:]
|
||||||
|
r.mem = r.mem[:l-3]
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RecyclableMemory) Push(args ...int) {
|
||||||
|
r.mem = append(r.mem, args...)
|
||||||
|
}
|
||||||
|
|
||||||
func (r *RecyclableMemory) Recycle() {
|
func (r *RecyclableMemory) Recycle() {
|
||||||
for i := 0; i < len(r.mem); i += 3 {
|
for i := 0; i < len(r.mem); i += 3 {
|
||||||
r.Free2(r.mem[i], r.mem[i+1], r.mem[i+2])
|
r.Free2(r.mem[i], r.mem[i+1], r.mem[i+2])
|
||||||
@@ -157,6 +177,9 @@ func (r *RecyclableMemory) RecycleBack(n int) {
|
|||||||
start := *end - n
|
start := *end - n
|
||||||
r.Free2(r.mem[l-3], start, *end)
|
r.Free2(r.mem[l-3], start, *end)
|
||||||
*end = start
|
*end = start
|
||||||
|
if start == r.mem[l-2] {
|
||||||
|
r.mem = r.mem[:l-3]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type RecyclableBuffers struct {
|
type RecyclableBuffers struct {
|
||||||
@@ -164,7 +187,7 @@ type RecyclableBuffers struct {
|
|||||||
Buffers
|
Buffers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RecyclableBuffers) Malloc(size int) (memory []byte) {
|
func (r *RecyclableBuffers) NextN(size int) (memory []byte) {
|
||||||
memory = r.ScalableMemoryAllocator.Malloc(size)
|
memory = r.ScalableMemoryAllocator.Malloc(size)
|
||||||
r.Buffers.ReadFromBytes(memory)
|
r.Buffers.ReadFromBytes(memory)
|
||||||
return
|
return
|
||||||
|
@@ -73,6 +73,7 @@ func (plugin *PluginMeta) Init(s *Server, userConfig map[string]any) {
|
|||||||
}
|
}
|
||||||
if p.Disabled {
|
if p.Disabled {
|
||||||
p.Warn("plugin disabled")
|
p.Warn("plugin disabled")
|
||||||
|
return
|
||||||
} else {
|
} else {
|
||||||
p.assign()
|
p.assign()
|
||||||
}
|
}
|
||||||
|
@@ -79,6 +79,20 @@ func (avcc *RTMPVideo) Parse(t *AVTrack) (isIDR, isSeq bool, raw any, err error)
|
|||||||
if err = parseSequence(); err != nil {
|
if err = parseSequence(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// var naluLen int
|
||||||
|
// for reader.Length > 0 {
|
||||||
|
// naluLen, err = reader.ReadBE(4) // naluLenM
|
||||||
|
// if err != nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// _, n := reader.ReadN(naluLen)
|
||||||
|
// fmt.Println(avcc.Timestamp, n)
|
||||||
|
// if n != naluLen {
|
||||||
|
// err = fmt.Errorf("naluLen:%d != n:%d", naluLen, n)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -112,7 +126,10 @@ func (avcc *RTMPVideo) DecodeConfig(t *AVTrack, from ICodecCtx) (err error) {
|
|||||||
seqFrame.Buffers.ReadFromBytes(b)
|
seqFrame.Buffers.ReadFromBytes(b)
|
||||||
t.SequenceFrame = seqFrame.WrapVideo()
|
t.SequenceFrame = seqFrame.WrapVideo()
|
||||||
if t.Enabled(context.TODO(), TraceLevel) {
|
if t.Enabled(context.TODO(), TraceLevel) {
|
||||||
t.Trace("decConfig", "codec", t.FourCC().String(), "size", seqFrame.GetSize(), "data", seqFrame.String())
|
codec := t.FourCC().String()
|
||||||
|
size := seqFrame.GetSize()
|
||||||
|
data := seqFrame.String()
|
||||||
|
t.Trace("decConfig", "codec", codec, "size", size, "data", data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,18 +228,18 @@ func (avcc *RTMPVideo) ToRaw(codecCtx ICodecCtx) (any, error) {
|
|||||||
|
|
||||||
func (h264 *H264Ctx) CreateFrame(from *AVFrame) (frame IAVFrame, err error) {
|
func (h264 *H264Ctx) CreateFrame(from *AVFrame) (frame IAVFrame, err error) {
|
||||||
var rtmpVideo RTMPVideo
|
var rtmpVideo RTMPVideo
|
||||||
|
rtmpVideo.Timestamp = uint32(from.Timestamp / time.Millisecond)
|
||||||
rtmpVideo.RecyclableBuffers = &util.RecyclableBuffers{}
|
rtmpVideo.RecyclableBuffers = &util.RecyclableBuffers{}
|
||||||
rtmpVideo.ScalableMemoryAllocator = from.Wraps[0].GetScalableMemoryAllocator()
|
// TODO: rtmpVideo.ScalableMemoryAllocator = from.Wraps[0].GetScalableMemoryAllocator()
|
||||||
nalus := from.Raw.(Nalus)
|
nalus := from.Raw.(Nalus)
|
||||||
head := rtmpVideo.Malloc(5)
|
head := rtmpVideo.NextN(5)
|
||||||
head[0] = util.Conditoinal[byte](from.IDR, 0x10, 0x20) | byte(ParseVideoCodec(h264.FourCC()))
|
head[0] = util.Conditoinal[byte](from.IDR, 0x10, 0x20) | byte(ParseVideoCodec(h264.FourCC()))
|
||||||
head[1] = 1
|
head[1] = 1
|
||||||
util.PutBE(head[2:5], (nalus.PTS-nalus.DTS)/90) // cts
|
util.PutBE(head[2:5], (nalus.PTS-nalus.DTS)/90) // cts
|
||||||
rtmpVideo.ReadFromBytes(head)
|
|
||||||
for _, nalu := range nalus.Nalus {
|
for _, nalu := range nalus.Nalus {
|
||||||
naluLenM := rtmpVideo.Malloc(4)
|
naluLenM := rtmpVideo.NextN(4)
|
||||||
binary.BigEndian.PutUint32(naluLenM, uint32(util.LenOfBuffers(nalu)))
|
naluLen := uint32(util.LenOfBuffers(nalu))
|
||||||
rtmpVideo.ReadFromBytes(naluLenM)
|
binary.BigEndian.PutUint32(naluLenM, naluLen)
|
||||||
rtmpVideo.ReadFromBytes(nalu...)
|
rtmpVideo.ReadFromBytes(nalu...)
|
||||||
}
|
}
|
||||||
frame = &rtmpVideo
|
frame = &rtmpVideo
|
||||||
|
@@ -50,16 +50,27 @@ func (r *RTPVideo) Parse(t *AVTrack) (isIDR, isSeq bool, raw any, err error) {
|
|||||||
} else {
|
} else {
|
||||||
ctx = &RTPH264Ctx{}
|
ctx = &RTPH264Ctx{}
|
||||||
ctx.RTPCodecParameters = *r.RTPCodecParameters
|
ctx.RTPCodecParameters = *r.RTPCodecParameters
|
||||||
|
t.ICodecCtx = ctx
|
||||||
}
|
}
|
||||||
raw, err = r.ToRaw(ctx)
|
raw, err = r.ToRaw(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
nalus := raw.(Nalus)
|
nalus := raw.(Nalus)
|
||||||
if len(nalus.Nalus) > 0 {
|
for _, nalu := range nalus.Nalus {
|
||||||
isIDR = nalus.H264Type() == codec.NALU_IDR_Picture
|
switch codec.ParseH264NALUType(nalu[0][0]) {
|
||||||
}
|
case codec.NALU_SPS:
|
||||||
|
ctx = &RTPH264Ctx{}
|
||||||
|
ctx.SPS = [][]byte{slices.Concat(nalu...)}
|
||||||
|
ctx.SPSInfo.Unmarshal(ctx.SPS[0])
|
||||||
|
ctx.RTPCodecParameters = *r.RTPCodecParameters
|
||||||
t.ICodecCtx = ctx
|
t.ICodecCtx = ctx
|
||||||
|
case codec.NALU_PPS:
|
||||||
|
ctx.PPS = [][]byte{slices.Concat(nalu...)}
|
||||||
|
case codec.NALU_IDR_Picture:
|
||||||
|
isIDR = true
|
||||||
|
}
|
||||||
|
}
|
||||||
case webrtc.MimeTypeVP9:
|
case webrtc.MimeTypeVP9:
|
||||||
// var ctx RTPVP9Ctx
|
// var ctx RTPVP9Ctx
|
||||||
// ctx.FourCC = codec.FourCC_VP9
|
// ctx.FourCC = codec.FourCC_VP9
|
||||||
@@ -136,22 +147,14 @@ func (h264 *RTPH264Ctx) CreateFrame(from *AVFrame) (frame IAVFrame, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *RTPVideo) ToRaw(ictx ICodecCtx) (any, error) {
|
func (r *RTPVideo) ToRaw(ictx ICodecCtx) (any, error) {
|
||||||
switch ctx := ictx.(type) {
|
switch ictx.(type) {
|
||||||
case *RTPH264Ctx:
|
case *RTPH264Ctx:
|
||||||
var nalus Nalus
|
var nalus Nalus
|
||||||
var nalu Nalu
|
var nalu Nalu
|
||||||
var naluType codec.H264NALUType
|
var naluType codec.H264NALUType
|
||||||
gotNalu := func(t codec.H264NALUType) {
|
gotNalu := func() {
|
||||||
if len(nalu) > 0 {
|
if len(nalu) > 0 {
|
||||||
switch t {
|
|
||||||
case codec.NALU_SPS:
|
|
||||||
ctx.SPS = [][]byte{slices.Concat(nalu...)}
|
|
||||||
ctx.SPSInfo.Unmarshal(ctx.SPS[0])
|
|
||||||
case codec.NALU_PPS:
|
|
||||||
ctx.PPS = [][]byte{slices.Concat(nalu...)}
|
|
||||||
default:
|
|
||||||
nalus.Nalus = append(nalus.Nalus, nalu)
|
nalus.Nalus = append(nalus.Nalus, nalu)
|
||||||
}
|
|
||||||
nalu = nil
|
nalu = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,9 +162,10 @@ func (r *RTPVideo) ToRaw(ictx ICodecCtx) (any, error) {
|
|||||||
packet := r.Packets[i]
|
packet := r.Packets[i]
|
||||||
nalus.PTS = time.Duration(packet.Timestamp)
|
nalus.PTS = time.Duration(packet.Timestamp)
|
||||||
nalus.DTS = nalus.PTS
|
nalus.DTS = nalus.PTS
|
||||||
if t := codec.ParseH264NALUType(packet.Payload[0]); t < 24 {
|
b0 := packet.Payload[0]
|
||||||
|
if t := codec.ParseH264NALUType(b0); t < 24 {
|
||||||
nalu = [][]byte{packet.Payload}
|
nalu = [][]byte{packet.Payload}
|
||||||
gotNalu(t)
|
gotNalu()
|
||||||
} else {
|
} else {
|
||||||
offset := t.Offset()
|
offset := t.Offset()
|
||||||
switch t {
|
switch t {
|
||||||
@@ -172,17 +176,17 @@ func (r *RTPVideo) ToRaw(ictx ICodecCtx) (any, error) {
|
|||||||
for buffer := util.Buffer(packet.Payload[offset:]); buffer.CanRead(); {
|
for buffer := util.Buffer(packet.Payload[offset:]); buffer.CanRead(); {
|
||||||
if nextSize := int(buffer.ReadUint16()); buffer.Len() >= nextSize {
|
if nextSize := int(buffer.ReadUint16()); buffer.Len() >= nextSize {
|
||||||
nalu = [][]byte{buffer.ReadN(nextSize)}
|
nalu = [][]byte{buffer.ReadN(nextSize)}
|
||||||
gotNalu(codec.ParseH264NALUType(nalu[0][0]))
|
gotNalu()
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("invalid nalu size %d", nextSize)
|
return nil, fmt.Errorf("invalid nalu size %d", nextSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case codec.NALU_FUA, codec.NALU_FUB:
|
case codec.NALU_FUA, codec.NALU_FUB:
|
||||||
b1 := packet.Payload[1]
|
b1 := packet.Payload[1]
|
||||||
|
fmt.Printf("%08b\n", b1)
|
||||||
if util.Bit1(b1, 0) {
|
if util.Bit1(b1, 0) {
|
||||||
naluType.Parse(b1)
|
naluType.Parse(b1)
|
||||||
firstByte := naluType.Or(packet.Payload[0] & 0x60)
|
nalu = [][]byte{{naluType.Or(b0 & 0x60)}}
|
||||||
nalu = append([][]byte{{firstByte}}, packet.Payload[offset:])
|
|
||||||
}
|
}
|
||||||
if len(nalu) > 0 {
|
if len(nalu) > 0 {
|
||||||
nalu = append(nalu, packet.Payload[offset:])
|
nalu = append(nalu, packet.Payload[offset:])
|
||||||
@@ -190,7 +194,7 @@ func (r *RTPVideo) ToRaw(ictx ICodecCtx) (any, error) {
|
|||||||
return nil, errors.New("fu have no start")
|
return nil, errors.New("fu have no start")
|
||||||
}
|
}
|
||||||
if util.Bit1(b1, 1) {
|
if util.Bit1(b1, 1) {
|
||||||
gotNalu(naluType)
|
gotNalu()
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported nalu type %d", t)
|
return nil, fmt.Errorf("unsupported nalu type %d", t)
|
||||||
|
@@ -195,8 +195,10 @@ func (conf *WebRTCPlugin) Push_(w http.ResponseWriter, r *http.Request) {
|
|||||||
if len(frame.Packets) == 0 || packet.Timestamp == frame.Packets[0].Timestamp {
|
if len(frame.Packets) == 0 || packet.Timestamp == frame.Packets[0].Timestamp {
|
||||||
frame.Packets = append(frame.Packets, &packet)
|
frame.Packets = append(frame.Packets, &packet)
|
||||||
} else {
|
} else {
|
||||||
|
m := frame.Pop()
|
||||||
publisher.WriteAudio(frame)
|
publisher.WriteAudio(frame)
|
||||||
frame = &mrtp.RTPAudio{}
|
frame = &mrtp.RTPAudio{}
|
||||||
|
frame.Push(m...)
|
||||||
frame.Packets = []*rtp.Packet{&packet}
|
frame.Packets = []*rtp.Packet{&packet}
|
||||||
frame.RTPCodecParameters = &codecP
|
frame.RTPCodecParameters = &codecP
|
||||||
frame.ScalableMemoryAllocator = mem
|
frame.ScalableMemoryAllocator = mem
|
||||||
@@ -219,8 +221,7 @@ func (conf *WebRTCPlugin) Push_(w http.ResponseWriter, r *http.Request) {
|
|||||||
var packet rtp.Packet
|
var packet rtp.Packet
|
||||||
buf := frame.Malloc(1460)
|
buf := frame.Malloc(1460)
|
||||||
if n, _, err = track.Read(buf); err == nil {
|
if n, _, err = track.Read(buf); err == nil {
|
||||||
buf := buf[:n]
|
err = packet.Unmarshal(buf[:n])
|
||||||
err = packet.Unmarshal(buf)
|
|
||||||
if n < 1460 {
|
if n < 1460 {
|
||||||
frame.RecycleBack(1460 - n)
|
frame.RecycleBack(1460 - n)
|
||||||
}
|
}
|
||||||
@@ -229,16 +230,18 @@ func (conf *WebRTCPlugin) Push_(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(packet.Payload) == 0 {
|
if len(packet.Payload) == 0 {
|
||||||
frame.RecycleBack(len(buf))
|
frame.RecycleBack(n)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if len(frame.Packets) == 0 || packet.Timestamp == frame.Packets[0].Timestamp {
|
if len(frame.Packets) == 0 || packet.Timestamp == frame.Packets[0].Timestamp {
|
||||||
frame.Packets = append(frame.Packets, &packet)
|
frame.Packets = append(frame.Packets, &packet)
|
||||||
} else {
|
} else {
|
||||||
// t := time.Now()
|
// t := time.Now()
|
||||||
|
m := frame.Pop()
|
||||||
publisher.WriteVideo(frame)
|
publisher.WriteVideo(frame)
|
||||||
// fmt.Println("write video", time.Since(t))
|
// fmt.Println("write video", time.Since(t))
|
||||||
frame = &mrtp.RTPVideo{}
|
frame = &mrtp.RTPVideo{}
|
||||||
|
frame.Push(m...)
|
||||||
frame.Packets = []*rtp.Packet{&packet}
|
frame.Packets = []*rtp.Packet{&packet}
|
||||||
frame.RTPCodecParameters = &codecP
|
frame.RTPCodecParameters = &codecP
|
||||||
frame.ScalableMemoryAllocator = mem
|
frame.ScalableMemoryAllocator = mem
|
||||||
|
41
publisher.go
41
publisher.go
@@ -23,6 +23,7 @@ type SpeedControl struct {
|
|||||||
speed float64
|
speed float64
|
||||||
beginTime time.Time
|
beginTime time.Time
|
||||||
beginTimestamp time.Duration
|
beginTimestamp time.Duration
|
||||||
|
Delta time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SpeedControl) speedControl(speed float64, ts time.Duration) {
|
func (s *SpeedControl) speedControl(speed float64, ts time.Duration) {
|
||||||
@@ -32,15 +33,21 @@ func (s *SpeedControl) speedControl(speed float64, ts time.Duration) {
|
|||||||
s.beginTimestamp = ts
|
s.beginTimestamp = ts
|
||||||
} else {
|
} else {
|
||||||
elapsed := time.Since(s.beginTime)
|
elapsed := time.Since(s.beginTime)
|
||||||
|
if speed == 0 {
|
||||||
|
s.Delta = ts - elapsed
|
||||||
|
return
|
||||||
|
}
|
||||||
should := time.Duration(float64(ts) / speed)
|
should := time.Duration(float64(ts) / speed)
|
||||||
if needSleep := should - elapsed; needSleep > time.Second {
|
s.Delta = should - elapsed
|
||||||
time.Sleep(needSleep)
|
if s.Delta > time.Second {
|
||||||
|
time.Sleep(s.Delta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type AVTracks struct {
|
type AVTracks struct {
|
||||||
*AVTrack
|
*AVTrack
|
||||||
|
SpeedControl
|
||||||
util.Collection[reflect.Type, *AVTrack]
|
util.Collection[reflect.Type, *AVTrack]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +66,6 @@ type Publisher struct {
|
|||||||
PubSubBase
|
PubSubBase
|
||||||
sync.RWMutex `json:"-" yaml:"-"`
|
sync.RWMutex `json:"-" yaml:"-"`
|
||||||
config.Publish
|
config.Publish
|
||||||
SpeedControl
|
|
||||||
State PublisherState
|
State PublisherState
|
||||||
VideoTrack AVTracks
|
VideoTrack AVTracks
|
||||||
AudioTrack AVTracks
|
AudioTrack AVTracks
|
||||||
@@ -100,9 +106,11 @@ func (p *Publisher) checkTimeout() (err error) {
|
|||||||
default:
|
default:
|
||||||
if p.PublishTimeout > 0 {
|
if p.PublishTimeout > 0 {
|
||||||
if !p.VideoTrack.IsEmpty() && !p.VideoTrack.LastValue.WriteTime.IsZero() && time.Since(p.VideoTrack.LastValue.WriteTime) > p.PublishTimeout {
|
if !p.VideoTrack.IsEmpty() && !p.VideoTrack.LastValue.WriteTime.IsZero() && time.Since(p.VideoTrack.LastValue.WriteTime) > p.PublishTimeout {
|
||||||
|
p.Error("video timeout", "writeTime", p.VideoTrack.LastValue.WriteTime)
|
||||||
err = ErrPublishTimeout
|
err = ErrPublishTimeout
|
||||||
}
|
}
|
||||||
if !p.AudioTrack.IsEmpty() && !p.AudioTrack.LastValue.WriteTime.IsZero() && time.Since(p.AudioTrack.LastValue.WriteTime) > p.PublishTimeout {
|
if !p.AudioTrack.IsEmpty() && !p.AudioTrack.LastValue.WriteTime.IsZero() && time.Since(p.AudioTrack.LastValue.WriteTime) > p.PublishTimeout {
|
||||||
|
p.Error("audio timeout", "writeTime", p.AudioTrack.LastValue.WriteTime)
|
||||||
err = ErrPublishTimeout
|
err = ErrPublishTimeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,7 +164,7 @@ func (p *Publisher) writeAV(t *AVTrack, data IAVFrame) {
|
|||||||
if p.Enabled(p, TraceLevel) {
|
if p.Enabled(p, TraceLevel) {
|
||||||
codec := t.FourCC().String()
|
codec := t.FourCC().String()
|
||||||
data := frame.Wraps[0].String()
|
data := frame.Wraps[0].String()
|
||||||
p.Trace("write", "seq", frame.Sequence, "ts", frame.Timestamp, "codec", codec, "size", bytesIn, "data", data)
|
p.Trace("write", "seq", frame.Sequence, "ts", uint32(frame.Timestamp/time.Millisecond), "codec", codec, "size", bytesIn, "data", data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +185,9 @@ func (p *Publisher) WriteVideo(data IAVFrame) (err error) {
|
|||||||
}
|
}
|
||||||
p.Unlock()
|
p.Unlock()
|
||||||
}
|
}
|
||||||
|
oldCodecCtx := t.ICodecCtx
|
||||||
isIDR, isSeq, raw, err := data.Parse(t)
|
isIDR, isSeq, raw, err := data.Parse(t)
|
||||||
|
codecCtxChanged := oldCodecCtx != t.ICodecCtx
|
||||||
if err != nil || (isSeq && !isIDR) {
|
if err != nil || (isSeq && !isIDR) {
|
||||||
p.Error("parse", "err", err)
|
p.Error("parse", "err", err)
|
||||||
return err
|
return err
|
||||||
@@ -189,7 +199,7 @@ func (p *Publisher) WriteVideo(data IAVFrame) (err error) {
|
|||||||
if idr != nil {
|
if idr != nil {
|
||||||
p.GOP = int(t.Value.Sequence - idr.Value.Sequence)
|
p.GOP = int(t.Value.Sequence - idr.Value.Sequence)
|
||||||
if hidr == nil {
|
if hidr == nil {
|
||||||
if l := t.Size - p.GOP; l > 12 && t.Size > 100 {
|
if l := t.Size - p.GOP; l > 50 {
|
||||||
t.Debug("resize", "gop", p.GOP, "before", t.Size, "after", t.Size-5)
|
t.Debug("resize", "gop", p.GOP, "before", t.Size, "after", t.Size-5)
|
||||||
t.Reduce(5) //缩小缓冲环节省内存
|
t.Reduce(5) //缩小缓冲环节省内存
|
||||||
}
|
}
|
||||||
@@ -226,7 +236,11 @@ func (p *Publisher) WriteVideo(data IAVFrame) (err error) {
|
|||||||
for i, track := range p.VideoTrack.Items[1:] {
|
for i, track := range p.VideoTrack.Items[1:] {
|
||||||
if track.ICodecCtx == nil {
|
if track.ICodecCtx == nil {
|
||||||
err = (reflect.New(track.FrameType.Elem()).Interface().(IAVFrame)).DecodeConfig(track, t.ICodecCtx)
|
err = (reflect.New(track.FrameType.Elem()).Interface().(IAVFrame)).DecodeConfig(track, t.ICodecCtx)
|
||||||
for rf := idr; rf != t.Next(); rf = rf.Next() {
|
if err != nil {
|
||||||
|
track.Error("DecodeConfig", "err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for rf := idr; rf != t.Ring; rf = rf.Next() {
|
||||||
if i == 0 && rf.Value.Raw == nil {
|
if i == 0 && rf.Value.Raw == nil {
|
||||||
rf.Value.Raw, err = rf.Value.Wraps[0].ToRaw(t.ICodecCtx)
|
rf.Value.Raw, err = rf.Value.Wraps[0].ToRaw(t.ICodecCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -234,29 +248,26 @@ func (p *Publisher) WriteVideo(data IAVFrame) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if toFrame, err = track.CreateFrame(&rf.Value); err != nil {
|
if toFrame, err = track.CreateFrame(&rf.Value); err != nil {
|
||||||
track.Error("from raw", "err", err)
|
track.Error("from raw", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rf.Value.Wraps = append(rf.Value.Wraps, toFrame)
|
rf.Value.Wraps = append(rf.Value.Wraps, toFrame)
|
||||||
}
|
}
|
||||||
track.Ready.Fulfill(err)
|
defer track.Ready.Fulfill(err)
|
||||||
if err != nil {
|
|
||||||
track.Error("DecodeConfig", "err", err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if toFrame, err = track.CreateFrame(&t.Value); err != nil {
|
if toFrame, err = track.CreateFrame(&t.Value); err != nil {
|
||||||
track.Error("from raw", "err", err)
|
track.Error("from raw", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if codecCtxChanged {
|
||||||
|
toFrame.DecodeConfig(track, t.ICodecCtx)
|
||||||
|
}
|
||||||
t.Value.Wraps = append(t.Value.Wraps, toFrame)
|
t.Value.Wraps = append(t.Value.Wraps, toFrame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
t.Step()
|
t.Step()
|
||||||
p.speedControl(p.Publish.Speed, p.lastTs)
|
p.VideoTrack.speedControl(p.Speed, p.lastTs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,7 +295,7 @@ func (p *Publisher) WriteAudio(data IAVFrame) (err error) {
|
|||||||
}
|
}
|
||||||
p.writeAV(t, data)
|
p.writeAV(t, data)
|
||||||
t.Step()
|
t.Step()
|
||||||
p.speedControl(p.Publish.Speed, p.lastTs)
|
p.AudioTrack.speedControl(p.Publish.Speed, p.lastTs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,6 +18,7 @@ import (
|
|||||||
type Owner struct {
|
type Owner struct {
|
||||||
Conn net.Conn
|
Conn net.Conn
|
||||||
File *os.File
|
File *os.File
|
||||||
|
MetaData any
|
||||||
}
|
}
|
||||||
|
|
||||||
type PubSubBase struct {
|
type PubSubBase struct {
|
||||||
@@ -50,6 +51,8 @@ func (ps *PubSubBase) Init(p *Plugin, streamPath string, options ...any) {
|
|||||||
ps.Closer = v
|
ps.Closer = v
|
||||||
case io.Closer:
|
case io.Closer:
|
||||||
ps.Closer = v
|
ps.Closer = v
|
||||||
|
default:
|
||||||
|
ps.MetaData = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ps.Context, ps.CancelCauseFunc = context.WithCancelCause(ctx)
|
ps.Context, ps.CancelCauseFunc = context.WithCancelCause(ctx)
|
||||||
@@ -63,6 +66,8 @@ type Subscriber struct {
|
|||||||
PubSubBase
|
PubSubBase
|
||||||
config.Subscribe
|
config.Subscribe
|
||||||
Publisher *Publisher
|
Publisher *Publisher
|
||||||
|
AudioReader *AVRingReader
|
||||||
|
VideoReader *AVRingReader
|
||||||
}
|
}
|
||||||
|
|
||||||
type SubscriberHandler struct {
|
type SubscriberHandler struct {
|
||||||
@@ -94,6 +99,7 @@ func (s *Subscriber) Handle(handler SubscriberHandler) {
|
|||||||
if at := s.Publisher.GetAudioTrack(a1); at != nil {
|
if at := s.Publisher.GetAudioTrack(a1); at != nil {
|
||||||
awi = at.WrapIndex
|
awi = at.WrapIndex
|
||||||
ar = NewAVRingReader(at)
|
ar = NewAVRingReader(at)
|
||||||
|
s.AudioReader = ar
|
||||||
ar.Logger = s.Logger.With("reader", a1.String())
|
ar.Logger = s.Logger.With("reader", a1.String())
|
||||||
ar.Info("start read")
|
ar.Info("start read")
|
||||||
ah = reflect.ValueOf(handler.OnAudio)
|
ah = reflect.ValueOf(handler.OnAudio)
|
||||||
@@ -106,6 +112,7 @@ func (s *Subscriber) Handle(handler SubscriberHandler) {
|
|||||||
if vt := s.Publisher.GetVideoTrack(v1); vt != nil {
|
if vt := s.Publisher.GetVideoTrack(v1); vt != nil {
|
||||||
vwi = vt.WrapIndex
|
vwi = vt.WrapIndex
|
||||||
vr = NewAVRingReader(vt)
|
vr = NewAVRingReader(vt)
|
||||||
|
s.VideoReader = vr
|
||||||
vr.Logger = s.Logger.With("reader", v1.String())
|
vr.Logger = s.Logger.With("reader", v1.String())
|
||||||
vr.Info("start read")
|
vr.Info("start read")
|
||||||
vh = reflect.ValueOf(handler.OnVideo)
|
vh = reflect.ValueOf(handler.OnVideo)
|
||||||
@@ -115,11 +122,9 @@ func (s *Subscriber) Handle(handler SubscriberHandler) {
|
|||||||
createVideoReader()
|
createVideoReader()
|
||||||
defer func() {
|
defer func() {
|
||||||
if lastSentVF != nil {
|
if lastSentVF != nil {
|
||||||
// lastSentVF.ReaderLeave()
|
|
||||||
lastSentVF.RUnlock()
|
lastSentVF.RUnlock()
|
||||||
}
|
}
|
||||||
if lastSentAF != nil {
|
if lastSentAF != nil {
|
||||||
// lastSentAF.ReaderLeave()
|
|
||||||
lastSentAF.RUnlock()
|
lastSentAF.RUnlock()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
Reference in New Issue
Block a user