Skip to content

Instantly share code, notes, and snippets.

@linnv
Last active October 22, 2022 02:20
Show Gist options
  • Save linnv/d00509f38a5ffd3e4d1fd0d11f371768 to your computer and use it in GitHub Desktop.
Save linnv/d00509f38a5ffd3e4d1fd0d11f371768 to your computer and use it in GitHub Desktop.
### A demo that shows how to exact RTP payload and convert to WAV, there are some key points on comment
module rtpdemo
go 1.18
require (
github.com/go-audio/audio v1.0.0
github.com/go-audio/wav v1.1.0
github.com/jart/gosip v0.0.0-20220818224804-29801cedf805
github.com/linnv/logx v1.3.5
github.com/zaf/g711 v0.0.0-20220109202201-cf0017bf0359
)
require (
github.com/go-audio/riff v1.0.0 // indirect
github.com/linnv/bufferlog v1.2.0 // indirect
github.com/pkg/errors v0.8.1 // indirect
)
package main
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"os"
"os/signal"
"syscall"
"github.com/go-audio/audio"
"github.com/go-audio/wav"
"github.com/jart/gosip/rtp"
"github.com/linnv/logx"
"github.com/zaf/g711"
)
func pcm2wav() {
// Read raw PCM data from input file.
in, err := os.Open(outName)
if err != nil {
log.Fatal(err)
}
// Output file.
out, err := os.Create(outName + ".wav")
if err != nil {
log.Fatal(err)
}
defer out.Close()
// 8 kHz, 16 bit, 1 channel, WAV.
e := wav.NewEncoder(out, 8000, 16, 1, 1)
// Create new audio.IntBuffer.
audioBuf, err := newAudioIntBuffer(in)
if err != nil {
log.Fatal(err)
}
// Write buffer to output file. This writes a RIFF header and the PCM chunks from the audio.IntBuffer.
if err := e.Write(audioBuf); err != nil {
log.Fatal(err)
}
if err := e.Close(); err != nil {
log.Fatal(err)
}
}
func newAudioIntBuffer(r io.Reader) (*audio.IntBuffer, error) {
buf := audio.IntBuffer{
Format: &audio.Format{
NumChannels: 1,
SampleRate: 8000,
},
}
for {
var sample int16
err := binary.Read(r, binary.LittleEndian, &sample)
switch {
case err == io.EOF:
return &buf, nil
case err != nil:
return nil, err
}
buf.Data = append(buf.Data, int(sample))
}
}
const outName = "/Users/jialin/Downloads/rtp-l-payload/decodeByGocode.alaw"
//Decode implements ...
func Decode() error {
input, err := os.Open("/Users/jialin/Downloads/rtp-l-payload/left-go-payload.raw")
if err != nil {
return err
}
defer input.Close()
decoder, err := g711.NewAlawDecoder(input)
if err != nil {
return err
}
outFile, err := os.Create(outName)
if err != nil {
return err
}
defer outFile.Close()
_, err = io.Copy(outFile, decoder)
return err
}
func ExactPayload() {
port := 30000
fmt.Println()
sigChan := make(chan os.Signal, 2)
exit := make(chan struct{})
signal.Notify(sigChan, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
log.Print("use c-c to exit: \n")
count := 0
var underBuf []byte
buf := bytes.NewBuffer(underBuf)
go func() {
logx.Debugf("port: %+v\n", port)
conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: port})
if err != nil {
log.Fatalf("Udp Service listen report udp fail:%v", err)
}
defer conn.Close()
for {
select {
case <-exit:
return
default:
}
data := make([]byte, 1024*4)
n, remoteAddr, err := conn.ReadFromUDP(data)
if err == nil {
const headerSize = 12
if n > headerSize {
bufn, bufErr := buf.Write(data[12:n])
logx.Debugf("bufn : %+v bufErr:%s\n", bufn, bufErr)
}
var rtpHeader rtp.Header
err = rtpHeader.Read(data)
if err != nil {
logx.Warnf("err: %+v\n", err)
}
logx.Debugf("rtpHeader: %+v\n", rtpHeader)
count += n
// ... do something
logx.Debugf("n: %+v remoteAddr %s err %s\n", n, remoteAddr, err)
logx.Debugf("total: %+v\n", count)
// conn.WriteToUDP(data[:n], remoteAddr)
} else {
logx.Debugf("n: %+v remoteAddr %s err %s\n", n, remoteAddr, err)
}
}
}()
<-sigChan
close(exit)
logx.Debugf("total: %+v\n", count)
logx.Debugf("buf: %+v\n", buf.Len())
if err := ioutil.WriteFile("./go-payload.raw", buf.Bytes(), 0622); err != nil {
logx.Errorf("err: %+v\n", err)
}
logx.Flush()
os.Exit(0)
}
func main() {
if err := Decode(); err != nil {
logx.Errorf("err: %+v\n", err)
}
pcm2wav()
logx.Flush()
}
@linnv
Copy link
Author

linnv commented Oct 22, 2022

  • Receive rtp streams from rtpplay which sends the stream.rtpdump export from Wireshark you can watch the video for how to export the file rtpdump
  • Exact rtp payload: remove the first 12 bytes, the last will be PCM which was encoded(by alaw or ulaw usually, here is alaw)
  • Decode the PCM to alaw
  • Encode the alaw to WAV (specify sample rate, channel and so on
    the finally output WAV file can be played on VLC or other media player

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment