package com.rayo.server.verb;
import javax.validation.ConstraintValidatorContext;
import com.rayo.server.exception.ExceptionMapper;
import com.rayo.server.validation.SsmlValidator;
import com.rayo.core.validation.ValidationException;
import com.rayo.core.verb.PauseCommand;
import com.rayo.core.verb.ResumeCommand;
import com.rayo.core.verb.Say;
import com.rayo.core.verb.SayCompleteEvent;
import com.rayo.core.verb.SayCompleteEvent.Reason;
import com.rayo.core.verb.Ssml;
import com.rayo.core.verb.VerbCommand;
import com.rayo.core.verb.VerbCompleteEvent;
import com.voxeo.logging.Loggerf;
import com.voxeo.moho.Participant;
import com.voxeo.moho.State;
import com.voxeo.moho.event.OutputCompleteEvent;
import com.voxeo.moho.media.Output;
import com.voxeo.moho.media.output.AudibleResource;
import com.voxeo.moho.media.output.OutputCommand;
import com.voxeo.moho.media.output.OutputCommand.BargeinType;
import com.voxeo.servlet.xmpp.StanzaError;
public class SayHandler extends AbstractLocalVerbHandler<Say, Participant> {
private Output<Participant> output;
private SsmlValidator ssmlValidator;
private static final Loggerf logger = Loggerf.getLogger(SayHandler.class);
// Verb Lifecycle
// ================================================================================
@Override
public void start() {
Ssml prompt = model.getPrompt();
AudibleResource audibleResource = resolveAudio(prompt);
OutputCommand outcommand = new OutputCommand(audibleResource);
outcommand.setBargeinType(BargeinType.NONE);
outcommand.setVoiceName(prompt.getVoice());
output = getMediaService().output(outcommand);
}
@Override
public boolean isStateValid(ConstraintValidatorContext context) {
if (!isReady(participant)) {
context.buildConstraintViolationWithTemplate("Call is not ready yet.")
.addNode(ExceptionMapper.toString(StanzaError.Condition.RESOURCE_CONSTRAINT))
.addConstraintViolation();
return false;
}
if (isOnHold(participant)) {
context.buildConstraintViolationWithTemplate(
"Call is currently on hold.")
.addNode(ExceptionMapper.toString(StanzaError.Condition.RESOURCE_CONSTRAINT))
.addConstraintViolation();
return false;
}
if (!canManipulateMedia()) {
context.buildConstraintViolationWithTemplate("Media operations are not allowed in the current call status.")
.addNode(ExceptionMapper.toString(StanzaError.Condition.RESOURCE_CONSTRAINT))
.addConstraintViolation();
return false;
}
return true;
}
// Commands
// ================================================================================
public void stop(boolean hangup) {
if(hangup) {
complete(new SayCompleteEvent(model, VerbCompleteEvent.Reason.HANGUP));
}
else {
if (output != null) {
output.stop();
}
}
}
@Override
public void onCommand(VerbCommand command) {
if (command instanceof PauseCommand) {
pause();
} else if (command instanceof ResumeCommand) {
resume();
}
}
@State
public void pause() {
output.pause();
}
@State
public void resume() {
output.resume();
}
// Moho Events
// ================================================================================
@State
public void onSpeakComplete(OutputCompleteEvent<Participant> event) {
if (event.getMediaOperation() != null && !event.getMediaOperation().equals(output)) {
logger.debug("Ignoring complete event as it is targeted to a different media operation");
return;
}
switch(event.getCause()) {
case BARGEIN:
case END:
complete(new SayCompleteEvent(model, Reason.SUCCESS));
break;
case DISCONNECT:
complete(new SayCompleteEvent(model, VerbCompleteEvent.Reason.HANGUP));
break;
case CANCEL:
complete(new SayCompleteEvent(model, VerbCompleteEvent.Reason.STOP));
break;
case ERROR:
case UNKNOWN:
complete(new SayCompleteEvent(model, VerbCompleteEvent.Reason.ERROR, findErrorCause(event)));
case TIMEOUT:
complete(new SayCompleteEvent(model, VerbCompleteEvent.Reason.ERROR, "Timeout"));
break;
}
}
private String findErrorCause(com.voxeo.moho.event.OutputCompleteEvent<Participant> event) {
try {
ssmlValidator.validateSsml(model.getPrompt().getText());
} catch (ValidationException ve) {
return ve.getMessage();
}
String cause = event.getErrorText();
if (cause != null) {
if (cause.startsWith("NOT_FOUND")) {
cause = "Could not find the Resource's URI";
}
} else {
cause = "Unknown cause";
}
return cause;
}
public void setSsmlValidator(SsmlValidator ssmlValidator) {
this.ssmlValidator = ssmlValidator;
}
}