add TrackG722 and client-publish-codec-g722 example

This commit is contained in:
aler9
2022-11-14 22:16:55 +01:00
parent 1656e0e823
commit cb05e71b46
7 changed files with 190 additions and 1 deletions

View File

@@ -71,6 +71,7 @@ Features:
* [client-read-options](examples/client-read-options/main.go) * [client-read-options](examples/client-read-options/main.go)
* [client-read-pause](examples/client-read-pause/main.go) * [client-read-pause](examples/client-read-pause/main.go)
* [client-read-republish](examples/client-read-republish/main.go) * [client-read-republish](examples/client-read-republish/main.go)
* [client-publish-codec-g722](examples/client-publish-codec-g722/main.go)
* [client-publish-codec-h264](examples/client-publish-codec-h264/main.go) * [client-publish-codec-h264](examples/client-publish-codec-h264/main.go)
* [client-publish-codec-mpeg4audio](examples/client-publish-codec-mpeg4audio/main.go) * [client-publish-codec-mpeg4audio](examples/client-publish-codec-mpeg4audio/main.go)
* [client-publish-codec-opus](examples/client-publish-codec-opus/main.go) * [client-publish-codec-opus](examples/client-publish-codec-opus/main.go)

View File

@@ -0,0 +1,69 @@
package main
import (
"log"
"net"
"github.com/aler9/gortsplib"
"github.com/pion/rtp"
)
// This example shows how to
// 1. generate RTP/G722 packets with GStreamer
// 2. connect to a RTSP server, announce a G722 track
// 3. route the packets from GStreamer to the server
func main() {
// open a listener to receive RTP/G722 packets
pc, err := net.ListenPacket("udp", "localhost:9000")
if err != nil {
panic(err)
}
defer pc.Close()
log.Println("Waiting for a RTP/G722 stream on UDP port 9000 - you can send one with GStreamer:\n" +
"gst-launch-1.0 audiotestsrc freq=300 ! audioconvert ! audioresample ! audio/x-raw,rate=16000" +
" ! avenc_g722 ! rtpg722pay ! udpsink host=127.0.0.1 port=9000")
// wait for first packet
buf := make([]byte, 2048)
n, _, err := pc.ReadFrom(buf)
if err != nil {
panic(err)
}
log.Println("stream connected")
// create a G722 track
track := &gortsplib.TrackG722{}
c := gortsplib.Client{}
// connect to the server and start publishing the track
err = c.StartPublishing("rtsp://localhost:8554/mystream",
gortsplib.Tracks{track})
if err != nil {
panic(err)
}
defer c.Close()
var pkt rtp.Packet
for {
// parse RTP packet
err = pkt.Unmarshal(buf[:n])
if err != nil {
panic(err)
}
// route RTP packet to the server
err = c.WritePacketRTP(0, &pkt)
if err != nil {
panic(err)
}
// read another RTP packet from source
n, _, err = pc.ReadFrom(buf)
if err != nil {
panic(err)
}
}
}

View File

@@ -124,6 +124,9 @@ func newTrackFromMediaDescription(md *psdp.MediaDescription) (Track, error) {
case payloadType == 8: case payloadType == 8:
return newTrackPCMAFromMediaDescription(control, clock) return newTrackPCMAFromMediaDescription(control, clock)
case payloadType == 9:
return newTrackG722FromMediaDescription(control, clock)
case payloadType == 14: case payloadType == 14:
return newTrackMPEG2AudioFromMediaDescription(control) return newTrackMPEG2AudioFromMediaDescription(control)

61
track_g722.go Normal file
View File

@@ -0,0 +1,61 @@
package gortsplib //nolint:dupl
import (
"fmt"
"strings"
psdp "github.com/pion/sdp/v3"
)
// TrackG722 is a G722 track.
type TrackG722 struct {
trackBase
}
func newTrackG722FromMediaDescription(
control string,
rtpmapPart1 string) (*TrackG722, error,
) {
tmp := strings.Split(rtpmapPart1, "/")
if len(tmp) == 2 && tmp[1] != "1" {
return nil, fmt.Errorf("G722 tracks can have only one channel")
}
return &TrackG722{
trackBase: trackBase{
control: control,
},
}, nil
}
// ClockRate returns the track clock rate.
func (t *TrackG722) ClockRate() int {
return 8000
}
// MediaDescription returns the track media description in SDP format.
func (t *TrackG722) MediaDescription() *psdp.MediaDescription {
return &psdp.MediaDescription{
MediaName: psdp.MediaName{
Media: "audio",
Protos: []string{"RTP", "AVP"},
Formats: []string{"9"},
},
Attributes: []psdp.Attribute{
{
Key: "rtpmap",
Value: "9 G722/8000",
},
{
Key: "control",
Value: t.control,
},
},
}
}
func (t *TrackG722) clone() Track {
return &TrackG722{
trackBase: t.trackBase,
}
}

44
track_g722_test.go Normal file
View File

@@ -0,0 +1,44 @@
package gortsplib //nolint:dupl
import (
"testing"
psdp "github.com/pion/sdp/v3"
"github.com/stretchr/testify/require"
)
func TestTrackG722Attributes(t *testing.T) {
track := &TrackG722{}
require.Equal(t, 8000, track.ClockRate())
require.Equal(t, "", track.GetControl())
}
func TestTrackG722Clone(t *testing.T) {
track := &TrackG722{}
clone := track.clone()
require.NotSame(t, track, clone)
require.Equal(t, track, clone)
}
func TestTrackG722MediaDescription(t *testing.T) {
track := &TrackG722{}
require.Equal(t, &psdp.MediaDescription{
MediaName: psdp.MediaName{
Media: "audio",
Protos: []string{"RTP", "AVP"},
Formats: []string{"9"},
},
Attributes: []psdp.Attribute{
{
Key: "rtpmap",
Value: "9 G722/8000",
},
{
Key: "control",
Value: "",
},
},
}, track.MediaDescription())
}

View File

@@ -18,7 +18,7 @@ func newTrackPCMAFromMediaDescription(
) { ) {
tmp := strings.Split(rtpmapPart1, "/") tmp := strings.Split(rtpmapPart1, "/")
if len(tmp) == 2 && tmp[1] != "1" { if len(tmp) == 2 && tmp[1] != "1" {
return nil, fmt.Errorf("PCMU tracks can have only one channel") return nil, fmt.Errorf("PCMA tracks can have only one channel")
} }
return &TrackPCMA{ return &TrackPCMA{

View File

@@ -38,6 +38,17 @@ func TestTrackNewFromMediaDescription(t *testing.T) {
}, },
&TrackPCMU{}, &TrackPCMU{},
}, },
{
"g722",
&psdp.MediaDescription{
MediaName: psdp.MediaName{
Media: "audio",
Protos: []string{"RTP", "AVP"},
Formats: []string{"9"},
},
},
&TrackG722{},
},
{ {
"mpeg audio", "mpeg audio",
&psdp.MediaDescription{ &psdp.MediaDescription{