/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * * Large portions of this software are based upon public domain software * https://sip-communicator.dev.java.net/ * *//* * SipProvider.java * * Created on November 18, 2003, 2:18 PM */ package net.sourceforge.gjtapi.raw.sipprovider; import java.io.IOException; import java.io.InputStream; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Properties; import javax.telephony.ConnectionEvent; import javax.telephony.Event; import javax.telephony.InvalidArgumentException; import javax.telephony.InvalidPartyException; import javax.telephony.MethodNotSupportedException; import javax.telephony.PrivilegeViolationException; import javax.telephony.ResourceUnavailableException; import javax.telephony.media.MediaResourceException; import net.sourceforge.gjtapi.CallId; import net.sourceforge.gjtapi.RawStateException; import net.sourceforge.gjtapi.ResourceFinder; import net.sourceforge.gjtapi.TermData; import net.sourceforge.gjtapi.raw.sipprovider.common.Console; import net.sourceforge.gjtapi.raw.sipprovider.common.NetworkAddressManager; import net.sourceforge.gjtapi.raw.sipprovider.media.MediaException; import net.sourceforge.gjtapi.raw.sipprovider.media.MediaManager; import net.sourceforge.gjtapi.raw.sipprovider.media.event.MediaErrorEvent; import net.sourceforge.gjtapi.raw.sipprovider.media.event.MediaEvent; import net.sourceforge.gjtapi.raw.sipprovider.media.event.MediaListener; import net.sourceforge.gjtapi.raw.sipprovider.sip.CommunicationsException; import net.sourceforge.gjtapi.raw.sipprovider.sip.SipManager; import net.sourceforge.gjtapi.raw.sipprovider.sip.event.CallRejectedEvent; import net.sourceforge.gjtapi.raw.sipprovider.sip.event.CallStateEvent; import net.sourceforge.gjtapi.raw.sipprovider.sip.event.CommunicationsErrorEvent; import net.sourceforge.gjtapi.raw.sipprovider.sip.event.CommunicationsListener; import net.sourceforge.gjtapi.raw.sipprovider.sip.event.MessageEvent; import net.sourceforge.gjtapi.raw.sipprovider.sip.event.RegistrationEvent; import net.sourceforge.gjtapi.raw.sipprovider.sip.event.UnknownMessageEvent; import net.sourceforge.gjtapi.raw.sipprovider.sip.security.SecurityAuthority; import net.sourceforge.gjtapi.raw.sipprovider.sip.security.UserCredentials; // import com.sun.jndi.cosnaming.IiopUrl.Address; /** * * @author root */ public class SipPhone implements MediaListener, CommunicationsListener, SecurityAuthority, net.sourceforge.gjtapi.raw.sipprovider.sip.event.CallListener { private static Console console = Console.getConsole(SipPhone.class); private TermData terminal; protected MediaManager mediaManager; protected SipManager sipManager; private final Collection ids; private final String address; private final SipProvider sipProvider; private final String password; private final Map settings; /** * Constructs a new object. * * @param propResource * Name of the resource containing properties for this phone * @param finder * utility to resolve resource * @param sipProvider * the provider * @throws IOException * Error loading the properties. */ public SipPhone(String propResource, ResourceFinder finder, SipProvider sipProvider, NetworkAddressManager manager) throws IOException { Properties sipProp = new Properties(); InputStream in = null; try { in = finder.findResource(propResource); sipProp.load(in); } finally { if (in != null) { in.close(); } } settings = new java.util.HashMap(); settings.putAll(sipProp); password = sipProp.getProperty ("net.java.sip.communicator.sip.PASSWORD"); ids = new java.util.ArrayList(); mediaManager = new MediaManager(sipProp, manager); this.sipProvider = sipProvider; sipManager = new SipManager(sipProp, manager); this.launch(); address = "sip:" + sipManager.getLocalUser() + "@" + sipManager.getLocalHostAddress(); } public String getAddress() { return address; } // sip call control // section------------------------------------------------------------------------- public void createCall(CallId id, String address, String term, String dest) throws ResourceUnavailableException, PrivilegeViolationException, InvalidPartyException, InvalidArgumentException, RawStateException, MethodNotSupportedException { console.logEntry(); console.debug("id = " + id); try { console.debug("trentative de connection a " + address); // CREATION D'UN CALL (SIP) net.sourceforge.gjtapi.raw.sipprovider.sip.Call call = sipManager .establishCall(dest, mediaManager.generateSdpDescription()); SipCallId sipCallId = (SipCallId) (id); sipCallId.setSipId(call.getID()); call.setCallId(sipCallId); // hook the call up to it's id ids.add(new ListIdElement(id, call.getID(), term, dest)); call.addStateChangeListener(this); } catch (net.sourceforge.gjtapi.raw.sipprovider.media.MediaException ex) { console.debug(ex.toString()); } catch (net.sourceforge.gjtapi.raw.sipprovider.sip.CommunicationsException ex) { console.debug(ex.toString()); } } public void answerCall(CallId callId, String address, String term) throws ResourceUnavailableException, PrivilegeViolationException, RawStateException, MethodNotSupportedException { console.logEntry(); try { ListIdElement listId = this.getElementIdListByJtapiId(callId); sipManager.answerCall(listId.getSipId(), mediaManager .generateSdpDescription()); } catch (net.sourceforge.gjtapi.raw.sipprovider.media.MediaException ex) { console.debug(ex.toString()); } catch (net.sourceforge.gjtapi.raw.sipprovider.sip.CommunicationsException ex) { console.debug(ex.toString()); } } public void sipHangup(CallId callId) { try { console.logEntry(); ListIdElement lI = this.getElementIdListByJtapiId(callId); sipManager.endCall(lI.getSipId()); } catch (CommunicationsException exc) { console.warn("Could not properly terminate call!\n" + "(This is not a fatal error)", exc); } finally { console.logExit(); } } // ======================= CALL LISTENER ============================== // callback du sipManager public void callStateChanged(CallStateEvent evt) { console.logEntry(); final String oldState = evt.getOldState(); final String newState = evt.getNewState(); if (console.isDebugEnabled()) { console.debug("new state: " + newState + ", old state: " + oldState); } try { net.sourceforge.gjtapi.raw.sipprovider.sip.Call call = evt .getSourceCall(); int sipId = evt.getSourceCall().getID(); ListIdElement el = getElementIdListBySipId(sipId); if (newState == net.sourceforge.gjtapi.raw.sipprovider.sip.Call.ALERTING) { if (console.isDebugEnabled()) { console.debug("remote address = " + el.getAddress()); } sipProvider.sipTerminalConnectionRinging(el.getJtapiId(), el .getAddress(), el.getTerminal(), ConnectionEvent.CAUSE_NORMAL); sipProvider.sipConnectionInProgress(el.getJtapiId(), el .getAddress(), Event.CAUSE_NORMAL); sipProvider.sipConnectionAlerting(el.getJtapiId(), el .getAddress(), ConnectionEvent.CAUSE_NORMAL); } if (newState == net.sourceforge.gjtapi.raw.sipprovider.sip.Call.RINGING) { if (oldState == net.sourceforge.gjtapi.raw.sipprovider.sip.Call.DIALING) { console.debug("remote address = " + el.getAddress()); sipProvider.sipTerminalConnectionCreated(el.getJtapiId(), el.getAddress(), "remote", ConnectionEvent.CAUSE_NORMAL); sipProvider.sipConnectionInProgress(el.getJtapiId(), el .getAddress(), Event.CAUSE_NORMAL); sipProvider.sipConnectionAlerting(el.getJtapiId(), el .getAddress(), ConnectionEvent.CAUSE_NORMAL); } } if (newState == net.sourceforge.gjtapi.raw.sipprovider.sip.Call.CONNECTED) { console.debug("connected"); // sipProvider.sipConnectionConnected(el.getJtapiId(), // el.getAddress(), ConnectionEvent.CAUSE_NORMAL); sipProvider.sipConnectionConnected(el.getJtapiId(), el .getAddress(), ConnectionEvent.CAUSE_NORMAL); sipProvider.sipCallActive(el.getJtapiId(), Event.CAUSE_NORMAL); try { final String sdp = call.getRemoteSdpDescription(); mediaManager.openMediaStreams(sdp); } catch (net.sourceforge.gjtapi.raw.sipprovider.media.MediaException ex) { console.warn(ex.toString(), ex); } } else if (newState == net.sourceforge.gjtapi.raw.sipprovider.sip.Call.DISCONNECTED) { console.debug("disconnected"); // listener.connectionSuspended(el.getJtapiId(), // el.getAddress(), ConnectionEvent.CAUSE_NORMAL); try { if (call.getRemoteSdpDescription() != null) { mediaManager.closeStreams(call .getRemoteSdpDescription()); } } catch (MediaException ex) { console.error( "The following exception occurred while trying to open media connection:\n" + ex.getMessage(), ex); } console.debug("disconnected " + call.getRemoteName()); sipProvider.sipConnectionDisconnected(el.getJtapiId(), el .getAddress(), ConnectionEvent.CAUSE_NORMAL); } } finally { console.logExit(); } } public void messageReceived(MessageEvent evt) { /* * try { console.logEntry(); String fromAddress = evt.getFromAddress(); * String fromName = evt.getFromName(); String messageBody = * evt.getBody(); console.showDetailedMsg( "Incoming MESSAGE", "You * received a MESSAGE\n" + "From: " + fromName + "\n" + "Address: " + * fromAddress + "\n" + "Message: " + messageBody + "\n"); } finally { * console.logExit(); } */ } public void nonFatalMediaErrorOccurred(MediaErrorEvent evt) { console.logEntry(); } /** * Returns a Credentials object associated with the specified realm. * * @param realm * The realm that the credentials are needed for. * @param defaultValues * the values to propose the user by default * @return The credentials associated with the specified realm or null if * none could be provided. * */ public UserCredentials obtainCredentials(String realm, UserCredentials defaultValues) { console.logEntry(); console.debug("Retrieving credentials"); UserCredentials credentials = new UserCredentials(); credentials.setUserName(defaultValues.getUserName()); char[] pass; if (password == null) { console.debug("Phone without password", new Throwable( "verify file properties of the phone")); pass = new char[0]; } else { pass = password.toCharArray(); } credentials.setPassword(pass); console.logExit(); return credentials; } public void playerStarting(MediaEvent evt) { console.logEntry(); } public void playerStopped() { console.logEntry(); } public void receivedUnknownMessage(UnknownMessageEvent evt) { console.logEntry(); } public void registered(RegistrationEvent evt) { console.logEntry(); } public void registering(RegistrationEvent evt) { } public void callReceived( net.sourceforge.gjtapi.raw.sipprovider.sip.event.CallEvent evt) { console.logEntry(); // register as a listener on the call net.sourceforge.gjtapi.raw.sipprovider.sip.Call call = evt .getSourceCall(); CallId callId = call.getCallId(); SipCallId sipCallId = (SipCallId) (callId); sipCallId.setSipId(call.getID()); call.setCallId(sipCallId); // hook the call up to it's id ids.add(new ListIdElement(callId, call.getID(), this.terminal.terminal, this.address)); evt.getSourceCall().addStateChangeListener(this); } public void callRejectedLocally(CallRejectedEvent evt) { console.logEntry(); } public void callRejectedRemotely(CallRejectedEvent evt) { console.logEntry(); } public void communicationsErrorOccurred(CommunicationsErrorEvent evt) { console.logEntry(); } public void unregistered(RegistrationEvent evt) { console.logEntry(); } // init methode // section--------------------------------------------------------------- public void launch() { try { console.logEntry(); // mode = PHONE_MODE; try { mediaManager.start(); } catch (MediaException exc) { console.error("Failed to start mediaManager", exc); } mediaManager.addMediaListener(this); sipManager.addCommunicationsListener(this); sipManager.setSecurityAuthority(this); try { sipManager.start(); if (sipManager.isStarted()) { terminal = new TermData("sip:" + sipManager.getLocalUser() + "@" + sipManager.getLocalHostAddress(), true); console .trace("sipManager appears to be successfully started"); // guiManager.setCommunicationActionsEnabled(true); } } catch (CommunicationsException exc) { console.warn( "An exception occurred while initializing communication stack!\n" + "You won't be able to send or receive calls", exc); return; } try { // sipManager.register(); sipManager.startRegisterProcess(); } catch (CommunicationsException exc) { console .error("An exception occurred while trying to register, exc"); } } finally { console.logExit(); } } // end of init method // section------------------------------------------------------- private ListIdElement getElementIdListBySipId(int sipId) { ListIdElement ret = null; Iterator iterator = ids.iterator(); while (iterator.hasNext()) { ListIdElement lst = (ListIdElement) iterator.next(); if (lst.getSipId() == sipId) { ret = lst; } } return ret; } private ListIdElement getElementIdListByJtapiId(CallId callid) { ListIdElement ret = null; Iterator iterator = ids.iterator(); while (iterator.hasNext()) { ListIdElement lst = (ListIdElement) iterator.next(); if (lst.getJtapiId().equals(callid)) { ret = lst; } } return ret; } public SipManager getSipManager() { return sipManager; } public void unregistering(RegistrationEvent evt) { } public void play(String url) throws MediaResourceException { try { mediaManager.play(url); } catch (MediaException ex) { throw new MediaResourceException(ex.getMessage()); } } public void record(String url) throws MediaResourceException { try { mediaManager.record(url); } catch (MediaException ex) { throw new MediaResourceException(ex.getMessage()); } } public void stop() { mediaManager.stopPlaying(); mediaManager.stopRecording(); } }