mirror of
https://github.com/lkmio/lkm.git
synced 2025-10-04 23:02:43 +08:00
支持GB28181三种推流
This commit is contained in:
110
jitterbuffer/receiver_interceptor.go
Normal file
110
jitterbuffer/receiver_interceptor.go
Normal file
@@ -0,0 +1,110 @@
|
||||
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package jitterbuffer
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/pion/interceptor"
|
||||
"github.com/pion/logging"
|
||||
"github.com/pion/rtp"
|
||||
)
|
||||
|
||||
// InterceptorFactory is a interceptor.Factory for a GeneratorInterceptor
|
||||
type InterceptorFactory struct {
|
||||
opts []ReceiverInterceptorOption
|
||||
}
|
||||
|
||||
// NewInterceptor constructs a new ReceiverInterceptor
|
||||
func (g *InterceptorFactory) NewInterceptor(_ string) (interceptor.Interceptor, error) {
|
||||
i := &ReceiverInterceptor{
|
||||
close: make(chan struct{}),
|
||||
log: logging.NewDefaultLoggerFactory().NewLogger("jitterbuffer"),
|
||||
buffer: New(),
|
||||
}
|
||||
|
||||
for _, opt := range g.opts {
|
||||
if err := opt(i); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// ReceiverInterceptor places a JitterBuffer in the chain to smooth packet arrival
|
||||
// and allow for network jitter
|
||||
//
|
||||
// The Interceptor is designed to fit in a RemoteStream
|
||||
// pipeline and buffer incoming packets for a short period (currently
|
||||
// defaulting to 50 packets) before emitting packets to be consumed by the
|
||||
// next step in the pipeline.
|
||||
//
|
||||
// The caller must ensure they are prepared to handle an
|
||||
// ErrPopWhileBuffering in the case that insufficient packets have been
|
||||
// received by the jitter buffer. The caller should retry the operation
|
||||
// at some point later as the buffer may have been filled in the interim.
|
||||
//
|
||||
// The caller should also be aware that an ErrBufferUnderrun may be
|
||||
// returned in the case that the initial buffering was sufficient and
|
||||
// playback began but the caller is consuming packets (or they are not
|
||||
// arriving) quickly enough.
|
||||
type ReceiverInterceptor struct {
|
||||
interceptor.NoOp
|
||||
buffer *JitterBuffer
|
||||
m sync.Mutex
|
||||
wg sync.WaitGroup
|
||||
close chan struct{}
|
||||
log logging.LeveledLogger
|
||||
}
|
||||
|
||||
// NewInterceptor returns a new InterceptorFactory
|
||||
func NewInterceptor(opts ...ReceiverInterceptorOption) (*InterceptorFactory, error) {
|
||||
return &InterceptorFactory{opts}, nil
|
||||
}
|
||||
|
||||
// BindRemoteStream lets you modify any incoming RTP packets. It is called once for per RemoteStream. The returned method
|
||||
// will be called once per rtp packet.
|
||||
func (i *ReceiverInterceptor) BindRemoteStream(_ *interceptor.StreamInfo, reader interceptor.RTPReader) interceptor.RTPReader {
|
||||
return interceptor.RTPReaderFunc(func(b []byte, a interceptor.Attributes) (int, interceptor.Attributes, error) {
|
||||
buf := make([]byte, len(b))
|
||||
n, attr, err := reader.Read(buf, a)
|
||||
if err != nil {
|
||||
return n, attr, err
|
||||
}
|
||||
packet := &rtp.Packet{}
|
||||
if err := packet.Unmarshal(buf); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
i.m.Lock()
|
||||
defer i.m.Unlock()
|
||||
i.buffer.Push(packet)
|
||||
if i.buffer.state == Emitting {
|
||||
newPkt, err := i.buffer.Pop()
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
nlen, err := newPkt.MarshalTo(b)
|
||||
return nlen, attr, err
|
||||
}
|
||||
return n, attr, ErrPopWhileBuffering
|
||||
})
|
||||
}
|
||||
|
||||
// UnbindRemoteStream is called when the Stream is removed. It can be used to clean up any data related to that track.
|
||||
func (i *ReceiverInterceptor) UnbindRemoteStream(_ *interceptor.StreamInfo) {
|
||||
defer i.wg.Wait()
|
||||
i.m.Lock()
|
||||
defer i.m.Unlock()
|
||||
i.buffer.Clear(true)
|
||||
}
|
||||
|
||||
// Close closes the interceptor
|
||||
func (i *ReceiverInterceptor) Close() error {
|
||||
defer i.wg.Wait()
|
||||
i.m.Lock()
|
||||
defer i.m.Unlock()
|
||||
i.buffer.Clear(true)
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user