|
|
|
package simphone
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"gitlab.com/ics_cinnamon/voicegateway/icsconf"
|
|
|
|
"gitlab.com/ics_cinnamon/voicegateway/icserror"
|
|
|
|
"gitlab.com/ics_cinnamon/voicegateway/icslog"
|
|
|
|
"gitlab.com/ics_cinnamon/voicegateway/icsmediaconv"
|
|
|
|
"gitlab.com/ics_cinnamon/voicegateway/icsnet"
|
|
|
|
"gitlab.com/ics_cinnamon/voicegateway/icssvc"
|
|
|
|
"gitlab.com/ics_cinnamon/voicegateway/sim/icspacketgen"
|
|
|
|
"gitlab.com/ics_cinnamon/voicegateway/sim/simprocnew"
|
|
|
|
)
|
|
|
|
|
|
|
|
type SimPhone struct {
|
|
|
|
isCaller bool
|
|
|
|
ID int
|
|
|
|
CallID string
|
|
|
|
PayloadType int
|
|
|
|
SSRC uint32
|
|
|
|
Seq uint16
|
|
|
|
Timestamp uint32
|
|
|
|
TSIPPort int
|
|
|
|
SIPPort int
|
|
|
|
RTPTxPort int
|
|
|
|
RTPCBTxPort int
|
|
|
|
TRTPTxPort int
|
|
|
|
lsaddr *icsnet.IcsNetAddr //local sip addr
|
|
|
|
laddr *icsnet.IcsNetAddr //local rtp addr
|
|
|
|
rsaddr *icsnet.IcsNetAddr //remote sip addr
|
|
|
|
raddr *icsnet.IcsNetAddr //remote rtp addr
|
|
|
|
localRTPUDP *icsnet.IcsUDPNet
|
|
|
|
sentTime int
|
|
|
|
sendRTPStatus bool
|
|
|
|
expTime time.Time
|
|
|
|
mediaStart int
|
|
|
|
wgMedia sync.WaitGroup
|
|
|
|
rtptimer *time.Timer
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewSimPhone(id int) *SimPhone {
|
|
|
|
s := &SimPhone{}
|
|
|
|
|
|
|
|
simconf := icsconf.GetSimConfig()
|
|
|
|
|
|
|
|
s.ID = id
|
|
|
|
if strings.Compare("YES", strings.ToUpper(simconf.IsCaller)) == 0 {
|
|
|
|
s.CallID = uuid.New().String()
|
|
|
|
s.isCaller = true
|
|
|
|
//fmt.Println("Call ID -", s.CallID)
|
|
|
|
}
|
|
|
|
s.SSRC = icspacketgen.GenSSRC()
|
|
|
|
s.Seq = 1
|
|
|
|
s.PayloadType = icsmediaconv.ICS_PT_ALAW
|
|
|
|
s.SIPPort = simconf.SimPhoneConfig.SIPPort
|
|
|
|
s.TSIPPort = simconf.TargetPhoneConfig.TSIPPort
|
|
|
|
s.TRTPTxPort = simconf.TargetPhoneConfig.TRTPPort + (s.ID * 2) //targetRTPTxPort
|
|
|
|
s.RTPTxPort = simconf.SimPhoneConfig.RTPPort + (s.ID * 2) //localRTPTxPort
|
|
|
|
la1 := icsnet.NewNetAddrWithIPPort(simconf.SimPhoneConfig.MYIP, s.SIPPort)
|
|
|
|
s.lsaddr = &la1
|
|
|
|
la2 := icsnet.NewNetAddrWithIPPort(simconf.SimPhoneConfig.MYIP, s.RTPTxPort)
|
|
|
|
s.laddr = &la2
|
|
|
|
s.sentTime = 0
|
|
|
|
s.sendRTPStatus = false
|
|
|
|
|
|
|
|
s.wgMedia = sync.WaitGroup{}
|
|
|
|
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *SimPhone) SetRemoteAddr(saddr *icsnet.IcsNetAddr, addr *icsnet.IcsNetAddr) { //sip addr, rtp addr
|
|
|
|
s.rsaddr = saddr
|
|
|
|
s.raddr = addr
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *SimPhone) Run() *icserror.IcsError {
|
|
|
|
svc := icssvc.GetServiceStatus()
|
|
|
|
|
|
|
|
l := icslog.GetIcsLog()
|
|
|
|
l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Phone[%d] Started! SIP addr: %v, RTP addr: %v\n",
|
|
|
|
s.ID, s.lsaddr, s.laddr)
|
|
|
|
l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "%s\n", s.String())
|
|
|
|
|
|
|
|
simconf := icsconf.GetSimConfig()
|
|
|
|
|
|
|
|
//make rtp event timer
|
|
|
|
s.rtptimer = time.NewTimer(time.Millisecond)
|
|
|
|
rtpReadTimer := time.NewTicker(time.Second)
|
|
|
|
wgRTPListen := sync.WaitGroup{}
|
|
|
|
|
|
|
|
//create rtp liesten goroutine
|
|
|
|
s.localRTPUDP = icsnet.NewUDP(s.laddr, nil)
|
|
|
|
lerr := s.localRTPUDP.Listen()
|
|
|
|
if lerr == nil {
|
|
|
|
wgRTPListen.Add(1)
|
|
|
|
go func() {
|
|
|
|
// fmt.Println("############### start rtp", s.laddr)
|
|
|
|
l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Start RTP Listen[%v]\n", s.laddr)
|
|
|
|
totalRlen := 0
|
|
|
|
for s.mediaStart != 2 || !svc.GetExit() || !svc.GetStop() {
|
|
|
|
_, _, rlen, rtperr := s.localRTPUDP.ReadRTP()
|
|
|
|
if rtperr == nil {
|
|
|
|
s.expTime = time.Now()
|
|
|
|
totalRlen += rlen
|
|
|
|
} else {
|
|
|
|
// fmt.Printf("\nTotal Recved RTP Length[%d]\n", totalRlen)
|
|
|
|
// fmt.Println("##### id : ", s.ID)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Stoped[%d] RTP Listen[%v] Total Recved RTP length %d\n", s.mediaStart, s.laddr, totalRlen)
|
|
|
|
wgRTPListen.Done()
|
|
|
|
}()
|
|
|
|
} else {
|
|
|
|
l.Printf(icslog.LOG_LEVEL_FATAL, s.ID, "Failed to listen RTP[%v] - %v\n", s.laddr, lerr)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////
|
|
|
|
//CALLER SIDE
|
|
|
|
l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "CALLER SIDE")
|
|
|
|
|
|
|
|
id := fmt.Sprintf("%d", s.ID+7000)
|
|
|
|
toid := fmt.Sprintf("%d", s.ID+21016)
|
|
|
|
// fmt.Println("############################################################################## id : ", id)
|
|
|
|
// fmt.Println("############################################################################## id : ", toid)
|
|
|
|
// fmt.Println("############################################################################## id : ", s.TRTPTxPort)
|
|
|
|
|
|
|
|
ra := icsnet.NewNetAddrWithIPPort(simconf.GetSimTargetIP(), s.TSIPPort)
|
|
|
|
s.rsaddr = &ra
|
|
|
|
l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "SIP address [%v] [%v]", s.lsaddr, s.rsaddr)
|
|
|
|
|
|
|
|
localSIPUDP := icsnet.NewUDP(s.lsaddr, s.rsaddr)
|
|
|
|
serr := localSIPUDP.Connect(s.lsaddr, s.rsaddr)
|
|
|
|
if serr != nil {
|
|
|
|
l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to Connect [%v]->[%v]", s.lsaddr, s.rsaddr)
|
|
|
|
return serr
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////
|
|
|
|
// send regi sip
|
|
|
|
// fmt.Println("###################### regi")
|
|
|
|
if simconf.RegiCount != 0 {
|
|
|
|
regiCount := 0
|
|
|
|
for {
|
|
|
|
buf, rlen, err := simprocnew.NewReadSIP(s.ID, s.CallID, simconf.SimPhoneConfig.MYIP, s.TSIPPort, ra, s.laddr, s.rsaddr, s.lsaddr, localSIPUDP)
|
|
|
|
if err != nil {
|
|
|
|
// fmt.Println(err)
|
|
|
|
}
|
|
|
|
n := bytes.Index(buf[:rlen], []byte{32})
|
|
|
|
if string(buf[:n]) == "REGISTER" {
|
|
|
|
regiSip := simprocnew.NewSIPSignal("REGI", s.ID, id, toid, ra, s.CallID, simconf.SimPhoneConfig.MYIP, s.TSIPPort, s.laddr, s.rsaddr, s.lsaddr, localSIPUDP, buf, rlen)
|
|
|
|
if regiSip != nil {
|
|
|
|
l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Send Invite error [%s]", regiSip)
|
|
|
|
return regiSip
|
|
|
|
}
|
|
|
|
regiCount += 1
|
|
|
|
}
|
|
|
|
if regiCount == simconf.RegiCount {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// time.Sleep(time.Second * 2)
|
|
|
|
|
|
|
|
////////////////////
|
|
|
|
// get call flow //
|
|
|
|
///////////////////
|
|
|
|
// ra = icsnet.NewNetAddrWithIPPort(simconf.GetSimTargetIP(), s.TRTPTxPort)
|
|
|
|
// l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Start sending RTP[%s:%d]", ra.IPv4String, ra.Port)
|
|
|
|
// s.raddr = &ra
|
|
|
|
// s.localRTPUDP.SetRemoteAddr(s.raddr)
|
|
|
|
|
|
|
|
simScenarioConf := icsconf.GetSimScenarioConfig()
|
|
|
|
// var stopByeTimer *time.Ticker
|
|
|
|
for _, ord := range simScenarioConf.SipOrder.Order {
|
|
|
|
// fmt.Println("######################################################## : ", strings.ToUpper(ord))
|
|
|
|
switch strings.ToUpper(ord) {
|
|
|
|
// case "WAIT": // set send bye time
|
|
|
|
// stopByeTimer = time.NewTicker(time.Second * time.Duration(simScenarioConf.SipOrder.StopTime))
|
|
|
|
case "BYE":
|
|
|
|
go func() {
|
|
|
|
// if stopByeTimer != nil {
|
|
|
|
// <-stopByeTimer.C
|
|
|
|
// }
|
|
|
|
sendSip := simprocnew.NewSIPSignal("BYE", s.ID, id, toid, ra, s.CallID, simconf.SimPhoneConfig.MYIP, s.TRTPTxPort, s.laddr, s.rsaddr, s.lsaddr, localSIPUDP, nil, 0)
|
|
|
|
if sendSip != nil {
|
|
|
|
l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Send bye error [%s]", sendSip)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
case "ACK":
|
|
|
|
sendSip := simprocnew.NewSIPSignal(strings.ToUpper(ord), s.ID, id, toid, ra, s.CallID, simconf.SimPhoneConfig.MYIP, s.TRTPTxPort, s.laddr, s.rsaddr, s.lsaddr, localSIPUDP, nil, 0)
|
|
|
|
if sendSip != nil {
|
|
|
|
l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Send SIP error (except BYE) [%s]", sendSip)
|
|
|
|
return sendSip
|
|
|
|
} else {
|
|
|
|
go func() {
|
|
|
|
buf, rlen, err := simprocnew.NewReadSIP(s.ID, s.CallID, simconf.SimPhoneConfig.MYIP, s.TRTPTxPort, ra, s.laddr, s.rsaddr, s.lsaddr, localSIPUDP)
|
|
|
|
if err != nil {
|
|
|
|
l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to recv BYE - %v", err)
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
// fmt.Println(string(buf[:rlen]))
|
|
|
|
l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Receved BYE Message : %s", string(buf[:rlen]))
|
|
|
|
// stopByeTimer.Stop()
|
|
|
|
sendSip := simprocnew.NewSIPSignal("BYE200", s.ID, id, toid, ra, s.CallID, simconf.SimPhoneConfig.MYIP, s.TRTPTxPort, s.laddr, s.rsaddr, s.lsaddr, localSIPUDP, nil, 0)
|
|
|
|
if sendSip != nil {
|
|
|
|
l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Send bye error [%s]", sendSip)
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
// s.mediaStart = 1
|
|
|
|
// s.wgMedia.Wait()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
case "TTS":
|
|
|
|
go s.ExpireReadRTP(rtpReadTimer)
|
|
|
|
for {
|
|
|
|
if s.sendRTPStatus {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case "STT":
|
|
|
|
// send rtp
|
|
|
|
ra = icsnet.NewNetAddrWithIPPort(simconf.GetSimTargetIP(), s.TRTPTxPort)
|
|
|
|
l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Start sending RTP[%s:%d]", ra.IPv4String, ra.Port)
|
|
|
|
s.raddr = &ra
|
|
|
|
s.localRTPUDP.SetRemoteAddr(s.raddr)
|
|
|
|
s.wgMedia.Add(1)
|
|
|
|
go s.RunMedia(s.raddr.Port, s.PayloadType)
|
|
|
|
// s.mediaStart = 1
|
|
|
|
s.wgMedia.Wait()
|
|
|
|
l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Sending RTP Done!")
|
|
|
|
s.mediaStart = 2
|
|
|
|
case "DTMF":
|
|
|
|
default:
|
|
|
|
sendSip := simprocnew.NewSIPSignal(strings.ToUpper(ord), s.ID, id, toid, ra, s.CallID, simconf.SimPhoneConfig.MYIP, s.TRTPTxPort, s.laddr, s.rsaddr, s.lsaddr, localSIPUDP, nil, 0)
|
|
|
|
if sendSip != nil {
|
|
|
|
l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Send SIP error (except BYE) [%s]", sendSip)
|
|
|
|
return sendSip
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
s.localRTPUDP.Close()
|
|
|
|
|
|
|
|
wgRTPListen.Wait()
|
|
|
|
|
|
|
|
s.rtptimer.Stop()
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *SimPhone) RunMedia(port int, pt int) {
|
|
|
|
// fmt.Println("#### RunMedia")
|
|
|
|
defer func() {
|
|
|
|
s.wgMedia.Done()
|
|
|
|
}()
|
|
|
|
l := icslog.GetIcsLog()
|
|
|
|
simconf := icsconf.GetSimConfig()
|
|
|
|
|
|
|
|
var voiceFileName string
|
|
|
|
if strings.Compare(simconf.IsCaller, "yes") == 0 {
|
|
|
|
voiceFileName = "./voice/9012-RX-1649749470147018876.raw"
|
|
|
|
} else {
|
|
|
|
voiceFileName = "./voice/9012-RX-1649749470147018876.raw"
|
|
|
|
}
|
|
|
|
fp, err := os.Open(voiceFileName)
|
|
|
|
if err != nil {
|
|
|
|
l.Printf(icslog.LOG_LEVEL_FATAL, s.ID, "Failed to Voice file-%v", err)
|
|
|
|
if s.isCaller {
|
|
|
|
s.wgMedia.Done()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer fp.Close()
|
|
|
|
|
|
|
|
fs, err := os.Stat(voiceFileName)
|
|
|
|
if err != nil {
|
|
|
|
l.Printf(icslog.LOG_LEVEL_FATAL, s.ID, "Failed to Voice file-%v", err)
|
|
|
|
if s.isCaller {
|
|
|
|
s.wgMedia.Done()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
fileLen := fs.Size()
|
|
|
|
voiceIdx := 0
|
|
|
|
voiceBuf := make([]byte, fileLen)
|
|
|
|
flen, err := fp.Read(voiceBuf)
|
|
|
|
if flen <= 0 || err != nil {
|
|
|
|
l.Printf(icslog.LOG_LEVEL_FATAL, s.ID, "Failed to Voice file-%v", err)
|
|
|
|
if s.isCaller {
|
|
|
|
s.wgMedia.Done()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ra := icsnet.NewNetAddrWithIPPort(simconf.GetSimTargetIP(), s.TRTPTxPort)
|
|
|
|
s.localRTPUDP.SetRemoteAddr(&ra)
|
|
|
|
|
|
|
|
before := time.Now()
|
|
|
|
for {
|
|
|
|
<-s.rtptimer.C
|
|
|
|
s.rtptimer.Reset(time.Millisecond)
|
|
|
|
|
|
|
|
if s.mediaStart == 0 {
|
|
|
|
time.Sleep(time.Millisecond * 2)
|
|
|
|
// continue
|
|
|
|
} else if s.mediaStart == 2 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
now := time.Now()
|
|
|
|
var delta time.Duration = (time.Millisecond * 20) - now.Sub(before)
|
|
|
|
if delta < 0 {
|
|
|
|
time.Sleep((time.Millisecond * 20) + delta)
|
|
|
|
} else {
|
|
|
|
time.Sleep((time.Millisecond * 20) - delta)
|
|
|
|
}
|
|
|
|
before = now
|
|
|
|
|
|
|
|
r := icspacketgen.NewRTP()
|
|
|
|
rtppacket := r.MakeRTPData(uint8(pt), &s.Seq, &s.Timestamp, s.SSRC, voiceBuf[voiceIdx:voiceIdx+160])
|
|
|
|
voiceIdx += 160
|
|
|
|
if int64(voiceIdx+160) >= fileLen {
|
|
|
|
voiceIdx = len(voiceBuf) - 1
|
|
|
|
rtppacket = r.MakeRTPData(uint8(pt), &s.Seq, &s.Timestamp, s.SSRC, voiceBuf[voiceIdx:])
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
wlen, werr := s.localRTPUDP.WriteRTP(rtppacket)
|
|
|
|
if werr != nil {
|
|
|
|
l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to write RTP packet %d-%s{%v}", wlen, werr.GetMessage(), werr.GetError())
|
|
|
|
if s.isCaller {
|
|
|
|
s.wgMedia.Done()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Sent Voice data length %d-%d", voiceIdx, s.sentTime)
|
|
|
|
|
|
|
|
s.sendRTPStatus = false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *SimPhone) String() string {
|
|
|
|
return fmt.Sprintf("ID: %d\nCall ID: %s\nPayload Type: %d\nSIP Port: %d\nTRTPTxPort: %d",
|
|
|
|
s.ID, s.CallID, s.PayloadType, s.SIPPort, s.TRTPTxPort)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *SimPhone) ExpireReadRTP(t *time.Ticker) {
|
|
|
|
// s.sendRTPStatus = false
|
|
|
|
s.expTime = time.Now()
|
|
|
|
for t := range t.C {
|
|
|
|
// if s.sendRTPStatus {
|
|
|
|
// s.sendRTPStatus = false
|
|
|
|
// } else
|
|
|
|
if time.Now().Sub(s.expTime) >= time.Second {
|
|
|
|
// fmt.Println(t)
|
|
|
|
s.sendRTPStatus = true
|
|
|
|
break
|
|
|
|
} else if s.sendRTPStatus {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|