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