feat: add change subscribe

This commit is contained in:
langhuihui
2024-06-13 17:15:30 +08:00
parent 68a7edf678
commit 00b39aee3e
26 changed files with 890 additions and 406 deletions

34
api.go
View File

@@ -41,7 +41,7 @@ func (s *Server) SysInfo(context.Context, *emptypb.Empty) (res *pb.SysInfoRespon
Arch: runtime.GOARCH, Arch: runtime.GOARCH,
Cpus: int32(runtime.NumCPU()), Cpus: int32(runtime.NumCPU()),
} }
for _, p := range s.Plugins.Items { for p := range s.Plugins.Range {
res.Plugins = append(res.Plugins, &pb.PluginInfo{ res.Plugins = append(res.Plugins, &pb.PluginInfo{
Name: p.Meta.Name, Name: p.Meta.Name,
Version: p.Meta.Version, Version: p.Meta.Version,
@@ -101,7 +101,7 @@ func (s *Server) getStreamInfo(pub *Publisher) (res *pb.StreamInfoResponse, err
Path: pub.StreamPath, Path: pub.StreamPath,
State: int32(pub.State), State: int32(pub.State),
StartTime: timestamppb.New(pub.StartTime), StartTime: timestamppb.New(pub.StartTime),
Subscribers: int32(len(pub.Subscribers)), Subscribers: int32(pub.Subscribers.Length),
Type: pub.Plugin.Meta.Name, Type: pub.Plugin.Meta.Name,
} }
@@ -148,7 +148,7 @@ func (s *Server) StreamInfo(ctx context.Context, req *pb.StreamSnapRequest) (res
func (s *Server) GetSubscribers(ctx context.Context, req *pb.SubscribersRequest) (res *pb.SubscribersResponse, err error) { func (s *Server) GetSubscribers(ctx context.Context, req *pb.SubscribersRequest) (res *pb.SubscribersResponse, err error) {
s.Call(func() { s.Call(func() {
var subscribers []*pb.SubscriberSnapShot var subscribers []*pb.SubscriberSnapShot
for _, subscriber := range s.Subscribers.Items { for subscriber := range s.Subscribers.Range {
meta, _ := json.Marshal(subscriber.MetaData) meta, _ := json.Marshal(subscriber.MetaData)
snap := &pb.SubscriberSnapShot{ snap := &pb.SubscriberSnapShot{
Id: uint32(subscriber.ID), Id: uint32(subscriber.ID),
@@ -195,7 +195,7 @@ func (s *Server) AudioTrackSnap(ctx context.Context, req *pb.StreamSnapRequest)
res.Memory = append(res.Memory, &pb.MemoryBlockGroup{List: list, Size: uint32(memlist.Size)}) res.Memory = append(res.Memory, &pb.MemoryBlockGroup{List: list, Size: uint32(memlist.Size)})
} }
res.Reader = make(map[uint32]uint32) res.Reader = make(map[uint32]uint32)
for sub := range pub.Subscribers { for sub := range pub.SubscriberRange {
if sub.AudioReader == nil { if sub.AudioReader == nil {
continue continue
} }
@@ -259,6 +259,7 @@ func (s *Server) api_VideoTrack_SSE(rw http.ResponseWriter, r *http.Request) {
return return
} }
} }
func (s *Server) VideoTrackSnap(ctx context.Context, req *pb.StreamSnapRequest) (res *pb.TrackSnapShotResponse, 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 && !pub.VideoTrack.IsEmpty() { if pub, ok := s.Streams.Get(req.StreamPath); ok && !pub.VideoTrack.IsEmpty() {
@@ -274,7 +275,7 @@ func (s *Server) VideoTrackSnap(ctx context.Context, req *pb.StreamSnapRequest)
res.Memory = append(res.Memory, &pb.MemoryBlockGroup{List: list, Size: uint32(memlist.Size)}) res.Memory = append(res.Memory, &pb.MemoryBlockGroup{List: list, Size: uint32(memlist.Size)})
} }
res.Reader = make(map[uint32]uint32) res.Reader = make(map[uint32]uint32)
for sub := range pub.Subscribers { for sub := range pub.SubscriberRange {
if sub.VideoReader == nil { if sub.VideoReader == nil {
continue continue
} }
@@ -325,6 +326,23 @@ func (s *Server) Shutdown(ctx context.Context, req *pb.RequestWithId) (res *empt
return empty, err return empty, err
} }
func (s *Server) ChangeSubscribe(ctx context.Context, req *pb.ChangeSubscribeRequest) (res *pb.SuccessResponse, err error) {
s.Call(func() {
if subscriber, ok := s.Subscribers.Get(int(req.Id)); ok {
if pub, ok := s.Streams.Get(req.StreamPath); ok {
subscriber.Publisher.RemoveSubscriber(subscriber)
subscriber.StreamPath = req.StreamPath
pub.AddSubscriber(subscriber)
return
}
}
err = pkg.ErrNotFound
})
return &pb.SuccessResponse{
Success: err == nil,
}, err
}
func (s *Server) StopSubscribe(ctx context.Context, req *pb.RequestWithId) (res *pb.SuccessResponse, 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 {
@@ -342,7 +360,7 @@ func (s *Server) StopSubscribe(ctx context.Context, req *pb.RequestWithId) (res
func (s *Server) StreamList(_ context.Context, req *pb.StreamListRequest) (res *pb.StreamListResponse, err error) { func (s *Server) StreamList(_ context.Context, req *pb.StreamListRequest) (res *pb.StreamListResponse, err error) {
s.Call(func() { s.Call(func() {
var streams []*pb.StreamInfoResponse var streams []*pb.StreamInfoResponse
for _, publisher := range s.Streams.Items { for publisher := range s.Streams.Range {
info, err := s.getStreamInfo(publisher) info, err := s.getStreamInfo(publisher)
if err != nil { if err != nil {
continue continue
@@ -359,8 +377,8 @@ func (s *Server) WaitList(context.Context, *emptypb.Empty) (res *pb.StreamWaitLi
res = &pb.StreamWaitListResponse{ res = &pb.StreamWaitListResponse{
List: make(map[string]int32), List: make(map[string]int32),
} }
for streamPath, subs := range s.Waiting { for subs := range s.Waiting.Range {
res.List[streamPath] = int32(len(subs)) res.List[subs.StreamPath] = int32(subs.Subscribers.Length)
} }
}) })
return return

View File

@@ -1680,6 +1680,61 @@ func (x *RequestWithId) GetId() uint32 {
return 0 return 0
} }
type ChangeSubscribeRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id uint32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
StreamPath string `protobuf:"bytes,2,opt,name=streamPath,proto3" json:"streamPath,omitempty"`
}
func (x *ChangeSubscribeRequest) Reset() {
*x = ChangeSubscribeRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_global_proto_msgTypes[24]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ChangeSubscribeRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ChangeSubscribeRequest) ProtoMessage() {}
func (x *ChangeSubscribeRequest) ProtoReflect() protoreflect.Message {
mi := &file_global_proto_msgTypes[24]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ChangeSubscribeRequest.ProtoReflect.Descriptor instead.
func (*ChangeSubscribeRequest) Descriptor() ([]byte, []int) {
return file_global_proto_rawDescGZIP(), []int{24}
}
func (x *ChangeSubscribeRequest) GetId() uint32 {
if x != nil {
return x.Id
}
return 0
}
func (x *ChangeSubscribeRequest) GetStreamPath() string {
if x != nil {
return x.StreamPath
}
return ""
}
type SubscribersRequest struct { type SubscribersRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@@ -1693,7 +1748,7 @@ type SubscribersRequest struct {
func (x *SubscribersRequest) Reset() { func (x *SubscribersRequest) Reset() {
*x = SubscribersRequest{} *x = SubscribersRequest{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_global_proto_msgTypes[24] mi := &file_global_proto_msgTypes[25]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1706,7 +1761,7 @@ func (x *SubscribersRequest) String() string {
func (*SubscribersRequest) ProtoMessage() {} func (*SubscribersRequest) ProtoMessage() {}
func (x *SubscribersRequest) ProtoReflect() protoreflect.Message { func (x *SubscribersRequest) ProtoReflect() protoreflect.Message {
mi := &file_global_proto_msgTypes[24] mi := &file_global_proto_msgTypes[25]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1719,7 +1774,7 @@ func (x *SubscribersRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use SubscribersRequest.ProtoReflect.Descriptor instead. // Deprecated: Use SubscribersRequest.ProtoReflect.Descriptor instead.
func (*SubscribersRequest) Descriptor() ([]byte, []int) { func (*SubscribersRequest) Descriptor() ([]byte, []int) {
return file_global_proto_rawDescGZIP(), []int{24} return file_global_proto_rawDescGZIP(), []int{25}
} }
func (x *SubscribersRequest) GetStreamPath() string { func (x *SubscribersRequest) GetStreamPath() string {
@@ -1757,7 +1812,7 @@ type RingReaderSnapShot struct {
func (x *RingReaderSnapShot) Reset() { func (x *RingReaderSnapShot) Reset() {
*x = RingReaderSnapShot{} *x = RingReaderSnapShot{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_global_proto_msgTypes[25] mi := &file_global_proto_msgTypes[26]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1770,7 +1825,7 @@ func (x *RingReaderSnapShot) String() string {
func (*RingReaderSnapShot) ProtoMessage() {} func (*RingReaderSnapShot) ProtoMessage() {}
func (x *RingReaderSnapShot) ProtoReflect() protoreflect.Message { func (x *RingReaderSnapShot) ProtoReflect() protoreflect.Message {
mi := &file_global_proto_msgTypes[25] mi := &file_global_proto_msgTypes[26]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1783,7 +1838,7 @@ func (x *RingReaderSnapShot) ProtoReflect() protoreflect.Message {
// Deprecated: Use RingReaderSnapShot.ProtoReflect.Descriptor instead. // Deprecated: Use RingReaderSnapShot.ProtoReflect.Descriptor instead.
func (*RingReaderSnapShot) Descriptor() ([]byte, []int) { func (*RingReaderSnapShot) Descriptor() ([]byte, []int) {
return file_global_proto_rawDescGZIP(), []int{25} return file_global_proto_rawDescGZIP(), []int{26}
} }
func (x *RingReaderSnapShot) GetSequence() uint32 { func (x *RingReaderSnapShot) GetSequence() uint32 {
@@ -1829,7 +1884,7 @@ type SubscriberSnapShot struct {
func (x *SubscriberSnapShot) Reset() { func (x *SubscriberSnapShot) Reset() {
*x = SubscriberSnapShot{} *x = SubscriberSnapShot{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_global_proto_msgTypes[26] mi := &file_global_proto_msgTypes[27]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1842,7 +1897,7 @@ func (x *SubscriberSnapShot) String() string {
func (*SubscriberSnapShot) ProtoMessage() {} func (*SubscriberSnapShot) ProtoMessage() {}
func (x *SubscriberSnapShot) ProtoReflect() protoreflect.Message { func (x *SubscriberSnapShot) ProtoReflect() protoreflect.Message {
mi := &file_global_proto_msgTypes[26] mi := &file_global_proto_msgTypes[27]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1855,7 +1910,7 @@ func (x *SubscriberSnapShot) ProtoReflect() protoreflect.Message {
// Deprecated: Use SubscriberSnapShot.ProtoReflect.Descriptor instead. // Deprecated: Use SubscriberSnapShot.ProtoReflect.Descriptor instead.
func (*SubscriberSnapShot) Descriptor() ([]byte, []int) { func (*SubscriberSnapShot) Descriptor() ([]byte, []int) {
return file_global_proto_rawDescGZIP(), []int{26} return file_global_proto_rawDescGZIP(), []int{27}
} }
func (x *SubscriberSnapShot) GetId() uint32 { func (x *SubscriberSnapShot) GetId() uint32 {
@@ -1907,7 +1962,7 @@ type SubscribersResponse struct {
func (x *SubscribersResponse) Reset() { func (x *SubscribersResponse) Reset() {
*x = SubscribersResponse{} *x = SubscribersResponse{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_global_proto_msgTypes[27] mi := &file_global_proto_msgTypes[28]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -1920,7 +1975,7 @@ func (x *SubscribersResponse) String() string {
func (*SubscribersResponse) ProtoMessage() {} func (*SubscribersResponse) ProtoMessage() {}
func (x *SubscribersResponse) ProtoReflect() protoreflect.Message { func (x *SubscribersResponse) ProtoReflect() protoreflect.Message {
mi := &file_global_proto_msgTypes[27] mi := &file_global_proto_msgTypes[28]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -1933,7 +1988,7 @@ func (x *SubscribersResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use SubscribersResponse.ProtoReflect.Descriptor instead. // Deprecated: Use SubscribersResponse.ProtoReflect.Descriptor instead.
func (*SubscribersResponse) Descriptor() ([]byte, []int) { func (*SubscribersResponse) Descriptor() ([]byte, []int) {
return file_global_proto_rawDescGZIP(), []int{27} return file_global_proto_rawDescGZIP(), []int{28}
} }
func (x *SubscribersResponse) GetTotal() int32 { func (x *SubscribersResponse) GetTotal() int32 {
@@ -2193,132 +2248,144 @@ var file_global_proto_rawDesc = []byte{
0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73,
0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x1f, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x1f, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x57, 0x69, 0x74, 0x68, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x74, 0x57, 0x69, 0x74, 0x68, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x22, 0x6a, 0x0a, 0x12, 0x53, 0x75, 0x62, 0x73, 0x63, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x22, 0x48, 0x0a, 0x16, 0x43, 0x68, 0x61, 0x6e, 0x67,
0x72, 0x69, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x0a, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69,
0x09, 0x52, 0x0a, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x18,
0x07, 0x70, 0x61, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61, 0x74,
0x70, 0x61, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x68, 0x22, 0x6a, 0x0a, 0x12, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x73,
0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x65, 0x61,
0x69, 0x7a, 0x65, 0x22, 0x7a, 0x0a, 0x12, 0x52, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x65, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x72,
0x72, 0x53, 0x6e, 0x61, 0x70, 0x53, 0x68, 0x6f, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x65, 0x61, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x67, 0x65, 0x4e,
0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x70, 0x61, 0x67, 0x65, 0x4e, 0x75,
0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20,
0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x7a, 0x0a,
0x61, 0x6d, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x12, 0x52, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x53, 0x6e, 0x61, 0x70, 0x53,
0x28, 0x0d, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x68, 0x6f, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18,
0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12,
0xe8, 0x01, 0x0a, 0x12, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x53, 0x6e, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01,
0x61, 0x70, 0x53, 0x68, 0x6f, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x14, 0x0a,
0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x64, 0x65,
0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x61, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x28, 0x05, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0xe8, 0x01, 0x0a, 0x12, 0x53, 0x75,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x53, 0x6e, 0x61, 0x70, 0x53, 0x68, 0x6f, 0x74,
0x12, 0x39, 0x0a, 0x0b, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64,
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x52, 0x69, 0x6e, 0x67, 0x12, 0x38, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20,
0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x53, 0x6e, 0x61, 0x70, 0x53, 0x68, 0x6f, 0x74, 0x52, 0x0b, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x61, 0x75, 0x64, 0x69, 0x6f, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x0b, 0x76, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
0x69, 0x64, 0x65, 0x6f, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0b, 0x61, 0x75,
0x32, 0x17, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x52, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x65, 0x64, 0x69, 0x6f, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x72, 0x53, 0x6e, 0x61, 0x70, 0x53, 0x68, 0x6f, 0x74, 0x52, 0x0b, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x17, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x52, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72,
0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x05, 0x53, 0x6e, 0x61, 0x70, 0x53, 0x68, 0x6f, 0x74, 0x52, 0x0b, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x52,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x8e, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x0b, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x52, 0x65,
0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x61, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6d, 0x37, 0x73,
0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x2e, 0x52, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x53, 0x6e, 0x61, 0x70, 0x53,
0x05, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x67, 0x65, 0x68, 0x6f, 0x74, 0x52, 0x0b, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72,
0x4e, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x70, 0x61, 0x67, 0x65, 0x4e, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x75, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x6d, 0x65, 0x74, 0x61, 0x22, 0x8e, 0x01, 0x0a, 0x13, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x2b, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05,
0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x74, 0x6f, 0x74,
0x37, 0x73, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x53, 0x6e, 0x61, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x18, 0x02, 0x20,
0x70, 0x53, 0x68, 0x6f, 0x74, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x32, 0xca, 0x0a, 0x0a, 0x06, 0x01, 0x28, 0x05, 0x52, 0x07, 0x70, 0x61, 0x67, 0x65, 0x4e, 0x75, 0x6d, 0x12, 0x1a, 0x0a, 0x08,
0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x12, 0x4d, 0x0a, 0x07, 0x53, 0x79, 0x73, 0x49, 0x6e, 0x66, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08,
0x6f, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x2b, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74,
0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x75, 0x62,
0x53, 0x79, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x53, 0x6e, 0x61, 0x70, 0x53, 0x68, 0x6f, 0x74, 0x52,
0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x79, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x32, 0xc7, 0x0b, 0x0a, 0x06, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c,
0x73, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x4d, 0x0a, 0x07, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x4d, 0x0a, 0x07, 0x53, 0x79, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x67, 0x6f,
0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x79, 0x73, 0x49, 0x6e, 0x66,
0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x75, 0x6d, 0x0e, 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x79, 0x73, 0x69, 0x6e, 0x66, 0x6f, 0x12,
0x6d, 0x61, 0x72, 0x79, 0x12, 0x52, 0x0a, 0x08, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4d, 0x0a, 0x07, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f,
0x12, 0x12, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, 0x69, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70,
0x74, 0x68, 0x49, 0x64, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x1a, 0x82, 0xd3, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e,
0xe4, 0x93, 0x02, 0x14, 0x22, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x68, 0x75, 0x74, 0x64, 0x12, 0x0c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x52,
0x6f, 0x77, 0x6e, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x50, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x74, 0x0a, 0x08, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x12, 0x2e, 0x6d, 0x37, 0x73,
0x61, 0x72, 0x74, 0x12, 0x12, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, 0x69, 0x74, 0x68, 0x49, 0x64, 0x1a, 0x16,
0x74, 0x57, 0x69, 0x74, 0x68, 0x49, 0x64, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x12,
0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x22, 0x11, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x2f, 0x7b, 0x69,
0x73, 0x74, 0x61, 0x72, 0x74, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x57, 0x0a, 0x0a, 0x53, 0x74, 0x64, 0x7d, 0x12, 0x50, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x12, 0x2e,
0x72, 0x65, 0x61, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x6d, 0x37, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, 0x69, 0x74, 0x68, 0x49,
0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x64, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x1a, 0x17, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x69, 0x73, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x22, 0x11, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x2f,
0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2f, 0x6c, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x57, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x69,
0x69, 0x73, 0x74, 0x12, 0x5d, 0x0a, 0x08, 0x57, 0x61, 0x69, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c,
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6d, 0x37, 0x73,
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x72, 0x65, 0x61, 0x6d, 0x57, 0x61, 0x69, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x61, 0x69, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2f, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x5d, 0x0a,
0x70, 0x69, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2f, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x08, 0x57, 0x61, 0x69, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x73, 0x74, 0x12, 0x67, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
0x12, 0x16, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x6e, 0x61, 0x79, 0x1a, 0x1b, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x57, 0x61,
0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x69, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c,
0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x74, 0x72,
0x65, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x61, 0x6d, 0x2f, 0x77, 0x61, 0x69, 0x74, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x67, 0x0a, 0x0a,
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x2f, 0x7b, 0x73, 0x74, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x6d, 0x37, 0x73,
0x65, 0x61, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0x6d, 0x0a, 0x0e, 0x47, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65,
0x65, 0x74, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x73, 0x12, 0x17, 0x2e, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49,
0x6d, 0x37, 0x73, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x73, 0x52, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x82, 0xd3, 0xe4,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x75, 0x62, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d,
0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x2f, 0x7b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61, 0x74,
0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x68, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0x6d, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x73,
0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x73, 0x74, 0x72, 0x65, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x73, 0x12, 0x17, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x75,
0x61, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0x72, 0x0a, 0x0e, 0x41, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x64, 0x69, 0x6f, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x53, 0x6e, 0x61, 0x70, 0x12, 0x16, 0x2e, 0x6d, 0x1a, 0x18, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
0x37, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x52, 0x65, 0x71, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
0x53, 0x6e, 0x61, 0x70, 0x53, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x62, 0x65, 0x72, 0x73, 0x2f, 0x7b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61, 0x74, 0x68,
0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x12, 0x24, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0x72, 0x0a, 0x0e, 0x41, 0x75, 0x64, 0x69, 0x6f, 0x54, 0x72, 0x61,
0x75, 0x64, 0x69, 0x6f, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x2f, 0x73, 0x6e, 0x61, 0x70, 0x2f, 0x7b, 0x63, 0x6b, 0x53, 0x6e, 0x61, 0x70, 0x12, 0x16, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x74, 0x72,
0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a,
0x0a, 0x0e, 0x56, 0x69, 0x64, 0x65, 0x6f, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x53, 0x6e, 0x61, 0x70, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x53, 0x6e, 0x61, 0x70, 0x53, 0x68,
0x12, 0x16, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x6e, 0x61, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93,
0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x54, 0x02, 0x26, 0x12, 0x24, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x74, 0x72,
0x72, 0x61, 0x63, 0x6b, 0x53, 0x6e, 0x61, 0x70, 0x53, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x61, 0x63, 0x6b, 0x2f, 0x73, 0x6e, 0x61, 0x70, 0x2f, 0x7b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x12, 0x24, 0x2f, 0x61, 0x50, 0x61, 0x74, 0x68, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0x72, 0x0a, 0x0e, 0x56, 0x69, 0x64, 0x65,
0x70, 0x69, 0x2f, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x2f, 0x73, 0x6e, 0x6f, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x53, 0x6e, 0x61, 0x70, 0x12, 0x16, 0x2e, 0x6d, 0x37, 0x73,
0x61, 0x70, 0x2f, 0x7b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x3d, 0x2a, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x6e, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65,
0x2a, 0x7d, 0x12, 0x5e, 0x0a, 0x0d, 0x53, 0x74, 0x6f, 0x70, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x53, 0x6e,
0x69, 0x62, 0x65, 0x12, 0x12, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x61, 0x70, 0x53, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c,
0x74, 0x57, 0x69, 0x74, 0x68, 0x49, 0x64, 0x1a, 0x14, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x75, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x12, 0x24, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x69, 0x64,
0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0x65, 0x6f, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x2f, 0x73, 0x6e, 0x61, 0x70, 0x2f, 0x7b, 0x73, 0x74,
0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x18, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x74, 0x6f, 0x70, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61, 0x74, 0x68, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0x7b, 0x0a, 0x0f,
0x2f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12,
0x01, 0x2a, 0x12, 0x5a, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1b, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x62, 0x73,
0x15, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6d,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x37, 0x73, 0x2e, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x73, 0x65, 0x22, 0x35, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2f, 0x22, 0x2a, 0x2f, 0x61, 0x70, 0x69,
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x2f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x67,
0x66, 0x69, 0x67, 0x2f, 0x67, 0x65, 0x74, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x5f, 0x65, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x50, 0x61,
0x0a, 0x0a, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x15, 0x2e, 0x6d, 0x74, 0x68, 0x3d, 0x2a, 0x2a, 0x7d, 0x3a, 0x01, 0x2a, 0x12, 0x5e, 0x0a, 0x0d, 0x53, 0x74, 0x6f,
0x37, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x70, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x12, 0x2e, 0x6d, 0x37, 0x73,
0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, 0x69, 0x74, 0x68, 0x49, 0x64, 0x1a, 0x14,
0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70,
0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x18, 0x2f, 0x61,
0x2f, 0x66, 0x6f, 0x72, 0x6d, 0x69, 0x6c, 0x79, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x70, 0x69, 0x2f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2f, 0x73, 0x74, 0x6f,
0x67, 0x0a, 0x0c, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x70, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x01, 0x2a, 0x12, 0x5a, 0x0a, 0x09, 0x47, 0x65, 0x74,
0x18, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x15, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x47, 0x65, 0x74,
0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e,
0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6d, 0x37, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73,
0x27, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, 0x22, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f,
0x6e, 0x66, 0x69, 0x67, 0x2f, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x67, 0x65, 0x74, 0x2f, 0x7b,
0x65, 0x7d, 0x3a, 0x04, 0x79, 0x61, 0x6d, 0x6c, 0x42, 0x14, 0x5a, 0x12, 0x6d, 0x37, 0x73, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x5f, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x6d,
0x6c, 0x69, 0x76, 0x65, 0x2f, 0x6d, 0x37, 0x73, 0x2f, 0x76, 0x35, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x69, 0x6c, 0x79, 0x12, 0x15, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x6d, 0x37, 0x73,
0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x61, 0x70, 0x69,
0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x66, 0x6f, 0x72, 0x6d, 0x69, 0x6c, 0x79, 0x2f,
0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x67, 0x0a, 0x0c, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x4d, 0x6f, 0x64,
0x69, 0x66, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x14, 0x2e, 0x6d, 0x37, 0x73, 0x2e, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x27, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, 0x22, 0x19,
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x6d, 0x6f, 0x64, 0x69,
0x66, 0x79, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x3a, 0x04, 0x79, 0x61, 0x6d, 0x6c, 0x42,
0x14, 0x5a, 0x12, 0x6d, 0x37, 0x73, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x2f, 0x6d, 0x37, 0x73, 0x2f,
0x76, 0x35, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@@ -2333,7 +2400,7 @@ func file_global_proto_rawDescGZIP() []byte {
return file_global_proto_rawDescData return file_global_proto_rawDescData
} }
var file_global_proto_msgTypes = make([]protoimpl.MessageInfo, 33) var file_global_proto_msgTypes = make([]protoimpl.MessageInfo, 34)
var file_global_proto_goTypes = []interface{}{ var file_global_proto_goTypes = []interface{}{
(*GetConfigRequest)(nil), // 0: m7s.GetConfigRequest (*GetConfigRequest)(nil), // 0: m7s.GetConfigRequest
(*Formily)(nil), // 1: m7s.Formily (*Formily)(nil), // 1: m7s.Formily
@@ -2359,76 +2426,79 @@ var file_global_proto_goTypes = []interface{}{
(*VideoTrackInfo)(nil), // 21: m7s.VideoTrackInfo (*VideoTrackInfo)(nil), // 21: m7s.VideoTrackInfo
(*SuccessResponse)(nil), // 22: m7s.SuccessResponse (*SuccessResponse)(nil), // 22: m7s.SuccessResponse
(*RequestWithId)(nil), // 23: m7s.RequestWithId (*RequestWithId)(nil), // 23: m7s.RequestWithId
(*SubscribersRequest)(nil), // 24: m7s.SubscribersRequest (*ChangeSubscribeRequest)(nil), // 24: m7s.ChangeSubscribeRequest
(*RingReaderSnapShot)(nil), // 25: m7s.RingReaderSnapShot (*SubscribersRequest)(nil), // 25: m7s.SubscribersRequest
(*SubscriberSnapShot)(nil), // 26: m7s.SubscriberSnapShot (*RingReaderSnapShot)(nil), // 26: m7s.RingReaderSnapShot
(*SubscribersResponse)(nil), // 27: m7s.SubscribersResponse (*SubscriberSnapShot)(nil), // 27: m7s.SubscriberSnapShot
nil, // 28: m7s.Formily.PropertiesEntry (*SubscribersResponse)(nil), // 28: m7s.SubscribersResponse
nil, // 29: m7s.Formily.ComponentPropsEntry nil, // 29: m7s.Formily.PropertiesEntry
nil, // 30: m7s.FormilyResponse.PropertiesEntry nil, // 30: m7s.Formily.ComponentPropsEntry
nil, // 31: m7s.StreamWaitListResponse.ListEntry nil, // 31: m7s.FormilyResponse.PropertiesEntry
nil, // 32: m7s.TrackSnapShotResponse.ReaderEntry nil, // 32: m7s.StreamWaitListResponse.ListEntry
(*timestamppb.Timestamp)(nil), // 33: google.protobuf.Timestamp nil, // 33: m7s.TrackSnapShotResponse.ReaderEntry
(*anypb.Any)(nil), // 34: google.protobuf.Any (*timestamppb.Timestamp)(nil), // 34: google.protobuf.Timestamp
(*emptypb.Empty)(nil), // 35: google.protobuf.Empty (*anypb.Any)(nil), // 35: google.protobuf.Any
(*emptypb.Empty)(nil), // 36: google.protobuf.Empty
} }
var file_global_proto_depIdxs = []int32{ var file_global_proto_depIdxs = []int32{
28, // 0: m7s.Formily.properties:type_name -> m7s.Formily.PropertiesEntry 29, // 0: m7s.Formily.properties:type_name -> m7s.Formily.PropertiesEntry
29, // 1: m7s.Formily.componentProps:type_name -> m7s.Formily.ComponentPropsEntry 30, // 1: m7s.Formily.componentProps:type_name -> m7s.Formily.ComponentPropsEntry
30, // 2: m7s.FormilyResponse.properties:type_name -> m7s.FormilyResponse.PropertiesEntry 31, // 2: m7s.FormilyResponse.properties:type_name -> m7s.FormilyResponse.PropertiesEntry
6, // 3: m7s.SummaryResponse.memory:type_name -> m7s.Usage 6, // 3: m7s.SummaryResponse.memory:type_name -> m7s.Usage
6, // 4: m7s.SummaryResponse.hardDisk:type_name -> m7s.Usage 6, // 4: m7s.SummaryResponse.hardDisk:type_name -> m7s.Usage
5, // 5: m7s.SummaryResponse.netWork:type_name -> m7s.NetWorkInfo 5, // 5: m7s.SummaryResponse.netWork:type_name -> m7s.NetWorkInfo
33, // 6: m7s.SysInfoResponse.startTime:type_name -> google.protobuf.Timestamp 34, // 6: m7s.SysInfoResponse.startTime:type_name -> google.protobuf.Timestamp
8, // 7: m7s.SysInfoResponse.plugins:type_name -> m7s.PluginInfo 8, // 7: m7s.SysInfoResponse.plugins:type_name -> m7s.PluginInfo
14, // 8: m7s.StreamListResponse.list:type_name -> m7s.StreamInfoResponse 14, // 8: m7s.StreamListResponse.list:type_name -> m7s.StreamInfoResponse
31, // 9: m7s.StreamWaitListResponse.list:type_name -> m7s.StreamWaitListResponse.ListEntry 32, // 9: m7s.StreamWaitListResponse.list:type_name -> m7s.StreamWaitListResponse.ListEntry
19, // 10: m7s.StreamInfoResponse.audioTrack:type_name -> m7s.AudioTrackInfo 19, // 10: m7s.StreamInfoResponse.audioTrack:type_name -> m7s.AudioTrackInfo
21, // 11: m7s.StreamInfoResponse.videoTrack:type_name -> m7s.VideoTrackInfo 21, // 11: m7s.StreamInfoResponse.videoTrack:type_name -> m7s.VideoTrackInfo
33, // 12: m7s.StreamInfoResponse.startTime:type_name -> google.protobuf.Timestamp 34, // 12: m7s.StreamInfoResponse.startTime:type_name -> google.protobuf.Timestamp
33, // 13: m7s.TrackSnapShot.writeTime:type_name -> google.protobuf.Timestamp 34, // 13: m7s.TrackSnapShot.writeTime:type_name -> google.protobuf.Timestamp
15, // 14: m7s.TrackSnapShot.wrap:type_name -> m7s.Wrap 15, // 14: m7s.TrackSnapShot.wrap:type_name -> m7s.Wrap
17, // 15: m7s.MemoryBlockGroup.list:type_name -> m7s.MemoryBlock 17, // 15: m7s.MemoryBlockGroup.list:type_name -> m7s.MemoryBlock
16, // 16: m7s.TrackSnapShotResponse.ring:type_name -> m7s.TrackSnapShot 16, // 16: m7s.TrackSnapShotResponse.ring:type_name -> m7s.TrackSnapShot
32, // 17: m7s.TrackSnapShotResponse.reader:type_name -> m7s.TrackSnapShotResponse.ReaderEntry 33, // 17: m7s.TrackSnapShotResponse.reader:type_name -> m7s.TrackSnapShotResponse.ReaderEntry
18, // 18: m7s.TrackSnapShotResponse.memory:type_name -> m7s.MemoryBlockGroup 18, // 18: m7s.TrackSnapShotResponse.memory:type_name -> m7s.MemoryBlockGroup
33, // 19: m7s.SubscriberSnapShot.startTime:type_name -> google.protobuf.Timestamp 34, // 19: m7s.SubscriberSnapShot.startTime:type_name -> google.protobuf.Timestamp
25, // 20: m7s.SubscriberSnapShot.audioReader:type_name -> m7s.RingReaderSnapShot 26, // 20: m7s.SubscriberSnapShot.audioReader:type_name -> m7s.RingReaderSnapShot
25, // 21: m7s.SubscriberSnapShot.videoReader:type_name -> m7s.RingReaderSnapShot 26, // 21: m7s.SubscriberSnapShot.videoReader:type_name -> m7s.RingReaderSnapShot
26, // 22: m7s.SubscribersResponse.list:type_name -> m7s.SubscriberSnapShot 27, // 22: m7s.SubscribersResponse.list:type_name -> m7s.SubscriberSnapShot
1, // 23: m7s.Formily.PropertiesEntry.value:type_name -> m7s.Formily 1, // 23: m7s.Formily.PropertiesEntry.value:type_name -> m7s.Formily
34, // 24: m7s.Formily.ComponentPropsEntry.value:type_name -> google.protobuf.Any 35, // 24: m7s.Formily.ComponentPropsEntry.value:type_name -> google.protobuf.Any
1, // 25: m7s.FormilyResponse.PropertiesEntry.value:type_name -> m7s.Formily 1, // 25: m7s.FormilyResponse.PropertiesEntry.value:type_name -> m7s.Formily
35, // 26: m7s.Global.SysInfo:input_type -> google.protobuf.Empty 36, // 26: m7s.Global.SysInfo:input_type -> google.protobuf.Empty
35, // 27: m7s.Global.Summary:input_type -> google.protobuf.Empty 36, // 27: m7s.Global.Summary:input_type -> google.protobuf.Empty
23, // 28: m7s.Global.Shutdown:input_type -> m7s.RequestWithId 23, // 28: m7s.Global.Shutdown:input_type -> m7s.RequestWithId
23, // 29: m7s.Global.Restart:input_type -> m7s.RequestWithId 23, // 29: m7s.Global.Restart:input_type -> m7s.RequestWithId
10, // 30: m7s.Global.StreamList:input_type -> m7s.StreamListRequest 10, // 30: m7s.Global.StreamList:input_type -> m7s.StreamListRequest
35, // 31: m7s.Global.WaitList:input_type -> google.protobuf.Empty 36, // 31: m7s.Global.WaitList:input_type -> google.protobuf.Empty
13, // 32: m7s.Global.StreamInfo:input_type -> m7s.StreamSnapRequest 13, // 32: m7s.Global.StreamInfo:input_type -> m7s.StreamSnapRequest
24, // 33: m7s.Global.GetSubscribers:input_type -> m7s.SubscribersRequest 25, // 33: m7s.Global.GetSubscribers:input_type -> m7s.SubscribersRequest
13, // 34: m7s.Global.AudioTrackSnap:input_type -> m7s.StreamSnapRequest 13, // 34: m7s.Global.AudioTrackSnap:input_type -> m7s.StreamSnapRequest
13, // 35: m7s.Global.VideoTrackSnap:input_type -> m7s.StreamSnapRequest 13, // 35: m7s.Global.VideoTrackSnap:input_type -> m7s.StreamSnapRequest
23, // 36: m7s.Global.StopSubscribe:input_type -> m7s.RequestWithId 24, // 36: m7s.Global.ChangeSubscribe:input_type -> m7s.ChangeSubscribeRequest
0, // 37: m7s.Global.GetConfig:input_type -> m7s.GetConfigRequest 23, // 37: m7s.Global.StopSubscribe:input_type -> m7s.RequestWithId
0, // 38: m7s.Global.GetFormily:input_type -> m7s.GetConfigRequest 0, // 38: m7s.Global.GetConfig:input_type -> m7s.GetConfigRequest
4, // 39: m7s.Global.ModifyConfig:input_type -> m7s.ModifyConfigRequest 0, // 39: m7s.Global.GetFormily:input_type -> m7s.GetConfigRequest
9, // 40: m7s.Global.SysInfo:output_type -> m7s.SysInfoResponse 4, // 40: m7s.Global.ModifyConfig:input_type -> m7s.ModifyConfigRequest
7, // 41: m7s.Global.Summary:output_type -> m7s.SummaryResponse 9, // 41: m7s.Global.SysInfo:output_type -> m7s.SysInfoResponse
35, // 42: m7s.Global.Shutdown:output_type -> google.protobuf.Empty 7, // 42: m7s.Global.Summary:output_type -> m7s.SummaryResponse
35, // 43: m7s.Global.Restart:output_type -> google.protobuf.Empty 36, // 43: m7s.Global.Shutdown:output_type -> google.protobuf.Empty
11, // 44: m7s.Global.StreamList:output_type -> m7s.StreamListResponse 36, // 44: m7s.Global.Restart:output_type -> google.protobuf.Empty
12, // 45: m7s.Global.WaitList:output_type -> m7s.StreamWaitListResponse 11, // 45: m7s.Global.StreamList:output_type -> m7s.StreamListResponse
14, // 46: m7s.Global.StreamInfo:output_type -> m7s.StreamInfoResponse 12, // 46: m7s.Global.WaitList:output_type -> m7s.StreamWaitListResponse
27, // 47: m7s.Global.GetSubscribers:output_type -> m7s.SubscribersResponse 14, // 47: m7s.Global.StreamInfo:output_type -> m7s.StreamInfoResponse
20, // 48: m7s.Global.AudioTrackSnap:output_type -> m7s.TrackSnapShotResponse 28, // 48: m7s.Global.GetSubscribers:output_type -> m7s.SubscribersResponse
20, // 49: m7s.Global.VideoTrackSnap:output_type -> m7s.TrackSnapShotResponse 20, // 49: m7s.Global.AudioTrackSnap:output_type -> m7s.TrackSnapShotResponse
22, // 50: m7s.Global.StopSubscribe:output_type -> m7s.SuccessResponse 20, // 50: m7s.Global.VideoTrackSnap:output_type -> m7s.TrackSnapShotResponse
3, // 51: m7s.Global.GetConfig:output_type -> m7s.GetConfigResponse 22, // 51: m7s.Global.ChangeSubscribe:output_type -> m7s.SuccessResponse
3, // 52: m7s.Global.GetFormily:output_type -> m7s.GetConfigResponse 22, // 52: m7s.Global.StopSubscribe:output_type -> m7s.SuccessResponse
22, // 53: m7s.Global.ModifyConfig:output_type -> m7s.SuccessResponse 3, // 53: m7s.Global.GetConfig:output_type -> m7s.GetConfigResponse
40, // [40:54] is the sub-list for method output_type 3, // 54: m7s.Global.GetFormily:output_type -> m7s.GetConfigResponse
26, // [26:40] is the sub-list for method input_type 22, // 55: m7s.Global.ModifyConfig:output_type -> m7s.SuccessResponse
41, // [41:56] is the sub-list for method output_type
26, // [26:41] is the sub-list for method input_type
26, // [26:26] is the sub-list for extension type_name 26, // [26:26] is the sub-list for extension type_name
26, // [26:26] is the sub-list for extension extendee 26, // [26:26] is the sub-list for extension extendee
0, // [0:26] is the sub-list for field type_name 0, // [0:26] is the sub-list for field type_name
@@ -2729,7 +2799,7 @@ func file_global_proto_init() {
} }
} }
file_global_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { file_global_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SubscribersRequest); i { switch v := v.(*ChangeSubscribeRequest); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@@ -2741,7 +2811,7 @@ func file_global_proto_init() {
} }
} }
file_global_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { file_global_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RingReaderSnapShot); i { switch v := v.(*SubscribersRequest); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@@ -2753,7 +2823,7 @@ func file_global_proto_init() {
} }
} }
file_global_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { file_global_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SubscriberSnapShot); i { switch v := v.(*RingReaderSnapShot); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@@ -2765,6 +2835,18 @@ func file_global_proto_init() {
} }
} }
file_global_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { file_global_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SubscriberSnapShot); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_global_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SubscribersResponse); i { switch v := v.(*SubscribersResponse); i {
case 0: case 0:
return &v.state return &v.state
@@ -2783,7 +2865,7 @@ func file_global_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_global_proto_rawDesc, RawDescriptor: file_global_proto_rawDesc,
NumEnums: 0, NumEnums: 0,
NumMessages: 33, NumMessages: 34,
NumExtensions: 0, NumExtensions: 0,
NumServices: 1, NumServices: 1,
}, },

View File

@@ -452,6 +452,86 @@ func local_request_Global_VideoTrackSnap_0(ctx context.Context, marshaler runtim
} }
func request_Global_ChangeSubscribe_0(ctx context.Context, marshaler runtime.Marshaler, client GlobalClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ChangeSubscribeRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.Uint32(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", 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)
}
msg, err := client.ChangeSubscribe(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Global_ChangeSubscribe_0(ctx context.Context, marshaler runtime.Marshaler, server GlobalServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ChangeSubscribeRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.Uint32(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", 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)
}
msg, err := server.ChangeSubscribe(ctx, &protoReq)
return msg, metadata, err
}
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 RequestWithId var protoReq RequestWithId
var metadata runtime.ServerMetadata var metadata runtime.ServerMetadata
@@ -932,6 +1012,31 @@ func RegisterGlobalHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser
}) })
mux.Handle("POST", pattern_Global_ChangeSubscribe_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/ChangeSubscribe", runtime.WithHTTPPathPattern("/api/subscribe/change/{id}/{streamPath=**}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Global_ChangeSubscribe_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_ChangeSubscribe_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Global_StopSubscribe_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { mux.Handle("POST", pattern_Global_StopSubscribe_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()
@@ -940,7 +1045,7 @@ func RegisterGlobalHandlerServer(ctx context.Context, mux *runtime.ServeMux, ser
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error var err error
var annotatedContext context.Context var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/m7s.Global/StopSubscribe", runtime.WithHTTPPathPattern("/api/stop/subscribe/{id}")) annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/m7s.Global/StopSubscribe", runtime.WithHTTPPathPattern("/api/subscribe/stop/{id}"))
if err != nil { if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return return
@@ -1293,13 +1398,35 @@ func RegisterGlobalHandlerClient(ctx context.Context, mux *runtime.ServeMux, cli
}) })
mux.Handle("POST", pattern_Global_ChangeSubscribe_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/ChangeSubscribe", runtime.WithHTTPPathPattern("/api/subscribe/change/{id}/{streamPath=**}"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Global_ChangeSubscribe_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_ChangeSubscribe_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Global_StopSubscribe_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { mux.Handle("POST", pattern_Global_StopSubscribe_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()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error var err error
var annotatedContext context.Context var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/m7s.Global/StopSubscribe", runtime.WithHTTPPathPattern("/api/stop/subscribe/{id}")) annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/m7s.Global/StopSubscribe", runtime.WithHTTPPathPattern("/api/subscribe/stop/{id}"))
if err != nil { if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return return
@@ -1405,7 +1532,9 @@ var (
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"}, ""))
pattern_Global_StopSubscribe_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "stop", "subscribe", "id"}, "")) pattern_Global_ChangeSubscribe_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 3, 0, 4, 1, 5, 4}, []string{"api", "subscribe", "change", "id", "streamPath"}, ""))
pattern_Global_StopSubscribe_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "subscribe", "stop", "id"}, ""))
pattern_Global_GetConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "config", "get", "name"}, "")) pattern_Global_GetConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "config", "get", "name"}, ""))
@@ -1435,6 +1564,8 @@ var (
forward_Global_VideoTrackSnap_0 = runtime.ForwardResponseMessage forward_Global_VideoTrackSnap_0 = runtime.ForwardResponseMessage
forward_Global_ChangeSubscribe_0 = runtime.ForwardResponseMessage
forward_Global_StopSubscribe_0 = runtime.ForwardResponseMessage forward_Global_StopSubscribe_0 = runtime.ForwardResponseMessage
forward_Global_GetConfig_0 = runtime.ForwardResponseMessage forward_Global_GetConfig_0 = runtime.ForwardResponseMessage

View File

@@ -57,9 +57,16 @@ service Global {
get: "/api/videotrack/snap/{streamPath=**}" get: "/api/videotrack/snap/{streamPath=**}"
}; };
} }
rpc ChangeSubscribe (ChangeSubscribeRequest) returns (SuccessResponse) {
option (google.api.http) = {
post: "/api/subscribe/change/{id}/{streamPath=**}"
body: "*"
};
}
rpc StopSubscribe (RequestWithId) returns (SuccessResponse) { rpc StopSubscribe (RequestWithId) returns (SuccessResponse) {
option (google.api.http) = { option (google.api.http) = {
post: "/api/stop/subscribe/{id}" post: "/api/subscribe/stop/{id}"
body: "*" body: "*"
}; };
} }
@@ -243,6 +250,11 @@ message RequestWithId {
uint32 id = 1; uint32 id = 1;
} }
message ChangeSubscribeRequest {
uint32 id = 1;
string streamPath = 2;
}
message SubscribersRequest { message SubscribersRequest {
string streamPath = 1; string streamPath = 1;
int32 pageNum = 2; int32 pageNum = 2;

View File

@@ -33,6 +33,7 @@ type GlobalClient interface {
GetSubscribers(ctx context.Context, in *SubscribersRequest, opts ...grpc.CallOption) (*SubscribersResponse, error) GetSubscribers(ctx context.Context, in *SubscribersRequest, opts ...grpc.CallOption) (*SubscribersResponse, error)
AudioTrackSnap(ctx context.Context, in *StreamSnapRequest, opts ...grpc.CallOption) (*TrackSnapShotResponse, error) AudioTrackSnap(ctx context.Context, in *StreamSnapRequest, opts ...grpc.CallOption) (*TrackSnapShotResponse, error)
VideoTrackSnap(ctx context.Context, in *StreamSnapRequest, opts ...grpc.CallOption) (*TrackSnapShotResponse, error) VideoTrackSnap(ctx context.Context, in *StreamSnapRequest, opts ...grpc.CallOption) (*TrackSnapShotResponse, error)
ChangeSubscribe(ctx context.Context, in *ChangeSubscribeRequest, opts ...grpc.CallOption) (*SuccessResponse, error)
StopSubscribe(ctx context.Context, in *RequestWithId, opts ...grpc.CallOption) (*SuccessResponse, 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)
@@ -137,6 +138,15 @@ func (c *globalClient) VideoTrackSnap(ctx context.Context, in *StreamSnapRequest
return out, nil return out, nil
} }
func (c *globalClient) ChangeSubscribe(ctx context.Context, in *ChangeSubscribeRequest, opts ...grpc.CallOption) (*SuccessResponse, error) {
out := new(SuccessResponse)
err := c.cc.Invoke(ctx, "/m7s.Global/ChangeSubscribe", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *globalClient) StopSubscribe(ctx context.Context, in *RequestWithId, opts ...grpc.CallOption) (*SuccessResponse, error) { func (c *globalClient) StopSubscribe(ctx context.Context, in *RequestWithId, opts ...grpc.CallOption) (*SuccessResponse, error) {
out := new(SuccessResponse) 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...)
@@ -187,6 +197,7 @@ type GlobalServer interface {
GetSubscribers(context.Context, *SubscribersRequest) (*SubscribersResponse, error) GetSubscribers(context.Context, *SubscribersRequest) (*SubscribersResponse, error)
AudioTrackSnap(context.Context, *StreamSnapRequest) (*TrackSnapShotResponse, error) AudioTrackSnap(context.Context, *StreamSnapRequest) (*TrackSnapShotResponse, error)
VideoTrackSnap(context.Context, *StreamSnapRequest) (*TrackSnapShotResponse, error) VideoTrackSnap(context.Context, *StreamSnapRequest) (*TrackSnapShotResponse, error)
ChangeSubscribe(context.Context, *ChangeSubscribeRequest) (*SuccessResponse, error)
StopSubscribe(context.Context, *RequestWithId) (*SuccessResponse, 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)
@@ -228,6 +239,9 @@ func (UnimplementedGlobalServer) AudioTrackSnap(context.Context, *StreamSnapRequ
func (UnimplementedGlobalServer) VideoTrackSnap(context.Context, *StreamSnapRequest) (*TrackSnapShotResponse, 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) ChangeSubscribe(context.Context, *ChangeSubscribeRequest) (*SuccessResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ChangeSubscribe not implemented")
}
func (UnimplementedGlobalServer) StopSubscribe(context.Context, *RequestWithId) (*SuccessResponse, 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")
} }
@@ -433,6 +447,24 @@ func _Global_VideoTrackSnap_Handler(srv interface{}, ctx context.Context, dec fu
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _Global_ChangeSubscribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ChangeSubscribeRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GlobalServer).ChangeSubscribe(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/m7s.Global/ChangeSubscribe",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GlobalServer).ChangeSubscribe(ctx, req.(*ChangeSubscribeRequest))
}
return interceptor(ctx, in, info, handler)
}
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(RequestWithId) in := new(RequestWithId)
if err := dec(in); err != nil { if err := dec(in); err != nil {
@@ -552,6 +584,10 @@ var Global_ServiceDesc = grpc.ServiceDesc{
MethodName: "VideoTrackSnap", MethodName: "VideoTrackSnap",
Handler: _Global_VideoTrackSnap_Handler, Handler: _Global_VideoTrackSnap_Handler,
}, },
{
MethodName: "ChangeSubscribe",
Handler: _Global_ChangeSubscribe_Handler,
},
{ {
MethodName: "StopSubscribe", MethodName: "StopSubscribe",
Handler: _Global_StopSubscribe_Handler, Handler: _Global_StopSubscribe_Handler,

View File

@@ -16,4 +16,5 @@ var (
ErrInterrupt = errors.New("interrupt") ErrInterrupt = errors.New("interrupt")
ErrUnsupportCodec = errors.New("unsupport codec") ErrUnsupportCodec = errors.New("unsupport codec")
ErrMuted = errors.New("muted") ErrMuted = errors.New("muted")
ErrorLost = errors.New("lost")
) )

View File

@@ -80,8 +80,11 @@ func (rb *RingWriter) Reduce(size int) (r *util.Ring[AVFrame]) {
return return
} }
func (rb *RingWriter) Dispose() {
rb.Value.Ready()
}
func (rb *RingWriter) Step() (normal bool) { func (rb *RingWriter) Step() (normal bool) {
// rb.LastValue.Broadcast() // 防止订阅者还在等待
rb.LastValue = &rb.Value rb.LastValue = &rb.Value
nextSeq := rb.LastValue.Sequence + 1 nextSeq := rb.LastValue.Sequence + 1
next := rb.Next() next := rb.Next()
@@ -91,7 +94,10 @@ func (rb *RingWriter) Step() (normal bool) {
} else { } else {
rb.Reduce(1) //抛弃还有订阅者的节点 rb.Reduce(1) //抛弃还有订阅者的节点
rb.Ring = rb.Glow(1) //补充一个新节点 rb.Ring = rb.Glow(1) //补充一个新节点
rb.Value.StartWrite() normal = rb.Value.StartWrite()
if !normal {
panic("RingWriter.Step")
}
} }
rb.Value.Sequence = nextSeq rb.Value.Sequence = nextSeq
rb.LastValue.Ready() rb.LastValue.Ready()

View File

@@ -20,12 +20,11 @@ func (unit *Unit) Trace(msg string, fields ...any) {
} }
func (unit *Unit) IsStopped() bool { func (unit *Unit) IsStopped() bool {
select { return unit.StopReason() != nil
case <-unit.Done(): }
return true
default: func (unit *Unit) StopReason() error {
} return context.Cause(unit.Context)
return false
} }
func (unit *Unit) Stop(err error) { func (unit *Unit) Stop(err error) {

View File

@@ -9,17 +9,17 @@ type (
Start, End int Start, End int
trees [2]Tree trees [2]Tree
} }
// History struct { History struct {
// Malloc bool Malloc bool
// Offset int Offset int
// Size int Size int
// } }
Allocator struct { Allocator struct {
pool []*Block pool []*Block
sizeTree *Block sizeTree *Block
offsetTree *Block offsetTree *Block
Size int Size int
// history []History //history []History
} }
) )
@@ -158,7 +158,7 @@ func (b *Block) delete(block *Block, treeIndex int) *Block {
} }
func (a *Allocator) Allocate(size int) (offset int) { func (a *Allocator) Allocate(size int) (offset int) {
// a.history = append(a.history, History{Malloc: true, Size: size}) //a.history = append(a.history, History{Malloc: true, Size: size})
block := a.findAvailableBlock(a.sizeTree, size) block := a.findAvailableBlock(a.sizeTree, size)
if block == nil { if block == nil {
return -1 return -1
@@ -207,7 +207,7 @@ func (a *Allocator) putBlock(b *Block) {
} }
func (a *Allocator) Free(offset, size int) { func (a *Allocator) Free(offset, size int) {
// a.history = append(a.history, History{Malloc: false, Offset: offset, Size: size}) //a.history = append(a.history, History{Malloc: false, Offset: offset, Size: size})
block := a.getBlock(offset, offset+size) block := a.getBlock(offset, offset+size)
a.sizeTree, a.offsetTree = a.sizeTree.insert(block, 0), a.offsetTree.insert(block, 1) a.sizeTree, a.offsetTree = a.sizeTree.insert(block, 0), a.offsetTree.insert(block, 1)
a.mergeAdjacentBlocks(block) a.mergeAdjacentBlocks(block)

122
pkg/util/buddy.go Normal file
View File

@@ -0,0 +1,122 @@
package util
import (
"errors"
)
type Buddy struct {
size int
longests []int
}
var (
InValidParameterErr = errors.New("buddy: invalid parameter")
NotFoundErr = errors.New("buddy: can't find block")
)
// NewBuddy creates a buddy instance.
// If the parameter isn't valid, return the nil and error as well
func NewBuddy(size int) *Buddy {
if !isPowerOf2(size) {
size = fixSize(size)
}
nodeCount := 2*size - 1
longests := make([]int, nodeCount)
for nodeSize, i := 2*size, 0; i < nodeCount; i++ {
if isPowerOf2(i + 1) {
nodeSize /= 2
}
longests[i] = nodeSize
}
return &Buddy{size, longests}
}
// Alloc find a unused block according to the size
// return the offset of the block(regard 0 as the beginning)
// and parameter error if any
func (b *Buddy) Alloc(size int) (offset int, err error) {
if size <= 0 {
err = InValidParameterErr
return
}
if !isPowerOf2(size) {
size = fixSize(size)
}
if size > b.longests[0] {
err = NotFoundErr
return
}
index := 0
for nodeSize := b.size; nodeSize != size; nodeSize /= 2 {
if left := leftChild(index); b.longests[left] >= size {
index = left
} else {
index = rightChild(index)
}
}
b.longests[index] = 0 // mark zero as used
offset = (index+1)*size - b.size
// update the parent node's size
for index != 0 {
index = parent(index)
b.longests[index] = max(b.longests[leftChild(index)], b.longests[rightChild(index)])
}
return
}
// Free find a block according to the offset and mark it as unused
// return error if not found or parameter invalid
func (b *Buddy) Free(offset int) error {
if offset < 0 || offset >= b.size {
return InValidParameterErr
}
nodeSize := 1
index := offset + b.size - 1
for ; b.longests[index] != 0; index = parent(index) {
nodeSize *= 2
if index == 0 {
return NotFoundErr
}
}
b.longests[index] = nodeSize
// update parent node's size
for index != 0 {
index = parent(index)
nodeSize *= 2
leftSize := b.longests[leftChild(index)]
rightSize := b.longests[rightChild(index)]
if leftSize+rightSize == nodeSize {
b.longests[index] = nodeSize
} else {
b.longests[index] = max(leftSize, rightSize)
}
}
return nil
}
// helpers
func isPowerOf2(size int) bool {
return size&(size-1) == 0
}
func fixSize(size int) int {
size |= size >> 1
size |= size >> 2
size |= size >> 4
size |= size >> 8
size |= size >> 16
return size + 1
}
func leftChild(index int) int {
return 2*index + 1
}
func rightChild(index int) int {
return 2*index + 2
}
func parent(index int) int {
return (index+1)/2 - 1
}

View File

@@ -4,7 +4,7 @@ import (
"io" "io"
) )
const defaultBufSize = 65536 const defaultBufSize = 1 << 16
type BufReader struct { type BufReader struct {
reader io.Reader reader io.Reader
@@ -95,6 +95,12 @@ func (r *BufReader) ReadBE32(n int) (num uint32, err error) {
func (r *BufReader) ReadBytes(n int) (mem RecyclableMemory, err error) { func (r *BufReader) ReadBytes(n int) (mem RecyclableMemory, err error) {
mem.ScalableMemoryAllocator = r.allocator mem.ScalableMemoryAllocator = r.allocator
defer func() {
if err != nil {
mem.Recycle()
mem = RecyclableMemory{}
}
}()
for r.recycleFront(); n > 0 && err == nil; err = r.eat() { for r.recycleFront(); n > 0 && err == nil; err = r.eat() {
if r.buf.Length > 0 { if r.buf.Length > 0 {
if r.buf.Length >= n { if r.buf.Length >= n {

View File

@@ -30,10 +30,11 @@ func (c *Collection[K, T]) Add(item T) {
c.Length++ c.Length++
} }
func (c *Collection[K, T]) AddUnique(item T) { func (c *Collection[K, T]) AddUnique(item T) (ok bool) {
if _, ok := c.Get(item.GetKey()); !ok { if _, ok = c.Get(item.GetKey()); !ok {
c.Add(item) c.Add(item)
} }
return !ok
} }
func (c *Collection[K, T]) Set(item T) { func (c *Collection[K, T]) Set(item T) {
@@ -50,6 +51,18 @@ func (c *Collection[K, T]) Set(item T) {
c.Add(item) c.Add(item)
} }
func (c *Collection[K, T]) Range(f func(T) bool) {
if c.L != nil {
c.L.RLock()
defer c.L.RUnlock()
}
for _, item := range c.Items {
if !f(item) {
break
}
}
}
func (c *Collection[K, T]) Remove(item T) { func (c *Collection[K, T]) Remove(item T) {
c.RemoveByKey(item.GetKey()) c.RemoveByKey(item.GetKey())
} }

View File

@@ -6,10 +6,19 @@ import (
"unsafe" "unsafe"
) )
const MaxBlockSize = 4 * 1024 * 1024 const (
MaxBlockSize = 1 << 22
BuddySize = MaxBlockSize << 4
MinPowerOf2 = 10
)
var pools sync.Map var (
var EnableCheckSize bool = false memoryPool [BuddySize]byte
buddy = NewBuddy(BuddySize >> MinPowerOf2)
lock sync.Mutex
poolStart = int64(uintptr(unsafe.Pointer(&memoryPool[0])))
//EnableCheckSize bool = false
)
type MemoryAllocator struct { type MemoryAllocator struct {
allocator *Allocator allocator *Allocator
@@ -19,11 +28,19 @@ type MemoryAllocator struct {
} }
func GetMemoryAllocator(size int) (ret *MemoryAllocator) { func GetMemoryAllocator(size int) (ret *MemoryAllocator) {
if value, ok := pools.Load(size); ok { lock.Lock()
ret = value.(*sync.Pool).Get().(*MemoryAllocator) offset, err := buddy.Alloc(size >> MinPowerOf2)
} else { lock.Unlock()
ret = NewMemoryAllocator(size) if err != nil {
return NewMemoryAllocator(size)
} }
offset = offset << MinPowerOf2
ret = &MemoryAllocator{
Size: size,
memory: memoryPool[offset : offset+size],
allocator: NewAllocator(size),
}
ret.start = poolStart + int64(offset)
return return
} }
@@ -38,14 +55,9 @@ func NewMemoryAllocator(size int) (ret *MemoryAllocator) {
} }
func (ma *MemoryAllocator) Recycle() { func (ma *MemoryAllocator) Recycle() {
ma.allocator = NewAllocator(ma.Size) lock.Lock()
size := ma.Size _ = buddy.Free(int((poolStart - ma.start) >> 10))
pool, _ := pools.LoadOrStore(size, &sync.Pool{ lock.Unlock()
New: func() any {
return NewMemoryAllocator(size)
},
})
pool.(*sync.Pool).Put(ma)
} }
func (ma *MemoryAllocator) Malloc(size int) (memory []byte) { func (ma *MemoryAllocator) Malloc(size int) (memory []byte) {
@@ -77,10 +89,11 @@ type ScalableMemoryAllocator struct {
totalMalloc int64 totalMalloc int64
totalFree int64 totalFree int64
size int size int
childSize int
} }
func NewScalableMemoryAllocator(size int) (ret *ScalableMemoryAllocator) { func NewScalableMemoryAllocator(size int) (ret *ScalableMemoryAllocator) {
return &ScalableMemoryAllocator{children: []*MemoryAllocator{GetMemoryAllocator(size)}, size: size} return &ScalableMemoryAllocator{children: []*MemoryAllocator{GetMemoryAllocator(size)}, size: size, childSize: size}
} }
func (sma *ScalableMemoryAllocator) checkSize() { func (sma *ScalableMemoryAllocator) checkSize() {
@@ -123,9 +136,9 @@ func (sma *ScalableMemoryAllocator) Malloc(size int) (memory []byte) {
if sma == nil { if sma == nil {
return make([]byte, size) return make([]byte, size)
} }
if EnableCheckSize { //if EnableCheckSize {
defer sma.checkSize() // defer sma.checkSize()
} //}
defer sma.addMallocCount(size) defer sma.addMallocCount(size)
var child *MemoryAllocator var child *MemoryAllocator
for _, child = range sma.children { for _, child = range sma.children {
@@ -133,7 +146,13 @@ func (sma *ScalableMemoryAllocator) Malloc(size int) (memory []byte) {
return return
} }
} }
child = GetMemoryAllocator(max(min(MaxBlockSize, child.Size*2), size)) for sma.childSize <= MaxBlockSize {
sma.childSize = sma.childSize << 1
if sma.childSize >= size {
break
}
}
child = GetMemoryAllocator(sma.childSize)
sma.size += child.Size sma.size += child.Size
memory = child.Malloc(size) memory = child.Malloc(size)
sma.children = append(sma.children, child) sma.children = append(sma.children, child)
@@ -148,9 +167,9 @@ func (sma *ScalableMemoryAllocator) Free(mem []byte) bool {
if sma == nil { if sma == nil {
return false return false
} }
if EnableCheckSize { //if EnableCheckSize {
defer sma.checkSize() // defer sma.checkSize()
} //}
ptr := int64(uintptr(unsafe.Pointer(&mem[0]))) ptr := int64(uintptr(unsafe.Pointer(&mem[0])))
size := len(mem) size := len(mem)
for i, child := range sma.children { for i, child := range sma.children {

View File

@@ -332,12 +332,6 @@ func (p *Plugin) Subscribe(streamPath string, options ...any) (subscriber *Subsc
switch v := option.(type) { switch v := option.(type) {
case func(*config.Subscribe): case func(*config.Subscribe):
v(&subscriber.Subscribe) v(&subscriber.Subscribe)
case SubscriberHandler:
defer func() {
if err == nil {
subscriber.Handle(v)
}
}()
} }
} }
subscriber.Init(p, streamPath, options...) subscriber.Init(p, streamPath, options...)

View File

@@ -109,11 +109,10 @@ func (p *HDLPlugin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer binary.BigEndian.PutUint32(b[:4], uint32(data.Size)+11) defer binary.BigEndian.PutUint32(b[:4], uint32(data.Size)+11)
return gotFlvTag(append(net.Buffers{b[:]}, data.Memory.Buffers...)) return gotFlvTag(append(net.Buffers{b[:]}, data.Memory.Buffers...))
} }
sub.Handle(m7s.SubscriberHandler{ m7s.PlayBlock(sub, func(audio *rtmp.RTMPAudio) error {
OnAudio: func(audio *rtmp.RTMPAudio) error {
return rtmpData2FlvTag(FLV_TAG_TYPE_AUDIO, &audio.RTMPData) return rtmpData2FlvTag(FLV_TAG_TYPE_AUDIO, &audio.RTMPData)
}, OnVideo: func(video *rtmp.RTMPVideo) error { }, func(video *rtmp.RTMPVideo) error {
return rtmpData2FlvTag(FLV_TAG_TYPE_VIDEO, &video.RTMPData) return rtmpData2FlvTag(FLV_TAG_TYPE_VIDEO, &video.RTMPData)
}}) })
gotFlvTag(net.Buffers{b[:4]}) gotFlvTag(net.Buffers{b[:4]})
} }

View File

@@ -104,7 +104,6 @@ func (puller *HDLPuller) Pull(p *m7s.Puller) (err error) {
var frame rtmp.RTMPData var frame rtmp.RTMPData
frame.RecyclableMemory, err = puller.ReadBytes(int(dataSize)) frame.RecyclableMemory, err = puller.ReadBytes(int(dataSize))
if err != nil { if err != nil {
frame.Recycle()
return err return err
} }
puller.absTS = offsetTs + (timestamp - startTs) puller.absTS = offsetTs + (timestamp - startTs)

View File

@@ -1,7 +1,7 @@
package plugin_rtmp package plugin_rtmp
import ( import (
"context" "errors"
"io" "io"
"net" "net"
@@ -42,13 +42,17 @@ func (p *RTMPPlugin) OnTCPConnect(conn *net.TCPConn) {
logger := p.Logger.With("remote", conn.RemoteAddr().String()) logger := p.Logger.With("remote", conn.RemoteAddr().String())
receivers := make(map[uint32]*RTMPReceiver) receivers := make(map[uint32]*RTMPReceiver)
var err error var err error
logger.Info("conn")
nc := NewNetConnection(conn, logger) nc := NewNetConnection(conn, logger)
defer nc.Destroy()
ctx, cancel := context.WithCancelCause(p)
defer func() { defer func() {
logger.Info("conn close") nc.Destroy()
cancel(err) if p := recover(); p != nil {
err = p.(error)
}
if len(receivers) > 0 {
for _, receiver := range receivers {
receiver.Dispose(err)
}
}
}() }()
/* Handshake */ /* Handshake */
if err = nc.Handshake(p.C2); err != nil { if err = nc.Handshake(p.C2); err != nil {
@@ -156,7 +160,7 @@ func (p *RTMPPlugin) OnTCPConnect(conn *net.TCPConn) {
StreamID: cmd.StreamId, StreamID: cmd.StreamId,
}, },
} }
receiver.Publisher, err = p.Publish(nc.AppName+"/"+cmd.PublishingName, ctx, conn, connectInfo) receiver.Publisher, err = p.Publish(nc.AppName+"/"+cmd.PublishingName, p.Context, conn, connectInfo)
if err != nil { if err != nil {
delete(receivers, cmd.StreamId) delete(receivers, cmd.StreamId)
err = receiver.Response(cmd.TransactionId, NetStream_Publish_BadName, Level_Error) err = receiver.Response(cmd.TransactionId, NetStream_Publish_BadName, Level_Error)
@@ -176,18 +180,13 @@ func (p *RTMPPlugin) OnTCPConnect(conn *net.TCPConn) {
} }
var suber *m7s.Subscriber var suber *m7s.Subscriber
// sender.ID = fmt.Sprintf("%s|%d", conn.RemoteAddr().String(), sender.StreamID) // sender.ID = fmt.Sprintf("%s|%d", conn.RemoteAddr().String(), sender.StreamID)
suber, err = p.Subscribe(streamPath, ctx, conn, connectInfo) suber, err = p.Subscribe(streamPath, p.Context, conn, connectInfo)
if err != nil { if err != nil {
err = ns.Response(cmd.TransactionId, NetStream_Play_Failed, Level_Error) err = ns.Response(cmd.TransactionId, NetStream_Play_Failed, Level_Error)
} else { } else {
ns.BeginPlay(cmd.TransactionId) ns.BeginPlay(cmd.TransactionId)
audio, video := ns.CreateSender() audio, video := ns.CreateSender(false)
go suber.Handle(m7s.SubscriberHandler{ go m7s.PlayBlock(suber, audio.HandleAudio, video.HandleVideo)
OnAudio: func(a *RTMPAudio) error {
return audio.SendFrame(&a.RTMPData)
}, OnVideo: func(v *RTMPVideo) error {
return video.SendFrame(&v.RTMPData)
}})
} }
if err != nil { if err != nil {
logger.Error("sendMessage play", "error", err) logger.Error("sendMessage play", "error", err)
@@ -209,7 +208,7 @@ func (p *RTMPPlugin) OnTCPConnect(conn *net.TCPConn) {
logger.Warn("ReceiveVideo", "MessageStreamID", msg.MessageStreamID) logger.Warn("ReceiveVideo", "MessageStreamID", msg.MessageStreamID)
} }
} }
} else if err == io.EOF || err == io.ErrUnexpectedEOF { } else if err == io.EOF || errors.Is(err, io.ErrUnexpectedEOF) {
logger.Info("rtmp client closed") logger.Info("rtmp client closed")
return return
} else { } else {

View File

@@ -9,7 +9,6 @@ import (
"strings" "strings"
"m7s.live/m7s/v5" "m7s.live/m7s/v5"
. "m7s.live/m7s/v5/pkg"
) )
type Client struct { type Client struct {
@@ -104,7 +103,13 @@ func (client *Client) Connect(p *m7s.Client) (err error) {
func (puller *Client) Pull(p *m7s.Puller) (err error) { func (puller *Client) Pull(p *m7s.Puller) (err error) {
p.MetaData = puller.ServerInfo p.MetaData = puller.ServerInfo
defer puller.Close() defer func() {
puller.Close()
if p := recover(); p != nil {
err = p.(error)
}
p.Dispose(err)
}()
err = puller.SendMessage(RTMP_MSG_AMF0_COMMAND, &CommandMessage{"createStream", 2}) err = puller.SendMessage(RTMP_MSG_AMF0_COMMAND, &CommandMessage{"createStream", 2})
for err == nil { for err == nil {
msg, err := puller.RecvMessage() msg, err := puller.RecvMessage()
@@ -185,19 +190,8 @@ func (pusher *Client) Push(p *m7s.Pusher) (err error) {
}) })
} else if response, ok := msg.MsgData.(*ResponsePublishMessage); ok { } else if response, ok := msg.MsgData.(*ResponsePublishMessage); ok {
if response.Infomation["code"] == NetStream_Publish_Start { if response.Infomation["code"] == NetStream_Publish_Start {
audio, video := pusher.CreateSender() audio, video := pusher.CreateSender(true)
go p.Handle(m7s.SubscriberHandler{ go m7s.PlayBlock(&p.Subscriber, audio.HandleAudio, video.HandleVideo)
OnAudio: func(a *RTMPAudio) error {
if audio.SendFrame(&a.RTMPData) != nil {
return ErrInterrupt
}
return nil
}, OnVideo: func(v *RTMPVideo) error {
if video.SendFrame(&v.RTMPData) != nil {
return ErrInterrupt
}
return nil
}})
} else { } else {
return errors.New(response.Infomation["code"].(string)) return errors.New(response.Infomation["code"].(string))
} }

View File

@@ -116,18 +116,18 @@ func (nc *NetConnection) simple_handshake(C1 []byte, checkC2 bool) error {
nc.Write(S0S1) nc.Write(S0S1)
nc.Write(C1) // S2 nc.Write(C1) // S2
C2, err := nc.ReadBytes(C1S1_SIZE) C2, err := nc.ReadBytes(C1S1_SIZE)
C2.Recycle()
if err != nil { if err != nil {
return err return err
} }
C2.Recycle()
if checkC2 { if checkC2 {
buf := nc.mediaDataPool.NextN(C2.Size) buf := nc.mediaDataPool.NextN(C2.Size)
C2.Read(buf) _, err = C2.Read(buf)
if !bytes.Equal(buf[8:], S0S1[9:]) { if !bytes.Equal(buf[8:], S0S1[9:]) {
return errors.New("C2 Error") return errors.New("C2 Error")
} }
} }
return nil return err
} }
func (nc *NetConnection) complex_handshake(C1 []byte) error { func (nc *NetConnection) complex_handshake(C1 []byte) error {
@@ -178,10 +178,10 @@ func (nc *NetConnection) complex_handshake(C1 []byte) error {
} }
buffer := net.Buffers{[]byte{RTMP_HANDSHAKE_VERSION}, S1, S2_Random, S2_Digest} buffer := net.Buffers{[]byte{RTMP_HANDSHAKE_VERSION}, S1, S2_Random, S2_Digest}
buffer.WriteTo(nc) _, err = buffer.WriteTo(nc)
b, _ := nc.ReadBytes(1536) b, _ := nc.ReadBytes(1536)
b.Recycle() b.Recycle()
return nil return err
} }
func validateClient(C1 []byte) (scheme int, challenge []byte, digest []byte, ok bool, err error) { func validateClient(C1 []byte) (scheme int, challenge []byte, digest []byte, ok bool, err error) {

View File

@@ -2,6 +2,7 @@ package rtmp
import ( import (
"errors" "errors"
"m7s.live/m7s/v5/pkg"
"runtime" "runtime"
"m7s.live/m7s/v5" "m7s.live/m7s/v5"
@@ -10,12 +11,28 @@ import (
type AVSender struct { type AVSender struct {
*NetConnection *NetConnection
ChunkHeader ChunkHeader
errContinue bool
lastAbs uint32 lastAbs uint32
} }
func (av *AVSender) HandleAudio(frame *RTMPAudio) (err error) {
return av.SendFrame(&frame.RTMPData)
}
func (av *AVSender) HandleVideo(frame *RTMPVideo) (err error) {
return av.SendFrame(&frame.RTMPData)
}
func (av *AVSender) SendFrame(frame *RTMPData) (err error) { func (av *AVSender) SendFrame(frame *RTMPData) (err error) {
// seq := frame.Sequence // seq := frame.Sequence
payloadLen := frame.Size payloadLen := frame.Size
if av.errContinue {
defer func() {
if err != nil {
err = pkg.ErrInterrupt
}
}()
}
if payloadLen == 0 { if payloadLen == 0 {
err = errors.New("payload is empty") err = errors.New("payload is empty")
// av.Error("payload is empty", zap.Error(err)) // av.Error("payload is empty", zap.Error(err))
@@ -47,7 +64,7 @@ func (av *AVSender) SendFrame(frame *RTMPData) (err error) {
// if seq != frame.Sequence { // if seq != frame.Sequence {
// return errors.New("sequence is not equal") // return errors.New("sequence is not equal")
// } // }
return err return
} }
type RTMPReceiver struct { type RTMPReceiver struct {

View File

@@ -74,13 +74,15 @@ func NewNetConnection(conn net.Conn, logger *slog.Logger) (ret *NetConnection) {
tmpBuf: make(util.Buffer, 4), tmpBuf: make(util.Buffer, 4),
chunkHeaderBuf: make(util.Buffer, 0, 20), chunkHeaderBuf: make(util.Buffer, 0, 20),
} }
ret.mediaDataPool.ScalableMemoryAllocator = util.NewScalableMemoryAllocator(1024) ret.mediaDataPool.ScalableMemoryAllocator = util.NewScalableMemoryAllocator(1 << util.MinPowerOf2)
ret.Info("new connection")
return return
} }
func (conn *NetConnection) Destroy() { func (conn *NetConnection) Destroy() {
conn.Conn.Close() conn.Conn.Close()
conn.BufReader.Recycle() conn.BufReader.Recycle()
conn.mediaDataPool.Recycle() conn.mediaDataPool.Recycle()
conn.Info("destroy connection")
} }
func (conn *NetConnection) SendStreamID(eventType uint16, streamID uint32) (err error) { func (conn *NetConnection) SendStreamID(eventType uint16, streamID uint32) (err error) {
return conn.SendMessage(RTMP_MSG_USER_CONTROL, &StreamIDMessage{UserControlMessage{EventType: eventType}, streamID}) return conn.SendMessage(RTMP_MSG_USER_CONTROL, &StreamIDMessage{UserControlMessage{EventType: eventType}, streamID})
@@ -141,13 +143,15 @@ func (conn *NetConnection) readChunk() (msg *Chunk, err error) {
return nil, errors.New("get chunk type error :" + err.Error()) return nil, errors.New("get chunk type error :" + err.Error())
} }
msgLen := int(chunk.MessageLength) msgLen := int(chunk.MessageLength)
if msgLen == 0 {
return nil, nil
}
var mem util.RecyclableMemory var mem util.RecyclableMemory
if unRead := msgLen - chunk.bufLen; unRead < conn.readChunkSize { if unRead := msgLen - chunk.bufLen; unRead < conn.readChunkSize {
mem, err = conn.ReadBytes(unRead) mem, err = conn.ReadBytes(unRead)
} else { } else {
mem, err = conn.ReadBytes(conn.readChunkSize) mem, err = conn.ReadBytes(conn.readChunkSize)
} }
mem.Recycle()
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -5,26 +5,28 @@ type NetStream struct {
StreamID uint32 StreamID uint32
} }
func (ns *NetStream) CreateAudioSender() *AVSender { func (ns *NetStream) CreateAudioSender(c bool) *AVSender {
var av AVSender var av AVSender
av.NetConnection = ns.NetConnection av.NetConnection = ns.NetConnection
av.ChunkStreamID = RTMP_CSID_AUDIO av.ChunkStreamID = RTMP_CSID_AUDIO
av.MessageTypeID = RTMP_MSG_AUDIO av.MessageTypeID = RTMP_MSG_AUDIO
av.MessageStreamID = ns.StreamID av.MessageStreamID = ns.StreamID
av.errContinue = c
return &av return &av
} }
func (ns *NetStream) CreateVideoSender() *AVSender { func (ns *NetStream) CreateVideoSender(c bool) *AVSender {
var av AVSender var av AVSender
av.NetConnection = ns.NetConnection av.NetConnection = ns.NetConnection
av.ChunkStreamID = RTMP_CSID_VIDEO av.ChunkStreamID = RTMP_CSID_VIDEO
av.MessageTypeID = RTMP_MSG_VIDEO av.MessageTypeID = RTMP_MSG_VIDEO
av.MessageStreamID = ns.StreamID av.MessageStreamID = ns.StreamID
av.errContinue = c
return &av return &av
} }
func (ns *NetStream) CreateSender() (audio *AVSender, video *AVSender) { func (ns *NetStream) CreateSender(c bool) (audio *AVSender, video *AVSender) {
return ns.CreateAudioSender(), ns.CreateVideoSender() return ns.CreateAudioSender(c), ns.CreateVideoSender(c)
} }
func (ns *NetStream) Response(tid uint64, code, level string) error { func (ns *NetStream) Response(tid uint64, code, level string) error {
@@ -63,7 +65,7 @@ func (ns *NetStream) BeginPlay(tid uint64) (err error) {
func (ns *NetStream) Close() error { func (ns *NetStream) Close() error {
if ns.NetConnection != nil { if ns.NetConnection != nil {
return ns.NetConnection.Close() ns.NetConnection.Destroy()
} }
return nil return nil
} }

View File

@@ -182,7 +182,7 @@ func (conf *WebRTCPlugin) Push_(w http.ResponseWriter, r *http.Request) {
if !publisher.PubAudio { if !publisher.PubAudio {
return return
} }
mem := util.NewScalableMemoryAllocator(1460 * 100) mem := util.NewScalableMemoryAllocator(1 << 12)
defer mem.Recycle() defer mem.Recycle()
frame := &mrtp.RTPAudio{} frame := &mrtp.RTPAudio{}
frame.RTPCodecParameters = &codecP frame.RTPCodecParameters = &codecP
@@ -222,7 +222,7 @@ func (conf *WebRTCPlugin) Push_(w http.ResponseWriter, r *http.Request) {
return return
} }
var lastPLISent time.Time var lastPLISent time.Time
mem := util.NewScalableMemoryAllocator(1460 * 100) mem := util.NewScalableMemoryAllocator(1 << 12)
defer mem.Recycle() defer mem.Recycle()
frame := &mrtp.RTPVideo{} frame := &mrtp.RTPVideo{}
frame.RTPCodecParameters = &codecP frame.RTPCodecParameters = &codecP
@@ -432,23 +432,20 @@ func (conf *WebRTCPlugin) Play_(w http.ResponseWriter, r *http.Request) {
if videoSender == nil { if videoSender == nil {
suber.SubVideo = false suber.SubVideo = false
} }
go suber.Handle(m7s.SubscriberHandler{ go m7s.PlayBlock(suber, func(frame *mrtp.RTPAudio) (err error) {
OnAudio: func(frame *mrtp.RTPAudio) (err error) {
for _, p := range frame.Packets { for _, p := range frame.Packets {
if err = audioTLSRTP.WriteRTP(p); err != nil { if err = audioTLSRTP.WriteRTP(p); err != nil {
return return
} }
} }
return return
}, }, func(frame *mrtp.RTPVideo) error {
OnVideo: func(frame *mrtp.RTPVideo) error {
for _, p := range frame.Packets { for _, p := range frame.Packets {
if err := videoTLSRTP.WriteRTP(p); err != nil { if err := videoTLSRTP.WriteRTP(p); err != nil {
return err return err
} }
} }
return nil return nil
},
}) })
} }
conn.OnICECandidate(func(ice *ICECandidate) { conn.OnICECandidate(func(ice *ICECandidate) {

View File

@@ -1,6 +1,7 @@
package m7s package m7s
import ( import (
"errors"
"reflect" "reflect"
"sync" "sync"
"time" "time"
@@ -17,6 +18,7 @@ const (
PublisherStateTrackAdded PublisherStateTrackAdded
PublisherStateSubscribed PublisherStateSubscribed
PublisherStateWaitSubscriber PublisherStateWaitSubscriber
PublisherStateDisposed
) )
type SpeedControl struct { type SpeedControl struct {
@@ -57,7 +59,7 @@ func (t *AVTracks) IsEmpty() bool {
func (t *AVTracks) CreateSubTrack(dataType reflect.Type) (track *AVTrack) { func (t *AVTracks) CreateSubTrack(dataType reflect.Type) (track *AVTrack) {
track = NewAVTrack(dataType, t.AVTrack) track = NewAVTrack(dataType, t.AVTrack)
track.WrapIndex = len(t.Items) track.WrapIndex = t.Length
t.Add(track) t.Add(track)
return return
} }
@@ -70,12 +72,16 @@ type Publisher struct {
VideoTrack AVTracks VideoTrack AVTracks
AudioTrack AVTracks AudioTrack AVTracks
DataTrack *DataTrack DataTrack *DataTrack
Subscribers map[*Subscriber]struct{} `json:"-" yaml:"-"` Subscribers util.Collection[int, *Subscriber] `json:"-" yaml:"-"`
GOP int GOP int
baseTs time.Duration baseTs time.Duration
lastTs time.Duration lastTs time.Duration
} }
func (p *Publisher) SubscriberRange(yield func(sub *Subscriber) bool) {
p.Subscribers.Range(yield)
}
func (p *Publisher) GetKey() string { func (p *Publisher) GetKey() string {
return p.StreamPath return p.StreamPath
} }
@@ -118,27 +124,25 @@ func (p *Publisher) checkTimeout() (err error) {
return return
} }
func (p *Publisher) RemoveSubscriber(subscriber *Subscriber) (err error) { func (p *Publisher) RemoveSubscriber(subscriber *Subscriber) {
p.Lock() p.Lock()
defer p.Unlock() defer p.Unlock()
delete(p.Subscribers, subscriber) p.Subscribers.Remove(subscriber)
p.Info("subscriber -1", "count", len(p.Subscribers)) p.Info("subscriber -1", "count", p.Subscribers.Length)
if p.State == PublisherStateSubscribed && len(p.Subscribers) == 0 { if p.State == PublisherStateSubscribed && p.Subscribers.Length == 0 {
p.State = PublisherStateWaitSubscriber p.State = PublisherStateWaitSubscriber
if p.DelayCloseTimeout > 0 { if p.DelayCloseTimeout > 0 {
p.TimeoutTimer.Reset(p.DelayCloseTimeout) p.TimeoutTimer.Reset(p.DelayCloseTimeout)
} }
} }
return
} }
func (p *Publisher) AddSubscriber(subscriber *Subscriber) (err error) { func (p *Publisher) AddSubscriber(subscriber *Subscriber) {
p.Lock() p.Lock()
defer p.Unlock() defer p.Unlock()
subscriber.Publisher = p subscriber.Publisher = p
if _, ok := p.Subscribers[subscriber]; !ok { if p.Subscribers.AddUnique(subscriber) {
p.Subscribers[subscriber] = struct{}{} p.Info("subscriber +1", "count", p.Subscribers.Length)
p.Info("subscriber +1", "count", len(p.Subscribers))
switch p.State { switch p.State {
case PublisherStateTrackAdded, PublisherStateWaitSubscriber: case PublisherStateTrackAdded, PublisherStateWaitSubscriber:
p.State = PublisherStateSubscribed p.State = PublisherStateSubscribed
@@ -147,7 +151,6 @@ func (p *Publisher) AddSubscriber(subscriber *Subscriber) (err error) {
} }
} }
} }
return
} }
func (p *Publisher) writeAV(t *AVTrack, data IAVFrame) { func (p *Publisher) writeAV(t *AVTrack, data IAVFrame) {
@@ -179,11 +182,11 @@ func (p *Publisher) WriteVideo(data IAVFrame) (err error) {
} }
t := p.VideoTrack.AVTrack t := p.VideoTrack.AVTrack
if t == nil { if t == nil {
t = NewAVTrack(data, p.Logger.With("track", "video"), 50) t = NewAVTrack(data, p.Logger.With("track", "video"), 100)
p.Lock() p.Lock()
p.VideoTrack.AVTrack = t p.VideoTrack.AVTrack = t
p.VideoTrack.Add(t) p.VideoTrack.Add(t)
if len(p.Subscribers) > 0 { if p.Subscribers.Length > 0 {
p.State = PublisherStateSubscribed p.State = PublisherStateSubscribed
} else { } else {
p.State = PublisherStateTrackAdded p.State = PublisherStateTrackAdded
@@ -294,7 +297,7 @@ func (p *Publisher) WriteAudio(data IAVFrame) (err error) {
p.Lock() p.Lock()
p.AudioTrack.AVTrack = t p.AudioTrack.AVTrack = t
p.AudioTrack.Add(t) p.AudioTrack.Add(t)
if len(p.Subscribers) > 0 { if p.Subscribers.Length > 0 {
p.State = PublisherStateSubscribed p.State = PublisherStateSubscribed
} else { } else {
p.State = PublisherStateTrackAdded p.State = PublisherStateTrackAdded
@@ -319,7 +322,7 @@ func (p *Publisher) WriteData(data IDataFrame) (err error) {
p.DataTrack = &DataTrack{} p.DataTrack = &DataTrack{}
p.DataTrack.Logger = p.Logger.With("track", "data") p.DataTrack.Logger = p.Logger.With("track", "data")
p.Lock() p.Lock()
if len(p.Subscribers) > 0 { if p.Subscribers.Length > 0 {
p.State = PublisherStateSubscribed p.State = PublisherStateSubscribed
} else { } else {
p.State = PublisherStateTrackAdded p.State = PublisherStateTrackAdded
@@ -354,6 +357,25 @@ func (p *Publisher) GetVideoTrack(dataType reflect.Type) (t *AVTrack) {
return return
} }
func (p *Publisher) Dispose(err error) {
p.Lock()
defer p.Unlock()
if p.State == PublisherStateDisposed {
return
}
if !errors.Is(p.StopReason(), ErrKick) && p.IsStopped() {
if !p.AudioTrack.IsEmpty() {
p.AudioTrack.Dispose()
}
if !p.VideoTrack.IsEmpty() {
p.VideoTrack.Dispose()
}
p.State = PublisherStateDisposed
return
}
p.Stop(err)
}
func (p *Publisher) TakeOver(old *Publisher) { func (p *Publisher) TakeOver(old *Publisher) {
p.baseTs = old.lastTs p.baseTs = old.lastTs
p.VideoTrack = old.VideoTrack p.VideoTrack = old.VideoTrack
@@ -363,7 +385,10 @@ func (p *Publisher) TakeOver(old *Publisher) {
p.AudioTrack.ICodecCtx = nil p.AudioTrack.ICodecCtx = nil
p.AudioTrack.Logger = p.Logger.With("track", "audio") p.AudioTrack.Logger = p.Logger.With("track", "audio")
p.DataTrack = old.DataTrack p.DataTrack = old.DataTrack
p.Subscribers = old.Subscribers for subscriber := range old.SubscriberRange {
p.AddSubscriber(subscriber)
}
old.Subscribers = util.Collection[int, *Subscriber]{}
// for _, track := range p.TransTrack { // for _, track := range p.TransTrack {
// track.ICodecCtx = nil // track.ICodecCtx = nil
// } // }

View File

@@ -51,7 +51,7 @@ type Server struct {
Streams util.Collection[string, *Publisher] Streams util.Collection[string, *Publisher]
Pulls util.Collection[string, *Puller] Pulls util.Collection[string, *Puller]
Pushs util.Collection[string, *Pusher] Pushs util.Collection[string, *Pusher]
Waiting map[string][]*Subscriber Waiting util.Collection[string, *Publisher]
Subscribers util.Collection[int, *Subscriber] Subscribers util.Collection[int, *Subscriber]
LogHandler MultiLogHandler LogHandler MultiLogHandler
pidG int pidG int
@@ -68,7 +68,6 @@ type Server struct {
func NewServer() (s *Server) { func NewServer() (s *Server) {
s = &Server{ s = &Server{
ID: int(serverIndexG.Add(1)), ID: int(serverIndexG.Add(1)),
Waiting: make(map[string][]*Subscriber),
eventChan: make(chan any, 10), eventChan: make(chan any, 10),
} }
s.config.HTTP.ListenAddrTLS = ":8443" s.config.HTTP.ListenAddrTLS = ":8443"
@@ -94,7 +93,6 @@ type rawconfig = map[string]map[string]any
func (s *Server) reset() { func (s *Server) reset() {
server := Server{ server := Server{
ID: s.ID, ID: s.ID,
Waiting: make(map[string][]*Subscriber),
eventChan: make(chan any, 10), eventChan: make(chan any, 10),
} }
server.Logger = s.Logger server.Logger = s.Logger
@@ -222,13 +220,13 @@ func (s *Server) run(ctx context.Context, conf any) (err error) {
s.eventLoop() s.eventLoop()
err = context.Cause(s) err = context.Cause(s)
s.Warn("Server is done", "reason", err) s.Warn("Server is done", "reason", err)
for _, publisher := range s.Streams.Items { for publisher := range s.Streams.Range {
publisher.Stop(err) publisher.Stop(err)
} }
for _, subscriber := range s.Subscribers.Items { for subscriber := range s.Subscribers.Range {
subscriber.Stop(err) subscriber.Stop(err)
} }
for _, p := range s.Plugins.Items { for p := range s.Plugins.Range {
p.Stop(err) p.Stop(err)
} }
httpConf.StopListen() httpConf.StopListen()
@@ -269,13 +267,21 @@ func (s *Server) eventLoop() {
case <-s.Done(): case <-s.Done():
return return
case <-pulse.C: case <-pulse.C:
for _, publisher := range s.Streams.Items { for publisher := range s.Streams.Range {
if err := publisher.checkTimeout(); err != nil { if err := publisher.checkTimeout(); err != nil {
publisher.Stop(err) publisher.Stop(err)
} }
} }
for subscriber := range s.Waiting { for publisher := range s.Waiting.Range {
for _, sub := range s.Waiting[subscriber] { if publisher.Plugin != nil {
if err := publisher.checkTimeout(); err != nil {
publisher.Dispose(err)
newPublisher := &Publisher{}
newPublisher.StreamPath = publisher.StreamPath
s.Waiting.Set(newPublisher)
}
}
for sub := range publisher.SubscriberRange {
select { select {
case <-sub.TimeoutTimer.C: case <-sub.TimeoutTimer.C:
sub.Stop(ErrSubscribeTimeout) sub.Stop(ErrSubscribeTimeout)
@@ -347,7 +353,7 @@ func (s *Server) eventLoop() {
case slog.Handler: case slog.Handler:
s.LogHandler.Add(v) s.LogHandler.Add(v)
} }
for _, plugin := range s.Plugins.Items { for plugin := range s.Plugins.Range {
if plugin.Disabled { if plugin.Disabled {
continue continue
} }
@@ -363,7 +369,7 @@ func (s *Server) onUnsubscribe(subscriber *Subscriber) {
if subscriber.Closer != nil { if subscriber.Closer != nil {
subscriber.Close() subscriber.Close()
} }
for _, pusher := range s.Pushs.Items { for pusher := range s.Pushs.Range {
if &pusher.Subscriber == subscriber { if &pusher.Subscriber == subscriber {
s.Pushs.Remove(pusher) s.Pushs.Remove(pusher)
break break
@@ -372,25 +378,17 @@ func (s *Server) onUnsubscribe(subscriber *Subscriber) {
if subscriber.Publisher != nil { if subscriber.Publisher != nil {
subscriber.Publisher.RemoveSubscriber(subscriber) subscriber.Publisher.RemoveSubscriber(subscriber)
} }
if subscribers, ok := s.Waiting[subscriber.StreamPath]; ok {
if index := slices.Index(subscribers, subscriber); index >= 0 {
s.Waiting[subscriber.StreamPath] = slices.Delete(subscribers, index, index+1)
if len(subscribers) == 1 {
delete(s.Waiting, subscriber.StreamPath)
}
}
}
} }
func (s *Server) onUnpublish(publisher *Publisher) { func (s *Server) onUnpublish(publisher *Publisher) {
s.Streams.Remove(publisher) s.Streams.Remove(publisher)
s.Waiting.Add(publisher)
s.Info("unpublish", "streamPath", publisher.StreamPath, "count", s.Streams.Length) s.Info("unpublish", "streamPath", publisher.StreamPath, "count", s.Streams.Length)
for subscriber := range publisher.Subscribers { for subscriber := range publisher.SubscriberRange {
s.Waiting[publisher.StreamPath] = append(s.Waiting[publisher.StreamPath], subscriber)
subscriber.TimeoutTimer.Reset(publisher.WaitCloseTimeout) subscriber.TimeoutTimer.Reset(publisher.WaitCloseTimeout)
} }
if publisher.Closer != nil { if publisher.Closer != nil {
publisher.Close() _ = publisher.Close()
} }
s.Pulls.RemoveByKey(publisher.StreamPath) s.Pulls.RemoveByKey(publisher.StreamPath)
} }
@@ -401,12 +399,9 @@ func (s *Server) OnPublish(publisher *Publisher) error {
publisher.Warn("kick") publisher.Warn("kick")
oldPublisher.Stop(ErrKick) oldPublisher.Stop(ErrKick)
publisher.TakeOver(oldPublisher) publisher.TakeOver(oldPublisher)
oldPublisher.Subscribers = nil
} else { } else {
return ErrStreamExist return ErrStreamExist
} }
} else {
publisher.Subscribers = make(map[*Subscriber]struct{})
} }
s.Streams.Set(publisher) s.Streams.Set(publisher)
s.pidG++ s.pidG++
@@ -415,14 +410,15 @@ func (s *Server) OnPublish(publisher *Publisher) error {
publisher.Logger = p.With("streamPath", publisher.StreamPath, "puber", publisher.ID) publisher.Logger = p.With("streamPath", publisher.StreamPath, "puber", publisher.ID)
publisher.TimeoutTimer = time.NewTimer(p.config.PublishTimeout) publisher.TimeoutTimer = time.NewTimer(p.config.PublishTimeout)
publisher.Info("publish") publisher.Info("publish")
if subscribers, ok := s.Waiting[publisher.StreamPath]; ok { if waiting, ok := s.Waiting.Get(publisher.StreamPath); ok {
for i, subscriber := range subscribers { if waiting.Plugin != nil {
if i == 0 && subscriber.Publisher != nil { publisher.TakeOver(waiting)
publisher.TakeOver(subscriber.Publisher) } else {
} for subscriber := range waiting.SubscriberRange {
publisher.AddSubscriber(subscriber) publisher.AddSubscriber(subscriber)
} }
delete(s.Waiting, publisher.StreamPath) }
s.Waiting.Remove(waiting)
} }
return nil return nil
} }
@@ -435,9 +431,13 @@ func (s *Server) OnSubscribe(subscriber *Subscriber) error {
s.Subscribers.Add(subscriber) s.Subscribers.Add(subscriber)
subscriber.Info("subscribe") subscriber.Info("subscribe")
if publisher, ok := s.Streams.Get(subscriber.StreamPath); ok { if publisher, ok := s.Streams.Get(subscriber.StreamPath); ok {
return publisher.AddSubscriber(subscriber) publisher.AddSubscriber(subscriber)
} else if publisher, ok = s.Waiting.Get(subscriber.StreamPath); ok {
publisher.AddSubscriber(subscriber)
} else { } else {
s.Waiting[subscriber.StreamPath] = append(s.Waiting[subscriber.StreamPath], subscriber) newPublisher := &Publisher{}
newPublisher.StreamPath = subscriber.StreamPath
newPublisher.AddSubscriber(subscriber)
} }
return nil return nil
} }
@@ -448,7 +448,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return return
} }
fmt.Fprintf(w, "visit:%s\nMonibuca Engine %s StartTime:%s\n", r.URL.Path, Version, s.StartTime) fmt.Fprintf(w, "visit:%s\nMonibuca Engine %s StartTime:%s\n", r.URL.Path, Version, s.StartTime)
for _, plugin := range s.Plugins.Items { for plugin := range s.Plugins.Range {
fmt.Fprintf(w, "Plugin %s Version:%s\n", plugin.Meta.Name, plugin.Meta.Version) fmt.Fprintf(w, "Plugin %s Version:%s\n", plugin.Meta.Name, plugin.Meta.Version)
} }
for _, api := range s.apiList { for _, api := range s.apiList {

View File

@@ -2,6 +2,7 @@ package m7s
import ( import (
"context" "context"
"errors"
"io" "io"
"net" "net"
"net/url" "net/url"
@@ -70,11 +71,6 @@ type Subscriber struct {
VideoReader *AVRingReader VideoReader *AVRingReader
} }
type SubscriberHandler struct {
OnAudio any
OnVideo any
}
func (s *Subscriber) OnVideoFrame(yield func(*AVFrame) bool) { func (s *Subscriber) OnVideoFrame(yield func(*AVFrame) bool) {
if !s.SubVideo || s.Publisher == nil { if !s.SubVideo || s.Publisher == nil {
return return
@@ -169,24 +165,24 @@ func HandleVideo[T IAVFrame](s *Subscriber) func(func(T) bool) {
} }
} }
func (s *Subscriber) Handle(handler SubscriberHandler) { func PlayBlock[A any, V any](s *Subscriber, onAudio func(A) error, onVideo func(V) error) {
var ar, vr *AVRingReader var ar, vr *AVRingReader
var ah, vh reflect.Value
var a1, v1 reflect.Type var a1, v1 reflect.Type
var at, vt *AVTrack var at, vt *AVTrack
var awi, vwi int var awi, vwi int
var startAudioTs, startVideoTs time.Duration
var initState = 0 var initState = 0
var prePublisher *Publisher
var subMode = s.SubMode //订阅模式 var subMode = s.SubMode //订阅模式
if s.Args.Has(s.SubModeArgName) { if s.Args.Has(s.SubModeArgName) {
subMode, _ = strconv.Atoi(s.Args.Get(s.SubModeArgName)) subMode, _ = strconv.Atoi(s.Args.Get(s.SubModeArgName))
} }
var audioFrame, videoFrame *AVFrame var audioFrame, videoFrame *AVFrame
if handler.OnAudio != nil && s.SubAudio { if s.SubAudio {
a1 = reflect.TypeOf(onAudio).In(0)
a1 = reflect.TypeOf(handler.OnAudio).In(0)
} }
if handler.OnVideo != nil && s.SubVideo { if s.SubVideo {
v1 = reflect.TypeOf(handler.OnVideo).In(0) v1 = reflect.TypeOf(onVideo).In(0)
} }
createAudioReader := func() { createAudioReader := func() {
if s.Publisher == nil || a1 == nil { if s.Publisher == nil || a1 == nil {
@@ -204,9 +200,9 @@ func (s *Subscriber) Handle(handler SubscriberHandler) {
if at != nil { if at != nil {
ar = NewAVRingReader(at) ar = NewAVRingReader(at)
s.AudioReader = ar s.AudioReader = ar
ar.StartTs = startAudioTs
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)
} }
} }
createVideoReader := func() { createVideoReader := func() {
@@ -224,14 +220,15 @@ func (s *Subscriber) Handle(handler SubscriberHandler) {
} }
if vt != nil { if vt != nil {
vr = NewAVRingReader(vt) vr = NewAVRingReader(vt)
vr.StartTs = startVideoTs
s.VideoReader = vr 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)
} }
} }
createAudioReader() createAudioReader()
createVideoReader() createVideoReader()
prePublisher = s.Publisher
defer func() { defer func() {
if ar != nil { if ar != nil {
ar.StopRead() ar.StopRead()
@@ -240,22 +237,18 @@ func (s *Subscriber) Handle(handler SubscriberHandler) {
vr.StopRead() vr.StopRead()
} }
}() }()
inputs := make([]reflect.Value, 1)
sendAudioFrame := func() (err error) { sendAudioFrame := func() (err error) {
if awi >= 0 { if awi >= 0 {
if s.Enabled(s, TraceLevel) { if s.Enabled(s, TraceLevel) {
s.Trace("send audio frame", "seq", audioFrame.Sequence) s.Trace("send audio frame", "seq", audioFrame.Sequence)
} }
inputs[0] = reflect.ValueOf(audioFrame.Wraps[awi]) err = onAudio(audioFrame.Wraps[awi].(A))
} else { } else {
inputs[0] = reflect.ValueOf(audioFrame) err = onAudio(any(audioFrame).(A))
} }
res := ah.Call(inputs) if err != nil && !errors.Is(err, ErrInterrupt) {
if len(res) > 0 && !res[0].IsNil() {
if err := res[0].Interface().(error); err != ErrInterrupt {
s.Stop(err) s.Stop(err)
} }
}
audioFrame = nil audioFrame = nil
return return
} }
@@ -264,19 +257,31 @@ func (s *Subscriber) Handle(handler SubscriberHandler) {
if s.Enabled(s, TraceLevel) { if s.Enabled(s, TraceLevel) {
s.Trace("send video frame", "seq", videoFrame.Sequence, "data", videoFrame.Wraps[vwi].String(), "size", videoFrame.Wraps[vwi].GetSize()) s.Trace("send video frame", "seq", videoFrame.Sequence, "data", videoFrame.Wraps[vwi].String(), "size", videoFrame.Wraps[vwi].GetSize())
} }
inputs[0] = reflect.ValueOf(videoFrame.Wraps[vwi]) err = onVideo(videoFrame.Wraps[vwi].(V))
} else { } else {
inputs[0] = reflect.ValueOf(videoFrame) err = onVideo(any(videoFrame).(V))
} }
res := vh.Call(inputs) if err != nil && !errors.Is(err, ErrInterrupt) {
if len(res) > 0 && !res[0].IsNil() {
if err = res[0].Interface().(error); err != ErrInterrupt {
s.Stop(err) s.Stop(err)
} }
}
videoFrame = nil videoFrame = nil
return return
} }
checkPublisherChange := func() {
if prePublisher != s.Publisher {
if ar != nil {
startAudioTs = time.Duration(ar.AbsTime) * time.Millisecond
ar.StopRead()
}
if vr != nil {
startVideoTs = time.Duration(vr.AbsTime) * time.Millisecond
vr.StopRead()
}
createAudioReader()
createVideoReader()
prePublisher = s.Publisher
}
}
var err error var err error
for err == nil { for err == nil {
err = s.Err() err = s.Err()
@@ -297,7 +302,7 @@ func (s *Subscriber) Handle(handler SubscriberHandler) {
vr.LastCodecCtx = vr.Track.ICodecCtx vr.LastCodecCtx = vr.Track.ICodecCtx
if seqFrame := vr.Track.SequenceFrame; seqFrame != nil { if seqFrame := vr.Track.SequenceFrame; seqFrame != nil {
s.Debug("video codec changed", "data", seqFrame.String()) s.Debug("video codec changed", "data", seqFrame.String())
vh.Call([]reflect.Value{reflect.ValueOf(seqFrame)}) err = onVideo(seqFrame.(V))
} }
} }
if ar != nil { if ar != nil {
@@ -315,6 +320,9 @@ func (s *Subscriber) Handle(handler SubscriberHandler) {
if !s.IFrameOnly || videoFrame.IDR { if !s.IFrameOnly || videoFrame.IDR {
err = sendVideoFrame() err = sendVideoFrame()
} }
if ar == nil {
break
}
} }
} else { } else {
createVideoReader() createVideoReader()
@@ -347,7 +355,7 @@ func (s *Subscriber) Handle(handler SubscriberHandler) {
if ar.DecConfChanged() { if ar.DecConfChanged() {
ar.LastCodecCtx = ar.Track.ICodecCtx ar.LastCodecCtx = ar.Track.ICodecCtx
if seqFrame := ar.Track.SequenceFrame; seqFrame != nil { if seqFrame := ar.Track.SequenceFrame; seqFrame != nil {
ah.Call([]reflect.Value{reflect.ValueOf(seqFrame)}) err = onAudio(seqFrame.(A))
} }
} }
if vr != nil && videoFrame != nil { if vr != nil && videoFrame != nil {
@@ -365,5 +373,6 @@ func (s *Subscriber) Handle(handler SubscriberHandler) {
} else { } else {
createAudioReader() createAudioReader()
} }
checkPublisherChange()
} }
} }