Files
go2rtc/pkg/pcm/handlers.go
T
2025-04-21 20:18:28 +03:00

100 lines
2.1 KiB
Go

package pcm
import (
"sync"
"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 BytesPerFrame(codec *core.Codec) byte {
channels := byte(codec.Channels)
if channels == 0 {
channels = 1
}
switch codec.Name {
case core.CodecPCML, core.CodecPCM:
return 2 * channels
case core.CodecPCMU, core.CodecPCMA:
return channels
}
return 0
}