package icssessionmanager import ( "bytes" "fmt" "runtime/debug" "strings" "sync" "sync/atomic" "time" "gitlab.com/cinnamon/voiceagent/icsconf" "gitlab.com/cinnamon/voiceagent/icserror" "gitlab.com/cinnamon/voiceagent/icsevent" "gitlab.com/cinnamon/voiceagent/icshttpclient" "gitlab.com/cinnamon/voiceagent/icslog" "gitlab.com/cinnamon/voiceagent/icsmediaconv" "gitlab.com/cinnamon/voiceagent/icsnet" "gitlab.com/cinnamon/voiceagent/icspacketparser" "gitlab.com/cinnamon/voiceagent/icssvc" "gitlab.com/cinnamon/voiceagent/icsws" "gitlab.com/cinnamon/voiceagent/recorddata" "gitlab.com/cinnamon/voiceagent/recorddata/readcallsignal" "gitlab.com/cinnamon/voiceagent/recorddata/responsecs" "gitlab.com/cinnamon/voiceagent/stt" "gitlab.com/ics_cinnamon/joy4/format" ) type IcsSession struct { ID int goroutineID int //bot callId string srcPort int dstPort int direction bool Station string sstation string botToken string url string custid string eventSystem *icsevent.EventSystem //manage session lastTimestamp time.Time isStart int32 //media invitePayloads []string payloadType icspacketparser.PayloadType isFoundPayload bool TxConverter *icsmediaconv.Converter RxConverter *icsmediaconv.Converter txSeq int //first TX seq num rxSeq int //first RX seq num STTTx *stt.STT STTRx *stt.STT cs *readcallsignal.CallSignal isSTTStartTimer *time.Timer isSTTStart bool dtmf string //websocket WSConn *icsws.WSClient //agent config AgentConfig *icsconf.AgentConfig //bot isBotStart bool botStatus *icshttpclient.ProcessResp TcpConn *icsnet.IcsTCPNet //call info StartTimeStamp int64 ChannelID string ServerID string /*////////////////// rxFile *os.File txFile *os.File */ ////////////////// //Voice capture conn CallSignalNeter icsnet.IcsNeter VoiceNeter icsnet.IcsNeter MethodAutomata int m *sync.Mutex } type IcsSessionID int const MAX_SESSION_IDLE = time.Hour const ( ICS_INBOUND_CALL = true ICS_OUTBOUND_CALL = false ) ////////////////////////////////////////////////////////////////// //session routine //init ffmpeg func init() { format.RegisterAll() } //on/off check the session idle func (s *IcsSession) Start() { s.SetTimestamp(time.Now()) //s.isStart = true atomic.StoreInt32(&s.isStart, 1) } func (s *IcsSession) Stop() { l := icslog.GetIcsLog() defer func() { if err := recover(); err != nil { switch v := err.(type) { case error: icserror.ICSERRNETNotConnectError.SetError(v) l.Printf(icslog.LOG_LEVEL_WARN, s.ID, "PANIC!\n%s", string(debug.Stack())) } } }() l.Print(icslog.LOG_LEVEL_INFO, s.ID, "Session Stop") l.Print(icslog.LOG_LEVEL_INFO, s.ID, "Timer Stop") s.isSTTStartTimer.Stop() atomic.StoreInt32(&s.isStart, 0) } func (s *IcsSession) Run() *icserror.IcsError { // MAX_SESSION_IDLE := time.Second * time.Duration(icsconf.GetIcsConfig().SessionExpired.SSec) mySessionID := s.GetSessionID() l := icslog.GetIcsLog() //conf := icsconf.GetIcsConfig() s.goroutineID = goid() l.Printf(icslog.LOG_LEVEL_INFO, int(mySessionID), "Session [%d] READY\n", mySessionID) svc := icssvc.GetServiceStatus() for !svc.GetExit() && !svc.GetStop() { //get event h := icsevent.NewEventH() evt, evterr := h.GetEvent(int(mySessionID)) if evt == nil { if evterr != nil { //evterr.Print() time.Sleep(time.Millisecond) continue } duration := time.Since(s.lastTimestamp) if atomic.LoadInt32(&s.isStart) == 1 && duration >= MAX_SESSION_IDLE { //Session expired! err := icserror.ICSERRSESSMaxSessionIdle logmsg := fmt.Sprintf("Session expired. Duration: %v(%v) - %s\n", duration, s.lastTimestamp, err.GetMessage()) l.Print(icslog.LOG_LEVEL_INFO, s.ID, logmsg) s.Stop() serr := s.RemoveSession() if serr != nil { //serr.Print() l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "RemoveSession Error %s", serr.GetMessage()) } //return err } time.Sleep(time.Millisecond) continue } //refresh session timestamp s.SetTimestamp(time.Now()) //l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Get Event[%d]", evt.ID) data := evt.GetData() switch v := (*data).(type) { case *readcallsignal.CallSignal: s.cs = v l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Get CallSignal Event[%d] - %+v", evt.ID, s.cs) //call start if s.cs.EventType == "S" { //call started switch s.AgentConfig.Action { case "voicecapture": l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Call Started - Station: %s, Tel: %s", s.cs.Station, s.cs.CustID) //fmt.Println("voice capture") s.STTRx = stt.NewSTT(nil) s.STTTx = stt.NewSTT(nil) s.isSTTStart = true go s.RecvVoice() case "voicegateway": l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Call Started - Station: %s, Tel: %s, %+v", s.cs.Station, s.cs.CustID, s.cs) //agentname := s.AgentConfig.Name s.STTRx = stt.NewSTT(nil) go s.RecvVoice() url := fmt.Sprintf("http://%s:%d%s", s.AgentConfig.BotConfig.IP, s.AgentConfig.BotConfig.Port, s.AgentConfig.BotConfig.URL2) //remove null terminator var custid, agentid string n := bytes.Index([]byte(s.cs.CustID), []byte{0}) if n != -1 { custid = string([]byte(s.cs.CustID)[:n]) } else { custid = s.cs.CustID } n = bytes.Index([]byte(s.cs.AgentID), []byte{0}) if n != -1 { agentid = string([]byte(s.cs.AgentID)[:n]) } else { agentid = s.cs.AgentID } n = bytes.Index([]byte(s.cs.Station), []byte{0}) var sstation string if n != -1 { sstation = string([]byte(s.cs.Station)[:n]) } else { sstation = s.cs.Station } //set callid timei := time.Now().UnixNano() if len(s.callId) == 0 { s.callId = fmt.Sprintf("%d@%s", timei, agentid) fmt.Println("callid :", s.callId) } s.url = url s.custid = custid s.sstation = sstation botRequest := icshttpclient.NewPostProcess(s.url, "INIT", "", s.custid, "ICS_RCP", s.callId, s.sstation, "", "") //////////////////////////////////////////////// //post event to the session h := icsevent.NewEventH() var evt *icsevent.Event var evtErr *icserror.IcsError if evt, evtErr = h.AllocEvent(botRequest); evtErr != nil { l.Print(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error") s.SendVoiceGatewayByeSignal() continue } l.Printf(icslog.LOG_LEVEL_INFO, -1, "Post BOT Request[%d] to Session[%03d]", evt.ID, s.ID) h.PostEvent(s.ID, evt) /* processResp := icshttpclient.PostProcess(url, "INIT", "", custid, "ICS_RCP", s.callId, sstation, "", "") //processResp := icshttpclient.PostProcess(url, "INIT", result, custid, "ICS_RCP", s.callId, "", filename) if processResp == nil { l.Print(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error") s.SendVoiceGatewayByeSignal() continue } else { if processResp.ResultCode == 200 { s.botStatus = processResp s.botToken = processResp.Token l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Response : %+v", processResp) fmt.Println(">>> ment", processResp.AnnounceMents) //tts pcm, ttsErr := tts.TTS(processResp.AnnounceMents, 8000) if ttsErr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "TTS Error[%s] - %s", processResp.AnnounceMents, ttsErr.GetError()) s.SendVoiceGatewayBotByeSignal(url, custid, sstation) continue } else { l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "%s!!! TTS Result: [%s] %d bytes", agentname, processResp.AnnounceMents, len(pcm)) //send tts data to voice gateway r := responsecs.NewResponse(agentname, responsecs.TTS_COMMAND, responsecs.RC_SUCCESS, len(pcm)) addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port) t, wlen, werr := icsnet.SendCallSignal2(&addr, nil, r.GetData()) //wlen, werr := s.TcpConn.Write(r.GetData()) if werr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS header - %s [%+v]", werr.GetError(), s.TcpConn) s.SendVoiceGatewayBotByeSignal(url, custid, sstation) continue } l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS header : %d [%s]", wlen, r) s.TcpConn = t wlen, werr = s.TcpConn.Write(pcm) if werr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS data - %s", werr.GetError()) s.SendVoiceGatewayBotByeSignal(url, custid, sstation) continue } l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS data : %d", wlen) l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Barge-In: %s", processResp.Data.BargeIn) switch processResp.Data.BargeIn { case "Y": //s.StartSTT(wlen) s.isSTTStart = true case "N": s.StartSTT(wlen) //s.isSTTStart = false } //s.StartSTT(wlen) } } else { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error : %+v", processResp) s.SendVoiceGatewayByeSignal() } } */ } } else if s.cs.EventType == "D" { //dtmf s.AddDtmf() //s.dtmf = s.cs.InOut l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "DTMF : %s(%s|%s)", s.cs.InOut, s.dtmf, s.GetDtmf(icsconf.GetIcsConfig().DtmfEndSignal.Signal)) s.DTMFCB() } else { fmt.Println("198LINE CALL END!!") } case *icshttpclient.IcsHttpClient: request := v l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Get http.Request Event[%d] - %+v", evt.ID, request) s.DoScenario(request) case *stt.STTResult: sttResult := v l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Get STT Result Event[%d] - %s, %s", evt.ID, sttResult.GetResult(), sttResult.GetError().GetError()) s.STTResultCB(sttResult) /* err := sttResult.GetError() if err == icserror.ICSERRSTTOK { l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "STT Completed - %s", err) s.STTResultCB(sttResult) } */ case icspacketparser.SIP: l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Get SIP Event[%d]", evt.ID) sip := v s.analyzeSIP(&sip) case icspacketparser.RTP: //l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Get RTP Event[%d]", evt.ID) rtp := v //fmt.Println(rtp) s.analyzeRTP(&rtp) //default: //fmt.Println(time.Now(), "NOT DEFINED EVENT TYPE!!!!!!!!!!!!!!!!!") default: l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Event Type : %T", v) } evt = nil } return nil } func (s *IcsSession) RecvVoice() { l := icslog.GetIcsLog() conf := icsconf.GetIcsConfig() //agentname := conf.AgentConfig[s.ID].Name agentname := s.AgentConfig.Name var uniq string wait := new(sync.WaitGroup) wait.Add(1) l.Print(icslog.LOG_LEVEL_DEBUG2, s.ID, "Started RecvVoice") go func() { defer wait.Done() start := atomic.LoadInt32(&s.isStart) for start == 1 { start = atomic.LoadInt32(&s.isStart) //receive voice data from voice server buf, rlen, rerr := s.VoiceNeter.Read(340) if rerr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to Read VoiceNeter - %s-%s", rerr.GetMessage(), rerr.GetError()) // s.SendVoiceGatewayByeSignal() break } if strings.Compare(s.AgentConfig.Action, "voicegateway") == 0 { //for barge-in if !s.isSTTStart { continue } else { //s.isSTTStartTimer.Stop() } } //parsing voice data header voicedata := recorddata.NewVoiceDataHDR(buf[:rlen]) switch voicedata.Type { case 0: //RX //var url, custid string //var processResp *icshttpclient.ProcessResp uniq = fmt.Sprintf("%s-RX-", s.cs.Station) //file.Write(voicedata.Payload) //file.Sync() //STT result, rmsval, err := s.STTRx.STT(voicedata) // s.STTStatus = s.STTStatus{err, err} //l.Printf(icslog.LOG_LEVEL_DEBUG2, a.ID, "[%f]%+v\n", rmsval, voicedata) //fmt.Printf("[%f]%+v\n", rms, voicedata) if err == icserror.ICSERRSTTContinue { //fmt.Printf("RX CONT >>> %f %s\n", rmsval, result) continue } else if err == icserror.ICSERRSTTBargeIn { //send barge-in command to voice gateway r := responsecs.NewResponse(agentname, "", responsecs.BARGEIN_COMMAND, responsecs.RC_SUCCESS, 0) addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port) _, wlen, werr := icsnet.SendCallSignal2(&addr, nil, r.GetData()) //wlen, werr := s.TcpConn.Write(r.GetData()) if werr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send Barge-In Command - %s [%+v]", werr.GetError(), s.TcpConn) continue } l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent Barge-In Command : %d", wlen) } else if err == icserror.ICSERRSTTOK { s.isSTTStart = false filename := s.STTRx.Save(uniq, conf.VoiceConfig.Path) size := s.STTRx.GetVoiceBufCur() s.STTRx.Close() switch s.AgentConfig.Action { case "voicegateway": //only RX!!! sttResult := stt.NewSTTResult(result, err) //////////////////////////////////////////////// //post event to the session h := icsevent.NewEventH() var evt *icsevent.Event var evtErr *icserror.IcsError if evt, evtErr = h.AllocEvent(sttResult); evtErr != nil { l.Print(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error") s.SendVoiceGatewayByeSignal() continue } l.Printf(icslog.LOG_LEVEL_INFO, -1, "Post STT Result[%d] to Session[%03d]", evt.ID, s.ID) h.PostEvent(s.ID, evt) /***************************** if s.botStatus != nil { //processing url = fmt.Sprintf("http://%s:%d%s", s.AgentConfig.BotConfig.IP, s.AgentConfig.BotConfig.Port, s.AgentConfig.BotConfig.URL2) //remove null terminator n := bytes.Index([]byte(s.cs.CustID), []byte{0}) if n != -1 { custid = string([]byte(s.cs.CustID)[:n]) } else { custid = s.cs.CustID } var agentid string n = bytes.Index([]byte(s.cs.AgentID), []byte{0}) if n != -1 { agentid = string([]byte(s.cs.AgentID)[:n]) } else { agentid = s.cs.AgentID } n = bytes.Index([]byte(s.cs.Station), []byte{0}) var sstation string if n != -1 { sstation = string([]byte(s.cs.Station)[:n]) } else { sstation = s.cs.Station } timei := time.Now().UnixNano() if len(s.callId) == 0 { s.callId = fmt.Sprintf("%d@%s", timei, agentid) } //var processResp *icshttpclient.ProcessResp if strings.Compare(s.botStatus.Action, "END") != 0 { fmt.Println(url, s.botStatus.Action, "", custid, "ICS_RCP", s.callId, s.botToken, "") processResp = icshttpclient.PostProcess(url, s.botStatus.Action, result, custid, "ICS_RCP", s.callId, sstation, s.botToken, "") } //processResp := icshttpclient.PostProcess(url, "INIT", result, custid, "ICS_RCP", s.callId, "", filename) if processResp == nil { l.Print(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error") continue // s.SendVoiceGatewayBotByeSignal(url, custid, sstation) // break // 특정 session에 대해서 처리하는 부분이라 break가 맞을거같음, 그래야 아랫쪽에서도 문제가 안생김 } else { if processResp.ResultCode == 200 { s.botStatus = processResp l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Response : %+v", processResp) if strings.Compare(s.botStatus.Action, "END") != 0 { fmt.Println(">>> ment", processResp.AnnounceMents) //tts pcm, ttsErr := tts.TTS(processResp.AnnounceMents, 8000) if ttsErr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "TTS Error[%s] - %s", processResp.AnnounceMents, ttsErr.GetError()) continue // s.SendVoiceGatewayBotByeSignal(url, custid, sstation) // break } else { l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "%s!!! TTS Result: [%s]%d bytes", agentname, processResp.AnnounceMents, len(pcm)) //send tts data to voice gateway r := responsecs.NewResponse(agentname, responsecs.TTS_COMMAND, responsecs.RC_SUCCESS, len(pcm)) addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port) t, wlen, werr := icsnet.SendCallSignal2(&addr, nil, r.GetData()) //wlen, werr := s.TcpConn.Write(r.GetData()) if werr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS header - %s [%+v]", werr.GetError(), s.TcpConn) continue // s.SendVoiceGatewayBotByeSignal(url, custid, sstation) // break } l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS header : %d", wlen) s.TcpConn = t wlen, werr = s.TcpConn.Write(pcm) if werr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS data - %s", werr.GetError()) continue // s.SendVoiceGatewayBotByeSignal(url, custid, sstation) // break } l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS data : %d", wlen) l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Barge-In: %s", processResp.Data.BargeIn) switch processResp.Data.BargeIn { case "Y": //s.StartSTT(wlen) s.isSTTStart = true case "N": s.StartSTT(wlen) //s.isSTTStart = false } } } else { //end fmt.Println(">>> ment", processResp.AnnounceMents) //tts pcm, ttsErr := tts.TTS(processResp.AnnounceMents, 8000) if ttsErr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "TTS Error[%s] - %s", processResp.AnnounceMents, ttsErr.GetError()) continue // s.SendVoiceGatewayBotByeSignal(url, custid, sstation) // break } else { l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "%s!!! TTS Result: [%s]%d bytes", agentname, processResp.AnnounceMents, len(pcm)) //send command BYE to voice gateway //send tts data to voice gateway r := responsecs.NewResponse(agentname, responsecs.BYE_COMMAND, responsecs.RC_SUCCESS, len(pcm)) addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port) t, wlen, werr := icsnet.SendCallSignal2(&addr, nil, r.GetData()) //wlen, werr := s.TcpConn.Write(r.GetData()) if werr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS header - %s [%+v]", werr.GetError(), s.TcpConn) continue // s.SendVoiceGatewayBotByeSignal(url, custid, sstation) // break } l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Barge-In: %s", processResp.Data.BargeIn) switch processResp.Data.BargeIn { case "Y": //s.StartSTT(wlen) s.isSTTStart = true case "N": s.StartSTT(wlen) //s.isSTTStart = false } s.TcpConn = t wlen, werr = s.TcpConn.Write(pcm) if werr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS data - %s", werr.GetError()) continue // s.SendVoiceGatewayBotByeSignal(url, custid, sstation) // break } l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS data : %d", wlen) } //send command BYE to voice gateway //r := responsecs.NewResponse(agentname, responsecs.BYE_COMMAND, responsecs.RC_SUCESS, 0) //addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port) //_, wlen, werr := icsnet.SendCallSignal2(&addr, nil, r.GetData()) //if werr != nil { //l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send BYE command - %s [%+v]", //werr.GetError(), s.TcpConn) //continue //} //l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent BYE command : %d", wlen) } } else { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error : %+v", processResp) } } } ********************************/ case "voicecapture": //TODO: websocket //fmt.Println("RX RESULT>>>", result, rms) s.rxSeq++ imsg := icsws.NewIAP() imsg.SendMessage("RX", agentname, result, s.rxSeq) l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Send Message: %+v", imsg) s.WSConn.Write(imsg.String()) } //voice save yn if conf.VoiceConfig.SaveYn == "N" { l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "[%d]RX Recog Result> %s, PCM(%f), BufLen(%d)", s.goroutineID, result, rmsval, size) } else { l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "[%d]RX Recog Result> %s, PCM(%f), BufLen(%d) %s", s.goroutineID, result, rmsval, size, filename) } } else if err == icserror.ICSERRSTTFail || err == icserror.ICSERRSTTFailEmpty { l.Printf(icslog.LOG_LEVEL_WARN, s.ID, "Rx STT Failed - %s", err.GetError()) s.isSTTStart = false //if err == icserror.ICSERRSTTFail { uniq = fmt.Sprintf("%s-RX-Fail-", s.cs.Station) filename := s.STTRx.Save(uniq, conf.VoiceConfig.Path) s.STTRx.Close() l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "RX Recog Failed> %s-%v, PCM(%f), %s", err.GetMessage(), err.GetError(), rmsval, filename) switch s.AgentConfig.Action { case "voicegateway": sttResult := stt.NewSTTResult(result, err) //////////////////////////////////////////////// //post event to the session h := icsevent.NewEventH() var evt *icsevent.Event var evtErr *icserror.IcsError if evt, evtErr = h.AllocEvent(sttResult); evtErr != nil { l.Print(icslog.LOG_LEVEL_ERROR, s.ID, "Response Error") s.SendVoiceGatewayByeSignal() continue } l.Printf(icslog.LOG_LEVEL_INFO, -1, "Post STT Result[%d] to Session[%03d]", evt.ID, s.ID) h.PostEvent(s.ID, evt) /********************** url = fmt.Sprintf("http://%s:%d%s", s.AgentConfig.BotConfig.IP, s.AgentConfig.BotConfig.Port, s.AgentConfig.BotConfig.URL2) //remove null terminator var custid, agentid string n := bytes.Index([]byte(s.cs.CustID), []byte{0}) if n != -1 { custid = string([]byte(s.cs.CustID)[:n]) } else { custid = s.cs.CustID } n = bytes.Index([]byte(s.cs.AgentID), []byte{0}) if n != -1 { agentid = string([]byte(s.cs.AgentID)[:n]) } else { agentid = s.cs.AgentID } n = bytes.Index([]byte(s.cs.Station), []byte{0}) var sstation string if n != -1 { sstation = string([]byte(s.cs.Station)[:n]) } else { sstation = s.cs.Station } timei := time.Now().UnixNano() if len(s.callId) == 0 { s.callId = fmt.Sprintf("%d@%s", timei, agentid) } fmt.Println(url, "STT_FAIL", "", custid, "ICS_RCP", s.callId, s.botToken, "") processResp = icshttpclient.PostProcess(url, "STT_FAIL", "", custid, "ICS_RCP", s.callId, sstation, s.botToken, "") s.botStatus = processResp l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "processResp - %+v", processResp) ////////////////////////////////////////////////////////////////// if strings.Compare(s.botStatus.Action, "END") != 0 { fmt.Println(">>> ment", processResp.AnnounceMents) //tts pcm, ttsErr := tts.TTS(processResp.AnnounceMents, 8000) if ttsErr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "TTS Error[%s] - %s", processResp.AnnounceMents, ttsErr.GetError()) continue // s.SendVoiceGatewayBotByeSignal(url, custid, sstation) // break } else { l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "%s!!! TTS Result: [%s]%d bytes", agentname, processResp.AnnounceMents, len(pcm)) //send tts data to voice gateway r := responsecs.NewResponse(agentname, responsecs.TTS_COMMAND, responsecs.RC_SUCCESS, len(pcm)) addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port) t, wlen, werr := icsnet.SendCallSignal2(&addr, nil, r.GetData()) //wlen, werr := s.TcpConn.Write(r.GetData()) if werr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS header - %s [%+v]", werr.GetError(), s.TcpConn) continue // s.SendVoiceGatewayBotByeSignal(url, custid, sstation) // break } l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS header : %d", wlen) s.TcpConn = t wlen, werr = s.TcpConn.Write(pcm) if werr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS data - %s", werr.GetError()) continue // s.SendVoiceGatewayBotByeSignal(url, custid, sstation) // break } l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS data : %d", wlen) l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Barge-In: %s", processResp.Data.BargeIn) switch processResp.Data.BargeIn { case "Y": //s.StartSTT(wlen) s.isSTTStart = true case "N": s.StartSTT(wlen) //s.isSTTStart = false } } } else { //end fmt.Println(">>> ment", processResp.AnnounceMents) //tts pcm, ttsErr := tts.TTS(processResp.AnnounceMents, 8000) if ttsErr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "TTS Error[%s] - %s", processResp.AnnounceMents, ttsErr.GetError()) continue // s.SendVoiceGatewayBotByeSignal(url, custid, sstation) // break } else { l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "%s!!! TTS Result: [%s]%d bytes", agentname, processResp.AnnounceMents, len(pcm)) //send command BYE to voice gateway //send tts data to voice gateway r := responsecs.NewResponse(agentname, responsecs.BYE_COMMAND, responsecs.RC_SUCCESS, len(pcm)) addr := icsnet.NewNetAddrWithIPPort(conf.VGWCommandConfig.IP, conf.VGWCommandConfig.Port) t, wlen, werr := icsnet.SendCallSignal2(&addr, nil, r.GetData()) //wlen, werr := s.TcpConn.Write(r.GetData()) if werr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS header - %s [%+v]", werr.GetError(), s.TcpConn) continue // s.SendVoiceGatewayBotByeSignal(url, custid, sstation) // break } l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent BYE command header(%d)", wlen) s.TcpConn = t wlen, werr = s.TcpConn.Write(pcm) if werr != nil { l.Printf(icslog.LOG_LEVEL_ERROR, s.ID, "Failed to send TTS data - %s", werr.GetError()) continue // s.SendVoiceGatewayBotByeSignal(url, custid, sstation) // break } l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Sent TTS data : %d", wlen) l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "Barge-In: %s", processResp.Data.BargeIn) switch processResp.Data.BargeIn { case "Y": //s.StartSTT(wlen) s.isSTTStart = true case "N": s.StartSTT(wlen) //s.isSTTStart = false } } } ////////////////////////////////////////////////////////////////// *********************************/ } /* } else { //empty activity voice s.STTRx.Close() //fmt.Printf("RX fail>> %+v, %f, %+v\n", result, rms, err) //l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "RX Recog Failed(empty result)> %s-%v(%f)", err.GetMessage(), err.GetError(), rmsval) } */ } case 1: //TX uniq = fmt.Sprintf("%s-TX-", s.cs.Station) //STT //l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "%s\n%s", s.STTTx, s.STTRx) result, rmsval, err := s.STTTx.STT(voicedata) //l.Printf(icslog.LOG_LEVEL_DEBUG2, a.ID, "[%f]%+v\n", rmsval, voicedata) if err == icserror.ICSERRSTTContinue { //fmt.Printf("TX >>> %f, %s\n", rms, result) continue } else if err == icserror.ICSERRSTTOK { filename := s.STTTx.Save(uniq, conf.VoiceConfig.Path) size := s.STTTx.GetVoiceBufCur() s.STTTx.Close() //websocket //fmt.Println("TX RESULT>>>", result, rms) s.txSeq++ imsg := icsws.NewIAP() imsg.SendMessage("TX", agentname, result, s.txSeq) l.Printf(icslog.LOG_LEVEL_DEBUG2, s.ID, "Send Message: %+v", imsg) s.WSConn.Write(imsg.String()) l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "[%d]TX Recog Result> %s, PCM(%f), BufLen(%d) %s", s.goroutineID, result, rmsval, size, filename) } else if err == icserror.ICSERRSTTFail || err == icserror.ICSERRSTTFailEmpty { l.Printf(icslog.LOG_LEVEL_WARN, s.ID, "Tx STT Failed - %s", err.GetError()) if err == icserror.ICSERRSTTFail { uniq = fmt.Sprintf("%s-TX-Fail-", s.cs.Station) filename := s.STTTx.Save(uniq, conf.VoiceConfig.Path) //voice save if conf.VoiceConfig.SaveYn == "N" { l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "TX Recog Failed> %s-%v, PCM(%f)>", err.GetMessage(), err.GetError(), rmsval) } else { l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "TX Recog Failed> %s-%v, PCM(%f)> %s", err.GetMessage(), err.GetError(), rmsval, filename) } s.STTTx.Close() } else { //empty activity voice s.STTTx.Close() //fmt.Printf("TX fail>> %+v, %f, %+v\n", result, rms, err) //l.Printf(icslog.LOG_LEVEL_INFO, a.ID, "TX Recog Failed> %s-%v(%f)", err.GetMessage(), err.GetError(), rmsval) } } default: fmt.Printf("Type: %T, value: %v\n", voicedata.Type, voicedata.Type) } } //file.Close() }() wait.Wait() l.Print(icslog.LOG_LEVEL_DEBUG2, s.ID, "Stoped RecvVoice") } func (s *IcsSession) StartSTT(length int) { l := icslog.GetIcsLog() fst := float32(length/16) * 0.6 //fst := float32(wlen/16) * 0.5 stttime := int64(fst) //stttime := time.Duration(wlen / 16) fmt.Println("STT timer", time.Duration(stttime), stttime, time.Now()) l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "STT timer ", time.Duration(stttime), stttime, time.Now()) // STTStartTimer := time.NewTimer(time.Millisecond * time.Duration(stttime)) s.isSTTStartTimer = time.NewTimer(time.Millisecond * time.Duration(stttime)) //s.isSTTStartTimer = *time.NewTimer(time.Millisecond * time.Duration(wlen/16)) go func() { // <-STTStartTimer.C <-s.isSTTStartTimer.C s.isSTTStart = true // fmt.Println("STT START2", time.Now()) l.Printf(icslog.LOG_LEVEL_INFO, s.ID, "STT START2 ", time.Now()) }() }