package org.mobicents.ipbx.session.call.model; import java.util.EventListener; import java.util.EventObject; import java.util.HashSet; import java.util.Set; import org.ajax4jsf.event.PushEventListener; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Logger; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Out; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.Unwrap; import org.jboss.seam.core.Events; import org.jboss.seam.log.Log; import org.mobicents.ipbx.entity.CallState; import org.mobicents.ipbx.entity.User; import org.mobicents.ipbx.session.configuration.PbxConfiguration; import org.mobicents.mscontrol.MsLink; import org.mobicents.mscontrol.MsLinkMode; import org.mobicents.servlet.sip.seam.entrypoint.media.MediaController; import org.mobicents.servlet.sip.seam.entrypoint.media.MediaControllerManager; import org.mobicents.servlet.sip.seam.media.framework.IVRHelperManager; @Name("currentWorkspaceState") @Scope(ScopeType.STATELESS) @AutoCreate public class CurrentWorkspaceState { @Logger private static Log log; @In(required=false) User user; private Conference conference; private Set<Conference> conferences; //using a global push listener instead of 3 listener because browsers can't handle more than 2 simulteanous connections @In(required=false, scope=ScopeType.SESSION) @Out(required=false, scope=ScopeType.SESSION) private Set<PushEventListener> globalListeners = new HashSet<PushEventListener>(); private HashSet<CallParticipant> incomingCalls = new HashSet<CallParticipant>(); private HashSet<CallParticipant> ongoingCalls = new HashSet<CallParticipant>(); private HashSet<CallParticipant> outgoingCalls = new HashSet<CallParticipant>(); public CallParticipant[] getIncomingCalls() { return incomingCalls.toArray(new CallParticipant[]{}); } public CallParticipant[] getOngoingCalls() { return ongoingCalls.toArray(new CallParticipant[]{}); } public CallParticipant[] getOutgoingCalls() { return outgoingCalls.toArray(new CallParticipant[]{}); } @Unwrap public CurrentWorkspaceState getState() { if(user == null) { return null; } CurrentWorkspaceState cus = WorkspaceStateManager.instance().getWorkspace(user.getName()); return cus; } public void endCall(CallParticipant participant) { endCall(participant, true); } public void endCall(CallParticipant participant, boolean sendBye) { endCall(participant, sendBye, true); } // Ends a call with another participant while keeping everyone else in the conf public void endCall(CallParticipant participant, boolean sendBye, boolean disconnectOthers) { try { removeCall(participant); Conference conf = participant.getConference(); // Already closed by someone if(conf == null) return; CallParticipant[] ps = conf.getParticipants(); for(CallParticipant cp : ps) { if(cp.getName() != null) { WorkspaceStateManager.instance().getWorkspace(cp.getName()).removeCall(participant); } } participant.setConference(null); participant.setCallState(CallState.DISCONNECTED); if(sendBye) { participant.getInitialRequest().getSession().createRequest("BYE").send(); } participant.setInitialRequest(null); // If there is only one other participant, attempt to disconnect him if(ps.length == 1 && disconnectOthers) { try { CallParticipant other = ps[0]; String name = other.getName(); // We can't use the injected callmanager here for some reason !! TODO: FIXME CurrentWorkspaceState cus = WorkspaceStateManager.instance().getWorkspace(name); try { cus.endCall(other, true); } catch (Exception e) {} try { other.getInitialRequest().createCancel().send(); } catch (Exception e) {} } catch (Exception e) { e=e; } } if(participant.getMsLink() != null) { participant.getMsLink().release(); } if(participant.getMsConnection() != null) { participant.getMsConnection().release(); } } catch (Exception e) { //e.printStackTrace(); } } // Mute an active participant public void mute(CallParticipant participant) { participant.setMuted(true); participant.getMsLink().setMode(MsLinkMode.HALF_DUPLEX); String ann = PbxConfiguration.getProperty("pbx.default.muted.announcement"); IVRHelperManager.instance().getIVRHelper(participant.getSipSession()).playAnnouncementWithDtmf(ann); } // Unmute an active participant public void unmute(CallParticipant participant) { participant.setMuted(false); participant.getMsLink().setMode(MsLinkMode.FULL_DUPLEX); String ann = PbxConfiguration.getProperty("pbx.default.unmuted.announcement"); IVRHelperManager.instance().getIVRHelper(participant.getSipSession()).playAnnouncementWithDtmf(ann); } // Put on-hold an active participant public void putOnhold(CallParticipant participant) { if(!participant.isOnhold()) { participant.setOnhold(true); participant.getMsLink().setMode(MsLinkMode.HALF_DUPLEX); makeStatusDirty(); String ann = PbxConfiguration.getProperty("pbx.default.onhold.announcement"); IVRHelperManager.instance().getIVRHelper(participant.getSipSession()).playAnnouncementWithDtmf(ann); Events.instance().raiseEvent("onHold", participant); } } // Restore user from on-hold as active participant public void unputOnhold(CallParticipant participant) { if(participant.isOnhold()) { participant.setOnhold(false); participant.getMsLink().setMode(MsLinkMode.FULL_DUPLEX); IVRHelperManager.instance().getIVRHelper(participant.getSipSession()).endAll(); IVRHelperManager.instance().getIVRHelper(participant.getSipSession()).detectDtmf(); makeStatusDirty(); Events.instance().raiseEvent("unonHold", participant); } } // Cancel an outgoing call public void cancel(CallParticipant participant) { try { endCall(participant); } catch (Exception e) {} } // Simply removed a call from the GUI, sip/media release is done elsewhere public void removeCall(CallParticipant participant) { log.info("Removing " + participant.getUri() + " from " + user); incomingCalls.remove(participant); outgoingCalls.remove(participant); ongoingCalls.remove(participant); makeStatusDirty(); } // Reject an incoming call public void reject(CallParticipant participant) { endCall(participant, true); // TODO: analyze who is that guy calling and cancel it } // Join a user in the conference public void join(CallParticipant participant) { MediaController mediaController = MediaControllerManager.instance().getMediaController(participant.getSipSession()); MsLink link = mediaController.createLink(MsLinkMode.FULL_DUPLEX); Conference conf = getConference(); link.join(participant.getPrEndpoint().getLocalName(), conf.getEndpointName()); conf.addParticipant(participant); for(CallParticipant cp:conf.getParticipants(CallState.INCALL)) { CurrentWorkspaceState cws = WorkspaceStateManager.instance() .getWorkspace(cp.getName()); cws.setOngoing(cp); } } // Update the UI when a call is active public void setOngoing(CallParticipant participant) { incomingCalls.remove(participant); outgoingCalls.remove(participant); ongoingCalls.add(participant); this.conference = participant.getConference(); makeStatusDirty(); } // Update the UI when there is an incoming call public void setIncoming(CallParticipant participant) { incomingCalls.add(participant); this.conference = participant.getConference(); makeStatusDirty(); } // Update the UI for outgoing call public void setOutgoing(CallParticipant participant) { outgoingCalls.add(participant); this.conference = participant.getConference(); makeStatusDirty(); } // These methods are about what is the status of the calls now public boolean hasOngoingCalls() { return ongoingCalls.size() > 0; } public boolean hasIncomingCalls() { return incomingCalls.size() > 0; } public boolean hasOutgoingCalls() { return outgoingCalls.size() > 0; } public boolean anythingGoingOn() { return hasOngoingCalls() || hasOutgoingCalls() || hasIncomingCalls(); } public void makeStatusDirty() { for(final PushEventListener globalListener : this.globalListeners) { new Thread() { public void run() { globalListener.onEvent(new EventObject(this)); }}.start(); } } public void makeHistoryDirty() { for(final PushEventListener globalListener : this.globalListeners) { new Thread() { public void run() { // Why new thread? Coz this thread will propage the current identity to all other users in the call LOL. globalListener.onEvent(new EventObject(this)); }}.start(); } } public void makeRegistrationsDirty() { for(final PushEventListener globalListener : this.globalListeners) { new Thread() { public void run() { // Why new thread? Coz this thread will propage the current identity to all other users in the call LOL. globalListener.onEvent(new EventObject(this)); }}.start(); } } public void addGlobalListener(EventListener listener) { this.globalListeners.add((PushEventListener) listener); } public Conference getConference() { return conference; } public void setConference(Conference conference) { this.conference = conference; } public void makeChatDirty() { for(final PushEventListener globalListener : this.globalListeners) { new Thread() { public void run() { // Why new thread? Coz this thread will propage the current identity to all other users in the call LOL. globalListener.onEvent(new EventObject(this)); }}.start(); } } }