# HG changeset patch # User nikita@nikita-laptop # Date 1266164738 -3600 # Node ID 532fdf132146e972b456caafbcdddc8151910a3f # Parent ea02c5b80cc0e5287c6a76a103c71114508283ce# Parent 9fb7971592360efee167c8ca73163877368970ac merge diff -r 9fb797159236 -r 532fdf132146 .classpath --- a/.classpath Sat Feb 13 22:43:21 2010 +0100 +++ b/.classpath Sun Feb 14 17:25:38 2010 +0100 @@ -1,9 +1,16 @@ - - - - + + + + + + + + + + + diff -r 9fb797159236 -r 532fdf132146 AndroidManifest.xml --- a/AndroidManifest.xml Sat Feb 13 22:43:21 2010 +0100 +++ b/AndroidManifest.xml Sun Feb 14 17:25:38 2010 +0100 @@ -65,6 +65,12 @@ android:name="com.beem.project.beem.service.XmppConnectionAdapter.CONNECTION_CLOSED" /> + + + + + - - diff -r 9fb797159236 -r 532fdf132146 res/layout/ongoing_call_notification.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/res/layout/ongoing_call_notification.xml Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + diff -r 9fb797159236 -r 532fdf132146 res/menu/call.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/res/menu/call.xml Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,10 @@ + + + + + + diff -r 9fb797159236 -r 532fdf132146 res/menu/contactlist_context.xml --- a/res/menu/contactlist_context.xml Sat Feb 13 22:43:21 2010 +0100 +++ b/res/menu/contactlist_context.xml Sun Feb 14 17:25:38 2010 +0100 @@ -2,7 +2,7 @@ + android:title="@string/CDCall" android:visible="true" /> diff -r 9fb797159236 -r 532fdf132146 res/raw/ringback.ogg Binary file res/raw/ringback.ogg has changed diff -r 9fb797159236 -r 532fdf132146 res/values-fr/strings.xml --- a/res/values-fr/strings.xml Sat Feb 13 22:43:21 2010 +0100 +++ b/res/values-fr/strings.xml Sun Feb 14 17:25:38 2010 +0100 @@ -140,6 +140,7 @@ Beem - Contacts Beem - ContactList Activity Beem - Informations + Beem - Appel Reset diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/BeemService.java --- a/src/com/beem/project/beem/BeemService.java Sat Feb 13 22:43:21 2010 +0100 +++ b/src/com/beem/project/beem/BeemService.java Sun Feb 14 17:25:38 2010 +0100 @@ -195,7 +195,7 @@ mConnection = new XmppConnectionAdapter(mConnectionConfiguration, mLogin, mPassword, this); Roster.setDefaultSubscriptionMode(SubscriptionMode.manual); - mJingle = new JingleService(mConnection.getAdaptee()); + mJingle = new JingleService(mConnection.getAdaptee(), this); mBind = new XmppFacade(mConnection, mJingle); Log.d(TAG, "ONCREATE"); } diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/jingle/JingleService.java --- a/src/com/beem/project/beem/jingle/JingleService.java Sat Feb 13 22:43:21 2010 +0100 +++ b/src/com/beem/project/beem/jingle/JingleService.java Sun Feb 14 17:25:38 2010 +0100 @@ -40,7 +40,7 @@ Flavien Astraud, November 26, 2009 Head of the EIP Laboratory. -*/ + */ package com.beem.project.beem.jingle; import java.util.ArrayList; @@ -58,30 +58,44 @@ import org.jivesoftware.smackx.jingle.nat.BasicTransportManager; import org.jivesoftware.smackx.jingle.nat.TransportCandidate; +import android.content.Context; +import android.net.Uri; +import android.os.RemoteCallbackList; +import android.os.RemoteException; import android.util.Log; +import android.content.Intent; -// TODO: Auto-generated Javadoc +import com.beem.project.beem.ui.Call; +import com.beem.project.beem.jingle.RTPAudioSession; +import com.beem.project.beem.service.aidl.IBeemJingleListener; +import com.beem.project.beem.service.aidl.IJingle; + /** * Beem Jingle Service, manage jingle call. * @author nikita */ -public class JingleService { +public class JingleService extends IJingle.Stub { private static final String TAG = "JingleService"; private JingleManager mJingleManager; private final List mMediaManagers; + private final RemoteCallbackList mRemoteJingleListeners = new RemoteCallbackList(); private JingleSession mIn; + private JingleSession mOut; + private JingleSessionRequest mRequest; + private Context mContext; + private boolean isCaller; + private RTPAudioSession mAudioSession; /** * JingleService constructor. * @param xmppConnection a valid XMPPConnection */ - public JingleService(final XMPPConnection xmppConnection) { + public JingleService(final XMPPConnection xmppConnection,final Context ctx) { BasicTransportManager bt = new BasicTransportManager(); - // JingleTransportManager tm = new ICETransportManager(); - mMediaManagers = new ArrayList(); - mMediaManagers.add(new MicrophoneRTPManager(bt)); + mMediaManagers.add(new MicrophoneRTPManager(bt, ctx)); + mContext = ctx; } /** @@ -94,75 +108,164 @@ } /** + * {@inheritDoc} + */ + @Override + public void addJingleListener(IBeemJingleListener listen) throws RemoteException { + if (listen != null) + mRemoteJingleListeners.register(listen); + } + + /** + * {@inheritDoc} + */ + @Override + public void removeJingleListener(IBeemJingleListener listen) throws RemoteException { + if (listen != null) + mRemoteJingleListeners.unregister(listen); + } + + /** * begin a jingle call. * @param receiver the call receiver */ - public void call(final String receiver) { + @Override + public void call(final String receiver) throws RemoteException { try { mOut = mJingleManager.createOutgoingJingleSession(receiver); - // TODO configure out avec addMediaSession et addNegociator - mOut.addListener(new BeemJingleCallerSessionListener()); + mOut.addListener(new BeemJingleSessionListener()); mOut.startOutgoing(); + isCaller = true; } catch (XMPPException e) { - // TODO Auto-generated catch block e.printStackTrace(); } } - /* - * private void receiveData(String ip, int port) throws IOException { Socket s = null; try { s = new Socket(ip, - * port); System.out.println("Waiting data"); InputStream in = s.getInputStream(); int a; while ((a = in.read()) != - * -1) { System.out.println("Received " + a); } System.out.println("End receiving data"); } finally { if (s != null) - * s.close(); } } + + @Override + public void acceptCall() throws RemoteException { + try { + mRequest.accept(); + mIn.start(); + } catch (XMPPException e) { + e.printStackTrace(); + } + isCaller = false; + } + + @Override + public void setSpeakerMode(int mode) throws RemoteException { + mAudioSession.setSpeakerMode(mode); + } + + /** + * close a jingle call. */ + @Override + public void closeCall() throws RemoteException { + mAudioSession = null; + if (isCaller) { + try { + mOut.terminate("Cancelled"); + mOut.close(); + } catch (XMPPException e) { + e.printStackTrace(); + } + mOut = null; + } else { + try { + mRequest.reject(); + mIn.terminate(); + mIn.close(); + } catch (XMPPException e) { + e.printStackTrace(); + } + mIn = null; + } + } + /** - * Listen on receiver session events. + * Listen on session events. * @author nikita */ - private class BeemJingleReceiverSessionListener implements JingleSessionListener { + private class BeemJingleSessionListener implements JingleSessionListener { /** * constructor. */ - public BeemJingleReceiverSessionListener() { + public BeemJingleSessionListener() { super(); - // TODO Auto-generated constructor stub } @Override public void sessionClosed(String reason, JingleSession jingleSession) { - // System.out.println("Session " + jingleSession.getResponder() + - // "closedd because " + reason); + System.out.println("Session " + jingleSession.getResponder() + "closedd because " + reason); + + final int n = mRemoteJingleListeners.beginBroadcast(); + for (int i = 0; i < n; i++) { + IBeemJingleListener listener = mRemoteJingleListeners.getBroadcastItem(i); + try { + listener.sessionClosed(reason); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + mRemoteJingleListeners.finishBroadcast(); } @Override public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) { - // TODO Auto-generated method stub - // System.out.println("Session " + jingleSession.getResponder() + - // " closed"); + System.out.println("Session " + jingleSession.getResponder() + " closed"); + final int n = mRemoteJingleListeners.beginBroadcast(); + for (int i = 0; i < n; i++) { + IBeemJingleListener listener = mRemoteJingleListeners.getBroadcastItem(i); + try { + listener.sessionClosedOnError(e.getMessage()); + } catch (RemoteException err) { + err.printStackTrace(); + } + } + mRemoteJingleListeners.finishBroadcast(); } @Override public void sessionDeclined(String reason, JingleSession jingleSession) { Log.d(TAG, "Session " + jingleSession.getResponder() + "declined because " + reason); + + final int n = mRemoteJingleListeners.beginBroadcast(); + for (int i = 0; i < n; i++) { + IBeemJingleListener listener = mRemoteJingleListeners.getBroadcastItem(i); + try { + listener.sessionDeclined(reason); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + mRemoteJingleListeners.finishBroadcast(); + } @Override public void sessionEstablished(PayloadType pt, TransportCandidate remoteCandidate, TransportCandidate localCandidate, JingleSession jingleSession) { - // System.out.println("Session established"); - // System.out.println("Je recois sur " + remoteCandidate.getIp() + - // ":" + remoteCandidate.getPort()); - // TODO choose the right RTPReceiver depending on the payload type - // RTPReceiver rtpReceiver = new - // RTPReceiver(remoteCandidate.getPort()); Log.d(TAG, "Session " + jingleSession.getResponder() + "established"); + mAudioSession = (RTPAudioSession) jingleSession.getSession().getMediaSession(MicrophoneRTPManager.MEDIA_NAME); + final int n = mRemoteJingleListeners.beginBroadcast(); + for (int i = 0; i < n; i++) { + IBeemJingleListener listener = mRemoteJingleListeners.getBroadcastItem(i); + try { + listener.sessionEstablished(); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + mRemoteJingleListeners.finishBroadcast(); } @Override public void sessionMediaReceived(JingleSession jingleSession, String participant) { - // System.out.println("Session Media received from " + participant); + Log.d(TAG, "Session Media received from " + participant); } @Override @@ -170,77 +273,6 @@ } } - /** - * Listen on caller session events. - * @author nikita - */ - private class BeemJingleCallerSessionListener implements JingleSessionListener { - - private static final int SLP_DURATION = 20000; - - /** - * constructor. - */ - public BeemJingleCallerSessionListener() { - super(); - // TODO Auto-generated constructor stub - } - - @Override - public void sessionClosed(final String reason, final JingleSession jingleSession) { - // System.out.println("Session " + jingleSession.getResponder() + - // "closed because " + reason); - } - - @Override - public void sessionClosedOnError(final XMPPException e, final JingleSession jingleSession) { - // System.out.println("Session " + jingleSession.getResponder() + - // " closed on error"); - - } - - @Override - public void sessionDeclined(final String reason, final JingleSession jingleSession) { - // System.out.println("Session " + jingleSession.getResponder() + - // "declined because " + reason); - Log.d(TAG, "Session " + jingleSession.getResponder() + "declined because " + reason); - } - - @Override - public void sessionEstablished(final PayloadType pt, final TransportCandidate remoteCandidate, - final TransportCandidate localCandidate, final JingleSession jingleSession) { - Log.d(TAG, "Session " + jingleSession.getResponder() + "established"); - // String name = localCandidate.getName(); - String ip = localCandidate.getIp(); - int port = localCandidate.getPort(); - // System.out.println("Session established waiting connection on " + - // ip + ":" + port); - - RTPTransmitter transm = new PCMTransmitter(ip, port); - - transm.run(); - try { - Thread.sleep(SLP_DURATION); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - transm.stop(); - // System.out.println("End of transfer"); - - } - - @Override - public void sessionMediaReceived(final JingleSession jingleSession, final String participant) { - // TODO Auto-generated method stub - System.out.println("Session Media received from " + participant); - } - - @Override - public void sessionRedirected(final String redirection, final JingleSession jingleSession) { - // TODO Auto-generated method stub - } - } /** * Listen for a Jingle session request. @@ -257,14 +289,21 @@ @Override public void sessionRequested(JingleSessionRequest request) { - System.out.println("Jingle Session request from " + request.getFrom()); + mRequest = request; try { - mIn = request.accept(); - mIn.addListener(new BeemJingleReceiverSessionListener()); + mIn = mJingleManager.createIncomingJingleSession(mRequest); + mIn.addListener(new BeemJingleSessionListener()); mIn.startIncoming(); } catch (XMPPException e) { e.printStackTrace(); } + System.out.println("Jingle Session request from " + request.getFrom()); + isCaller = false; + Intent intent = new Intent(mContext, Call.class); + intent.setData(Uri.parse("jingle:"+request.getFrom())); + intent.putExtra("isCaller", false); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); } } diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/jingle/MicrophoneRTPManager.java --- a/src/com/beem/project/beem/jingle/MicrophoneRTPManager.java Sat Feb 13 22:43:21 2010 +0100 +++ b/src/com/beem/project/beem/jingle/MicrophoneRTPManager.java Sun Feb 14 17:25:38 2010 +0100 @@ -53,61 +53,64 @@ import org.jivesoftware.smackx.jingle.nat.JingleTransportManager; import org.jivesoftware.smackx.jingle.nat.TransportCandidate; -// TODO: Auto-generated Javadoc +import android.content.Context; + /** * RTPMediaManager, gere les payloads et renvoie une session RTP. * @author nikita */ public class MicrophoneRTPManager extends JingleMediaManager { - - /** RTP media name. */ - public static final String MEDIA_NAME = "Microphone"; + /** + * RTP media name. + */ + public static final String MEDIA_NAME = "Microphone"; - private List mPayloads; + private List mPayloads; + + private Context mCtx; - /** - * Manage Microphone data transmission trough RTP. - * @param transportManager current jingle transport manager(basic,upnp,ice...). - */ - public MicrophoneRTPManager(final JingleTransportManager transportManager) { - super(transportManager); - // TODO Auto-generated constructor stub - setupPayloads(); - } + /** + * Manage Microphone data transmission trough RTP. + * @param transportManager current jingle transport manager(basic,upnp,ice...). + */ + public MicrophoneRTPManager(final JingleTransportManager transportManager, Context ctx) { + super(transportManager); + setupPayloads(); + mCtx = ctx; + } /* (non-Javadoc) * @see org.jivesoftware.smackx.jingle.media.JingleMediaManager#createMediaSession(org.jivesoftware.smackx.jingle.media.PayloadType, org.jivesoftware.smackx.jingle.nat.TransportCandidate, org.jivesoftware.smackx.jingle.nat.TransportCandidate, org.jivesoftware.smackx.jingle.JingleSession) */ - @Override - public JingleMediaSession createMediaSession(PayloadType payloadType, TransportCandidate remote, - TransportCandidate local, JingleSession jingleSession) { - // TODO Auto-generated method stub - return new MicrophoneRTPSession(payloadType, remote, local, null, jingleSession); - } + @Override + public JingleMediaSession createMediaSession(PayloadType payloadType, TransportCandidate remote, + TransportCandidate local, JingleSession jingleSession) { + return new RTPAudioSession(payloadType, remote, local, null, jingleSession, mCtx); + } /* (non-Javadoc) * @see org.jivesoftware.smackx.jingle.media.JingleMediaManager#getName() */ - @Override - public String getName() { - return MEDIA_NAME; - } + @Override + public String getName() { + return MEDIA_NAME; + } /* (non-Javadoc) * @see org.jivesoftware.smackx.jingle.media.JingleMediaManager#getPayloads() */ - @Override - public List getPayloads() { - // TODO Auto-generated method stub - return mPayloads; - } + @Override + public List getPayloads() { + return mPayloads; + } - /** - * Supported payload list. - */ - private void setupPayloads() { - mPayloads = new ArrayList(); - mPayloads.add(new PayloadType.Audio(0, "PCMU")); - mPayloads.add(new PayloadType.Audio(8, "PCMA")); - } + /** + * Supported payload list. + */ + private void setupPayloads() { + mPayloads = new ArrayList(); + mPayloads.add(new PayloadType.Audio(8, "PCMA")); +// mPayloads.add(new PayloadType.Audio(9, "G722")); +// mPayloads.add(new PayloadType.Audio(3, "GSM")); + } } diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/jingle/MicrophoneRTPSession.java --- a/src/com/beem/project/beem/jingle/MicrophoneRTPSession.java Sat Feb 13 22:43:21 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -/* - BEEM is a videoconference application on the Android Platform. - - Copyright (C) 2009 by Frederic-Charles Barthelery, - Jean-Manuel Da Silva, - Nikita Kozlov, - Philippe Lago, - Jean Baptiste Vergely, - Vincent Veronis. - - This file is part of BEEM. - - BEEM is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - BEEM is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with BEEM. If not, see . - - Please send bug reports with examples or suggestions to - contact@beem-project.com or http://dev.beem-project.com/ - - Epitech, hereby disclaims all copyright interest in the program "Beem" - written by Frederic-Charles Barthelery, - Jean-Manuel Da Silva, - Nikita Kozlov, - Philippe Lago, - Jean Baptiste Vergely, - Vincent Veronis. - - Nicolas Sadirac, November 26, 2009 - President of Epitech. - - Flavien Astraud, November 26, 2009 - Head of the EIP Laboratory. - -*/ -package com.beem.project.beem.jingle; - -import org.jivesoftware.smackx.jingle.JingleSession; -import org.jivesoftware.smackx.jingle.media.JingleMediaSession; -import org.jivesoftware.smackx.jingle.media.PayloadType; -import org.jivesoftware.smackx.jingle.nat.TransportCandidate; - -// TODO: Auto-generated Javadoc -/** - * Manage microphone RTP session. - * @author nikita - */ -public class MicrophoneRTPSession extends JingleMediaSession { - - private RTPTransmitter mTransmitter; - private RTPReceiver mReceiver; - - /** - * constructor. - * @param payloadType the payload typ used - * @param remote the remote transport info - * @param local the local tranport info - * @param mediaLocator don't know - * @param jingleSession the current jingle session - */ - public MicrophoneRTPSession(final PayloadType payloadType, final TransportCandidate remote, - final TransportCandidate local, final String mediaLocator, final JingleSession jingleSession) { - super(payloadType, remote, local, mediaLocator, jingleSession); - - // TODO le transmitter ne devrait peut etre pas etre init ici, c'est - // peut etre encore un peu tot, a voir. - mTransmitter = new PCMTransmitter(remote.getIp(), getRemote().getPort()); - // mReceiver = new MicroRTPReceiver(getLocal().getPort()); - } - - /* (non-Javadoc) - * @see org.jivesoftware.smackx.jingle.media.JingleMediaSession#initialize() - */ - @Override - public void initialize() { - // TODO Auto-generated method stub - - } - - /* (non-Javadoc) - * @see org.jivesoftware.smackx.jingle.media.JingleMediaSession#setTrasmit(boolean) - */ - @Override - public void setTrasmit(boolean active) { - } - - /* (non-Javadoc) - * @see org.jivesoftware.smackx.jingle.media.JingleMediaSession#startReceive() - */ - @Override - public void startReceive() { - - } - - /* (non-Javadoc) - * @see org.jivesoftware.smackx.jingle.media.JingleMediaSession#startTrasmit() - */ - @Override - public void startTrasmit() { - - } - - /* (non-Javadoc) - * @see org.jivesoftware.smackx.jingle.media.JingleMediaSession#stopReceive() - */ - @Override - public void stopReceive() { - if (mReceiver != null) { - mReceiver.stop(); - } - } - - /* (non-Javadoc) - * @see org.jivesoftware.smackx.jingle.media.JingleMediaSession#stopTrasmit() - */ - @Override - public void stopTrasmit() { - if (mTransmitter != null) { - mTransmitter.stop(); - } - } -} diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/jingle/PCMTransmitter.java --- a/src/com/beem/project/beem/jingle/PCMTransmitter.java Sat Feb 13 22:43:21 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* - BEEM is a videoconference application on the Android Platform. - - Copyright (C) 2009 by Frederic-Charles Barthelery, - Jean-Manuel Da Silva, - Nikita Kozlov, - Philippe Lago, - Jean Baptiste Vergely, - Vincent Veronis. - - This file is part of BEEM. - - BEEM is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - BEEM is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with BEEM. If not, see . - - Please send bug reports with examples or suggestions to - contact@beem-project.com or http://dev.beem-project.com/ - - Epitech, hereby disclaims all copyright interest in the program "Beem" - written by Frederic-Charles Barthelery, - Jean-Manuel Da Silva, - Nikita Kozlov, - Philippe Lago, - Jean Baptiste Vergely, - Vincent Veronis. - - Nicolas Sadirac, November 26, 2009 - President of Epitech. - - Flavien Astraud, November 26, 2009 - Head of the EIP Laboratory. - -*/ -package com.beem.project.beem.jingle; - -import android.media.AudioFormat; -import android.media.AudioRecord; -import android.media.MediaRecorder; - -// TODO: Auto-generated Javadoc -/** - * Transmit Microphone data through RTP. - * @author nikita - */ -public class PCMTransmitter extends RTPTransmitter { - - private static final int BUFF_SIZE = 1024; - private static final int RATE_IN_HZ = 8000; - private static final int SLP_DURATION = 200; - - /** - * Constructor. - * @param remoteIP receiver IP. - * @param remotePort receiver port. - */ - public PCMTransmitter(final String remoteIP, final int remotePort) { - super(remoteIP, remotePort); - } - - /* (non-Javadoc) - * @see com.beem.project.beem.jingle.RTPTransmitter#start() - */ - @Override - void start() { - AudioRecord audRec = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, RATE_IN_HZ, - AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, AudioRecord.getMinBufferSize( - RATE_IN_HZ, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT) * 4); - byte[] audioData = new byte[BUFF_SIZE]; - int byteReaded = 0; - while (!isKillme()) { - byteReaded = audRec.read(audioData, byteReaded, BUFF_SIZE); - System.out.println("readed " + byteReaded); - getRtpSession().sendData(audioData); - } - try { - Thread.sleep(SLP_DURATION); - } catch (InterruptedException e) { - e.printStackTrace(); - } - this.getRtpSession().endSession(); - } -} diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/jingle/RTPAudioSession.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/beem/project/beem/jingle/RTPAudioSession.java Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,89 @@ +package com.beem.project.beem.jingle; + +import org.jivesoftware.smackx.jingle.JingleSession; +import org.jivesoftware.smackx.jingle.media.JingleMediaSession; +import org.jivesoftware.smackx.jingle.media.PayloadType; +import org.jivesoftware.smackx.jingle.nat.TransportCandidate; +import org.sipdroid.media.RtpStreamReceiver; +import org.sipdroid.media.RtpStreamSender; +import org.sipdroid.net.SipdroidSocket; + +import android.content.Context; +import android.util.Log; + +/** + * Manage microphone RTP session. + * @author nikita + */ +public class RTPAudioSession extends JingleMediaSession { + + private RtpStreamSender mSender=null; + private RtpStreamReceiver mReceiver=null; + + /** + * constructor. + * @param payloadType the payload typ used + * @param remote the remote transport info + * @param local the local tranport info + * @param mediaLocator don't know + * @param jingleSession the current jingle session + * @param ctx + */ + public RTPAudioSession(final PayloadType pt, final TransportCandidate remote, + final TransportCandidate local, final String mediaLocator, final JingleSession jingleSession, Context ctx) { + super(pt, remote, local, mediaLocator, jingleSession); + Log.d("AUDIO", String.format("payload type : %s ipdest %s port dest %d port src %d",pt.getName(), remote.getIp(), remote.getPort(), local.getPort())); + + SipdroidSocket rtpSocket = null; + try { + rtpSocket = new SipdroidSocket(local.getPort()); + } catch (Exception e) { + e.printStackTrace(); + } + mSender = new RtpStreamSender(true, 8, 8000, 160, rtpSocket, remote.getIp(), remote.getPort()); + mReceiver = new RtpStreamReceiver(rtpSocket, 8); + } + + @Override + public void initialize() { + } + + public void setSpeakerMode(final int mode) { + mReceiver.speaker(mode); + } + + @Override + public void setTrasmit(boolean active) { + } + + @Override + public void startReceive() { + if (mReceiver != null) { + mReceiver.start(); + } + } + + @Override + public void startTrasmit() { + if (mSender != null) { + mSender.start(); + } + } + + @Override + public void stopReceive() { + if (mReceiver != null) { + mReceiver.halt(); + mReceiver = null; + } + + } + + @Override + public void stopTrasmit() { + if (mSender != null) { + mSender.halt(); + mSender = null; + } + } +} diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/jingle/RTPReceiver.java --- a/src/com/beem/project/beem/jingle/RTPReceiver.java Sat Feb 13 22:43:21 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/* - BEEM is a videoconference application on the Android Platform. - - Copyright (C) 2009 by Frederic-Charles Barthelery, - Jean-Manuel Da Silva, - Nikita Kozlov, - Philippe Lago, - Jean Baptiste Vergely, - Vincent Veronis. - - This file is part of BEEM. - - BEEM is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - BEEM is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with BEEM. If not, see . - - Please send bug reports with examples or suggestions to - contact@beem-project.com or http://dev.beem-project.com/ - - Epitech, hereby disclaims all copyright interest in the program "Beem" - written by Frederic-Charles Barthelery, - Jean-Manuel Da Silva, - Nikita Kozlov, - Philippe Lago, - Jean Baptiste Vergely, - Vincent Veronis. - - Nicolas Sadirac, November 26, 2009 - President of Epitech. - - Flavien Astraud, November 26, 2009 - Head of the EIP Laboratory. - -*/ -package com.beem.project.beem.jingle; - -import java.net.DatagramSocket; -import java.net.SocketException; - -import org.jlibrtp.jlibrtp.Participant; -import org.jlibrtp.jlibrtp.RTPAppIntf; -import org.jlibrtp.jlibrtp.RTPSession; - -// TODO: Auto-generated Javadoc -/** - * abstract RTP receiver class. - * @author nikita - */ -public abstract class RTPReceiver implements Runnable, RTPAppIntf { - - private boolean mKillme; - private RTPSession mRtpSession; - - /** - * constructor. - * @param rtpPort local or distant?. - */ - public RTPReceiver(final int rtpPort) { - DatagramSocket rtpSocket = null; - - try { - rtpSocket = new DatagramSocket(rtpPort); - } catch (SocketException e) { - e.printStackTrace(); - return; - } - mRtpSession = new RTPSession(rtpSocket, null); - mRtpSession.naivePktReception(true); - mRtpSession.RTPSessionRegister(this, null, null); - } - - /* (non-Javadoc) - * @see org.jlibrtp.jlibrtp.RTPAppIntf#frameSize(int) - */ - @Override - public int frameSize(int payloadType) { - return 1; - } - - /* (non-Javadoc) - * @see java.lang.Runnable#run() - */ - @Override - public void run() { - start(); - this.mRtpSession.endSession(); - } - - /** - * main reception loop. - */ - protected abstract void start(); - - /** - * Stop the reception. - */ - public void stop() { - this.setKillme(true); - } - - /* (non-Javadoc) - * @see org.jlibrtp.jlibrtp.RTPAppIntf#userEvent(int, org.jlibrtp.jlibrtp.Participant[]) - */ - @Override - public void userEvent(int arg0, Participant[] arg1) { - // TODO Auto-generated method stub - } - - /** - * mKillme setter. - * @param killme the mKillme to set - */ - public void setKillme(final boolean killme) { - this.mKillme = killme; - } - - /** - * mKillme getter. - * @return the mKillme - */ - public boolean isKillme() { - return mKillme; - } -} diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/jingle/RTPTransmitter.java --- a/src/com/beem/project/beem/jingle/RTPTransmitter.java Sat Feb 13 22:43:21 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,170 +0,0 @@ -/* - BEEM is a videoconference application on the Android Platform. - - Copyright (C) 2009 by Frederic-Charles Barthelery, - Jean-Manuel Da Silva, - Nikita Kozlov, - Philippe Lago, - Jean Baptiste Vergely, - Vincent Veronis. - - This file is part of BEEM. - - BEEM is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - BEEM is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with BEEM. If not, see . - - Please send bug reports with examples or suggestions to - contact@beem-project.com or http://dev.beem-project.com/ - - Epitech, hereby disclaims all copyright interest in the program "Beem" - written by Frederic-Charles Barthelery, - Jean-Manuel Da Silva, - Nikita Kozlov, - Philippe Lago, - Jean Baptiste Vergely, - Vincent Veronis. - - Nicolas Sadirac, November 26, 2009 - President of Epitech. - - Flavien Astraud, November 26, 2009 - Head of the EIP Laboratory. - -*/ -package com.beem.project.beem.jingle; - -import java.net.DatagramSocket; -import java.net.SocketException; - -import org.jlibrtp.jlibrtp.DataFrame; -import org.jlibrtp.jlibrtp.Participant; -import org.jlibrtp.jlibrtp.RTPAppIntf; -import org.jlibrtp.jlibrtp.RTPSession; - -import com.beem.project.beem.utils.FreePort; - -// TODO: Auto-generated Javadoc -/** - * abstract RTP transmitter class. - * @author nikita - */ -public abstract class RTPTransmitter implements Runnable, RTPAppIntf { - /** - * RTPSession instance. - */ - private RTPSession mRtpSession; - /** - * process status manipulation. - */ - private boolean mKillme; - - /** - * constructor. - * @param remoteIP receiver IP. - * @param remotePort receiver port. - */ - public RTPTransmitter(final String remoteIP, final int remotePort) { - DatagramSocket rtpSocket = null; - int rtpPort = 0; - - try { - rtpPort = FreePort.getFreePort(); - rtpSocket = new DatagramSocket(rtpPort); - } catch (SocketException e) { - e.printStackTrace(); - return; - } - setRtpSession(new RTPSession(rtpSocket, null)); - getRtpSession().naivePktReception(true); - getRtpSession().RTPSessionRegister(this, null, null); - getRtpSession().addParticipant(new Participant(remoteIP, remotePort, 0)); - } - - /* (non-Javadoc) - * @see org.jlibrtp.jlibrtp.RTPAppIntf#frameSize(int) - */ - @Override - public int frameSize(int payloadType) { - return 1; - } - - /* (non-Javadoc) - * @see org.jlibrtp.jlibrtp.RTPAppIntf#receiveData(org.jlibrtp.jlibrtp.DataFrame, org.jlibrtp.jlibrtp.Participant) - */ - @Override - public void receiveData(DataFrame frame, Participant participant) { - // On envoie uniquement - } - - /* (non-Javadoc) - * @see java.lang.Runnable#run() - */ - @Override - public void run() { - start(); - } - - /** - * A implementer pour chaque type d'envoi specifique. - */ - abstract void start(); - - /** - * Stop the transmission. - */ - public void stop() { - mKillme = true; - } - - /* (non-Javadoc) - * @see org.jlibrtp.jlibrtp.RTPAppIntf#userEvent(int, org.jlibrtp.jlibrtp.Participant[]) - */ - @Override - public void userEvent(int type, Participant[] participant) { - // je sais pas ce que c'est - - } - - /** - * mKillme setter. - * @param killme the mKillme to set - */ - public void setKillme(final boolean killme) { - this.mKillme = killme; - } - - /** - * mKillme getter. - * @return the mKillme. - */ - public boolean isKillme() { - return mKillme; - } - - /** - * mRtpSession setter. - * @param rtpSession the mRtpSession to set. - */ - public void setRtpSession(RTPSession rtpSession) { - this.mRtpSession = rtpSession; - } - - /** - * mRtpSession getter. - * @return the mRtpSession - */ - public RTPSession getRtpSession() { - return mRtpSession; - } - -} diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/jingle/demo/JingleCallActivity.java --- a/src/com/beem/project/beem/jingle/demo/JingleCallActivity.java Sat Feb 13 22:43:21 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,147 +0,0 @@ -/* - BEEM is a videoconference application on the Android Platform. - - Copyright (C) 2009 by Frederic-Charles Barthelery, - Jean-Manuel Da Silva, - Nikita Kozlov, - Philippe Lago, - Jean Baptiste Vergely, - Vincent Veronis. - - This file is part of BEEM. - - BEEM is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - BEEM is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with BEEM. If not, see . - - Please send bug reports with examples or suggestions to - contact@beem-project.com or http://dev.beem-project.com/ - - Epitech, hereby disclaims all copyright interest in the program "Beem" - written by Frederic-Charles Barthelery, - Jean-Manuel Da Silva, - Nikita Kozlov, - Philippe Lago, - Jean Baptiste Vergely, - Vincent Veronis. - - Nicolas Sadirac, November 26, 2009 - President of Epitech. - - Flavien Astraud, November 26, 2009 - Head of the EIP Laboratory. - -*/ -package com.beem.project.beem.jingle.demo; -/* -import org.jivesoftware.smack.ConnectionConfiguration; -import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode; -import org.jivesoftware.smack.util.StringUtils; - -import android.os.Bundle; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.EditText; -import android.widget.Toast; - -import com.beem.project.beem.R; -import com.beem.project.beem.jingle.JingleService; -*/ -import android.app.Activity; - -/** - * Activity used to test Jingle call. - * @author darisk - */ -public class JingleCallActivity extends Activity { -/* - private static final int SLP_DURATION = 3000; - private static final int DEFAULT_XMPP_PORT = 5222; - - private XMPPConnection mConnection; - private ConnectionConfiguration mConf; - private JingleService mJingle; - - private Button mBtconnect; - private Button mBtcall; - private EditText mEdJID; - private EditText mEdPassword; - private EditText mEdReceiver; - - /** - * Constructor. - * - public JingleCallActivity() { - } - - /* (non-Javadoc) - * @see android.app.Activity#onCreate(android.os.Bundle) - * - @Override - protected void onCreate(Bundle savedInstanceState) { - java.security.Security.addProvider(new com.sun.security.sasl.Provider()); - super.onCreate(savedInstanceState); - setContentView(R.layout.jingle_call_activity); - mConf = new ConnectionConfiguration("10.0.2.2", DEFAULT_XMPP_PORT); - // mConf = new ConnectionConfiguration("elyzion.net", - // DEFAULT_XMPP_PORT); - mConf.setSecurityMode(SecurityMode.required); - mEdJID = (EditText) findViewById(R.id.jingledemocalljid); - mEdPassword = (EditText) findViewById(R.id.jingledemocallpassword); - mEdReceiver = (EditText) findViewById(R.id.jingledemocallreceiver); - mBtconnect = (Button) findViewById(R.id.jingledemocallconnectbutton); - mBtconnect.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View arg0) { - String jid = mEdJID.getText().toString(); - String login = StringUtils.parseName(jid); - mConnection = new XMPPConnection(mConf); - String password = mEdPassword.getText().toString(); - try { - mConnection.connect(); - Thread.sleep(SLP_DURATION); - mConnection.login(login, password); - mJingle = new JingleService(mConnection); - mJingle.initWhenConntected(mConnection); - mBtcall.setEnabled(true); - Toast.makeText(JingleCallActivity.this, "Connected", Toast.LENGTH_SHORT); - } catch (XMPPException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - }); - mBtcall = (Button) findViewById(R.id.jingledemocallbutton); - mBtcall.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View arg0) { - String jid = mEdReceiver.getText().toString(); - if (!"".equals(jid)) { - mJingle.call(jid); - Toast.makeText(JingleCallActivity.this, "Appel en cours", Toast.LENGTH_SHORT); - } else - Toast.makeText(JingleCallActivity.this, "Remplir le champ (JID complet en toto@tutu.com/truc)", - Toast.LENGTH_SHORT); - } - }); - - } -*/ -} diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/jingle/demo/package-info.java --- a/src/com/beem/project/beem/jingle/demo/package-info.java Sat Feb 13 22:43:21 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - BEEM is a videoconference application on the Android Platform. - - Copyright (C) 2009 by Frederic-Charles Barthelery, - Jean-Manuel Da Silva, - Nikita Kozlov, - Philippe Lago, - Jean Baptiste Vergely, - Vincent Veronis. - - This file is part of BEEM. - - BEEM is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - BEEM is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with BEEM. If not, see . - - Please send bug reports with examples or suggestions to - contact@beem-project.com or http://dev.beem-project.com/ - - Epitech, hereby disclaims all copyright interest in the program "Beem" - written by Frederic-Charles Barthelery, - Jean-Manuel Da Silva, - Nikita Kozlov, - Philippe Lago, - Jean Baptiste Vergely, - Vincent Veronis. - - Nicolas Sadirac, November 26, 2009 - President of Epitech. - - Flavien Astraud, November 26, 2009 - Head of the EIP Laboratory. - -*/ -package com.beem.project.beem.jingle.demo; - diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/service/Contact.java --- a/src/com/beem/project/beem/service/Contact.java Sat Feb 13 22:43:21 2010 +0100 +++ b/src/com/beem/project/beem/service/Contact.java Sun Feb 14 17:25:38 2010 +0100 @@ -194,7 +194,6 @@ */ @Override public int describeContents() { - // TODO Auto-generated method stub return 0; } diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/service/RosterAdapter.java --- a/src/com/beem/project/beem/service/RosterAdapter.java Sat Feb 13 22:43:21 2010 +0100 +++ b/src/com/beem/project/beem/service/RosterAdapter.java Sun Feb 14 17:25:38 2010 +0100 @@ -64,6 +64,7 @@ import com.beem.project.beem.R; import com.beem.project.beem.service.aidl.IBeemRosterListener; import com.beem.project.beem.utils.Status; +import com.beem.project.beem.service.aidl.IRoster; /** * This class implement a Roster adapter for BEEM. @@ -371,8 +372,6 @@ */ @Override public void presenceChanged(Presence presence) { - // Log.i(TAG, "presence Changed"); - /* redispatch vers les IBeemRosterListener */ final int n = mRemoteRosListeners.beginBroadcast(); for (int i = 0; i < n; i++) { @@ -385,8 +384,6 @@ } listener.onPresenceChanged(new PresenceAdapter(presence)); } catch (RemoteException e) { - // The RemoteCallbackList will take care of removing the - // dead listeners. Log.w(TAG, "Error while updating roster presence entries", e); } } diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/service/XmppFacade.java --- a/src/com/beem/project/beem/service/XmppFacade.java Sat Feb 13 22:43:21 2010 +0100 +++ b/src/com/beem/project/beem/service/XmppFacade.java Sun Feb 14 17:25:38 2010 +0100 @@ -55,6 +55,7 @@ import com.beem.project.beem.service.aidl.IRoster; import com.beem.project.beem.service.aidl.IXmppConnection; import com.beem.project.beem.service.aidl.IXmppFacade; +import com.beem.project.beem.service.aidl.IJingle; import com.beem.project.beem.utils.PresenceType; /** @@ -123,6 +124,14 @@ public IChatManager getChatManager() throws RemoteException { return mConnexion.getChatManager(); } + + /** + * {@inheritDoc} + */ + @Override + public IJingle getJingleService() throws RemoteException { + return mJingle; + } /** * {@inheritDoc} @@ -148,14 +157,6 @@ } /* (non-Javadoc) - * @see com.beem.project.beem.service.aidl.IXmppFacade#call(java.lang.String) - */ - @Override - public void call(String jid) throws RemoteException { - mJingle.call(jid); - } - - /* (non-Javadoc) * @see com.beem.project.beem.service.aidl.IXmppFacade#getVcardAvatar(java.lang.String) */ @Override diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/service/aidl/IBeemJingleListener.aidl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/beem/project/beem/service/aidl/IBeemJingleListener.aidl Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,77 @@ +/* + BEEM is a videoconference application on the Android Platform. + + Copyright (C) 2009 by Frederic-Charles Barthelery, + Jean-Manuel Da Silva, + Nikita Kozlov, + Philippe Lago, + Jean Baptiste Vergely, + Vincent Veronis. + + This file is part of BEEM. + + BEEM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + BEEM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with BEEM. If not, see . + + Please send bug reports with examples or suggestions to + contact@beem-project.com or http://dev.beem-project.com/ + + Epitech, hereby disclaims all copyright interest in the program "Beem" + written by Frederic-Charles Barthelery, + Jean-Manuel Da Silva, + Nikita Kozlov, + Philippe Lago, + Jean Baptiste Vergely, + Vincent Veronis. + + Nicolas Sadirac, November 26, 2009 + President of Epitech. + + Flavien Astraud, November 26, 2009 + Head of the EIP Laboratory. + +*/ +package com.beem.project.beem.service.aidl; + +/** + * Interface to listen for jingle sessions events + * @author Nikita Kozlov + */ +interface IBeemJingleListener { + + /** + * Callback to call when the session is closed + */ + void sessionClosed(in String reason); + + /** + * Callback to call when the session is declined + */ + void sessionDeclined(in String reason); + + + /** + * Callback to call when the session is closed on error + */ + void sessionClosedOnError(in String error); + + /** + * Callback to call when session is established + */ + void sessionEstablished(); + + /** + * Callback to call when session is requested + */ + void sessionRequested(in String fromJID); +} diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/service/aidl/IJingle.aidl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/beem/project/beem/service/aidl/IJingle.aidl Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,75 @@ +/* + BEEM is a videoconference application on the Android Platform. + + Copyright (C) 2009 by Frederic-Charles Barthelery, + Jean-Manuel Da Silva, + Nikita Kozlov, + Philippe Lago, + Jean Baptiste Vergely, + Vincent Veronis. + + This file is part of BEEM. + + BEEM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + BEEM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with BEEM. If not, see . + + Please send bug reports with examples or suggestions to + contact@beem-project.com or http://dev.beem-project.com/ + + Epitech, hereby disclaims all copyright interest in the program "Beem" + written by Frederic-Charles Barthelery, + Jean-Manuel Da Silva, + Nikita Kozlov, + Philippe Lago, + Jean Baptiste Vergely, + Vincent Veronis. + + Nicolas Sadirac, November 26, 2009 + President of Epitech. + + Flavien Astraud, November 26, 2009 + Head of the EIP Laboratory. + +*/ +package com.beem.project.beem.service.aidl; + +import com.beem.project.beem.service.aidl.IBeemJingleListener; + + +interface IJingle { + + void addJingleListener(in IBeemJingleListener listen); + void removeJingleListener(in IBeemJingleListener listen); + + /** + * make a jingle audio call + * @param jid the receiver id + */ + void call(in String jid); + + /** + * Accept call a jingle audio call + */ + void acceptCall(); + + /** + * close a jingle audio call + */ + void closeCall(); + + /** + * Set speaker mode + */ + void setSpeakerMode(in int mode); + +} diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/service/aidl/IXmppFacade.aidl --- a/src/com/beem/project/beem/service/aidl/IXmppFacade.aidl Sat Feb 13 22:43:21 2010 +0100 +++ b/src/com/beem/project/beem/service/aidl/IXmppFacade.aidl Sun Feb 14 17:25:38 2010 +0100 @@ -45,9 +45,10 @@ import com.beem.project.beem.service.aidl.IXmppConnection; import com.beem.project.beem.service.aidl.IRoster; +import com.beem.project.beem.service.aidl.IJingle; import com.beem.project.beem.service.aidl.IChatManager; import com.beem.project.beem.service.aidl.IPrivacyListManager; -import com.beem.project.beem.service.PresenceAdapter; +import com.beem.project.beem.service.PresenceAdapter; interface IXmppFacade { @@ -80,6 +81,11 @@ * Get the chat manager. */ IChatManager getChatManager(); + + /** + * Get the Jingle service. + */ + IJingle getJingleService(); /** * Change the status of the user. @@ -90,12 +96,6 @@ void sendPresencePacket(in PresenceAdapter presence); - /** - * make a jingle audio call - * @param jid the receiver id - */ - void call(in String jid); - /** * get the user vcard avatar * @param jid the user jid diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/ui/Call.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/beem/project/beem/ui/Call.java Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,349 @@ +/* + BEEM is a videoconference application on the Android Platform. + + Copyright (C) 2009 by Frederic-Charles Barthelery, + Jean-Manuel Da Silva, + Nikita Kozlov, + Philippe Lago, + Jean Baptiste Vergely, + Vincent Veronis. + + This file is part of BEEM. + + BEEM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + BEEM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with BEEM. If not, see . + + Please send bug reports with examples or suggestions to + contact@beem-project.com or http://dev.beem-project.com/ + + Epitech, hereby disclaims all copyright interest in the program "Beem" + written by Frederic-Charles Barthelery, + Jean-Manuel Da Silva, + Nikita Kozlov, + Philippe Lago, + Jean Baptiste Vergely, + Vincent Veronis. + + Nicolas Sadirac, November 26, 2009 + President of Epitech. + + Flavien Astraud, November 26, 2009 + Head of the EIP Laboratory. + + */ +package com.beem.project.beem.ui; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.media.AudioManager; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Vibrator; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; +import android.os.RemoteCallbackList; +import android.os.RemoteException; + +import com.beem.project.beem.R; +import com.beem.project.beem.service.aidl.IXmppFacade; +import com.beem.project.beem.service.aidl.IJingle; +import com.beem.project.beem.service.aidl.IBeemJingleListener; + +/** + * This class is an activity which display an animation during the connection with the server. + * @author Da Risk + */ +public class Call extends Activity { + + private static final Intent SERVICE_INTENT = new Intent(); + static { + SERVICE_INTENT.setComponent(new ComponentName("com.beem.project.beem", "com.beem.project.beem.BeemService")); + } + private ImageView mLogo; + private TextView mCallInfo; + private Animation mRotateAnim; + private final ServiceConnection mServConn = new BeemServiceConnection(); + private BeemJingleSessionListener mJingleListener = new BeemJingleSessionListener(); + private IXmppFacade mXmppFacade; + private final Handler mHandler = new Handler(); + private Button mCloseCall; + private Button mAcceptCall; + private IJingle mJingle; + + final static long[] vibratePattern = {0,1000,1000}; + + public static final int UA_STATE_IDLE = 0; + public static final int UA_STATE_INCOMING_CALL = 1; + public static final int UA_STATE_OUTGOING_CALL = 2; + public static final int UA_STATE_INCALL = 3; + public static final int UA_STATE_HOLD = 4; + + public static int call_state = UA_STATE_IDLE; + public static int docked = -1,headset = -1; + public static Ringtone oRingtone; + public static Context mContext; + + public static void stopRingtone() { + android.os.Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); + v.cancel(); + if (oRingtone != null) { + Ringtone ringtone = oRingtone; + oRingtone = null; + ringtone.stop(); + } + } + + public static void startRingtone() { + android.os.Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); + v.vibrate(vibratePattern,1); + oRingtone = RingtoneManager.getRingtone(mContext, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)); + oRingtone.play(); + } + + /** + * Constructor. + */ + public Call() { + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Call.mContext = this; + setContentView(R.layout.call); + Intent callingIntent = this.getIntent(); + + mLogo = (ImageView) findViewById(R.id.call_logo_anim); + mRotateAnim = AnimationUtils.loadAnimation(this, R.anim.rotate_and_scale); + mCloseCall = (Button) findViewById(R.id.call_cancel_button); + mCloseCall.setOnClickListener(new ClickListener()); + if (callingIntent.getBooleanExtra("isCaller", false)) { + mAcceptCall = (Button) findViewById(R.id.call_accept_button); + mAcceptCall.setVisibility(View.GONE); + call_state = UA_STATE_OUTGOING_CALL; + } else { + mAcceptCall = (Button) findViewById(R.id.call_accept_button); + mAcceptCall.setOnClickListener(new ClickListener()); + call_state = UA_STATE_INCOMING_CALL; + Call.startRingtone(); + } + mCallInfo = (TextView) findViewById(R.id.call_info); + } + + @Override + protected void onStart() { + super.onStart(); + mLogo.startAnimation(mRotateAnim); + } + + @Override + protected void onResume() { + super.onResume(); + if (mXmppFacade == null) + bindService(Call.SERVICE_INTENT, mServConn, BIND_AUTO_CREATE); + } + + @Override + protected void onPause() { + super.onPause(); + if (mXmppFacade != null) { + try { + mJingle.removeJingleListener(mJingleListener); + } catch (RemoteException e) { + e.printStackTrace(); + } + unbindService(mServConn); + mXmppFacade = null; + } + } + + @Override + public final boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.call, menu); + return true; + } + + /** + * Callback for menu item selected. + * @param item the item selected + * @return true on success, false otherwise + */ + @Override + public final boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.call_speaker_on: + try { + mJingle.setSpeakerMode(AudioManager.MODE_NORMAL); + } catch (RemoteException e) { + e.printStackTrace(); + } + return true; + case R.id.call_speaker_off: + try { + mJingle.setSpeakerMode(AudioManager.MODE_IN_CALL); + } catch (RemoteException e) { + e.printStackTrace(); + } + return true; + case R.id.call_hold_on: + Call.call_state = UA_STATE_HOLD; + return true; + case R.id.call_hold_off: + Call.call_state = UA_STATE_INCALL; + return true; + default: + return false; + } + } + + /** + * Click event listener on cancel button. + */ + private class ClickListener implements OnClickListener { + + /** + * Constructor. + */ + ClickListener() { + } + + @Override + public void onClick(View v) { + try { + if (v == mCloseCall) { + mJingle.closeCall(); + stopRingtone(); + Call.call_state = UA_STATE_IDLE; + } else if (v == mAcceptCall) { + mJingle.acceptCall(); + stopRingtone(); + Call.call_state = UA_STATE_INCALL; + } + } catch (RemoteException e) { + e.printStackTrace(); + } + //finish(); + } + } + + private class BeemJingleSessionListener extends IBeemJingleListener.Stub { + + /** + * Refresh the call activity. + */ + private class RunnableChange implements Runnable { + + private String mStr; + /** + * Constructor. + */ + public RunnableChange(String str) { + mStr = str; + } + + /** + * {@inheritDoc} + */ + @Override + public void run() { + mCallInfo.setText(mStr); + } + } + + public BeemJingleSessionListener() { + } + + @Override + public void sessionClosed(final String reason) { + android.util.Log.d("TEST", "TEST " + reason); + Call.stopRingtone(); + call_state = UA_STATE_IDLE; + mHandler.post(new RunnableChange(reason)); + } + + @Override + public void sessionDeclined(final String reason) { + android.util.Log.d("TEST", "TEST4 " + reason); + Call.stopRingtone(); + call_state = UA_STATE_IDLE; + mHandler.post(new RunnableChange(reason)); + } + + @Override + public void sessionClosedOnError(final String error) { + android.util.Log.d("TEST", "TEST5 " + error); + Call.stopRingtone(); + call_state = UA_STATE_IDLE; + mHandler.post(new RunnableChange(error)); + } + + @Override + public void sessionEstablished() { + android.util.Log.d("TEST", "TEST2 "); + call_state = UA_STATE_INCALL; + Call.stopRingtone(); + mHandler.post(new RunnableChange("established")); + } + + @Override + public void sessionRequested(final String fromJID) { + android.util.Log.d("TEST", "TEST3 " + fromJID); + mHandler.post(new RunnableChange(fromJID)); + } + } + + /** + * The service connection used to connect to the Beem service. + */ + private class BeemServiceConnection implements ServiceConnection { + + /** + * Constructor. + */ + public BeemServiceConnection() { + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + mXmppFacade = IXmppFacade.Stub.asInterface(service); + try { + mJingle = mXmppFacade.getJingleService(); + mJingle.addJingleListener(mJingleListener); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mXmppFacade = null; + } + } +} diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/ui/ContactList.java --- a/src/com/beem/project/beem/ui/ContactList.java Sat Feb 13 22:43:21 2010 +0100 +++ b/src/com/beem/project/beem/ui/ContactList.java Sun Feb 14 17:25:38 2010 +0100 @@ -39,7 +39,7 @@ Flavien Astraud, November 26, 2009 -*/ + */ package com.beem.project.beem.ui; import java.util.ArrayList; @@ -87,6 +87,7 @@ import com.beem.project.beem.service.Contact; import com.beem.project.beem.service.PresenceAdapter; import com.beem.project.beem.service.aidl.IBeemRosterListener; +import com.beem.project.beem.service.aidl.IJingle; import com.beem.project.beem.service.aidl.IRoster; import com.beem.project.beem.service.aidl.IXmppFacade; import com.beem.project.beem.ui.dialogs.builders.Alias; @@ -125,6 +126,7 @@ private String mCurGroup; private Contact mContact; private IXmppFacade mXmppFacade; + private IJingle mJingle; private SharedPreferences mSettings; private LayoutInflater mInflater; @@ -202,7 +204,11 @@ break; case R.id.contact_list_context_menu_call_item: try { - mXmppFacade.call(mContact.getJID() + "/psi"); + mJingle.call(mContact.getJID() + "/Beem"); + in = new Intent(this, Call.class); + in.setData(mContact.toUri()); + in.putExtra("isCaller", true); + startActivity(in); result = true; } catch (RemoteException e) { e.printStackTrace(); @@ -768,6 +774,7 @@ mXmppFacade = IXmppFacade.Stub.asInterface(service); try { mRoster = mXmppFacade.getRoster(); + mJingle = mXmppFacade.getJingleService(); if (mRoster != null) { mRoster.addRosterListener(mBeemRosterListener); List tmpContactList = mRoster.getContactList(); @@ -817,6 +824,7 @@ } mXmppFacade = null; mRoster = null; + mJingle = null; mListContact.clear(); mListGroup.clear(); mContactOnGroup.clear(); diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/utils/Random.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/beem/project/beem/utils/Random.java Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2005 Luca Veltri - University of Parma - Italy + * + * This file is part of MjSip (http://www.mjsip.org) + * + * MjSip is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MjSip is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MjSip; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author(s): + * Luca Veltri (luca.veltri@unipr.it) + */ + +package com.beem.project.beem.utils; + +/** + * Class Random collects some static methods for generating random numbers and + * other stuff. + */ +public class Random { + /** The random seed */ + static final long seed = System.currentTimeMillis(); + // static final long seed=0; + + static java.util.Random rand = new java.util.Random(seed); + + // static java.util.Random rand=new java.util.Random(); + + /** Returns a random integer between 0 and n-1 */ + /* + * static public int nextInt(int n) { seed=(seed*37)%987654321; return + * (int)(seed%n); } + */ + + /** Returns true or false respectively with probability p/100 and (1-p/100) */ + /* + * static boolean percent(int p) { return integer(100)> 4]; + } + + public static void alaw2linear(byte alaw[],short lin[],int frames) { + int i; + for (i = 0; i < frames; i++) + lin[i] = a2s[alaw[i+12] & 0xff]; + } + + public static void linear2alaw(short lin[],int offset,byte alaw[],int frames) { + int i; + for (i = 0; i < frames; i++) + alaw[i+12] = s2a[lin[i+offset] & 0xffff]; + } + + //change g711 ulaw start + protected static int alaw2ulaw(int aval) + { aval&=0xff; + return ((aval & 0x80)!=0)? (0xFF^_a2u[aval^0xD5]) : (0x7F^_a2u[aval^0x55]); + } + + protected static int ulaw2alaw(int uval) + { uval&=0xff; + return ((uval&0x80)!=0)? (0xD5^(_u2a[0xFF^uval]-1)) : (0x55^(_u2a[0x7F^uval]-1)); + } + + public static void ulaw2linear(byte ulaw[],short lin[],int frames) { + int i; + for (i = 0; i < frames; i++) + lin[i] = a2s[ulaw2alaw(ulaw[i+12] & 0xff)]; + } + public static void linear2ulaw(short lin[],int offset,byte ulaw[],int frames) { + int i; + for (i = 0; i < frames; i++) + ulaw[i+12] = (byte)alaw2ulaw(s2a[lin[i+offset] & 0xffff]); + } + //change end +} diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/media/RtpStreamReceiver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/sipdroid/media/RtpStreamReceiver.java Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,474 @@ +/* + * Copyright (C) 2009 The Sipdroid Open Source Project + * Copyright (C) 2005 Luca Veltri - University of Parma - Italy + * + * This file is part of Sipdroid (http://www.sipdroid.org) + * + * Sipdroid is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this source code; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package org.sipdroid.media; + +import java.io.IOException; +import java.net.SocketException; + +import com.beem.project.beem.jingle.JingleService; +import com.beem.project.beem.ui.Call; +import org.sipdroid.net.RtpPacket; +import org.sipdroid.net.RtpSocket; +import org.sipdroid.net.SipdroidSocket; +import org.sipdroid.pjlib.Codec; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.SharedPreferences.Editor; +import android.media.AudioFormat; +import android.media.AudioManager; +import android.media.AudioTrack; +import android.media.ToneGenerator; +import android.os.PowerManager; +import android.os.RemoteException; +import android.preference.PreferenceManager; +import android.provider.Settings; + +/** + * RtpStreamReceiver is a generic stream receiver. It receives packets from RTP + * and writes them into an OutputStream. + */ +public class RtpStreamReceiver extends Thread { + + /** Whether working in debug mode. */ + public static boolean DEBUG = true; + + /** Payload type */ + int p_type; + + /** Size of the read buffer */ + public static final int BUFFER_SIZE = 1024; + + /** Maximum blocking time, spent waiting for reading new bytes [milliseconds] */ + public static final int SO_TIMEOUT = 200; + + /** The RtpSocket */ + private RtpSocket rtp_socket = null; + + /** Whether it is running */ + private boolean running; + private AudioManager am; + private ContentResolver cr; + public static int speakermode; + private JingleService mJingle; + + /** + * Constructs a RtpStreamReceiver. + * + * @param output_stream + * the stream sink + * @param socket + * the local receiver SipdroidSocket + */ + public RtpStreamReceiver(SipdroidSocket socket, int payload_type) { + init(socket); + p_type = payload_type; + } + + /** Inits the RtpStreamReceiver */ + private void init(SipdroidSocket socket) { + if (socket != null) + rtp_socket = new RtpSocket(socket); + } + + /** Whether is running */ + public boolean isRunning() { + return running; + } + + /** Stops running */ + public void halt() { + running = false; + } + + public int speaker(int mode) { + int old = speakermode; + + if (Call.headset > 0 && mode == AudioManager.MODE_NORMAL) + return old; + saveVolume(); + setMode(speakermode = mode); + restoreVolume(); + return old; + } + + double smin = 200,s; + public static int nearend; + + void calc(short[] lin,int off,int len) { + int i,j; + double sm = 30000,r; + + for (i = 0; i < len; i += 5) { + j = lin[i+off]; + s = 0.03*Math.abs(j) + 0.97*s; + if (s < sm) sm = s; + if (s > smin) nearend = 3000/5; + else if (nearend > 0) nearend--; + } + for (i = 0; i < len; i++) { + j = lin[i+off]; + if (j > 6550) + lin[i+off] = 6550*5; + else if (j < -6550) + lin[i+off] = -6550*5; + else + lin[i+off] = (short)(j*5); + } + r = (double)len/100000; + smin = sm*r + smin*(1-r); + } + + static void setStreamVolume(final int stream,final int vol,final int flags) { + (new Thread() { + public void run() { + AudioManager am = (AudioManager) Call.mContext.getSystemService(Context.AUDIO_SERVICE); + am.setStreamVolume(stream, vol, flags); + if (stream == AudioManager.STREAM_MUSIC) restored = true; + } + }).start(); + } + + static boolean restored; + + public static float getEarGain() { + try { + return Float.valueOf(PreferenceManager.getDefaultSharedPreferences(Call.mContext).getString(Call.headset > 0?"heargain":"eargain", "0.25")); + } catch (NumberFormatException i) { + return (float)0.25; + } + } + + void restoreVolume() { + switch (am.getMode()) { + case AudioManager.MODE_IN_CALL: + setStreamVolume(AudioManager.STREAM_RING,(int)( + am.getStreamMaxVolume(AudioManager.STREAM_RING)* + getEarGain()), 0); + track.setStereoVolume(AudioTrack.getMaxVolume()* + getEarGain() + ,AudioTrack.getMaxVolume()* + getEarGain()); + break; + case AudioManager.MODE_NORMAL: + track.setStereoVolume(AudioTrack.getMaxVolume(),AudioTrack.getMaxVolume()); + break; + } + setStreamVolume(AudioManager.STREAM_MUSIC, + PreferenceManager.getDefaultSharedPreferences(Call.mContext).getInt("volume"+speakermode, + am.getStreamMaxVolume(AudioManager.STREAM_MUSIC)* + (speakermode == AudioManager.MODE_NORMAL?4:3)/4 + ),0); + } + + void saveVolume() { + if (restored) { + Editor edit = PreferenceManager.getDefaultSharedPreferences(Call.mContext).edit(); + edit.putInt("volume"+speakermode,am.getStreamVolume(AudioManager.STREAM_MUSIC)); + edit.commit(); + } + } + + void saveSettings() { + if (!PreferenceManager.getDefaultSharedPreferences(Call.mContext).getBoolean("oldvalid",false)) { + int oldvibrate = am.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); + int oldvibrate2 = am.getVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); + if (!PreferenceManager.getDefaultSharedPreferences(Call.mContext).contains("oldvibrate2")) + oldvibrate2 = AudioManager.VIBRATE_SETTING_ON; + int oldpolicy = android.provider.Settings.System.getInt(cr, android.provider.Settings.System.WIFI_SLEEP_POLICY, + Settings.System.WIFI_SLEEP_POLICY_DEFAULT); + Editor edit = PreferenceManager.getDefaultSharedPreferences(Call.mContext).edit(); + edit.putInt("oldvibrate", oldvibrate); + edit.putInt("oldvibrate2", oldvibrate2); + edit.putInt("oldpolicy", oldpolicy); + edit.putInt("oldring",am.getStreamVolume(AudioManager.STREAM_RING)); + edit.putBoolean("oldvalid", true); + edit.commit(); + } + } + + public static void setMode(int mode) { + Editor edit = PreferenceManager.getDefaultSharedPreferences(Call.mContext).edit(); + edit.putBoolean("setmode", mode != AudioManager.MODE_NORMAL); + edit.commit(); + AudioManager am = (AudioManager) Call.mContext.getSystemService(Context.AUDIO_SERVICE); + am.setMode(mode); + } + + public static void restoreMode() { + if (PreferenceManager.getDefaultSharedPreferences(Call.mContext).getBoolean("setmode",true)) { + setMode(AudioManager.MODE_NORMAL); + } + } + + public static void restoreSettings() { + if (PreferenceManager.getDefaultSharedPreferences(Call.mContext).getBoolean("oldvalid",true)) { + AudioManager am = (AudioManager) Call.mContext.getSystemService(Context.AUDIO_SERVICE); + ContentResolver cr = Call.mContext.getContentResolver(); + int oldvibrate = PreferenceManager.getDefaultSharedPreferences(Call.mContext).getInt("oldvibrate",0); + int oldvibrate2 = PreferenceManager.getDefaultSharedPreferences(Call.mContext).getInt("oldvibrate2",0); + int oldpolicy = PreferenceManager.getDefaultSharedPreferences(Call.mContext).getInt("oldpolicy",0); + am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,oldvibrate); + am.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,oldvibrate2); + Settings.System.putInt(cr, Settings.System.WIFI_SLEEP_POLICY, oldpolicy); + setStreamVolume(AudioManager.STREAM_RING, PreferenceManager.getDefaultSharedPreferences(Call.mContext).getInt("oldring",0), 0); + Editor edit = PreferenceManager.getDefaultSharedPreferences(Call.mContext).edit(); + edit.putBoolean("oldvalid", false); + edit.commit(); + PowerManager pm = (PowerManager) Call.mContext.getSystemService(Context.POWER_SERVICE); + PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | + PowerManager.ACQUIRE_CAUSES_WAKEUP, "Sipdroid.RtpStreamReceiver"); + wl.acquire(1000); + } + restoreMode(); + } + + public static float good, late, lost, loss; + public static int timeout; + + void empty() { + try { + rtp_socket.getDatagramSocket().setSoTimeout(1); + for (;;) + rtp_socket.receive(rtp_packet); + } catch (SocketException e2) { + e2.printStackTrace(); + } catch (IOException e) { + } + try { + rtp_socket.getDatagramSocket().setSoTimeout(1000); + } catch (SocketException e2) { + e2.printStackTrace(); + } + } + + RtpPacket rtp_packet; + AudioTrack track; + + /** Runs it in a new Thread. */ + public void run() { + boolean nodata = PreferenceManager.getDefaultSharedPreferences(Call.mContext).getBoolean("nodata",false); + + if (rtp_socket == null) { + if (DEBUG) + println("ERROR: RTP socket is null"); + return; + } + + byte[] buffer = new byte[BUFFER_SIZE+12]; + byte[] buffer_gsm = new byte[33+12]; + int i; + rtp_packet = new RtpPacket(buffer, 0); + + if (DEBUG) + println("Reading blocks of max " + buffer.length + " bytes"); + + running = true; + speakermode = Call.docked > 0?AudioManager.MODE_NORMAL:AudioManager.MODE_IN_CALL; + restored = false; + + android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO); + am = (AudioManager) Call.mContext.getSystemService(Context.AUDIO_SERVICE); + cr = Call.mContext.getContentResolver(); + saveSettings(); + Settings.System.putInt(cr, Settings.System.WIFI_SLEEP_POLICY,Settings.System.WIFI_SLEEP_POLICY_NEVER); + am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,AudioManager.VIBRATE_SETTING_OFF); + am.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,AudioManager.VIBRATE_SETTING_OFF); + int oldvol = am.getStreamVolume(AudioManager.STREAM_MUSIC); + track = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, + BUFFER_SIZE*2*2, AudioTrack.MODE_STREAM); + short lin[] = new short[BUFFER_SIZE]; + short lin2[] = new short[BUFFER_SIZE]; + int user, server, lserver, luser, cnt, todo, headroom, len = 0, seq = 0, cnt2 = 0, m = 1, + expseq, getseq, vm = 1, gap, gseq; + timeout = 1; + boolean islate; + user = 0; + lserver = 0; + luser = -8000; + cnt = 0; + switch (p_type) { + case 3: + Codec.init(); + break; + case 0: + case 8: + G711.init(); + break; + } + ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_MUSIC,(int)(ToneGenerator.MAX_VOLUME*2*0.95)); + track.play(); + if (Call.headset > 0 && Call.oRingtone != null) { + ToneGenerator tg2 = new ToneGenerator(AudioManager.STREAM_RING,(int)(ToneGenerator.MAX_VOLUME*2*0.95)); + tg2.startTone(ToneGenerator.TONE_SUP_RINGTONE); + System.gc(); + tg2.stopTone(); + } else + System.gc(); + while (running) { + if (Call.call_state == Call.UA_STATE_HOLD) { + tg.stopTone(); + track.pause(); + while (running && Call.call_state == Call.UA_STATE_HOLD) { + try { + sleep(1000); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + } + track.play(); + System.gc(); + timeout = 1; + seq = 0; + } + try { + rtp_socket.receive(rtp_packet); + if (timeout != 0) { + tg.stopTone(); + track.pause(); + user += track.write(lin2,0,BUFFER_SIZE); + user += track.write(lin2,0,BUFFER_SIZE); + track.play(); + cnt += 2*BUFFER_SIZE; + empty(); + } + timeout = 0; + } catch (IOException e) { + if (timeout == 0 && nodata) { + tg.startTone(ToneGenerator.TONE_SUP_RINGTONE); + } + rtp_socket.getDatagramSocket().disconnect(); + if (++timeout > 22) { + try { + mJingle.closeCall(); + } catch (RemoteException e1) { + e1.printStackTrace(); + } + break; + } + } + if (running && timeout == 0) { + gseq = rtp_packet.getSequenceNumber(); + if (seq == gseq) { + m++; + continue; + } + + server = track.getPlaybackHeadPosition(); + headroom = user-server; + + if (headroom > 1500) + cnt += len; + else + cnt = 0; + + if (lserver == server) + cnt2++; + else + cnt2 = 0; + + if (cnt <= 500 || cnt2 >= 2 || headroom - 875 < len) { + switch (rtp_packet.getPayloadType()) { + case 0: + len = rtp_packet.getPayloadLength(); + G711.ulaw2linear(buffer, lin, len); + break; + case 8: + len = rtp_packet.getPayloadLength(); + G711.alaw2linear(buffer, lin, len); + break; + case 3: + for (i = 12; i < 45; i++) + buffer_gsm[i] = buffer[i]; + len = Codec.decode(buffer_gsm, lin, 0); + break; + } + + if (speakermode == AudioManager.MODE_NORMAL) + calc(lin,0,len); + } + + if (headroom < 250) { + todo = 875 - headroom; + println("insert "+todo); + islate = true; + user += track.write(lin2,0,todo); + } else + islate = false; + + if (cnt > 500 && cnt2 < 2) { + todo = headroom - 875; + println("cut "+todo); + if (todo < len) + user += track.write(lin,todo,len-todo); + } else + user += track.write(lin,0,len); + + seq = gseq; + + if (user >= luser + 8000 && Call.call_state == Call.UA_STATE_INCALL) { + if (luser == -8000 || am.getMode() != speakermode) { + saveVolume(); + setMode(speakermode); + restoreVolume(); + } + luser = user; + } + lserver = server; + } + } + track.stop(); + saveVolume(); + setStreamVolume(AudioManager.STREAM_MUSIC,oldvol,0); + restoreSettings(); + setStreamVolume(AudioManager.STREAM_MUSIC,oldvol,0); + tg.stopTone(); + tg = new ToneGenerator(AudioManager.STREAM_RING,ToneGenerator.MAX_VOLUME/4*3); + tg.startTone(ToneGenerator.TONE_PROP_PROMPT); + try { + sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + tg.stopTone(); + + rtp_socket.close(); + rtp_socket = null; + + if (DEBUG) + println("rtp receiver terminated"); + } + + /** Debug output */ + private static void println(String str) { + System.out.println("RtpStreamReceiver: " + str); + } + + public static int byte2int(byte b) { // return (b>=0)? b : -((b^0xFF)+1); + // return (b>=0)? b : b+0x100; + return (b + 0x100) % 0x100; + } + + public static int byte2int(byte b1, byte b2) { + return (((b1 + 0x100) % 0x100) << 8) + (b2 + 0x100) % 0x100; + } +} diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/media/RtpStreamSender.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/sipdroid/media/RtpStreamSender.java Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2009 The Sipdroid Open Source Project + * Copyright (C) 2005 Luca Veltri - University of Parma - Italy + * + * This file is part of Sipdroid (http://www.sipdroid.org) + * + * Sipdroid is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this source code; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package org.sipdroid.media; + +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.util.Random; + + +import org.sipdroid.pjlib.Codec; + +import org.sipdroid.media.RtpStreamReceiver; +import org.sipdroid.net.RtpPacket; +import org.sipdroid.net.RtpSocket; +import org.sipdroid.net.SipdroidSocket; + +import com.beem.project.beem.ui.Call; +import com.beem.project.beem.utils.BeemConnectivity; + +import android.content.Context; +import android.media.AudioFormat; +import android.media.AudioManager; +import android.media.AudioRecord; +import android.media.MediaRecorder; +import android.preference.PreferenceManager; +import android.provider.Settings; +import android.telephony.TelephonyManager; + +/** + * RtpStreamSender is a generic stream sender. It takes an InputStream and sends + * it through RTP. + */ +public class RtpStreamSender extends Thread { + /** Whether working in debug mode. */ + public static boolean DEBUG = true; + + /** The RtpSocket */ + RtpSocket rtp_socket = null; + + /** Payload type */ + int p_type; + + /** Number of frame per second */ + long frame_rate; + + /** Number of bytes per frame */ + int frame_size; + + /** + * Whether it works synchronously with a local clock, or it it acts as slave + * of the InputStream + */ + boolean do_sync = true; + + /** + * Synchronization correction value, in milliseconds. It accellarates the + * sending rate respect to the nominal value, in order to compensate program + * latencies. + */ + int sync_adj = 0; + + /** Whether it is running */ + boolean running = false; + boolean muted = false; + + /** + * Constructs a RtpStreamSender. + * + * @param input_stream + * the stream to be sent + * @param do_sync + * whether time synchronization must be performed by the + * RtpStreamSender, or it is performed by the InputStream (e.g. + * the system audio input) + * @param payload_type + * the payload type + * @param frame_rate + * the frame rate, i.e. the number of frames that should be sent + * per second; it is used to calculate the nominal packet time + * and,in case of do_sync==true, the next departure time + * @param frame_size + * the size of the payload + * @param src_socket + * the socket used to send the RTP packet + * @param dest_addr + * the destination address + * @param dest_port + * the destination port + */ + public RtpStreamSender(boolean do_sync, + int payload_type, long frame_rate, int frame_size, + SipdroidSocket src_socket, String dest_addr, int dest_port) { + init(do_sync, payload_type, frame_rate, frame_size, + src_socket, dest_addr, dest_port); + } + + /** Inits the RtpStreamSender */ + private void init(boolean do_sync, + int payload_type, long frame_rate, int frame_size, + SipdroidSocket src_socket, String dest_addr, + int dest_port) { + this.p_type = payload_type; + this.frame_rate = frame_rate; + this.frame_size = frame_size; + this.do_sync = do_sync; + try { + rtp_socket = new RtpSocket(src_socket, InetAddress + .getByName(dest_addr), dest_port); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** Sets the synchronization adjustment time (in milliseconds). */ + public void setSyncAdj(int millisecs) { + sync_adj = millisecs; + } + + /** Whether is running */ + public boolean isRunning() { + return running; + } + + public boolean mute() { + return muted = !muted; + } + + public static int delay = 0; + + /** Stops running */ + public void halt() { + running = false; + } + + Random random; + double smin = 200,s; + int nearend; + + void calc(short[] lin,int off,int len) { + int i,j; + double sm = 30000,r; + + for (i = 0; i < len; i += 5) { + j = lin[i+off]; + s = 0.03*Math.abs(j) + 0.97*s; + if (s < sm) sm = s; + if (s > smin) nearend = 3000/5; + else if (nearend > 0) nearend--; + } + for (i = 0; i < len; i++) { + j = lin[i+off]; + if (j > 6550) + lin[i+off] = 6550*5; + else if (j < -6550) + lin[i+off] = -6550*5; + else + lin[i+off] = (short)(j*5); + } + r = (double)len/100000; + smin = sm*r + smin*(1-r); + } + + void calc1(short[] lin,int off,int len) { + int i,j; + + for (i = 0; i < len; i++) { + j = lin[i+off]; + lin[i+off] = (short)(j>>1); + } + } + + void calc5(short[] lin,int off,int len) { + int i,j; + + for (i = 0; i < len; i++) { + j = lin[i+off]; + if (j > 16350) + lin[i+off] = 16350<<1; + else if (j < -16350) + lin[i+off] = -16350<<1; + else + lin[i+off] = (short)(j<<1); + } + } + + void calc10(short[] lin,int off,int len) { + int i,j; + + for (i = 0; i < len; i++) { + j = lin[i+off]; + if (j > 8150) + lin[i+off] = 8150<<2; + else if (j < -8150) + lin[i+off] = -8150<<2; + else + lin[i+off] = (short)(j<<2); + } + } + + void noise(short[] lin,int off,int len,double power) { + int i,r = (int)(power*2); + short ran; + + if (r == 0) r = 1; + for (i = 0; i < len; i += 4) { + ran = (short)(random.nextInt(r*2)-r); + lin[i+off] = ran; + lin[i+off+1] = ran; + lin[i+off+2] = ran; + lin[i+off+3] = ran; + } + } + public static float getMicGain() { + if (Call.headset > 0) + return Float.valueOf(PreferenceManager.getDefaultSharedPreferences(Call.mContext).getString("hmicgain", "1.0")); + return Float.valueOf(PreferenceManager.getDefaultSharedPreferences(Call.mContext).getString("micgain", "0.25")); + } + + /** Runs it in a new Thread. */ + public void run() { + if (rtp_socket == null) + return; + byte[] buffer = new byte[frame_size + 12]; + RtpPacket rtp_packet = new RtpPacket(buffer, 0); + rtp_packet.setPayloadType(p_type); + int seqn = 0; + long time = 0; + double p = 0; + TelephonyManager tm = (TelephonyManager) Call.mContext.getSystemService(Context.TELEPHONY_SERVICE); + boolean improve = PreferenceManager.getDefaultSharedPreferences(Call.mContext).getBoolean("improve",false); + boolean useGSM = !PreferenceManager.getDefaultSharedPreferences(Call.mContext).getString("compression","edge").equals("never"); + int micgain = (int)(getMicGain()*10); + running = true; + + if (DEBUG) + println("Reading blocks of " + buffer.length + " bytes"); + + android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); + AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, + AudioRecord.getMinBufferSize(8000, + AudioFormat.CHANNEL_CONFIGURATION_MONO, + AudioFormat.ENCODING_PCM_16BIT)*3/2); + short[] lin = new short[frame_size*11]; + int num,ring = 0; + random = new Random(); + InputStream alerting = null; + try { + alerting = Call.mContext.getAssets().open("alerting"); + } catch (IOException e2) { + e2.printStackTrace(); + } + switch (p_type) { + case 3: + Codec.init(); + break; + case 0: + case 8: + G711.init(); + break; + } + record.startRecording(); + while (running) { + if (muted || Call.call_state == Call.UA_STATE_HOLD) { + record.stop(); + while (running && (muted || Call.call_state == Call.UA_STATE_HOLD)) { + try { + sleep(1000); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + } + record.startRecording(); + } + num = record.read(lin,(ring+delay)%(frame_size*11),frame_size); + + if (RtpStreamReceiver.speakermode == AudioManager.MODE_NORMAL) { + calc(lin,(ring+delay)%(frame_size*11),num); + if (RtpStreamReceiver.nearend != 0) + noise(lin,(ring+delay)%(frame_size*11),num,p); + else if (RtpStreamReceiver.nearend == 0) + p = 0.9*p + 0.1*s; + } else switch (micgain) { + case 1: + calc1(lin,(ring+delay)%(frame_size*11),num); + break; + case 5: + calc5(lin,(ring+delay)%(frame_size*11),num); + break; + case 10: + calc10(lin,(ring+delay)%(frame_size*11),num); + break; + } + if (Call.call_state != Call.UA_STATE_INCALL && alerting != null) { + try { + if (alerting.available() < num) + alerting.reset(); + alerting.read(buffer,12,num); + } catch (IOException e) { + e.printStackTrace(); + } + switch (p_type) {// have to add ulaw case? + case 3: + G711.alaw2linear(buffer, lin, num); + num = Codec.encode(lin, 0, buffer, num); + break; + case 0: + G711.alaw2linear(buffer, lin, num); + G711.linear2ulaw(lin, 0, buffer, num); + break; + } + } else { + switch (p_type) { + case 3: + num = Codec.encode(lin, ring%(frame_size*11), buffer, num); + break; + case 0: + G711.linear2ulaw(lin, ring%(frame_size*11), buffer, num); + break; + case 8: + G711.linear2alaw(lin, ring%(frame_size*11), buffer, num); + break; + } + } + ring += frame_size; + rtp_packet.setSequenceNumber(seqn++); + rtp_packet.setTimestamp(time); + rtp_packet.setPayloadLength(num); + try { + rtp_socket.send(rtp_packet); + } catch (IOException e) { + e.printStackTrace(); + } + time += frame_size; + /*if (useGSM && p_type == 8 && !BeemConnectivity.isWifi(Call.mContext) && tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_EDGE) { + rtp_packet.setPayloadType(p_type = 3); + if (frame_size == 1024) { + frame_size = 960; + ring = 0; + } + }*/ + } + record.stop(); + + rtp_socket.close(); + rtp_socket = null; + + if (DEBUG) + println("rtp sender terminated"); + } + + /** Debug output */ + private static void println(String str) { + System.out.println("RtpStreamSender: " + str); + } + +} \ No newline at end of file diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/net/RtpPacket.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/sipdroid/net/RtpPacket.java Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2009 The Sipdroid Open Source Project + * Copyright (C) 2005 Luca Veltri - University of Parma - Italy + * + * This file is part of Sipdroid (http://www.sipdroid.org) + * + * Sipdroid is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this source code; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package org.sipdroid.net; + +import com.beem.project.beem.utils.Random; + +/** + * RtpPacket implements a RTP packet. + */ +public class RtpPacket { + /* RTP packet buffer containing both the RTP header and payload */ + byte[] packet; + + /* RTP packet length */ + int packet_len; + + /* RTP header length */ + // int header_len; + /** Gets the RTP packet */ + public byte[] getPacket() { + return packet; + } + + /** Gets the RTP packet length */ + public int getLength() { + return packet_len; + } + + /** Gets the RTP header length */ + public int getHeaderLength() { + if (packet_len >= 12) + return 12 + 4 * getCscrCount(); + else + return packet_len; // broken packet + } + + /** Gets the RTP header length */ + public int getPayloadLength() { + if (packet_len >= 12) + return packet_len - getHeaderLength(); + else + return 0; // broken packet + } + + /** Sets the RTP payload length */ + public void setPayloadLength(int len) { + packet_len = getHeaderLength() + len; + } + + // version (V): 2 bits + // padding (P): 1 bit + // extension (X): 1 bit + // CSRC count (CC): 4 bits + // marker (M): 1 bit + // payload type (PT): 7 bits + // sequence number: 16 bits + // timestamp: 32 bits + // SSRC: 32 bits + // CSRC list: 0 to 15 items, 32 bits each + + /** Gets the version (V) */ + public int getVersion() { + if (packet_len >= 12) + return (packet[0] >> 6 & 0x03); + else + return 0; // broken packet + } + + /** Sets the version (V) */ + public void setVersion(int v) { + if (packet_len >= 12) + packet[0] = (byte) ((packet[0] & 0x3F) | ((v & 0x03) << 6)); + } + + /** Whether has padding (P) */ + public boolean hasPadding() { + if (packet_len >= 12) + return getBit(packet[0], 5); + else + return false; // broken packet + } + + /** Set padding (P) */ + public void setPadding(boolean p) { + if (packet_len >= 12) + packet[0] = setBit(p, packet[0], 5); + } + + /** Whether has extension (X) */ + public boolean hasExtension() { + if (packet_len >= 12) + return getBit(packet[0], 4); + else + return false; // broken packet + } + + /** Set extension (X) */ + public void setExtension(boolean x) { + if (packet_len >= 12) + packet[0] = setBit(x, packet[0], 4); + } + + /** Gets the CSCR count (CC) */ + public int getCscrCount() { + if (packet_len >= 12) + return (packet[0] & 0x0F); + else + return 0; // broken packet + } + + /** Whether has marker (M) */ + public boolean hasMarker() { + if (packet_len >= 12) + return getBit(packet[1], 7); + else + return false; // broken packet + } + + /** Set marker (M) */ + public void setMarker(boolean m) { + if (packet_len >= 12) + packet[1] = setBit(m, packet[1], 7); + } + + /** Gets the payload type (PT) */ + public int getPayloadType() { + if (packet_len >= 12) + return (packet[1] & 0x7F); + else + return -1; // broken packet + } + + /** Sets the payload type (PT) */ + public void setPayloadType(int pt) { + if (packet_len >= 12) + packet[1] = (byte) ((packet[1] & 0x80) | (pt & 0x7F)); + } + + /** Gets the sequence number */ + public int getSequenceNumber() { + if (packet_len >= 12) + return getInt(packet, 2, 4); + else + return 0; // broken packet + } + + /** Sets the sequence number */ + public void setSequenceNumber(int sn) { + if (packet_len >= 12) + setInt(sn, packet, 2, 4); + } + + /** Gets the timestamp */ + public long getTimestamp() { + if (packet_len >= 12) + return getLong(packet, 4, 8); + else + return 0; // broken packet + } + + /** Sets the timestamp */ + public void setTimestamp(long timestamp) { + if (packet_len >= 12) + setLong(timestamp, packet, 4, 8); + } + + /** Gets the SSCR */ + public long getSscr() { + if (packet_len >= 12) + return getLong(packet, 8, 12); + else + return 0; // broken packet + } + + /** Sets the SSCR */ + public void setSscr(long ssrc) { + if (packet_len >= 12) + setLong(ssrc, packet, 8, 12); + } + + /** Gets the CSCR list */ + public long[] getCscrList() { + int cc = getCscrCount(); + long[] cscr = new long[cc]; + for (int i = 0; i < cc; i++) + cscr[i] = getLong(packet, 12 + 4 * i, 16 + 4 * i); + return cscr; + } + + /** Sets the CSCR list */ + public void setCscrList(long[] cscr) { + if (packet_len >= 12) { + int cc = cscr.length; + if (cc > 15) + cc = 15; + packet[0] = (byte) (((packet[0] >> 4) << 4) + cc); + cscr = new long[cc]; + for (int i = 0; i < cc; i++) + setLong(cscr[i], packet, 12 + 4 * i, 16 + 4 * i); + // header_len=12+4*cc; + } + } + + /** Sets the payload */ + public void setPayload(byte[] payload, int len) { + if (packet_len >= 12) { + int header_len = getHeaderLength(); + for (int i = 0; i < len; i++) + packet[header_len + i] = payload[i]; + packet_len = header_len + len; + } + } + + /** Gets the payload */ + public byte[] getPayload() { + int header_len = getHeaderLength(); + int len = packet_len - header_len; + byte[] payload = new byte[len]; + for (int i = 0; i < len; i++) + payload[i] = packet[header_len + i]; + return payload; + } + + /** Creates a new RTP packet */ + public RtpPacket(byte[] buffer, int packet_length) { + packet = buffer; + packet_len = packet_length; + if (packet_len < 12) + packet_len = 12; + init(0x0F); + } + + /** init the RTP packet header (only PT) */ + public void init(int ptype) { + init(ptype, Random.nextLong()); + } + + /** init the RTP packet header (PT and SSCR) */ + public void init(int ptype, long sscr) { + init(ptype, Random.nextInt(), Random.nextLong(), sscr); + } + + /** init the RTP packet header (PT, SQN, TimeStamp, SSCR) */ + public void init(int ptype, int seqn, long timestamp, long sscr) { + setVersion(2); + setPayloadType(ptype); + setSequenceNumber(seqn); + setTimestamp(timestamp); + setSscr(sscr); + } + + // *********************** Private and Static *********************** + + /** Gets int value */ + private static int getInt(byte b) { + return ((int) b + 256) % 256; + } + + /** Gets long value */ + private static long getLong(byte[] data, int begin, int end) { + long n = 0; + for (; begin < end; begin++) { + n <<= 8; + n += data[begin]; + } + return n; + } + + /** Sets long value */ + private static void setLong(long n, byte[] data, int begin, int end) { + for (end--; end >= begin; end--) { + data[end] = (byte) (n % 256); + n >>= 8; + } + } + + /** Gets Int value */ + private static int getInt(byte[] data, int begin, int end) { + return (int) getLong(data, begin, end); + } + + /** Sets Int value */ + private static void setInt(int n, byte[] data, int begin, int end) { + setLong(n, data, begin, end); + } + + /** Gets bit value */ + private static boolean getBit(byte b, int bit) { + return (b >> bit) == 1; + } + + /** Sets bit value */ + private static byte setBit(boolean value, byte b, int bit) { + if (value) + return (byte) (b | (1 << bit)); + else + return (byte) ((b | (1 << bit)) ^ (1 << bit)); + } +} diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/net/RtpSocket.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/sipdroid/net/RtpSocket.java Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2009 The Sipdroid Open Source Project + * Copyright (C) 2005 Luca Veltri - University of Parma - Italy + * + * This file is part of Sipdroid (http://www.sipdroid.org) + * + * Sipdroid is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this source code; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package org.sipdroid.net; + +import java.net.InetAddress; +import java.net.DatagramPacket; +import java.io.IOException; + + + +/** + * RtpSocket implements a RTP socket for receiving and sending RTP packets. + *

