// Copyright 2022, Chef. All rights reserved. // https://github.com/q191201771/lal // // Use of this source code is governed by a MIT-style license // that can be found in the License file. // // Author: Chef (191201771@qq.com) package logic import ( "github.com/q191201771/lal/pkg/gb28181" "github.com/q191201771/naza/pkg/nazalog" "time" "github.com/q191201771/lal/pkg/base" "github.com/q191201771/lal/pkg/remux" "github.com/q191201771/lal/pkg/rtmp" "github.com/q191201771/lal/pkg/rtsp" ) func (group *Group) AddCustomizePubSession(streamName string) (ICustomizePubSessionContext, error) { group.mutex.Lock() defer group.mutex.Unlock() if group.hasInSession() { Log.Errorf("[%s] in stream already exist at group. add customize pub session, exist=%s", group.UniqueKey, group.inSessionUniqueKey()) return nil, base.ErrDupInStream } group.customizePubSession = NewCustomizePubSessionContext(streamName) Log.Debugf("[%s] [%s] add customize pub session into group.", group.UniqueKey, group.customizePubSession.UniqueKey()) group.addIn() if group.shouldStartRtspRemuxer() { group.rtmp2RtspRemuxer = remux.NewRtmp2RtspRemuxer( group.onSdpFromRemux, group.onRtpPacketFromRemux, ) } group.customizePubSession.WithOnRtmpMsg(group.OnReadRtmpAvMsg) return group.customizePubSession, nil } func (group *Group) AddRtmpPubSession(session *rtmp.ServerSession) error { group.mutex.Lock() defer group.mutex.Unlock() if group.hasInSession() { Log.Errorf("[%s] in stream already exist at group. add=%s, exist=%s", group.UniqueKey, session.UniqueKey(), group.inSessionUniqueKey()) return base.ErrDupInStream } Log.Debugf("[%s] [%s] add rtmp pub session into group.", group.UniqueKey, session.UniqueKey()) group.rtmpPubSession = session group.addIn() if group.shouldStartRtspRemuxer() { group.rtmp2RtspRemuxer = remux.NewRtmp2RtspRemuxer( group.onSdpFromRemux, group.onRtpPacketFromRemux, ) } session.SetPubSessionObserver(group) return nil } // AddRtspPubSession TODO chef: rtsp package中,增加回调返回值判断,如果是false,将连接关掉 func (group *Group) AddRtspPubSession(session *rtsp.PubSession) error { group.mutex.Lock() defer group.mutex.Unlock() if group.hasInSession() { Log.Errorf("[%s] in stream already exist at group. wanna add=%s", group.UniqueKey, session.UniqueKey()) return base.ErrDupInStream } Log.Debugf("[%s] [%s] add RTSP PubSession into group.", group.UniqueKey, session.UniqueKey()) group.rtspPubSession = session group.addIn() group.rtsp2RtmpRemuxer = remux.NewAvPacket2RtmpRemuxer().WithOnRtmpMsg(group.onRtmpMsgFromRemux) session.SetObserver(group) return nil } func (group *Group) StartRtpPub(req base.ApiCtrlStartRtpPubReq) (ret base.ApiCtrlStartRtpPubResp) { group.mutex.Lock() defer group.mutex.Unlock() if group.hasInSession() { // TODO(chef): [fix] 处理已经有输入session的情况 202207 } if req.DebugDumpPacket != "" { group.psPubDumpFile = base.NewDumpFile() if err := group.psPubDumpFile.OpenToWrite(req.DebugDumpPacket); err != nil { Log.Errorf("%+v", err) } } pubSession := gb28181.NewPubSession().WithStreamName(req.StreamName).WithOnAvPacket(group.OnAvPacketFromPsPubSession) pubSession.WithHookReadPacket(func(b []byte) { if group.psPubDumpFile != nil { group.psPubDumpFile.WriteWithType(b, base.DumpTypePsRtpData) } }) Log.Debugf("[%s] [%s] add RTP PubSession into group.", group.UniqueKey, pubSession.UniqueKey()) group.psPubSession = pubSession group.psPubTimeoutSec = uint32(req.TimeoutMs / 1000) group.addIn() group.rtsp2RtmpRemuxer = remux.NewAvPacket2RtmpRemuxer() group.rtsp2RtmpRemuxer.WithOption(func(option *base.AvPacketStreamOption) { option.VideoFormat = base.AvPacketStreamVideoFormatAnnexb option.AudioFormat = base.AvPacketStreamAudioFormatAdtsAac }) group.rtsp2RtmpRemuxer.WithOnRtmpMsg(group.onRtmpMsgFromRemux) if group.shouldStartRtspRemuxer() { group.rtmp2RtspRemuxer = remux.NewRtmp2RtspRemuxer( group.onSdpFromRemux, group.onRtpPacketFromRemux, ) } port, err := pubSession.Listen(req.Port, req.IsTcpFlag != 0) if err != nil { group.delPsPubSession(pubSession) ret.ErrorCode = base.ErrorCodeListenUdpPortFail ret.Desp = err.Error() return } go func() { runErr := pubSession.RunLoop() nazalog.Debugf("[%s] [%s] ps PubSession run loop exit, err=%v", group.UniqueKey, pubSession.UniqueKey(), runErr) group.DelPsPubSession(pubSession) }() ret.ErrorCode = base.ErrorCodeSucc ret.Desp = base.DespSucc ret.Data.SessionId = pubSession.UniqueKey() ret.Data.StreamName = pubSession.StreamName() ret.Data.Port = port return } func (group *Group) AddRtmpPullSession(session *rtmp.PullSession) error { group.mutex.Lock() defer group.mutex.Unlock() if group.hasInSession() { Log.Errorf("[%s] in stream already exist. wanna add=%s", group.UniqueKey, session.UniqueKey()) return base.ErrDupInStream } Log.Debugf("[%s] [%s] add PullSession into group.", group.UniqueKey, session.UniqueKey()) group.setRtmpPullSession(session) group.addIn() if group.shouldStartRtspRemuxer() { group.rtmp2RtspRemuxer = remux.NewRtmp2RtspRemuxer( group.onSdpFromRemux, group.onRtpPacketFromRemux, ) } var info base.PullStartInfo info.SessionId = session.UniqueKey() info.Url = session.Url() info.Protocol = session.GetStat().Protocol info.RemoteAddr = session.GetStat().RemoteAddr info.AppName = session.AppName() info.StreamName = session.StreamName() info.UrlParam = session.RawQuery() info.HasInSession = group.hasInSession() info.HasOutSession = group.hasOutSession() group.observer.OnRelayPullStart(info) return nil } func (group *Group) AddRtspPullSession(session *rtsp.PullSession) error { group.mutex.Lock() defer group.mutex.Unlock() if group.hasInSession() { Log.Errorf("[%s] in stream already exist. wanna add=%s", group.UniqueKey, session.UniqueKey()) return base.ErrDupInStream } Log.Debugf("[%s] [%s] add PullSession into group.", group.UniqueKey, session.UniqueKey()) group.setRtspPullSession(session) group.addIn() group.rtsp2RtmpRemuxer = remux.NewAvPacket2RtmpRemuxer().WithOnRtmpMsg(group.onRtmpMsgFromRemux) var info base.PullStartInfo info.SessionId = session.UniqueKey() info.Url = session.Url() info.Protocol = session.GetStat().Protocol info.RemoteAddr = session.GetStat().RemoteAddr info.AppName = session.AppName() info.StreamName = session.StreamName() info.UrlParam = session.RawQuery() info.HasInSession = group.hasInSession() info.HasOutSession = group.hasOutSession() group.observer.OnRelayPullStart(info) return nil } // --------------------------------------------------------------------------------------------------------------------- func (group *Group) DelPsPubSession(session *gb28181.PubSession) { group.mutex.Lock() defer group.mutex.Unlock() group.delPsPubSession(session) } func (group *Group) DelCustomizePubSession(sessionCtx ICustomizePubSessionContext) { group.mutex.Lock() defer group.mutex.Unlock() group.delCustomizePubSession(sessionCtx) } func (group *Group) DelRtmpPubSession(session *rtmp.ServerSession) { group.mutex.Lock() defer group.mutex.Unlock() group.delRtmpPubSession(session) } func (group *Group) DelRtspPubSession(session *rtsp.PubSession) { group.mutex.Lock() defer group.mutex.Unlock() group.delRtspPubSession(session) } func (group *Group) DelRtmpPullSession(session *rtmp.PullSession) { group.mutex.Lock() defer group.mutex.Unlock() group.delPullSession(session) var info base.PullStopInfo info.SessionId = session.UniqueKey() info.Url = session.Url() info.Protocol = session.GetStat().Protocol info.RemoteAddr = session.GetStat().RemoteAddr info.AppName = session.AppName() info.StreamName = session.StreamName() info.UrlParam = session.RawQuery() info.HasInSession = group.hasInSession() info.HasOutSession = group.hasOutSession() group.observer.OnRelayPullStop(info) } func (group *Group) DelRtspPullSession(session *rtsp.PullSession) { group.mutex.Lock() defer group.mutex.Unlock() group.delPullSession(session) var info base.PullStopInfo info.SessionId = session.UniqueKey() info.Url = session.Url() info.Protocol = session.GetStat().Protocol info.RemoteAddr = session.GetStat().RemoteAddr info.AppName = session.AppName() info.StreamName = session.StreamName() info.UrlParam = session.RawQuery() info.HasInSession = group.hasInSession() info.HasOutSession = group.hasOutSession() group.observer.OnRelayPullStop(info) } // --------------------------------------------------------------------------------------------------------------------- func (group *Group) delPsPubSession(session *gb28181.PubSession) { Log.Debugf("[%s] [%s] del ps PubSession from group.", group.UniqueKey, session.UniqueKey()) if session != group.psPubSession { Log.Warnf("[%s] del ps pub session but not match. del session=%s, group session=%p", group.UniqueKey, session.UniqueKey(), group.psPubSession) return } group.delIn() } func (group *Group) delCustomizePubSession(sessionCtx ICustomizePubSessionContext) { Log.Debugf("[%s] [%s] del customize PubSession from group.", group.UniqueKey, sessionCtx.UniqueKey()) if sessionCtx != group.customizePubSession { Log.Warnf("[%s] del customize pub session but not match. del session=%s, group session=%p", group.UniqueKey, sessionCtx.UniqueKey(), group.customizePubSession) return } group.delIn() } func (group *Group) delRtmpPubSession(session *rtmp.ServerSession) { Log.Debugf("[%s] [%s] del rtmp PubSession from group.", group.UniqueKey, session.UniqueKey()) if session != group.rtmpPubSession { Log.Warnf("[%s] del rtmp pub session but not match. del session=%s, group session=%p", group.UniqueKey, session.UniqueKey(), group.rtmpPubSession) return } group.delIn() } func (group *Group) delRtspPubSession(session *rtsp.PubSession) { Log.Debugf("[%s] [%s] del rtsp PubSession from group.", group.UniqueKey, session.UniqueKey()) if session != group.rtspPubSession { Log.Warnf("[%s] del rtmp pub session but not match. del session=%s, group session=%p", group.UniqueKey, session.UniqueKey(), group.rtspPubSession) return } group.delIn() } func (group *Group) delPullSession(session base.IObject) { Log.Debugf("[%s] [%s] del PullSession from group.", group.UniqueKey, session.UniqueKey()) group.resetRelayPullSession() group.delIn() } // --------------------------------------------------------------------------------------------------------------------- // addIn 有pub或pull的输入型session加入时,需要调用该函数 func (group *Group) addIn() { now := time.Now().Unix() if group.shouldStartMpegtsRemuxer() { group.rtmp2MpegtsRemuxer = remux.NewRtmp2MpegtsRemuxer(group) nazalog.Debugf("[%s] [%s] NewRtmp2MpegtsRemuxer in group.", group.UniqueKey, group.rtmp2MpegtsRemuxer.UniqueKey()) } if group.config.InSessionConfig.AddDummyAudioEnable { group.dummyAudioFilter = remux.NewDummyAudioFilter(group.UniqueKey, group.config.InSessionConfig.AddDummyAudioWaitAudioMs, group.broadcastByRtmpMsg) } if group.option.onHookSession != nil { group.customizeHookSessionContext = group.option.onHookSession(group.inSessionUniqueKey(), group.streamName) } group.startPushIfNeeded() group.startHlsIfNeeded() group.startRecordFlvIfNeeded(now) group.startRecordMpegtsIfNeeded(now) } // delIn 有pub或pull的输入型session离开时,需要调用该函数 func (group *Group) delIn() { // 注意,remuxer放前面,使得有机会将内部缓存的数据吐出来 if group.rtmp2MpegtsRemuxer != nil { group.rtmp2MpegtsRemuxer.Dispose() group.rtmp2MpegtsRemuxer = nil } if group.customizeHookSessionContext != nil { group.customizeHookSessionContext.OnStop() group.customizeHookSessionContext = nil } group.stopPushIfNeeded() group.stopHlsIfNeeded() group.stopRecordFlvIfNeeded() group.stopRecordMpegtsIfNeeded() group.rtmpPubSession = nil group.rtspPubSession = nil group.customizePubSession = nil group.psPubSession = nil group.rtsp2RtmpRemuxer = nil group.rtmp2RtspRemuxer = nil group.dummyAudioFilter = nil if group.psPubDumpFile != nil { group.psPubDumpFile.Close() group.psPubDumpFile = nil } group.rtmpGopCache.Clear() group.httpflvGopCache.Clear() group.httptsGopCache.Clear() group.sdpCtx = nil group.patpmt = nil }