diff --git a/go.mod b/go.mod index c865893b..cacd7673 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/alecthomas/kong v0.8.1 github.com/aler9/writerseeker v1.1.0 github.com/bluenviron/gohlslib v1.2.0 - github.com/bluenviron/gortsplib/v4 v4.6.3 + github.com/bluenviron/gortsplib/v4 v4.6.4-0.20240108201647-63a81d0896f5 github.com/bluenviron/mediacommon v1.7.1 github.com/datarhei/gosrt v0.5.5 github.com/fsnotify/fsnotify v1.7.0 diff --git a/go.sum b/go.sum index ccf5f8ba..15a85f5a 100644 --- a/go.sum +++ b/go.sum @@ -22,8 +22,8 @@ github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c h1:8XZeJrs4+ZYh github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c/go.mod h1:x1vxHcL/9AVzuk5HOloOEPrtJY0MaalYr78afXZ+pWI= github.com/bluenviron/gohlslib v1.2.0 h1:Hrx2/n/AcmKKIV+MjZLKs5kmW+O7xCdUSPJQoS39JKw= github.com/bluenviron/gohlslib v1.2.0/go.mod h1:kG/Sjebsxnf5asMGaGcQ0aSvtFGNChJPgctds2wDHOI= -github.com/bluenviron/gortsplib/v4 v4.6.3 h1:/FgUhxe/DGFkmwHNGNnw7NhcuZeSwnxCzYHDbyAtMjo= -github.com/bluenviron/gortsplib/v4 v4.6.3/go.mod h1:UqdkRR5YvKHP/wHEQQySJFKJm6tIZcftdP7cNszIZ1g= +github.com/bluenviron/gortsplib/v4 v4.6.4-0.20240108201647-63a81d0896f5 h1:DU63YvVivfcIq7jcA1KCwi9YO+jEVglYNJCIrOLj8QE= +github.com/bluenviron/gortsplib/v4 v4.6.4-0.20240108201647-63a81d0896f5/go.mod h1:UqdkRR5YvKHP/wHEQQySJFKJm6tIZcftdP7cNszIZ1g= github.com/bluenviron/mediacommon v1.7.1 h1:7Lm2b8M9gUk3Ben1w+OPwadAeYseIBscwgdiL+aLtfw= github.com/bluenviron/mediacommon v1.7.1/go.mod h1:Ij/kE1LEucSjryNBVTyPL/gBI0d6/Css3f5PyrM957w= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= diff --git a/internal/formatprocessor/g711.go b/internal/formatprocessor/g711.go index a1b83843..38b3bb0e 100644 --- a/internal/formatprocessor/g711.go +++ b/internal/formatprocessor/g711.go @@ -5,7 +5,7 @@ import ( "time" "github.com/bluenviron/gortsplib/v4/pkg/format" - "github.com/bluenviron/gortsplib/v4/pkg/format/rtpsimpleaudio" + "github.com/bluenviron/gortsplib/v4/pkg/format/rtplpcm" "github.com/pion/rtp" "github.com/bluenviron/mediamtx/internal/unit" @@ -14,8 +14,8 @@ import ( type formatProcessorG711 struct { udpMaxPayloadSize int format *format.G711 - encoder *rtpsimpleaudio.Encoder - decoder *rtpsimpleaudio.Decoder + encoder *rtplpcm.Encoder + decoder *rtplpcm.Decoder } func newG711( @@ -39,9 +39,11 @@ func newG711( } func (t *formatProcessorG711) createEncoder() error { - t.encoder = &rtpsimpleaudio.Encoder{ + t.encoder = &rtplpcm.Encoder{ PayloadMaxSize: t.udpMaxPayloadSize - 12, PayloadType: t.format.PayloadType(), + BitDepth: 8, + ChannelCount: t.format.ChannelCount, } return t.encoder.Init() } @@ -49,14 +51,16 @@ func (t *formatProcessorG711) createEncoder() error { func (t *formatProcessorG711) ProcessUnit(uu unit.Unit) error { //nolint:dupl u := uu.(*unit.G711) - pkt, err := t.encoder.Encode(u.Samples) + pkts, err := t.encoder.Encode(u.Samples) if err != nil { return err } - u.RTPPackets = []*rtp.Packet{pkt} + u.RTPPackets = pkts ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second)) - u.RTPPackets[0].Timestamp += ts + for _, pkt := range u.RTPPackets { + pkt.Timestamp += ts + } return nil } diff --git a/internal/formatprocessor/g711_test.go b/internal/formatprocessor/g711_test.go index 85211403..d907442f 100644 --- a/internal/formatprocessor/g711_test.go +++ b/internal/formatprocessor/g711_test.go @@ -12,7 +12,10 @@ import ( func TestG611Encode(t *testing.T) { t.Run("alaw", func(t *testing.T) { forma := &format.G711{ - MULaw: false, + PayloadTyp: 8, + MULaw: false, + SampleRate: 8000, + ChannelCount: 1, } p, err := New(1472, forma, true) @@ -37,7 +40,10 @@ func TestG611Encode(t *testing.T) { t.Run("mulaw", func(t *testing.T) { forma := &format.G711{ - MULaw: true, + PayloadTyp: 0, + MULaw: true, + SampleRate: 8000, + ChannelCount: 1, } p, err := New(1472, forma, true) diff --git a/internal/protocols/rtmp/reader.go b/internal/protocols/rtmp/reader.go index 61f9d6af..6daf3b79 100644 --- a/internal/protocols/rtmp/reader.go +++ b/internal/protocols/rtmp/reader.go @@ -95,17 +95,9 @@ func hasAudio(md flvio.AMFMap, audioTrack *format.Format) (bool, error) { return true, nil case message.CodecPCMA: - v, ok := md.GetV("stereo") - if ok && v == true { - return false, fmt.Errorf("stereo PCMA is not supported") - } return true, nil case message.CodecPCMU: - v, ok := md.GetV("stereo") - if ok && v == true { - return false, fmt.Errorf("stereo PCMU is not supported") - } return true, nil } @@ -336,19 +328,31 @@ func tracksFromMetadata(conn *Conn, payload []interface{}) (format.Format, forma } case msg.Codec == message.CodecPCMA: - if msg.Channels == message.ChannelsStereo { - return nil, nil, fmt.Errorf("stereo PCMA is not supported") + audioTrack = &format.G711{ + PayloadTyp: 8, + MULaw: false, + SampleRate: 8000, + ChannelCount: func() int { + if msg.Channels == message.ChannelsStereo { + return 2 + } + return 1 + }(), } - audioTrack = &format.G711{MULaw: false} - case msg.Codec == message.CodecPCMU: - if msg.Channels == message.ChannelsStereo { - return nil, nil, fmt.Errorf("stereo PCMU is not supported") + audioTrack = &format.G711{ + PayloadTyp: 0, + MULaw: true, + SampleRate: 8000, + ChannelCount: func() int { + if msg.Channels == message.ChannelsStereo { + return 2 + } + return 1 + }(), } - audioTrack = &format.G711{MULaw: true} - case msg.Codec == message.CodecLPCM: audioTrack = &format.LPCM{ PayloadTyp: 96, diff --git a/internal/protocols/rtmp/reader_test.go b/internal/protocols/rtmp/reader_test.go index 40776ceb..af39979d 100644 --- a/internal/protocols/rtmp/reader_test.go +++ b/internal/protocols/rtmp/reader_test.go @@ -786,7 +786,12 @@ func TestReadTracks(t *testing.T) { { "pcma", nil, - &format.G711{}, + &format.G711{ + PayloadTyp: 8, + MULaw: false, + SampleRate: 8000, + ChannelCount: 1, + }, []message.Message{ &message.DataAMF0{ ChunkStreamID: 4, @@ -817,7 +822,10 @@ func TestReadTracks(t *testing.T) { "pcmu", nil, &format.G711{ - MULaw: true, + PayloadTyp: 0, + MULaw: true, + SampleRate: 8000, + ChannelCount: 1, }, []message.Message{ &message.DataAMF0{ diff --git a/internal/protocols/webrtc/incoming_track.go b/internal/protocols/webrtc/incoming_track.go index a3c6b99c..7f11868f 100644 --- a/internal/protocols/webrtc/incoming_track.go +++ b/internal/protocols/webrtc/incoming_track.go @@ -80,12 +80,18 @@ func newIncomingTrack( case strings.ToLower(webrtc.MimeTypePCMU): t.format = &format.G711{ - MULaw: true, + PayloadTyp: 0, + MULaw: true, + SampleRate: 8000, + ChannelCount: 1, } case strings.ToLower(webrtc.MimeTypePCMA): t.format = &format.G711{ - MULaw: false, + PayloadTyp: 8, + MULaw: false, + SampleRate: 8000, + ChannelCount: 1, } default: diff --git a/internal/record/agent_test.go b/internal/record/agent_test.go index eae58d87..15dda68f 100644 --- a/internal/record/agent_test.go +++ b/internal/record/agent_test.go @@ -56,13 +56,19 @@ func TestAgent(t *testing.T) { { Type: description.MediaTypeAudio, Formats: []rtspformat.Format{&rtspformat.G711{ - MULaw: false, + PayloadTyp: 8, + MULaw: false, + SampleRate: 8000, + ChannelCount: 1, }}, }, { Type: description.MediaTypeAudio, Formats: []rtspformat.Format{&rtspformat.G711{ - MULaw: true, + PayloadTyp: 0, + MULaw: true, + SampleRate: 8000, + ChannelCount: 1, }}, }, }} diff --git a/internal/record/format_fmp4.go b/internal/record/format_fmp4.go index 4a5a4629..d08b94cf 100644 --- a/internal/record/format_fmp4.go +++ b/internal/record/format_fmp4.go @@ -775,8 +775,8 @@ func (f *formatFMP4) initialize() { codec := &fmp4.CodecLPCM{ LittleEndian: false, BitDepth: 16, - SampleRate: 8000, - ChannelCount: 1, + SampleRate: forma.SampleRate, + ChannelCount: forma.ChannelCount, } track := addTrack(codec) diff --git a/internal/servers/webrtc/session.go b/internal/servers/webrtc/session.go index fb81dec2..8b480942 100644 --- a/internal/servers/webrtc/session.go +++ b/internal/servers/webrtc/session.go @@ -244,6 +244,14 @@ func findAudioTrack( if g711Format != nil { return g711Format, func(track *webrtc.OutgoingTrack) error { + if g711Format.SampleRate != 8000 { + return fmt.Errorf("unsupported G711 sample rate") + } + + if g711Format.ChannelCount != 1 { + return fmt.Errorf("unsupported G711 channel count") + } + stream.AddReader(writer, media, g711Format, func(u unit.Unit) error { for _, pkt := range u.GetRTPPackets() { track.WriteRTP(pkt) //nolint:errcheck