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/gb28181/pub_session.go

174 lines
4.4 KiB
Go

// 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 gb28181
import (
"fmt"
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/naza/pkg/nazanet"
"net"
"sync"
)
type PubSession struct {
unpacker *PsUnpacker
streamName string
hookOnReadUdpPacket nazanet.OnReadUdpPacket
disposeOnce sync.Once
conn *nazanet.UdpConnection
sessionStat base.BasicSessionStat
}
func NewPubSession() *PubSession {
return &PubSession{
unpacker: NewPsUnpacker(),
sessionStat: base.NewBasicSessionStat(base.SessionTypePsPub, ""),
}
}
// WithOnAvPacket 设置音视频的回调
//
// @param onAvPacket 见 PsUnpacker.WithOnAvPacket 的注释
//
func (session *PubSession) WithOnAvPacket(onAvPacket base.OnAvPacketFunc) *PubSession {
session.unpacker.WithOnAvPacket(onAvPacket)
return session
}
func (session *PubSession) WithStreamName(streamName string) *PubSession {
session.streamName = streamName
return session
}
// WithHookReadUdpPacket
//
// 将udp接收数据返回给上层。
// 注意,底层的解析逻辑依然走。
// 可以用这个方式来截取数据进行调试。
//
func (session *PubSession) WithHookReadUdpPacket(fn nazanet.OnReadUdpPacket) *PubSession {
session.hookOnReadUdpPacket = fn
return session
}
// Listen
//
// 注意,当`port`参数为0时内部会自动选择一个可用端口监听并通过返回值返回该端口
//
func (session *PubSession) Listen(port int) (int, error) {
var err error
var uconn *net.UDPConn
var addr string
if port == 0 {
uconn, _, err = defaultUdpConnPoll.Acquire()
if err != nil {
return -1, err
}
port = uconn.LocalAddr().(*net.UDPAddr).Port
} else {
addr = fmt.Sprintf(":%d", port)
}
session.conn, err = nazanet.NewUdpConnection(func(option *nazanet.UdpConnectionOption) {
option.LAddr = addr
option.Conn = uconn
})
return port, err
}
// RunLoop ...
//
func (session *PubSession) RunLoop() error {
err := session.conn.RunLoop(func(b []byte, raddr *net.UDPAddr, err error) bool {
if len(b) == 0 && err != nil {
return false
}
if session.hookOnReadUdpPacket != nil {
session.hookOnReadUdpPacket(b, raddr, err)
}
session.sessionStat.AddReadBytes(len(b))
session.unpacker.FeedRtpPacket(b)
return true
})
return err
}
// ----- IServerSessionLifecycle ---------------------------------------------------------------------------------------
func (session *PubSession) Dispose() error {
return session.dispose(nil)
}
// ----- ISessionUrlContext --------------------------------------------------------------------------------------------
func (session *PubSession) Url() string {
Log.Warnf("[%s] PubSession.Url() is not implemented", session.UniqueKey())
return "invalid"
}
func (session *PubSession) AppName() string {
Log.Warnf("[%s] PubSession.AppName() is not implemented", session.UniqueKey())
return "invalid"
}
func (session *PubSession) StreamName() string {
// 如果stream name没有设置则使用session的unique key作为stream name
if session.streamName == "" {
return session.UniqueKey()
}
return session.streamName
}
func (session *PubSession) RawQuery() string {
Log.Warnf("[%s] PubSession.RawQuery() is not implemented", session.UniqueKey())
return "invalid"
}
// ----- IObject -------------------------------------------------------------------------------------------------------
func (session *PubSession) UniqueKey() string {
return session.sessionStat.UniqueKey()
}
// ----- ISessionStat --------------------------------------------------------------------------------------------------
func (session *PubSession) UpdateStat(intervalSec uint32) {
session.sessionStat.UpdateStat(intervalSec)
}
func (session *PubSession) GetStat() base.StatSession {
return session.sessionStat.GetStat()
}
func (session *PubSession) IsAlive() (readAlive, writeAlive bool) {
return session.sessionStat.IsAlive()
}
// ---------------------------------------------------------------------------------------------------------------------
func (session *PubSession) dispose(err error) error {
var retErr error
session.disposeOnce.Do(func() {
Log.Infof("[%s] lifecycle dispose gb28181 PubSession. err=%+v", session.UniqueKey(), err)
if session.conn == nil {
retErr = base.ErrSessionNotStarted
return
}
retErr = session.conn.Dispose()
})
return retErr
}