package com.voxeo.moho.sip;
import javax.media.mscontrol.MediaEventListener;
import javax.media.mscontrol.MsControlException;
import javax.media.mscontrol.MsControlFactory;
import javax.media.mscontrol.join.Joinable;
import javax.media.mscontrol.join.Joinable.Direction;
import javax.media.mscontrol.networkconnection.NetworkConnection;
import javax.media.mscontrol.networkconnection.SdpPortManagerEvent;
import org.apache.log4j.Logger;
import com.voxeo.moho.ApplicationContext;
import com.voxeo.moho.ApplicationContextImpl;
import com.voxeo.moho.Call;
import com.voxeo.moho.CallImpl;
import com.voxeo.moho.NegotiateException;
import com.voxeo.moho.Participant;
import com.voxeo.moho.Participant.JoinType;
import com.voxeo.moho.ParticipantContainer;
import com.voxeo.moho.common.event.MohoJoinCompleteEvent;
import com.voxeo.moho.event.JoinCompleteEvent;
import com.voxeo.moho.event.JoinCompleteEvent.Cause;
import com.voxeo.moho.remotejoin.RemoteParticipant;
public class LocalRemoteJoinDelegate extends JoinDelegate implements MediaEventListener<SdpPortManagerEvent> {
private static final Logger LOG = Logger.getLogger(LocalRemoteJoinDelegate.class);
protected Participant _localParticipant;
protected RemoteParticipantImpl _remoteParticipant;
protected boolean waitAnswerProcessed;
protected boolean notifyRemote;
protected boolean started;
public LocalRemoteJoinDelegate(final Participant local, final RemoteParticipant remoteParticipant,
final Direction direction) {
_localParticipant = local;
_remoteParticipant = (RemoteParticipantImpl) remoteParticipant;
_direction = direction;
_joinType = JoinType.BRIDGE;
}
@Override
public void doJoin() throws Exception {
LOG.debug("LocalRemoteJoinDelegate is starting");
if (!started) {
_remoteParticipant.startJoin(_localParticipant, this);
((ParticipantContainer) _localParticipant).startJoin(_remoteParticipant, this);
}
started = true;
if(_localParticipant instanceof Call){
doDisengage((SIPCallImpl)_localParticipant, JoinType.BRIDGE);
}
if (_localParticipant.getMediaObject() == null && _localParticipant instanceof Call) {
((Call) _localParticipant).join(Direction.DUPLEX);
return;
}
// 1 create network connection
this.createNetworkConnection(_localParticipant.getApplicationContext(), _remoteParticipant);
// 2 join network connection
((Joinable) _localParticipant.getMediaObject()).join(_direction, _remoteParticipant.getNetworkConnection());
// generate sdp offer.
_remoteParticipant.getNetworkConnection().getSdpPortManager().generateSdpOffer();
}
@Override
public void onEvent(SdpPortManagerEvent event) {
LOG.debug("LocalRemoteJoinDelegate received SdpPortManagerEvent");
if (event.getEventType().equals(SdpPortManagerEvent.OFFER_GENERATED)) {
if (event.isSuccessful()) {
waitAnswerProcessed = true;
final byte[] sdp = event.getMediaServerSdp();
try {
((ApplicationContextImpl) _remoteParticipant.getApplicationContext()).getRemoteCommunication().join(
_localParticipant.getId(), _remoteParticipant.getId(), _joinType, sdp);
}
catch (final Exception e) {
LOG.error("", e);
done(Cause.ERROR, e);
}
}
else {
Exception ex = new NegotiateException(event);
done(Cause.ERROR, ex);
}
}
else if (event.getEventType().equals(SdpPortManagerEvent.ANSWER_PROCESSED)) {
if (event.isSuccessful()) {
if (waitAnswerProcessed) {
notifyRemote = true;
done(JoinCompleteEvent.Cause.JOINED, null);
return;
}
}
Exception ex = new NegotiateException(event);
notifyRemote = true;
done(Cause.ERROR, ex);
}
}
public void remoteJoinAnswer(byte[] sdp) throws Exception {
try {
_remoteParticipant.getNetworkConnection().getSdpPortManager().processSdpAnswer(sdp);
}
catch (Exception e) {
LOG.error("Error when doing remote join:" + e.getMessage(), e);
done(Cause.ERROR, e);
throw e;
}
}
protected synchronized void createNetworkConnection(ApplicationContext context,
RemoteParticipantImpl remoteParticipant) throws MsControlException {
MsControlFactory mf = context.getMSFactory();
remoteParticipant.setMediaSession(mf.createMediaSession());
NetworkConnection network = remoteParticipant.getMediaSession().createNetworkConnection(NetworkConnection.BASIC,
null);
remoteParticipant.setNetworkConnection(network);
network.getSdpPortManager().addListener(this);
}
@Override
public synchronized void done(final Cause cause, Exception exception) {
if (done) {
return;
}
_cause = cause;
_exception = exception;
((ParticipantContainer) _localParticipant).joinDone(_remoteParticipant, this);
JoinCompleteEvent joinCompleteEvent = new MohoJoinCompleteEvent(_localParticipant, _remoteParticipant, cause,
exception, true);
if (cause == Cause.JOINED) {
((ParticipantContainer) _localParticipant).addParticipant(_remoteParticipant, _joinType, _direction, null);
}
_remoteParticipant.joinDone(notifyRemote);
_settableJoint.done(joinCompleteEvent);
_localParticipant.dispatch(joinCompleteEvent);
done = true;
}
}