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

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)
}