mirror of
https://github.com/AlexxIT/go2rtc.git
synced 2025-09-26 20:31:11 +08:00
110 lines
2.4 KiB
Go
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)
|
|
}
|