You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
196 lines
3.9 KiB
Go
196 lines
3.9 KiB
Go
3 years ago
|
/*
|
||
|
RFC 3550. RTP: A Transport Protocol for Real-Time Applications
|
||
|
*/
|
||
|
package icspacketparser
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
"fmt"
|
||
|
|
||
|
"gitlab.com/ics_cinnamon/voicegateway/icserror"
|
||
|
"gitlab.com/ics_cinnamon/voicegateway/icsnet"
|
||
|
)
|
||
|
|
||
|
type RTP struct {
|
||
|
Version int
|
||
|
Mark bool
|
||
|
PayloadType PayloadType
|
||
|
Seq uint16
|
||
|
Timestamp uint32
|
||
|
SSID uint32
|
||
|
PayloadLen int
|
||
|
Payload []byte
|
||
|
SrcAddr *icsnet.IcsNetAddr
|
||
|
DstAddr *icsnet.IcsNetAddr
|
||
|
}
|
||
|
|
||
|
type RTPHeader struct {
|
||
|
v byte //2bits
|
||
|
m byte //1
|
||
|
pt byte //7
|
||
|
seq []byte //16
|
||
|
ts []byte //4
|
||
|
ssrc []byte //4
|
||
|
}
|
||
|
type PayloadType int
|
||
|
|
||
|
const RTPHeaderLen = 12
|
||
|
|
||
|
//RTP payload type
|
||
|
const (
|
||
|
PCMU PayloadType = 0
|
||
|
PCMA PayloadType = 8
|
||
|
G729 PayloadType = 18
|
||
|
DTMF101 PayloadType = 101
|
||
|
)
|
||
|
|
||
|
type RTPPayloadType struct {
|
||
|
Name string
|
||
|
PType PayloadType
|
||
|
SamplingRate int
|
||
|
PTime int
|
||
|
PSize int
|
||
|
}
|
||
|
|
||
|
func NewRTPPayloadType(t PayloadType) *RTPPayloadType {
|
||
|
var pt RTPPayloadType
|
||
|
|
||
|
switch t {
|
||
|
case PCMU:
|
||
|
pt = RTPPayloadType{
|
||
|
Name: "PCMU",
|
||
|
PType: t,
|
||
|
SamplingRate: 8000,
|
||
|
PTime: 20,
|
||
|
PSize: 160,
|
||
|
}
|
||
|
case PCMA:
|
||
|
pt = RTPPayloadType{
|
||
|
Name: "PCMA",
|
||
|
PType: t,
|
||
|
SamplingRate: 8000,
|
||
|
PTime: 20,
|
||
|
PSize: 160,
|
||
|
}
|
||
|
case G729:
|
||
|
pt = RTPPayloadType{
|
||
|
Name: "G729",
|
||
|
PType: t,
|
||
|
SamplingRate: 8000,
|
||
|
PTime: 20,
|
||
|
PSize: 160,
|
||
|
}
|
||
|
case DTMF101:
|
||
|
pt = RTPPayloadType{
|
||
|
Name: "DTMF101",
|
||
|
PType: t,
|
||
|
SamplingRate: 8000,
|
||
|
PTime: 20,
|
||
|
PSize: 160,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return &pt
|
||
|
}
|
||
|
|
||
|
var RTPPayloadInfo map[PayloadType]*RTPPayloadType
|
||
|
|
||
|
func init() {
|
||
|
RTPPayloadInfo = make(map[PayloadType]*RTPPayloadType, 100)
|
||
|
RTPPayloadInfo[PCMU] = NewRTPPayloadType(PCMU)
|
||
|
RTPPayloadInfo[PCMA] = NewRTPPayloadType(PCMA)
|
||
|
RTPPayloadInfo[G729] = NewRTPPayloadType(G729)
|
||
|
RTPPayloadInfo[DTMF101] = NewRTPPayloadType(DTMF101)
|
||
|
}
|
||
|
|
||
|
func NewRTP() RTP {
|
||
|
rtp := RTP{}
|
||
|
return rtp
|
||
|
}
|
||
|
|
||
|
func (r *RTP) RTPParser(data []byte) *icserror.IcsError {
|
||
|
datalen := len(data)
|
||
|
if datalen <= RTPHeaderLen {
|
||
|
return icserror.ICSERRRTPNo
|
||
|
}
|
||
|
|
||
|
//fmt.Println(data)
|
||
|
|
||
|
r.PayloadLen = datalen - RTPHeaderLen
|
||
|
//fmt.Println("Payload Len:", r.PayloadLen)
|
||
|
|
||
|
header := RTPHeader{}
|
||
|
|
||
|
//RTP version 2bit
|
||
|
header.v = data[0] >> 6
|
||
|
r.Version = int(header.v)
|
||
|
if r.Version != 2 {
|
||
|
return icserror.ICSERRRTPNo
|
||
|
}
|
||
|
//fmt.Println("Version", r.Version)
|
||
|
|
||
|
//mark 1bit
|
||
|
header.m = data[1] >> 7
|
||
|
//fmt.Println("Mark", header.m)
|
||
|
r.Mark = header.m == 1
|
||
|
|
||
|
//payload type 7bit
|
||
|
ptint := data[1]
|
||
|
ptint = ptint << 1
|
||
|
header.pt = ptint >> 1
|
||
|
r.PayloadType = PayloadType(header.pt)
|
||
|
//fmt.Println("PayloadType:", r.PayloadType)
|
||
|
if r.PayloadType == 18 { //g729
|
||
|
if datalen != 32 {
|
||
|
return icserror.ICSERRRTPNo
|
||
|
}
|
||
|
}
|
||
|
|
||
|
header.seq = make([]byte, 2)
|
||
|
copy(header.seq, data[2:4])
|
||
|
r.Seq = binary.BigEndian.Uint16(header.seq[0:])
|
||
|
//fmt.Println("SEQ:", r.Seq)
|
||
|
|
||
|
header.ts = make([]byte, 4)
|
||
|
copy(header.ts, data[4:8])
|
||
|
r.Timestamp = binary.BigEndian.Uint32(header.ts[0:])
|
||
|
//fmt.Println("Timestamp:", r.Timestamp)
|
||
|
|
||
|
header.ssrc = make([]byte, 4)
|
||
|
copy(header.ssrc, data[8:12])
|
||
|
r.SSID = binary.BigEndian.Uint32(header.ssrc[0:])
|
||
|
//fmt.Println("SSID:", r.SSID)
|
||
|
|
||
|
r.Payload = make([]byte, r.PayloadLen)
|
||
|
copy(r.Payload, data[12:])
|
||
|
//fmt.Println("Payload data:", r.Payload)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
//implm interface Packeter
|
||
|
func (r *RTP) GetPacketData(addr []*icsnet.IcsNetAddr, packet []byte) *icserror.IcsError {
|
||
|
r.SrcAddr = addr[0]
|
||
|
r.DstAddr = addr[1]
|
||
|
//fmt.Println("RTP GetPacketData()", r.SrcAddr, r.DstAddr)
|
||
|
|
||
|
if err := r.RTPParser(packet); err != nil {
|
||
|
//err.Print()
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (r RTP) GetPayloadType() PayloadType {
|
||
|
return r.PayloadType
|
||
|
}
|
||
|
|
||
|
func (r RTP) GetPayloadLen() int {
|
||
|
return r.PayloadLen
|
||
|
}
|
||
|
|
||
|
func (r RTP) String() string {
|
||
|
return fmt.Sprintf("ssrc: %d, seq: %d, ts: %d, pt: %d, payload len: %d", r.SSID, r.Seq, r.Timestamp, r.PayloadType, r.PayloadLen)
|
||
|
}
|