Files
go2rtc/pkg/hksv/session.go
T
Sergey Krashevich c567831c91 feat: add motion detection feature with EMA-based P-frame size analysis
- Implemented MotionDetector for detecting motion based on H.264 P-frame sizes.
- Introduced adjustable sensitivity threshold for motion detection.
- Added tests for various scenarios including motion detection, hold time, cooldown, and baseline adaptation.
- Created hksvSession to manage HDS DataStream connections for HKSV recording.
- Updated schema.json to include a new speaker option for 2-way audio support.
2026-03-06 19:58:15 +03:00

118 lines
2.8 KiB
Go

// Author: Sergei "svk" Krashevich <svk@svk.su>
package hksv
import (
"sync"
"github.com/AlexxIT/go2rtc/pkg/hap"
"github.com/AlexxIT/go2rtc/pkg/hap/hds"
"github.com/rs/zerolog"
)
// hksvSession manages the HDS DataStream connection for HKSV recording
type hksvSession struct {
server *Server
hapConn *hap.Conn
hdsConn *hds.Conn
session *hds.Session
log zerolog.Logger
mu sync.Mutex
consumer *HKSVConsumer
}
func newHKSVSession(srv *Server, hapConn *hap.Conn, hdsConn *hds.Conn) *hksvSession {
session := hds.NewSession(hdsConn)
hs := &hksvSession{
server: srv,
hapConn: hapConn,
hdsConn: hdsConn,
session: session,
log: srv.log,
}
session.OnDataSendOpen = hs.handleOpen
session.OnDataSendClose = hs.handleClose
return hs
}
func (hs *hksvSession) Run() error {
return hs.session.Run()
}
func (hs *hksvSession) Close() {
hs.mu.Lock()
defer hs.mu.Unlock()
if hs.consumer != nil {
hs.stopRecording()
}
_ = hs.session.Close()
}
func (hs *hksvSession) handleOpen(streamID int) error {
hs.mu.Lock()
defer hs.mu.Unlock()
hs.log.Debug().Str("stream", hs.server.stream).Int("streamID", streamID).Msg("[hksv] dataSend open")
if hs.consumer != nil {
hs.stopRecording()
}
// Try to use the pre-started consumer from pair-verify
consumer := hs.server.takePreparedConsumer()
if consumer != nil {
hs.log.Debug().Str("stream", hs.server.stream).Msg("[hksv] using prepared consumer")
hs.consumer = consumer
hs.server.AddConn(consumer)
// Activate: set the HDS session and send init + start streaming
if err := consumer.Activate(hs.session, streamID); err != nil {
hs.log.Error().Err(err).Str("stream", hs.server.stream).Msg("[hksv] activate failed")
hs.stopRecording()
return nil
}
return nil
}
// Fallback: create new consumer (will be slow ~3s)
hs.log.Debug().Str("stream", hs.server.stream).Msg("[hksv] no prepared consumer, creating new")
consumer = NewHKSVConsumer(hs.log)
if err := hs.server.streams.AddConsumer(hs.server.stream, consumer); err != nil {
hs.log.Error().Err(err).Str("stream", hs.server.stream).Msg("[hksv] add consumer failed")
return nil
}
hs.consumer = consumer
hs.server.AddConn(consumer)
go func() {
if err := consumer.Activate(hs.session, streamID); err != nil {
hs.log.Error().Err(err).Str("stream", hs.server.stream).Msg("[hksv] activate failed")
}
}()
return nil
}
func (hs *hksvSession) handleClose(streamID int) error {
hs.mu.Lock()
defer hs.mu.Unlock()
hs.log.Debug().Str("stream", hs.server.stream).Int("streamID", streamID).Msg("[hksv] dataSend close")
if hs.consumer != nil {
hs.stopRecording()
}
return nil
}
func (hs *hksvSession) stopRecording() {
consumer := hs.consumer
hs.consumer = nil
hs.server.streams.RemoveConsumer(hs.server.stream, consumer)
_ = consumer.Stop()
hs.server.DelConn(consumer)
}