Files
go2rtc/pkg/pcm/handlers.go
2025-04-24 21:23:16 +03:00

110 lines
2.4 KiB
Go

package pcm
import (
"sync"
"time"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/pion/rtp"
)
// RepackG711 - Repack G.711 PCMA/PCMU into frames of size 1024
// 1. Fixes WebRTC audio quality issue (monotonic timestamp)
// 2. Fixes Reolink Doorbell backchannel issue (zero timestamp)
// https://github.com/AlexxIT/go2rtc/issues/331
func RepackG711(zeroTS bool, handler core.HandlerFunc) core.HandlerFunc {
const PacketSize = 1024
var buf []byte
var seq uint16
var ts uint32
// fix https://github.com/AlexxIT/go2rtc/issues/432
var mu sync.Mutex
return func(packet *rtp.Packet) {
mu.Lock()
buf = append(buf, packet.Payload...)
if len(buf) < PacketSize {
mu.Unlock()
return
}
pkt := &rtp.Packet{
Header: rtp.Header{
Version: 2,
Marker: true, // should be true
PayloadType: packet.PayloadType, // will be owerwriten
SequenceNumber: seq,
SSRC: packet.SSRC,
},
Payload: buf[:PacketSize],
}
seq++
// don't know if zero TS important for Reolink Doorbell
// don't have this strange devices for tests
if !zeroTS {
pkt.Timestamp = ts
ts += PacketSize
}
buf = buf[PacketSize:]
mu.Unlock()
handler(pkt)
}
}
// LittleToBig - convert PCM little endian to PCM big endian
func LittleToBig(handler core.HandlerFunc) core.HandlerFunc {
return func(packet *rtp.Packet) {
clone := *packet
clone.Payload = FlipEndian(packet.Payload)
handler(&clone)
}
}
func TranscodeHandler(dst, src *core.Codec, handler core.HandlerFunc) core.HandlerFunc {
var ts uint32
k := float32(BytesPerFrame(dst)) / float32(BytesPerFrame(src))
f := Transcode(dst, src)
return func(packet *rtp.Packet) {
ts += uint32(k * float32(len(packet.Payload)))
clone := *packet
clone.Payload = f(packet.Payload)
clone.Timestamp = ts
handler(&clone)
}
}
func BytesPerSample(codec *core.Codec) int {
switch codec.Name {
case core.CodecPCML, core.CodecPCM:
return 2
case core.CodecPCMU, core.CodecPCMA:
return 1
}
return 0
}
func BytesPerFrame(codec *core.Codec) int {
if codec.Channels <= 1 {
return BytesPerSample(codec)
}
return int(codec.Channels) * BytesPerSample(codec)
}
func FramesPerDuration(codec *core.Codec, duration time.Duration) int {
return int(time.Duration(codec.ClockRate) * duration / time.Second)
}
func BytesPerDuration(codec *core.Codec, duration time.Duration) int {
return BytesPerFrame(codec) * FramesPerDuration(codec, duration)
}