private int iterationResult; // Stores result of iteration #endregion Fields #region Constructors /// <summary> /// Class constructor /// </summary> /// <param name="_iterationResult"></param> /// <param name="_category"></param> /// <param name="_callerData"></param> /// <param name="_calleeData"></param> /// <param name="_spResult"></param> private IterationResult(int _iterationResult, CallerIterationInfo _callerData, CalleeIterationInfo _calleeData, SpeechRecognizerResult _callerSpResult, SpeechRecognizerResult _calleeSpResult) { iterationResult = _iterationResult; callerData = _callerData; calleeData = _calleeData; callerSpeechResult = _callerSpResult; calleeSpeechResult = _calleeSpResult; audioPowerResult = AudioVolume.NOT_ATTENUATED; audioVolConf = AudioVolumeConfidence.GOOD_CONFIDENCE; // determine the classification (category) for IterationResult if (iterationResult == ValidationErrors.NO_ERROR) category = TestIterationCategory.PASSED; else if (conditionExists(iterationResult, ValidationErrors.FAILED_CALL) || conditionExists(iterationResult, ValidationErrors.MISSING_HANGUP) || conditionExists(iterationResult, ValidationErrors.ECHO_DETECTED) || conditionExists(iterationResult, ValidationErrors.CALLER_NOISE_DETECTED) || conditionExists(iterationResult, ValidationErrors.CALLEE_NOISE_DETECTED) || conditionExists(iterationResult, ValidationErrors.CALLEE_NOT_HEARD) || conditionExists(iterationResult, ValidationErrors.CALLER_NOT_HEARD)) category = TestIterationCategory.FAILED; //if(iterationResult == ValidationErrors.FAILED_CALL || iterationResult == ValidationErrors.NOISE_DETECTED || iterationResult == ValidationErrors.ECHO_DETECTED) // category = TestIterationCategory.FAILED; else { // Use invalid for all others errors such as callee could not play prompt, execution error etc category = TestIterationCategory.INVALID; } }
/// <summary> /// Method that applies various validation rules to interpret the result of the iteration /// </summary> /// <param name="callerInfo"></param> /// <param name="calleeInfo"></param> /// <returns></returns> public IterationResult applyValidationRules(CallerIterationInfo callerInfo, CalleeIterationInfo calleeInfo) { IterationResult result = null; SpeechRecognizerResult callerSpeechResult = null; SpeechRecognizerResult calleeSpeechResult = null; callerData = callerInfo; calleeData = calleeInfo; int hangupRuleOutcome = ValidationErrors.NO_ERROR; int timestampRuleOutcome = ValidationErrors.NO_ERROR; int latencyRuleResult = ValidationErrors.NO_ERROR; int speechRecoRuleResult = ValidationErrors.NO_ERROR; NextRule rule = NextRule.None; // First rule - check if call was completed end to end between caller and callee. // If not, fail the iteration and return the result if (applyCallFailureValidationRule() == ValidationErrors.FAILED_CALL) { result = IterationResult.getInstance(ValidationErrors.FAILED_CALL, callerData, calleeData, null, null); return result; } hangupRuleOutcome = applyHangupValidationRule(); timestampRuleOutcome = applyTimeStampValidationRule(out rule); // Next apply timestamp validation rule and if we encounter a failure in that, and, we find that we don't need // to apply another rule, return result. if (rule == NextRule.None) { result = IterationResult.getInstance(hangupRuleOutcome | timestampRuleOutcome, callerData, calleeData, null, null); return result; } latencyRuleResult = applyLatencyValidationRule(); speechRecoRuleResult = applySpeechRecognitionRule(out calleeSpeechResult, out callerSpeechResult); result = IterationResult.getInstance(hangupRuleOutcome | timestampRuleOutcome | latencyRuleResult | speechRecoRuleResult, callerData, calleeData, callerSpeechResult, calleeSpeechResult); return result; }
/// <summary> /// Method to create an instance of IterationResult. /// </summary> /// <param name="_iterationResult"></param> /// <param name="_category"></param> /// <param name="_callerData"></param> /// <param name="_calleeData"></param> /// <param name="_spResult"></param> /// <returns></returns> public static IterationResult getInstance(int _iterationResult, CallerIterationInfo _callerData, CalleeIterationInfo _calleeData, SpeechRecognizerResult _callerSpResult, SpeechRecognizerResult _calleeSpResult) { try { return new IterationResult(_iterationResult, _callerData, _calleeData, _callerSpResult, _calleeSpResult); } catch (Exception e) { return null; } }
/// <summary> /// Method that places a call to the callee and sets caller state to dialing /// <returns>true if call has been attempted, false otherwise</returns> /// </summary> public bool placeCall() { int nextCallIter; // Local temp variable /** * Place a call only if no other call was in progress and caller is ready. */ CurrentState localState = getState(); if (localState == CurrentState.READY) { lock (this) { numRemainingIter--; nextCallIter = ++numCallsPlaced; } conn = null; /** * Create a new instance of caller iteration info while attempting to place a call. */ callerData = null; callerData = new CallerIterationInfo(); display("Starting iteration " + nextCallIter); phone.MakeCall("SIP:" + inputParam.remoteExtension + "@" + inputParam.sipServerIP); // Store the current time callerData.makeCallMethodTime = DateTime.Now; setState(CurrentState.DIALING); return true; } else return false; }
/// <summary> /// This method is fired when call is hungup. /// </summary> /// <param name="sender"></param> /// <param name="args"></param> void phone_ConnectionCleared(object sender, ConnectionClearedEventArgs args) { DateTime callReleaseTimeStamp = DateTime.Now; Connection droppedConn = args.DroppedConnection; /** * If connection cleared was received in response to active or dialing connection, take appropriate action * or else do nothing. */ if (conn != null && conn.Equals(droppedConn) == true) { conn = args.DroppedConnection; // Store the timestamp when call was disconnected with callerData callerData.callReleaseTime = callReleaseTimeStamp; // Disable all timers to prevent them from accidentally firing in next iteration callDurationTimer.Enabled = false; bargeTimer.Enabled = false; try { if (ll != null) ll.Stop(); if (recorder != null) recorder.Stop(); } catch (Exception e) { Trace.TraceError("Exception in phone_ConnectionCleared. Message: " + e.Message + "Current time = " + DateTime.Now + "\r\nStack Trace : \r\n" + e.StackTrace, "Warning"); } // After processing a connection cleared, send the notification of call state for the caller to the observer. // Make sure to set the callerData to null - this is a safety mechanism to prevent same iteration being logged // multiple times (if multiple connection cleared) are received in response to makecall if (OnIterationCompleted != null && callerData != null) { OnIterationCompleted(this, callerData); callerData = null; } int temp; lock (this) { temp = numRemainingIter; } if (temp > 0) { setState(CurrentState.READY); display("Enabling inter-call wait timer"); // Start the timer to place the next call interCallTimer.Enabled = true; } else { setState(CurrentState.EXECUTION_COMPLETED); } } else { /** * If connection cleared was ignored, print out the time that happened, and also the reason. * If conn was null say that. If conn was not equivalent to dropped connection, say that, otherwise * set the reason as "Unknown". */ StringBuilder message = new StringBuilder(); message.Append("Ignoring connection cleared event at time = " + DateTime.Now + " Reason: "); if (conn == null) { message.Append("Preserved connection was null"); } else { message.Append("Preserved connection is not equivalent to dropped connection"); } display(message.ToString()); } }
/// <summary> /// Method that reads the corresponding callee and caller log files and finds out which lines of caller /// and callee belong to same call and processes them /// </summary> public void generateResults() { string callerLine; string calleeLine; CallerIterationInfo callerInfo = null; // Caller's iteration info CalleeIterationInfo calleeInfo = null; // Callee's iteration info int returnCode; bool calleeFileEmpty = false; while (true) { // If callerInfo is null, read the next line and create a callerInfo from it. // If callerFile is empty or exception in creating callerInfo, break. if (callerInfo == null) { callerLine = callerFileReader.ReadLine(); currentCallerLineNum++; if (callerLine == null) { break; } else { try { callerInfo = new CallerIterationInfo(callerLine); } catch(Exception e) { Console.WriteLine("Error in Analyer.generateResults. Could not create CallerIterationInfo instance. Terminating reading of input logs"); Trace.TraceError("Exception while creating callerInfo: " + e.Message + "\r\nStack Trace : " + e.StackTrace); break; } } } // If calleeInfo is null, read the next line and create a calleeInfo from it. // If calleeFile is empty then create a dummy callee object. Exception in creating calleeInfo, break. if (calleeInfo == null) { calleeLine = calleeFileReader.ReadLine(); currentCalleeLineNum++; if (calleeLine == null) { calleeFileEmpty = true; calleeInfo = new CalleeIterationInfo(); } else { try { calleeInfo = new CalleeIterationInfo(calleeLine); } catch(Exception e2) { Console.WriteLine("Error in Analyer.generateResults. Could not create CalleeIterationInfo instance. Terminating reading of input logs"); Trace.TraceError("Exception while creating calleeInfo: " + e2.Message + "\r\nStack Trace : " + e2.StackTrace); break; } } } if (!calleeFileEmpty) { returnCode = causalOrderBetweenCallerAndCallee(callerInfo, calleeInfo); switch (returnCode) { case 0: // both belong to same call case -3: // both have uninitialized connect timestamps processTokens(callerInfo, calleeInfo, true); callerInfo = null; calleeInfo = null; break; case 1: // caller's current call after callee's call case -2: // callee's current call had uninitialized connection timestamp // discard calleeInfo as it could not be matched with caller // continue to store callerInfo calleeInfo = null; break; case 2: // callee's current call after caller's call case -1: // caller's current call had uninitialized conneciton timestamp // processTokens with callerInfo and dummy calleeInfo // and discard callerInfo processTokens(callerInfo, new CalleeIterationInfo(), false); callerInfo = null; break; } } else { processTokens(callerInfo, new CalleeIterationInfo(), false); callerInfo = null; } } aggResult.displayResult(resultDir + "\\GatewayTestResults.txt"); }
/// <summary> /// Private method that applies the token validation rules and generates iteration result instances /// </summary> /// <param name="callerInfo"></param> /// <param name="calleeInfo"></param> private void processTokens(CallerIterationInfo callerInfo, CalleeIterationInfo calleeInfo, bool matchRecordedWav) { IterationResult result = null; /** * If the current objects indeed belong to a same call, we can locate corresponding wav files and rename them * to ensure that the file from caller and the callee can be correlated. */ if (matchRecordedWav == true) { string callerFile = resultDir + "\\Caller_RecordedWav_" + currentCallerLineNum + ".wav"; string calleeFile = resultDir + "\\Callee_RecordedWav_" + currentCalleeLineNum + ".wav"; string newCallerFile = resultDir + "\\Caller_RecordedWav_" + currentCallerLineNum + "_matched.wav"; string newCalleeFile = resultDir + "\\Callee_RecordedWav_" + currentCallerLineNum + "_matched.wav"; try { if (File.Exists(callerFile) && File.Exists(calleeFile)) { File.Move(callerFile, newCallerFile); File.Move(calleeFile, newCalleeFile); } } catch (Exception e) { Console.WriteLine("Exception encountered in matching " + callerFile + " with " + calleeFile + ". Message:\n" + e.Message); Trace.TraceError("Exception occurred. Message : " + e.Message + "\r\nStack Trace : " + e.StackTrace); } } result = ri.applyValidationRules(callerInfo, calleeInfo); Console.WriteLine("\nIteration = " + ++iterationNum + "\n" + result.ToString()); aggResult.addIterationResult(result); }
/// <summary> /// Method to determine causal ordering between caller and callee's current call /// </summary> /// <param name="callerInfo"></param> /// <param name="calleeInfo"></param> /// <returns></returns> private int causalOrderBetweenCallerAndCallee(CallerIterationInfo callerInfo, CalleeIterationInfo calleeInfo) { DateTime uninitDate = new DateTime(); // Uninitialized date int result = -1; /** * If either caller or callee did not have valid connection time, return -1 to indicate that no matching is possible * with this caller callee pair */ if (callerInfo.callConnectTime == uninitDate && calleeInfo.callConnectTime == uninitDate) { return -3; } else if(callerInfo.callConnectTime == uninitDate) { result = -1; } else if (calleeInfo.callConnectTime == uninitDate) { result = -2; } else if ((callerInfo.callConnectTime <= calleeInfo.callConnectTime && calleeInfo.callConnectTime < callerInfo.callReleaseTime) || (calleeInfo.callConnectTime <= callerInfo.callConnectTime && callerInfo.callConnectTime < calleeInfo.callReleaseTime)) { /** * If caller and callee belong to same call return 0 */ result = 0; } else if (calleeInfo.callConnectTime >= callerInfo.callReleaseTime) { /** * If callee's current call is causally after caller's current call, return 2. */ result = 2; } else if (calleeInfo.callReleaseTime <= callerInfo.callConnectTime) { /** * If caller's current call is causally before caller's current call, return 2 */ result = 1; } return result; }
private WavFileInfo wInfo; // WavFileInfo instance #endregion Fields #region Constructors /// <summary> /// Class constructor /// </summary> public ResultInterpreter(WavFileInfo _wInfo) { wInfo = _wInfo; callerData = null; calleeData = null; }