|
|
// 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 (
|
|
|
"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)
|
|
|
group.addIn()
|
|
|
|
|
|
if group.shouldStartRtspRemuxer() {
|
|
|
group.rtmp2RtspRemuxer = remux.NewRtmp2RtspRemuxer(
|
|
|
group.onSdpFromRemux,
|
|
|
group.onRtpPacketFromRemux,
|
|
|
)
|
|
|
}
|
|
|
|
|
|
if group.config.RtmpConfig.AddDummyAudioEnable {
|
|
|
group.dummyAudioFilter = remux.NewDummyAudioFilter(group.UniqueKey, group.config.RtmpConfig.AddDummyAudioWaitAudioMs, group.OnReadRtmpAvMsg)
|
|
|
group.customizePubSession.WithOnRtmpMsg(group.dummyAudioFilter.OnReadRtmpAvMsg)
|
|
|
} else {
|
|
|
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,
|
|
|
)
|
|
|
}
|
|
|
|
|
|
// TODO(chef): feat 为其他输入流也添加假音频。比如rtmp pull以及rtsp
|
|
|
// TODO(chef): refactor 可考虑抽象出一个输入流的配置块
|
|
|
// TODO(chef): refactor 考虑放入addIn中
|
|
|
if group.config.RtmpConfig.AddDummyAudioEnable {
|
|
|
// TODO(chef): 从整体控制和锁关系来说,应该让pub的数据回调到group中进锁后再让数据流入filter
|
|
|
// TODO(chef): 这里用OnReadRtmpAvMsg正确吗,是否会重复进锁
|
|
|
group.dummyAudioFilter = remux.NewDummyAudioFilter(group.UniqueKey, group.config.RtmpConfig.AddDummyAudioWaitAudioMs, group.OnReadRtmpAvMsg)
|
|
|
session.SetPubSessionObserver(group.dummyAudioFilter)
|
|
|
} else {
|
|
|
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) 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,
|
|
|
)
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
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)
|
|
|
}
|
|
|
|
|
|
func (group *Group) DelRtspPullSession(session *rtsp.PullSession) {
|
|
|
group.mutex.Lock()
|
|
|
defer group.mutex.Unlock()
|
|
|
group.delPullSession(session)
|
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
func (group *Group) delCustomizePubSession(sessionCtx ICustomizePubSessionContext) {
|
|
|
Log.Debugf("[%s] [%s] del rtmp PubSession from group.", group.UniqueKey, sessionCtx.UniqueKey())
|
|
|
|
|
|
if sessionCtx != group.customizePubSession {
|
|
|
Log.Warnf("[%s] del rtmp pub session but not match. del session=%s, group session=%p",
|
|
|
group.UniqueKey, sessionCtx.UniqueKey(), group.rtmpPubSession)
|
|
|
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 rtmp 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)
|
|
|
}
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
group.stopPushIfNeeded()
|
|
|
group.stopHlsIfNeeded()
|
|
|
group.stopRecordFlvIfNeeded()
|
|
|
group.stopRecordMpegtsIfNeeded()
|
|
|
|
|
|
group.rtmpPubSession = nil
|
|
|
group.rtspPubSession = nil
|
|
|
group.customizePubSession = nil
|
|
|
group.rtsp2RtmpRemuxer = nil
|
|
|
group.rtmp2RtspRemuxer = nil
|
|
|
group.dummyAudioFilter = nil
|
|
|
|
|
|
group.rtmpGopCache.Clear()
|
|
|
group.httpflvGopCache.Clear()
|
|
|
group.httptsGopCache.Clear()
|
|
|
group.sdpCtx = nil
|
|
|
group.patpmt = nil
|
|
|
}
|