You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lal/pkg/httpflv/group.go

147 lines
3.6 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package httpflv
import (
"fmt"
"github.com/q191201771/lal/pkg/util/log"
"sync"
)
// TODO chef: set me by config
var gopCacheNum = 2
// TODO chef: 所有新增对象的UniqueKey
type GroupObserver interface {
PullSessionObserver
}
type Group struct {
appName string
streamName string
pullSession *PullSession
subSessionSet map[*SubSession]struct{}
gopCache *GOPCache
mutex sync.Mutex
obs GroupObserver
}
func NewGroup(appName string, streamName string) *Group {
return &Group{
appName: appName,
streamName: streamName,
subSessionSet: make(map[*SubSession]struct{}),
gopCache: NewGOPCache(gopCacheNum),
}
}
func (group *Group) RunLoop() {
}
func (group *Group) AddHTTPFlvSubSession(session *SubSession) {
group.mutex.Lock()
defer group.mutex.Unlock()
log.Debugf("add SubSession into group. [%s]", session.UniqueKey)
group.subSessionSet[session] = struct{}{}
go func() {
if err := session.RunLoop(); err != nil {
log.Debugf("SubSession loop done. [%s] err=%v", session.UniqueKey, err)
}
group.mutex.Lock()
defer group.mutex.Unlock()
log.Infof("del SubSession out of group. [%s]", session.UniqueKey)
delete(group.subSessionSet, session)
}()
// TODO chef: 在这里发送http和flv的头还是确保有数据了再发
session.WriteHTTPResponseHeader()
session.WriteFlvHeader()
if group.gopCache.WriteWholeThings(session) {
session.HasKeyFrame = true
}
}
func (group *Group) Pull(addr string, connectTimeout int64, readTimeout int64) {
group.pullSession = NewPullSession(group, connectTimeout, readTimeout)
defer func() {
group.mutex.Lock()
defer group.mutex.Unlock()
group.pullSession = nil
log.Infof("del httpflv PullSession out of group. [%s]", group.pullSession.UniqueKey)
}()
log.Infof("<----- connect. [%s]", group.pullSession.UniqueKey)
url := fmt.Sprintf("http://%s/%s/%s.flv", addr, group.appName, group.streamName)
if err := group.pullSession.Connect(url); err != nil {
log.Errorf("-----> connect error. [%s] err=%v", group.pullSession.UniqueKey, err)
return
}
log.Infof("-----> connect succ. [%s]", group.pullSession.UniqueKey)
if err := group.pullSession.RunLoop(); err != nil {
log.Debugf("PullSession loop done. [%s] err=%v", group.pullSession.UniqueKey, err)
return
}
}
func (group *Group) IsTotalEmpty() bool {
group.mutex.Lock()
defer group.mutex.Unlock()
return group.pullSession == nil && len(group.subSessionSet) == 0
}
func (group *Group) IsInExist() bool {
group.mutex.Lock()
defer group.mutex.Unlock()
return false
}
func (group *Group) SetObserver(obs GroupObserver) {
// 确保如果调用SetObserver那么调用发生在Pull之前就不对obs加锁保护了
group.obs = obs
}
// PullSessionObserver
func (group *Group) ReadHTTPRespHeaderCB() {
if group.obs != nil {
group.obs.ReadHTTPRespHeaderCB()
}
}
// PullSessionObserver
func (group *Group) ReadFlvHeaderCB(flvHeader []byte) {
if group.obs != nil {
group.obs.ReadFlvHeaderCB(flvHeader)
}
}
// PullSessionObserver
func (group *Group) ReadFlvTagCB(tag *Tag) {
group.mutex.Lock()
defer group.mutex.Unlock()
// TODO chef: assume that write fast and would not block
for session := range group.subSessionSet {
// TODO chef: 如果一个流上只有音频永远没有视频该如何处理
if session.HasKeyFrame {
session.WriteRawPacket(tag.Raw)
} else {
if tag.IsMetadata() || tag.IsAVCKeySeqHeader() || tag.IsAACSeqHeader() || tag.IsAVCKeyNalu() {
if tag.IsAVCKeyNalu() {
session.HasKeyFrame = true
}
session.WriteRawPacket(tag.Raw)
}
}
}
group.gopCache.Push(tag)
if group.obs != nil {
group.obs.ReadFlvTagCB(tag)
}
}