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.
133 lines
2.8 KiB
Go
133 lines
2.8 KiB
Go
3 years ago
|
package icsdtmf
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
"fmt"
|
||
|
|
||
|
"gitlab.com/ics_cinnamon/voicegateway/icserror"
|
||
|
"gitlab.com/ics_cinnamon/voicegateway/icspacketparser"
|
||
|
)
|
||
|
|
||
|
type ICSDTMF struct {
|
||
|
rfc2833 *RFC2833
|
||
|
}
|
||
|
|
||
|
func NewICSDTMF() *ICSDTMF {
|
||
|
d := ICSDTMF{rfc2833: nil}
|
||
|
|
||
|
return &d
|
||
|
}
|
||
|
|
||
|
func DTMF(dtmf *ICSDTMF, data interface{}, pcm []byte) (string, *icserror.IcsError) {
|
||
|
switch v := (data).(type) {
|
||
|
case icspacketparser.RTP:
|
||
|
rtp := v
|
||
|
switch rtp.GetPayloadType() { //in band
|
||
|
case icspacketparser.DTMF101: //rtp 101
|
||
|
//fmt.Println("101")
|
||
|
rfc2833, d, derr := dtmfRFC2833(rtp)
|
||
|
if rfc2833.Mark { //if rtp mark, reset old dtmf handle
|
||
|
dtmf.rfc2833 = nil
|
||
|
return "", icserror.ICSERRDTMFCont
|
||
|
}
|
||
|
if derr != icserror.ICSERRDTMFCont {
|
||
|
if dtmf.rfc2833 == nil || !dtmf.rfc2833.isEqual(rfc2833) {
|
||
|
dtmf.rfc2833 = rfc2833
|
||
|
dtmf := fmt.Sprintf("%d", d)
|
||
|
return dtmf, derr
|
||
|
} else {
|
||
|
return "", icserror.ICSERRDTMFCont
|
||
|
}
|
||
|
} else {
|
||
|
return "", derr
|
||
|
}
|
||
|
case icspacketparser.PCMA:
|
||
|
fallthrough
|
||
|
case icspacketparser.G729:
|
||
|
fallthrough
|
||
|
case icspacketparser.PCMU: //bypass
|
||
|
dtmfBypass(pcm)
|
||
|
}
|
||
|
case icspacketparser.SIP: //sip info. rfc2976
|
||
|
}
|
||
|
|
||
|
return "", icserror.ICSERRDTMFFail
|
||
|
}
|
||
|
|
||
|
func (d *ICSDTMF) Reset() {
|
||
|
d.rfc2833 = nil
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////
|
||
|
//RFC 2833 - rtp event
|
||
|
|
||
|
type RFC2833 struct {
|
||
|
Event int
|
||
|
End bool
|
||
|
Volume int
|
||
|
Duration int
|
||
|
Mark bool
|
||
|
}
|
||
|
|
||
|
func dtmfRFC2833(rtp icspacketparser.RTP) (*RFC2833, int, *icserror.IcsError) {
|
||
|
r, err := parseRFC2833(rtp)
|
||
|
if err == icserror.ICSERRDTMFFail {
|
||
|
return nil, -1, err
|
||
|
} else if err == icserror.ICSERRDTMFCont {
|
||
|
return r, -1, err
|
||
|
}
|
||
|
event, err := r.GetDTMF()
|
||
|
return r, event, err
|
||
|
}
|
||
|
|
||
|
func parseRFC2833(rtp icspacketparser.RTP) (*RFC2833, *icserror.IcsError) {
|
||
|
r := RFC2833{}
|
||
|
data := rtp.Payload
|
||
|
|
||
|
r.End = data[1]&0x80 == 0x80
|
||
|
if r.End {
|
||
|
//fmt.Println("RTP Event End?", r.End, data[1], len(data))
|
||
|
|
||
|
r.Event = int(data[0])
|
||
|
//fmt.Println("DTMF :", r.Event)
|
||
|
|
||
|
vol := data[1] << 2
|
||
|
r.Volume = int(vol >> 2)
|
||
|
//fmt.Println("vol", r.Volume, vol, data[1])
|
||
|
|
||
|
dur := binary.BigEndian.Uint16(data[2:])
|
||
|
r.Duration = int(dur)
|
||
|
//fmt.Println("Dur", dur)
|
||
|
} else {
|
||
|
r.Mark = rtp.Mark
|
||
|
return &r, icserror.ICSERRDTMFCont
|
||
|
}
|
||
|
|
||
|
r.Mark = rtp.Mark
|
||
|
|
||
|
return &r, icserror.ICSERRDTMFOK
|
||
|
}
|
||
|
|
||
|
func (r RFC2833) GetDTMF() (int, *icserror.IcsError) {
|
||
|
return r.Event, icserror.ICSERRDTMFOK
|
||
|
}
|
||
|
|
||
|
func (r RFC2833) isEqual(rfc2833 *RFC2833) bool {
|
||
|
if r.Duration == rfc2833.Duration && r.End == rfc2833.End && r.Event == rfc2833.Event && r.Volume == rfc2833.Volume {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////
|
||
|
//bypass - audio
|
||
|
type ByPassDTMF struct {
|
||
|
VoiceBuf []byte
|
||
|
}
|
||
|
|
||
|
func dtmfBypass(data []byte) (string, *icserror.IcsError) {
|
||
|
|
||
|
return "", icserror.ICSERRDTMFFail
|
||
|
}
|