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