package com.voxeo.moho.media;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.media.mscontrol.join.Joinable.Direction;
import org.apache.log4j.Logger;
import com.voxeo.moho.MixerImpl;
import com.voxeo.moho.Participant.JoinType;
import com.voxeo.moho.SignalException;
import com.voxeo.moho.State;
import com.voxeo.moho.common.event.MohoRecordCompleteEvent;
import com.voxeo.moho.common.util.SettableResultFuture;
import com.voxeo.moho.event.CallCompleteEvent;
import com.voxeo.moho.event.EventSource;
import com.voxeo.moho.event.JoinCompleteEvent;
import com.voxeo.moho.event.Observer;
import com.voxeo.moho.event.RecordCompleteEvent;
import com.voxeo.moho.sip.SipRecordingCall;
public class SIPRecordingImpl<T extends EventSource> implements Recording<T>, Observer {
private static final Logger LOG = Logger.getLogger(SIPRecordingImpl.class);
private SipRecordingCall _sipRecordingCall;
private MixerImpl _mixer;
protected SettableResultFuture<RecordCompleteEvent<T>> _future = new SettableResultFuture<RecordCompleteEvent<T>>();
protected Long startTimestamp;
protected Long pauseTimestamp;
protected Long totalPauseDuration = 0l;
protected Exception exception;
public SIPRecordingImpl(SipRecordingCall sipRecordingCall, MixerImpl mixer) {
super();
this._sipRecordingCall = sipRecordingCall;
_mixer = mixer;
_sipRecordingCall.addObserver(this);
}
public void start() {
try {
LOG.debug("SIPRecording joining siprecording call:" + _sipRecordingCall.toString());
JoinCompleteEvent joinEvent = _sipRecordingCall.join().get();
if (joinEvent.getCause() != JoinCompleteEvent.Cause.JOINED) {
throw new SignalException("Exception when starting SIPRecording.", joinEvent.getException());
}
LOG.debug("SIPRecording joining siprecording call to mixer.");
_sipRecordingCall.join(_mixer, JoinType.BRIDGE_SHARED, Direction.DUPLEX);
startTimestamp = System.currentTimeMillis();
LOG.debug("SIPRecording started.");
}
catch (InterruptedException e) {
LOG.error("Exception when starting SIPRecording.", e);
exception = e;
throw new SignalException(e);
}
catch (ExecutionException e) {
LOG.error("Exception when starting SIPRecording.", e);
exception = e;
throw new SignalException(e.getCause());
}
finally {
if (exception != null) {
_sipRecordingCall.hangup();
}
}
}
@Override
public void stop() {
LOG.debug("stopping SIPRecording, hangup siprecording call:" + _sipRecordingCall.toString());
_sipRecordingCall.hangup();
}
@Override
public boolean cancel(boolean arg0) {
return false;
}
@Override
public RecordCompleteEvent<T> get() throws InterruptedException, ExecutionException {
return _future.get();
}
@Override
public RecordCompleteEvent<T> get(long arg0, TimeUnit arg1) throws InterruptedException, ExecutionException,
TimeoutException {
return _future.get(arg0, arg1);
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return _future.isDone();
}
@Override
public void pause() {
if (pauseTimestamp != null) {
throw new IllegalStateException("Recording already paused.");
}
LOG.debug("Pausing SIPRecording: " + _sipRecordingCall.toString());
_sipRecordingCall.pauseRecording();
pauseTimestamp = System.currentTimeMillis();
}
@Override
public void resume() {
if (pauseTimestamp == null) {
throw new IllegalStateException("Recording is not paused.");
}
LOG.debug("Resuming SIPRecording: " + _sipRecordingCall.toString());
_sipRecordingCall.resumeRecording();
long pauseDuration = System.currentTimeMillis() - pauseTimestamp;
totalPauseDuration += pauseDuration;
pauseTimestamp = null;
}
@State
public void onEvent(CallCompleteEvent event) {
if (startTimestamp == null) {
recordComplete(RecordCompleteEvent.Cause.ERROR, event.getException());
}
else {
recordComplete(RecordCompleteEvent.Cause.DISCONNECT, null);
}
}
private void recordComplete(RecordCompleteEvent.Cause cause, Exception ex) {
if (_future.isDone()) {
return;
}
LOG.debug(_sipRecordingCall + " SIPRecording complete, cause:" + cause);
_mixer.setSipRecording(null);
MohoRecordCompleteEvent recordCompleteEvent = null;
if (startTimestamp != null) {
if (pauseTimestamp != null) {
long pauseDuration = System.currentTimeMillis() - pauseTimestamp;
totalPauseDuration += pauseDuration;
pauseTimestamp = null;
}
long duration = System.currentTimeMillis() - startTimestamp;
if (totalPauseDuration != null) {
duration -= totalPauseDuration;
}
recordCompleteEvent = new MohoRecordCompleteEvent(_mixer, cause, duration, this);
}
else {
recordCompleteEvent = new MohoRecordCompleteEvent(_mixer, cause, 0, ex != null ? ex : exception, this);
}
_mixer.dispatch(recordCompleteEvent);
_future.setResult(recordCompleteEvent);
}
}