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.

906 lines
32 KiB
Go

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