+ * RtpSocket is associated to a DatagramSocket that is used to send and/or + * receive RtpPackets. + */ +public class RtpSocket { + /** UDP socket */ + SipdroidSocket socket; + DatagramPacket datagram; + + /** Remote address */ + InetAddress r_addr; + + /** Remote port */ + int r_port; + + /** Creates a new RTP socket (only receiver) */ + public RtpSocket(SipdroidSocket datagram_socket) { + socket = datagram_socket; + r_addr = null; + r_port = 0; + datagram = new DatagramPacket(new byte[1],1); + } + + /** Creates a new RTP socket (sender and receiver) */ + public RtpSocket(SipdroidSocket datagram_socket, + InetAddress remote_address, int remote_port) { + socket = datagram_socket; + r_addr = remote_address; + r_port = remote_port; + datagram = new DatagramPacket(new byte[1],1); + } + + /** Returns the RTP SipdroidSocket */ + public SipdroidSocket getDatagramSocket() { + return socket; + } + + /** Receives a RTP packet from this socket */ + public void receive(RtpPacket rtpp) throws IOException { + datagram.setData(rtpp.packet); + datagram.setLength(rtpp.packet.length); + socket.receive(datagram); + if (!socket.isConnected()) + socket.connect(datagram.getAddress(),datagram.getPort()); + rtpp.packet_len = datagram.getLength(); + } + + /** Sends a RTP packet from this socket */ + public void send(RtpPacket rtpp) throws IOException { + datagram.setData(rtpp.packet); + datagram.setLength(rtpp.packet_len); + datagram.setAddress(r_addr); + datagram.setPort(r_port); + socket.send(datagram); + } + + /** Closes this socket */ + public void close() { // socket.close(); + } + +} diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/net/SipdroidSocket.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/sipdroid/net/SipdroidSocket.java Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2009 The Sipdroid Open Source Project + * + * This file is part of Sipdroid (http://www.sipdroid.org) + * + * Sipdroid is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this source code; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package org.sipdroid.net; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.SocketOptions; +import java.net.UnknownHostException; + +import org.sipdroid.net.impl.OSNetworkSystem; +import org.sipdroid.net.impl.PlainDatagramSocketImpl; + +public class SipdroidSocket extends DatagramSocket { + + PlainDatagramSocketImpl impl; + public static boolean loaded = false; + + public SipdroidSocket(int port) throws SocketException, UnknownHostException { + super(!loaded?port:0); + if (loaded) { + impl = new PlainDatagramSocketImpl(); + impl.create(); + impl.bind(port,InetAddress.getByName("0")); + } + } + + public void close() { + super.close(); + if (loaded) impl.close(); + } + + public void setSoTimeout(int val) throws SocketException { + if (loaded) impl.setOption(SocketOptions.SO_TIMEOUT, val); + else super.setSoTimeout(val); + } + + public void receive(DatagramPacket pack) throws IOException { + if (loaded) impl.receive(pack); + else super.receive(pack); + } + + public void send(DatagramPacket pack) throws IOException { + if (loaded) impl.send(pack); + else super.send(pack); + } + + public boolean isConnected() { + if (loaded) return true; + else return super.isConnected(); + } + + public void disconnect() { + if (!loaded) super.disconnect(); + } + + public void connect(InetAddress addr,int port) { + if (!loaded) super.connect(addr,port); + } + + static { + try { + System.loadLibrary("OSNetworkSystem"); + OSNetworkSystem.getOSNetworkSystem().oneTimeInitialization(true); + SipdroidSocket.loaded = true; + } catch (Throwable e) { + e.printStackTrace(); + } + } +} diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/net/impl/OSNetworkSystem.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/sipdroid/net/impl/OSNetworkSystem.java Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,748 @@ +/* + * Copyright (C) 2009 The Sipdroid Open Source Project + * + * This file is part of Sipdroid (http://www.sipdroid.org) + * + * Sipdroid is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this source code; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// BEGIN android-note +// address length was changed from long to int for performance reasons. +// END android-note + +package org.sipdroid.net.impl; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.SocketImpl; +import java.net.UnknownHostException; +import java.nio.channels.Channel; +// BEGIN android-removed +// import java.nio.channels.SelectableChannel; +// END android-removed +/* + * + * This Class is used for native code wrap, the implement class of + * INetworkSystem. + * + */ +public final class OSNetworkSystem { + + // ---------------------------------------------------- + // Class Variables + // ---------------------------------------------------- + + private static final int ERRORCODE_SOCKET_TIMEOUT = -209; + + private static OSNetworkSystem ref = new OSNetworkSystem(); + + private static final int INETADDR_REACHABLE = 0; + + private static boolean isNetworkInited = false; + + // ---------------------------------------------------- + // Class Constructor + // ---------------------------------------------------- + + // can not be instantiated. + private OSNetworkSystem() { + super(); + } + + /* + * @return a static ref of this class + */ + public static OSNetworkSystem getOSNetworkSystem() { + return ref; + } + + // Useing when cache set/get is OK + // public static native void oneTimeInitializationDatagram( + // boolean jcl_IPv6_support); + // + // public static native void oneTimeInitializationSocket( + // boolean jcl_IPv6_support); + + // -------------------------------------------------- + // java codes that wrap native codes + // -------------------------------------------------- + + public void createSocket(FileDescriptor fd, boolean preferIPv4Stack) + throws IOException { + createSocketImpl(fd, preferIPv4Stack); + } + + public void createDatagramSocket(FileDescriptor fd, boolean preferIPv4Stack) + throws SocketException { + createDatagramSocketImpl(fd, preferIPv4Stack); + } + + public int read(FileDescriptor aFD, byte[] data, int offset, int count, + int timeout) throws IOException { + return readSocketImpl(aFD, data, offset, count, timeout); + } + + public int readDirect(FileDescriptor aFD, int address, int offset, int count, + int timeout) throws IOException { + return readSocketDirectImpl(aFD, address, offset, count, timeout); + } + + public int write(FileDescriptor aFD, byte[] data, int offset, int count) + throws IOException { + return writeSocketImpl(aFD, data, offset, count); + } + + public int writeDirect(FileDescriptor aFD, int address, int offset, + int count) throws IOException { + return writeSocketDirectImpl(aFD, address, offset, count); + } + + public void setNonBlocking(FileDescriptor aFD, boolean block) + throws IOException { + setNonBlockingImpl(aFD, block); + } + + public void connectDatagram(FileDescriptor aFD, int port, int trafficClass, + InetAddress inetAddress) throws SocketException { + connectDatagramImpl2(aFD, port, trafficClass, inetAddress); + } + + public int connect(FileDescriptor aFD, int trafficClass, + InetAddress inetAddress, int port) throws IOException{ + return connectSocketImpl(aFD, trafficClass, inetAddress, port); + } + + // BEGIN android-changed + public int connectWithTimeout(FileDescriptor aFD, int timeout, + int trafficClass, InetAddress inetAddress, int port, int step, + byte[] context) throws IOException{ + return connectWithTimeoutSocketImpl(aFD, timeout, trafficClass, + inetAddress, port, step, context); + } + // END android-changed + + public void connectStreamWithTimeoutSocket(FileDescriptor aFD, int aport, + int timeout, int trafficClass, InetAddress inetAddress) + throws IOException { + connectStreamWithTimeoutSocketImpl(aFD, aport, timeout, trafficClass, + inetAddress); + } + + public void bind(FileDescriptor aFD, int port, InetAddress inetAddress) + throws SocketException { + socketBindImpl(aFD, port, inetAddress); + } + + public boolean bind2(FileDescriptor aFD, int port, boolean bindToDevice, + InetAddress inetAddress) throws SocketException { + return socketBindImpl2(aFD, port, bindToDevice, inetAddress); + } + + public void accept(FileDescriptor fdServer, SocketImpl newSocket, + FileDescriptor fdnewSocket, int timeout) throws IOException { + acceptSocketImpl(fdServer, newSocket, fdnewSocket, timeout); + } + + public int sendDatagram(FileDescriptor fd, byte[] data, int offset, + int length, int port, boolean bindToDevice, int trafficClass, + InetAddress inetAddress) throws IOException { + return sendDatagramImpl(fd, data, offset, length, port, bindToDevice, + trafficClass, inetAddress); + } + + public int sendDatagramDirect(FileDescriptor fd, int address, int offset, + int length, int port, boolean bindToDevice, int trafficClass, + InetAddress inetAddress) throws IOException { + return sendDatagramDirectImpl(fd, address, offset, length, port, bindToDevice, + trafficClass, inetAddress); + } + + public int sendDatagram2(FileDescriptor fd, byte[] data, int offset, + int length, int port, InetAddress inetAddress) throws IOException { + return sendDatagramImpl2(fd, data, offset, length, port, inetAddress); + } + + public int receiveDatagram(FileDescriptor aFD, DatagramPacket packet, + byte[] data, int offset, int length, int receiveTimeout, + boolean peek) throws IOException { + return receiveDatagramImpl(aFD, packet, data, offset, length, + receiveTimeout, peek); + } + + public int receiveDatagramDirect(FileDescriptor aFD, DatagramPacket packet, + int address, int offset, int length, int receiveTimeout, + boolean peek) throws IOException { + return receiveDatagramDirectImpl(aFD, packet, address, offset, length, + receiveTimeout, peek); + } + + public int recvConnectedDatagram(FileDescriptor aFD, DatagramPacket packet, + byte[] data, int offset, int length, int receiveTimeout, + boolean peek) throws IOException { + return recvConnectedDatagramImpl(aFD, packet, data, offset, length, + receiveTimeout, peek); + } + + public int recvConnectedDatagramDirect(FileDescriptor aFD, DatagramPacket packet, int address, + int offset, int length, int receiveTimeout, boolean peek) + throws IOException { + return recvConnectedDatagramDirectImpl(aFD, packet, address, offset, length, receiveTimeout, peek); + } + + public int peekDatagram(FileDescriptor aFD, InetAddress sender, + int receiveTimeout) throws IOException { + return peekDatagramImpl(aFD, sender, receiveTimeout); + } + + public int sendConnectedDatagram(FileDescriptor fd, byte[] data, + int offset, int length, boolean bindToDevice) throws IOException { + return sendConnectedDatagramImpl(fd, data, offset, length, bindToDevice); + } + + public int sendConnectedDatagramDirect(FileDescriptor fd, int address, + int offset, int length, boolean bindToDevice) throws IOException { + return sendConnectedDatagramDirectImpl(fd, address, offset, length, bindToDevice); + } + + public void disconnectDatagram(FileDescriptor aFD) throws SocketException { + disconnectDatagramImpl(aFD); + } + + public void createMulticastSocket(FileDescriptor aFD, + boolean preferIPv4Stack) throws SocketException { + createMulticastSocketImpl(aFD, preferIPv4Stack); + } + + public void createServerStreamSocket(FileDescriptor aFD, + boolean preferIPv4Stack) throws SocketException { + createServerStreamSocketImpl(aFD, preferIPv4Stack); + } + + public int receiveStream(FileDescriptor aFD, byte[] data, int offset, + int count, int timeout) throws IOException { + return receiveStreamImpl(aFD, data, offset, count, timeout); + } + + public int sendStream(FileDescriptor fd, byte[] data, int offset, int count) + throws IOException { + return sendStreamImpl(fd, data, offset, count); + } + + public void shutdownInput(FileDescriptor descriptor) throws IOException { + shutdownInputImpl(descriptor); + } + + public void shutdownOutput(FileDescriptor descriptor) throws IOException { + shutdownOutputImpl(descriptor); + } + + public boolean supportsUrgentData(FileDescriptor fd) { + return supportsUrgentDataImpl(fd); + } + + public void sendUrgentData(FileDescriptor fd, byte value) { + sendUrgentDataImpl(fd, value); + } + + public int availableStream(FileDescriptor aFD) throws SocketException { + return availableStreamImpl(aFD); + } + + // BEGIN android-removed + // public void acceptStreamSocket(FileDescriptor fdServer, + // SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout) + // throws IOException { + // acceptStreamSocketImpl(fdServer, newSocket, fdnewSocket, timeout); + // } + // + // public void createStreamSocket(FileDescriptor aFD, boolean preferIPv4Stack) + // throws SocketException { + // createStreamSocketImpl(aFD, preferIPv4Stack); + // } + // END android-removed + + public void listenStreamSocket(FileDescriptor aFD, int backlog) + throws SocketException { + listenStreamSocketImpl(aFD, backlog); + } + + // BEGIN android-removed + // public boolean isReachableByICMP(final InetAddress dest, + // InetAddress source, final int ttl, final int timeout) { + // return INETADDR_REACHABLE == isReachableByICMPImpl(dest, source, ttl, + // timeout); + // } + // END android-removed + + /* + * + * @param + * readChannels all channels interested in read and accept + * @param + * writeChannels all channels interested in write and connect + * @param timeout + * timeout in millis @return a set of channels that are ready for operation + * @throws + * SocketException @return int array, each int approve one of the * channel if OK + */ + + public int[] select(FileDescriptor[] readFDs, + FileDescriptor[] writeFDs, long timeout) + throws SocketException { + int countRead = readFDs.length; + int countWrite = writeFDs.length; + int result = 0; + if (0 == countRead + countWrite) { + return (new int[0]); + } + int[] flags = new int[countRead + countWrite]; + + // handle timeout in native + result = selectImpl(readFDs, writeFDs, countRead, countWrite, flags, + timeout); + + if (0 <= result) { + return flags; + } + if (ERRORCODE_SOCKET_TIMEOUT == result) { + return new int[0]; + } + throw new SocketException(); + + } + + public InetAddress getSocketLocalAddress(FileDescriptor aFD, + boolean preferIPv6Addresses) { + return getSocketLocalAddressImpl(aFD, preferIPv6Addresses); + } + + /* + * Query the IP stack for the local port to which this socket is bound. + * + * @param aFD the socket descriptor @param preferIPv6Addresses address + * preference for nodes that support both IPv4 and IPv6 @return int the + * local port to which the socket is bound + */ + public int getSocketLocalPort(FileDescriptor aFD, + boolean preferIPv6Addresses) { + return getSocketLocalPortImpl(aFD, preferIPv6Addresses); + } + + /* + * Query the IP stack for the nominated socket option. + * + * @param aFD the socket descriptor @param opt the socket option type + * @return the nominated socket option value + * + * @throws SocketException if the option is invalid + */ + public Object getSocketOption(FileDescriptor aFD, int opt) + throws SocketException { + return getSocketOptionImpl(aFD, opt); + } + + /* + * Set the nominated socket option in the IP stack. + * + * @param aFD the socket descriptor @param opt the option selector @param + * optVal the nominated option value + * + * @throws SocketException if the option is invalid or cannot be set + */ + public void setSocketOption(FileDescriptor aFD, int opt, Object optVal) + throws SocketException { + setSocketOptionImpl(aFD, opt, optVal); + } + + public int getSocketFlags() { + return getSocketFlagsImpl(); + } + + /* + * Close the socket in the IP stack. + * + * @param aFD the socket descriptor + */ + public void socketClose(FileDescriptor aFD) throws IOException { + socketCloseImpl(aFD); + } + + public InetAddress getHostByAddr(byte[] addr) throws UnknownHostException { + return getHostByAddrImpl(addr); + } + + public InetAddress getHostByName(String addr, boolean preferIPv6Addresses) + throws UnknownHostException { + return getHostByNameImpl(addr, preferIPv6Addresses); + } + + public void setInetAddress(InetAddress sender, byte[] address) { + setInetAddressImpl(sender, address); + } + + // --------------------------------------------------- + // Native Codes + // --------------------------------------------------- + + static native void createSocketImpl(FileDescriptor fd, + boolean preferIPv4Stack); + + /* + * Allocate a datagram socket in the IP stack. The socket is associated with + * the aFD. + * + * @param aFD the FileDescriptor to associate with the socket @param + * preferIPv4Stack IP stack preference if underlying platform is V4/V6 + * @exception SocketException upon an allocation error + */ + static native void createDatagramSocketImpl(FileDescriptor aFD, + boolean preferIPv4Stack) throws SocketException; + + static native int readSocketImpl(FileDescriptor aFD, byte[] data, + int offset, int count, int timeout) throws IOException; + + static native int readSocketDirectImpl(FileDescriptor aFD, int address, + int offset, int count, int timeout) throws IOException; + + static native int writeSocketImpl(FileDescriptor fd, byte[] data, + int offset, int count) throws IOException; + + static native int writeSocketDirectImpl(FileDescriptor fd, int address, + int offset, int count) throws IOException; + + static native void setNonBlockingImpl(FileDescriptor aFD, + boolean block); + + static native int connectSocketImpl(FileDescriptor aFD, + int trafficClass, InetAddress inetAddress, int port); + + // BEGIN android-changed + static native int connectWithTimeoutSocketImpl( + FileDescriptor aFD, int timeout, int trafficClass, + InetAddress hostname, int port, int step, byte[] context); + // END android-changed + + static native void connectStreamWithTimeoutSocketImpl(FileDescriptor aFD, + int aport, int timeout, int trafficClass, InetAddress inetAddress) + throws IOException; + + static native void socketBindImpl(FileDescriptor aFD, int port, + InetAddress inetAddress) throws SocketException; + + static native void listenStreamSocketImpl(FileDescriptor aFD, int backlog) + throws SocketException; + + static native int availableStreamImpl(FileDescriptor aFD) + throws SocketException; + + static native void acceptSocketImpl(FileDescriptor fdServer, + SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout) + throws IOException; + + static native boolean supportsUrgentDataImpl(FileDescriptor fd); + + static native void sendUrgentDataImpl(FileDescriptor fd, byte value); + + /* + * Connect the socket to a port and address + * + * @param aFD the FileDescriptor to associate with the socket @param port + * the port to connect to @param trafficClass the traffic Class to be used + * then the connection is made @param inetAddress address to connect to. + * + * @exception SocketException if the connect fails + */ + static native void connectDatagramImpl2(FileDescriptor aFD, + int port, int trafficClass, InetAddress inetAddress) + throws SocketException; + + /* + * Disconnect the socket to a port and address + * + * @param aFD the FileDescriptor to associate with the socket + * + * @exception SocketException if the disconnect fails + */ + static native void disconnectDatagramImpl(FileDescriptor aFD) + throws SocketException; + + /* + * Allocate a datagram socket in the IP stack. The socket is associated with + * the aFD. + * + * @param aFD the FileDescriptor to associate with the socket @param + * preferIPv4Stack IP stack preference if underlying platform is V4/V6 + * @exception SocketException upon an allocation error + */ + + /* + * Bind the socket to the port/localhost in the IP stack. + * + * @param aFD the socket descriptor @param port the option selector @param + * bindToDevice bind the socket to the specified interface @param + * inetAddress address to connect to. @return if bind successful @exception + * SocketException thrown if bind operation fails + */ + static native boolean socketBindImpl2(FileDescriptor aFD, + int port, boolean bindToDevice, InetAddress inetAddress) + throws SocketException; + + /* + * Peek on the socket, update sender address and answer the + * sender port. + * + * @param aFD the socket FileDescriptor @param sender an InetAddress, to be + * updated with the sender's address @param receiveTimeout the maximum + * length of time the socket should block, reading @return int the sender + * port + * + * @exception IOException upon an read error or timeout + */ + static native int peekDatagramImpl(FileDescriptor aFD, + InetAddress sender, int receiveTimeout) throws IOException; + + /* + * Recieve data on the socket into the specified buffer. The packet fields + * data & length are passed in addition to + * packet to eliminate the JNI field access calls. + * + * @param aFD the socket FileDescriptor @param packet the DatagramPacket to + * receive into @param data the data buffer of the packet @param offset the + * offset in the data buffer @param length the length of the data buffer in + * the packet @param receiveTimeout the maximum length of time the socket + * should block, reading @param peek indicates to peek at the data @return + * number of data received @exception IOException upon an read error or + * timeout + */ + static native int receiveDatagramImpl(FileDescriptor aFD, + DatagramPacket packet, byte[] data, int offset, int length, + int receiveTimeout, boolean peek) throws IOException; + + static native int receiveDatagramDirectImpl(FileDescriptor aFD, + DatagramPacket packet, int address, int offset, int length, + int receiveTimeout, boolean peek) throws IOException; + + /* + * Recieve data on the connected socket into the specified buffer. The + * packet fields data & length are passed in + * addition to packet to eliminate the JNI field access + * calls. + * + * @param aFD the socket FileDescriptor @param packet the DatagramPacket to + * receive into @param data the data buffer of the packet @param offset the + * offset in the data buffer @param length the length of the data buffer in + * the packet @param receiveTimeout the maximum length of time the socket + * should block, reading @param peek indicates to peek at the data @return + * number of data received @exception IOException upon an read error or + * timeout + */ + static native int recvConnectedDatagramImpl(FileDescriptor aFD, + DatagramPacket packet, byte[] data, int offset, int length, + int receiveTimeout, boolean peek) throws IOException; + + static native int recvConnectedDatagramDirectImpl(FileDescriptor aFD, + DatagramPacket packet, int address, int offset, int length, + int receiveTimeout, boolean peek) throws IOException; + + /* + * Send the data to the nominated target address + * and port. These values are derived from the + * DatagramPacket to reduce the field calls within JNI. + * + * @param fd the socket FileDescriptor @param data the data buffer of the + * packet @param offset the offset in the data buffer @param length the + * length of the data buffer in the packet @param port the target host port + * @param bindToDevice if bind to device @param trafficClass the traffic + * class to be used when the datagram is sent @param inetAddress address to + * connect to. @return number of data send + * + * @exception IOException upon an read error or timeout + */ + static native int sendDatagramImpl(FileDescriptor fd, + byte[] data, int offset, int length, int port, + boolean bindToDevice, int trafficClass, InetAddress inetAddress) + throws IOException; + + static native int sendDatagramDirectImpl(FileDescriptor fd, + int address, int offset, int length, int port, + boolean bindToDevice, int trafficClass, InetAddress inetAddress) + throws IOException; + + /* + * Send the data to the address and port to which the was + * connnected and port. + * + * @param fd the socket FileDescriptor @param data the data buffer of the + * packet @param offset the offset in the data buffer @param length the + * length of the data buffer in the packet @param bindToDevice not used, + * current kept in case needed as was the case for sendDatagramImpl @return + * number of data send @exception IOException upon an read error or timeout + */ + static native int sendConnectedDatagramImpl(FileDescriptor fd, + byte[] data, int offset, int length, boolean bindToDevice) + throws IOException; + + static native int sendConnectedDatagramDirectImpl(FileDescriptor fd, + int address, int offset, int length, boolean bindToDevice) + throws IOException; + + /* + * Answer the result of attempting to create a server stream socket in the + * IP stack. Any special options required for server sockets will be set by + * this method. + * + * @param aFD the socket FileDescriptor @param preferIPv4Stack if use IPV4 + * @exception SocketException if an error occurs while creating the socket + */ + static native void createServerStreamSocketImpl(FileDescriptor aFD, + boolean preferIPv4Stack) throws SocketException; + + /* + * Answer the result of attempting to create a multicast socket in the IP + * stack. Any special options required for server sockets will be set by + * this method. + * + * @param aFD the socket FileDescriptor @param preferIPv4Stack if use IPV4 + * @exception SocketException if an error occurs while creating the socket + */ + static native void createMulticastSocketImpl(FileDescriptor aFD, + boolean preferIPv4Stack) throws SocketException; + + /* + * Recieve at most count bytes into the buffer data + * at the offset on the socket. + * + * @param aFD the socket FileDescriptor @param data the receive buffer + * @param offset the offset into the buffer @param count the max number of + * bytes to receive @param timeout the max time the read operation should + * block waiting for data @return int the actual number of bytes read + * @throws IOException @exception SocketException if an error occurs while + * reading + */ + static native int receiveStreamImpl(FileDescriptor aFD, byte[] data, + int offset, int count, int timeout) throws IOException; + + /* + * Send count bytes from the buffer data at + * the offset, on the socket. + * + * @param fd + * + * @param data the send buffer @param offset the offset into the buffer + * @param count the number of bytes to receive @return int the actual number + * of bytes sent @throws IOException @exception SocketException if an error + * occurs while writing + */ + static native int sendStreamImpl(FileDescriptor fd, byte[] data, + int offset, int count) throws IOException; + + private native void shutdownInputImpl(FileDescriptor descriptor) + throws IOException; + + private native void shutdownOutputImpl(FileDescriptor descriptor) + throws IOException; + + // BEGIN android-removed + // static native void acceptStreamSocketImpl(FileDescriptor fdServer, + // SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout) + // throws IOException; + // + // static native void createStreamSocketImpl(FileDescriptor aFD, + // boolean preferIPv4Stack) throws SocketException; + // END android-removed + + static native int sendDatagramImpl2(FileDescriptor fd, byte[] data, + int offset, int length, int port, InetAddress inetAddress) + throws IOException; + + static native int selectImpl(FileDescriptor[] readfd, + FileDescriptor[] writefd, int cread, int cwirte, int[] flags, + long timeout); + + static native InetAddress getSocketLocalAddressImpl(FileDescriptor aFD, + boolean preferIPv6Addresses); + + /* + * Query the IP stack for the local port to which this socket is bound. + * + * @param aFD the socket descriptor @param preferIPv6Addresses address + * preference for nodes that support both IPv4 and IPv6 @return int the + * local port to which the socket is bound + */ + static native int getSocketLocalPortImpl(FileDescriptor aFD, + boolean preferIPv6Addresses); + + /* + * Query the IP stack for the nominated socket option. + * + * @param aFD the socket descriptor @param opt the socket option type + * @return the nominated socket option value + * + * @throws SocketException if the option is invalid + */ + static native Object getSocketOptionImpl(FileDescriptor aFD, int opt) + throws SocketException; + + /* + * Set the nominated socket option in the IP stack. + * + * @param aFD the socket descriptor @param opt the option selector @param + * optVal the nominated option value + * + * @throws SocketException if the option is invalid or cannot be set + */ + static native void setSocketOptionImpl(FileDescriptor aFD, int opt, + Object optVal) throws SocketException; + + static native int getSocketFlagsImpl(); + + /* + * Close the socket in the IP stack. + * + * @param aFD the socket descriptor + */ + static native void socketCloseImpl(FileDescriptor aFD); + + static native InetAddress getHostByAddrImpl(byte[] addr) + throws UnknownHostException; + + static native InetAddress getHostByNameImpl(String addr, + boolean preferIPv6Addresses) throws UnknownHostException; + + native void setInetAddressImpl(InetAddress sender, byte[] address); + + // BEGIN android-removed + // native int isReachableByICMPImpl(InetAddress addr, InetAddress local, + // int ttl, int timeout); + // END android-removed + + native Channel inheritedChannelImpl(); + + public Channel inheritedChannel() { + return inheritedChannelImpl(); + } + + public void oneTimeInitialization(boolean jcl_supports_ipv6){ + if (!isNetworkInited){ + oneTimeInitializationImpl(jcl_supports_ipv6); + isNetworkInited = true; + } + } + + native void oneTimeInitializationImpl (boolean jcl_supports_ipv6); +} \ No newline at end of file diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/net/impl/PlainDatagramSocketImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/sipdroid/net/impl/PlainDatagramSocketImpl.java Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2009 The Sipdroid Open Source Project + * + * This file is part of Sipdroid (http://www.sipdroid.org) + * + * Sipdroid is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this source code; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package org.sipdroid.net.impl; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.DatagramPacket; +import java.net.DatagramSocketImpl; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketOptions; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.security.AccessController; + +/** + * The default, concrete instance of datagram sockets. This class does not + * support security checks. Alternative types of DatagramSocketImpl's may be + * used by setting the impl.prefix system property. + */ +public class PlainDatagramSocketImpl extends DatagramSocketImpl { + + static final int MULTICAST_IF = 1; + + static final int MULTICAST_TTL = 2; + + static final int TCP_NODELAY = 4; + + static final int FLAG_SHUTDOWN = 8; + + private final static int SO_BROADCAST = 32; + + final static int IP_MULTICAST_ADD = 19; + + final static int IP_MULTICAST_DROP = 20; + + final static int IP_MULTICAST_TTL = 17; + + /** + * for datagram and multicast sockets we have to set REUSEADDR and REUSEPORT + * when REUSEADDR is set for other types of sockets we need to just set + * REUSEADDR therefore we have this other option which sets both if + * supported by the platform. this cannot be in SOCKET_OPTIONS because since + * it is a public interface it ends up being public even if it is not + * declared public + */ + static final int REUSEADDR_AND_REUSEPORT = 10001; + + private boolean bindToDevice; + + private byte[] ipaddress = { 0, 0, 0, 0 }; + + private int ttl = 1; + + private OSNetworkSystem netImpl = OSNetworkSystem.getOSNetworkSystem(); + + private volatile boolean isNativeConnected; + + public int receiveTimeout; + + public boolean streaming = true; + + public boolean shutdownInput; + + /** + * used to keep address to which the socket was connected to at the native + * level + */ + private InetAddress connectedAddress; + + private int connectedPort = -1; + + /** + * used to store the trafficClass value which is simply returned as the + * value that was set. We also need it to pass it to methods that specify an + * address packets are going to be sent to + */ + private int trafficClass; + + public PlainDatagramSocketImpl(FileDescriptor fd, int localPort) { + super(); + this.fd = fd; + this.localPort = localPort; + } + + public PlainDatagramSocketImpl() { + super(); + fd = new FileDescriptor(); + } + + @Override + public void bind(int port, InetAddress addr) throws SocketException { + String prop = null; //AccessController.doPrivileged(new PriviAction("bindToDevice")); //$NON-NLS-1$ + boolean useBindToDevice = prop != null && prop.toLowerCase().equals("true"); //$NON-NLS-1$ + bindToDevice = netImpl.bind2(fd, port, useBindToDevice, addr); + if (0 != port) { + localPort = port; + } else { +// localPort = netImpl.getSocketLocalPort(fd, NetUtil.preferIPv6Addresses()); + } + + try { + // Ignore failures + setOption(SO_BROADCAST, Boolean.TRUE); + } catch (IOException e) { + } + } + + @Override + public void close() { + synchronized (fd) { + if (fd.valid()) { + try { + netImpl.socketClose(fd); + } catch (IOException e) { + } + fd = new FileDescriptor(); + } + } + } + + @Override + public void create() throws SocketException { + netImpl.createDatagramSocket(fd, false); //NetUtil.preferIPv4Stack()); + } + + @Override + protected void finalize() { + close(); + } + + @Override + public Object getOption(int optID) throws SocketException { + if (optID == SocketOptions.SO_TIMEOUT) { + return Integer.valueOf(receiveTimeout); + } else if (optID == SocketOptions.IP_TOS) { + return Integer.valueOf(trafficClass); + } else { + // Call the native first so there will be + // an exception if the socket if closed. + Object result = netImpl.getSocketOption(fd, optID); + if (optID == SocketOptions.IP_MULTICAST_IF + && (netImpl.getSocketFlags() & MULTICAST_IF) != 0) { + try { + return InetAddress.getByAddress(ipaddress); + } catch (UnknownHostException e) { + return null; + } + } + return result; + } + } + + @Override + public int getTimeToLive() throws IOException { + // Call the native first so there will be an exception if the socket if + // closed. + int result = (((Byte) getOption(IP_MULTICAST_TTL)).byteValue()) & 0xFF; + if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) { + return ttl; + } + return result; + } + + @Override + public byte getTTL() throws IOException { + // Call the native first so there will be an exception if the socket if + // closed. + byte result = ((Byte) getOption(IP_MULTICAST_TTL)).byteValue(); + if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) { + return (byte) ttl; + } + return result; + } + + @Override + public void join(InetAddress addr) throws IOException { +// setOption(IP_MULTICAST_ADD, new GenericIPMreq(addr)); + } + + @Override + public void joinGroup(SocketAddress addr, NetworkInterface netInterface) throws IOException { + if (addr instanceof InetSocketAddress) { + InetAddress groupAddr = ((InetSocketAddress) addr).getAddress(); +// setOption(IP_MULTICAST_ADD, new GenericIPMreq(groupAddr, netInterface)); + } + } + + @Override + public void leave(InetAddress addr) throws IOException { +// setOption(IP_MULTICAST_DROP, new GenericIPMreq(addr)); + } + + @Override + public void leaveGroup(SocketAddress addr, NetworkInterface netInterface) + throws IOException { + if (addr instanceof InetSocketAddress) { + InetAddress groupAddr = ((InetSocketAddress) addr).getAddress(); +// setOption(IP_MULTICAST_DROP, new GenericIPMreq(groupAddr, netInterface)); + } + } + + @Override + protected int peek(InetAddress sender) throws IOException { + if (isNativeConnected) { + /* + * in this case we know the port and address from which the data + * must have be been received as the socket is connected. However, + * we still need to do the receive in order to know that there was + * data received. We use a short buffer as we don't actually need + * the packet, only the knowledge that it is there + */ + byte[] storageArray = new byte[10]; + DatagramPacket pack = new DatagramPacket(storageArray, storageArray.length); + netImpl.recvConnectedDatagram(fd, pack, pack.getData(), pack.getOffset(), pack + .getLength(), receiveTimeout, true); // peek + // to set the sender ,we now use a native function + // sender.ipaddress = connectedAddress.getAddress(); + netImpl.setInetAddress(sender, connectedAddress.getAddress()); + return connectedPort; + } + return netImpl.peekDatagram(fd, sender, receiveTimeout); + } + + @Override + public void receive(DatagramPacket pack) throws java.io.IOException { + try { + if (isNativeConnected) { + // do not peek + netImpl.recvConnectedDatagram(fd, pack, pack.getData(), pack.getOffset(), pack + .getLength(), receiveTimeout, false); + updatePacketRecvAddress(pack); + } else { + // receiveDatagramImpl2 + netImpl.receiveDatagram(fd, pack, pack.getData(), pack.getOffset(), pack + .getLength(), receiveTimeout, false); + } + } catch (InterruptedIOException e) { + throw new SocketTimeoutException(e.getMessage()); + } + } + + @Override + public void send(DatagramPacket packet) throws IOException { + + if (isNativeConnected) { + netImpl.sendConnectedDatagram(fd, packet.getData(), packet.getOffset(), packet + .getLength(), bindToDevice); + } else { + // sendDatagramImpl2 + netImpl.sendDatagram(fd, packet.getData(), packet.getOffset(), packet.getLength(), + packet.getPort(), bindToDevice, trafficClass, packet.getAddress()); + } + } + + /** + * Set the nominated socket option. As the timeouts are not set as options + * in the IP stack, the value is stored in an instance field. + * + * @throws SocketException thrown if the option value is unsupported or + * invalid + */ + @Override + public void setOption(int optID, Object val) throws SocketException { + /* + * for datagram sockets on some platforms we have to set both the + * REUSEADDR AND REUSEPORT so for REUSEADDR set this option option which + * tells the VM to set the two values as appropriate for the platform + */ + if (optID == SocketOptions.SO_REUSEADDR) { + optID = REUSEADDR_AND_REUSEPORT; + } + + if (optID == SocketOptions.SO_TIMEOUT) { + receiveTimeout = ((Integer) val).intValue(); + } else { + int flags = netImpl.getSocketFlags(); + try { + netImpl.setSocketOption(fd, optID | (flags << 16), val); + } catch (SocketException e) { + // we don't throw an exception for IP_TOS even if the platform + // won't let us set the requested value + if (optID != SocketOptions.IP_TOS) { + throw e; + } + } + if (optID == SocketOptions.IP_MULTICAST_IF && (flags & MULTICAST_IF) != 0) { + InetAddress inet = (InetAddress) val; +// if (NetUtil.bytesToInt(inet.getAddress(), 0) == 0 || inet.isLoopbackAddress()) { +// ipaddress = ((InetAddress) val).getAddress(); +// } else + { + InetAddress local = null; + try { + local = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + throw new SocketException("getLocalHost(): " + e.toString()); + } + if (inet.equals(local)) { + ipaddress = ((InetAddress) val).getAddress(); + } else { + throw new SocketException(val + " != getLocalHost(): " + local); + } + } + } + /* + * save this value as it is actually used differently for IPv4 and + * IPv6 so we cannot get the value using the getOption. The option + * is actually only set for IPv4 and a masked version of the value + * will be set as only a subset of the values are allowed on the + * socket. Therefore we need to retain it to return the value that + * was set. We also need the value to be passed into a number of + * natives so that it can be used properly with IPv6 + */ + if (optID == SocketOptions.IP_TOS) { + trafficClass = ((Integer) val).intValue(); + } + } + } + + @Override + public void setTimeToLive(int ttl) throws java.io.IOException { + setOption(IP_MULTICAST_TTL, Byte.valueOf((byte) (ttl & 0xFF))); + if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) { + this.ttl = ttl; + } + } + + @Override + public void setTTL(byte ttl) throws java.io.IOException { + setOption(IP_MULTICAST_TTL, Byte.valueOf(ttl)); + if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) { + this.ttl = ttl; + } + } + + @Override + public void connect(InetAddress inetAddr, int port) throws SocketException { + + // connectDatagram impl2 + netImpl.connectDatagram(fd, port, trafficClass, inetAddr); + + // if we get here then we are connected at the native level + try { + connectedAddress = InetAddress.getByAddress(inetAddr.getAddress()); + } catch (UnknownHostException e) { + // this is never expected to happen as we should not have gotten + // here if the address is not resolvable + throw new SocketException("K0317 "+inetAddr.getHostName()); //$NON-NLS-1$ + } + connectedPort = port; + isNativeConnected = true; + } + + @Override + public void disconnect() { + try { + netImpl.disconnectDatagram(fd); + } catch (Exception e) { + // there is currently no way to return an error so just eat any + // exception + } + connectedPort = -1; + connectedAddress = null; + isNativeConnected = false; + } + + @Override + public int peekData(DatagramPacket pack) throws IOException { + try { + if (isNativeConnected) { + netImpl.recvConnectedDatagram(fd, pack, pack.getData(), pack.getOffset(), pack + .getLength(), receiveTimeout, true); // peek + updatePacketRecvAddress(pack); + } else { + // receiveDatagram 2 + netImpl.receiveDatagram(fd, pack, pack.getData(), pack.getOffset(), pack + .getLength(), receiveTimeout, true); // peek + } + } catch (InterruptedIOException e) { + throw new SocketTimeoutException(e.toString()); + } + return pack.getPort(); + } + + /** + * Set the received address and port in the packet. We do this when the + * Datagram socket is connected at the native level and the + * recvConnnectedDatagramImpl does not update the packet with address from + * which the packet was received + * + * @param packet + * the packet to be updated + */ + private void updatePacketRecvAddress(DatagramPacket packet) { + packet.setAddress(connectedAddress); + packet.setPort(connectedPort); + } + +} \ No newline at end of file diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/pjlib/Codec.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/sipdroid/pjlib/Codec.java Sun Feb 14 17:25:38 2010 +0100 @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 The Sipdroid Open Source Project + * + * This file is part of Sipdroid (http://www.sipdroid.org) + * + * Sipdroid is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This source code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this source code; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package org.sipdroid.pjlib; + +import java.lang.String; + +public class Codec { + public static native int open(String codec_id); + public static native int decode(byte alaw[], short lin[], int frames); + public static native int encode(short lin[], int offset, byte alaw[], int frames); + public static native int close(); + + public static void init() { + } + + public static boolean loaded; + + static { + try { + System.loadLibrary("pjlib_linker_jni"); + open("gsm"); + loaded = true; + } catch (Throwable e) { + e.printStackTrace(); + } + } +}