Question

during the last days I tried to get JAIN SIP working on Android. I took some code that works fine on a Java Application and ported it to an Android Application.

I checked:

  • Permissions in the Manifest (INTERNET / ALL)
  • JAIN SIP API works fine (other threads on stackoverflow focus that).
  • Communication runs on an own Thread, not the MainThread.
  • IPs are valid.
  • The code works if I'm not using Android as platform but Ubuntu.
  • I tried Android 4.0.3 and above.

My Code:

public class MainActivity extends Activity implements SipListener {

private static final String LOG = "JAIN";
private static final int PORT = 5060;
private SipFactory mSipFactory;
private AddressFactory mAddressFactory;
private MessageFactory mMessageFacory;
private HeaderFactory mHeaderFactory;
private SipStack mSipStack;
private SipProvider mSipProvider;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    new Thread(new Runnable(){

        @Override
        public void run() {
            try {
                // Create factories
                mSipFactory = SipFactory.getInstance();
                mAddressFactory = mSipFactory.createAddressFactory();
                mMessageFacory = mSipFactory.createMessageFactory();
                mHeaderFactory = mSipFactory.createHeaderFactory();

                // Create the SipStack
                Properties properties = new Properties();
                properties.setProperty("javax.sip.STACK_NAME","Stack");
                mSipStack = mSipFactory.createSipStack(properties);

                // Create the SipProvider 
                String localIP = InetAddress.getLocalHost().getHostAddress();
                ListeningPoint listeningPoint = mSipStack
                        .createListeningPoint(localIP, PORT, "udp");
                mSipProvider = mSipStack.createSipProvider(listeningPoint);
                mSipProvider.addSipListener(MainActivity.this);

                // Create addresses and via header for the request
                Address fromToAddress = mAddressFactory
                        .createAddress("sip:192.168.0.198");
                Address contactAddress = mAddressFactory
                        .createAddress("sip:me@192.168.0.195");
                ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
                ViaHeader myViaHeader = mHeaderFactory
                        .createViaHeader("me.bla.com", PORT, "udp", "tlf64");
                viaHeaders.add(myViaHeader);

                // Build the request
                final Request request = mMessageFacory.createRequest(
                        mAddressFactory.createAddress("sip:192.168.0.195:9876").getURI(), 
                        "REGISTER",
                        mHeaderFactory.createCallIdHeader("12345678"),
                        mHeaderFactory.createCSeqHeader(1234l, "REGISTER"), 
                        mHeaderFactory.createFromHeader(fromToAddress, "sdf6"),
                        mHeaderFactory.createToHeader(fromToAddress, null), 
                        viaHeaders, 
                        mHeaderFactory.createMaxForwardsHeader(70));

                // Add the contact header
                request.addHeader(mHeaderFactory.createContactHeader(contactAddress));

                // Print the request
                System.out.println(request.toString());

                // Send the request --- triggers an IOException
                mSipProvider.sendRequest(request);
            } catch (Exception e) {
                Log.d(LOG, Log.getStackTraceString(e));
            }
        }}).start();
}

As you can see in the StackTrace, an IOException occurs:

javax.sip.SipException: IO Exception occured while Sending Request
at gov.nist.javax.sip.SipProviderImpl.sendRequest(SipProviderImpl.java:722)
at com.example.jainsiptest.MainActivity$1.run(MainActivity.java:97)
at java.lang.Thread.run(Thread.java:856)
 Caused by: java.net.SocketException: sendto failed: EINVAL (Invalid argument)
at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:506)
at libcore.io.IoBridge.sendto(IoBridge.java:475)
at java.net.PlainDatagramSocketImpl.send(PlainDatagramSocketImpl.java:182)
at java.net.DatagramSocket.send(DatagramSocket.java:284)
at gov.nist.javax.sip.stack.UDPMessageChannel.sendMessage(UDPMessageChannel.java:724)
at gov.nist.javax.sip.stack.MessageChannel.sendMessage(MessageChannel.java:222)
at gov.nist.javax.sip.SipProviderImpl.sendRequest(SipProviderImpl.java:711)
... 2 more
 Caused by: libcore.io.ErrnoException: sendto failed: EINVAL (Invalid argument)
at libcore.io.Posix.sendtoBytes(Native Method)
at libcore.io.Posix.sendto(Posix.java:151)
at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:177)
at libcore.io.IoBridge.sendto(IoBridge.java:473)
... 7 more

The

java.net.SocketException: sendto failed: EINVAL (Invalid argument)

is not thrown on Ubuntu with the same arguments.

Got any ideas how to fix it? Thanks a lot for any help!

Was it helpful?

Solution

It seems that the Android OS processes the given Strings in a different way than the Ubuntu OS. I don't know why.


After all, I fixed the problem by using MjSip instead of JAIN SIP.

Since I need RTP, SDP and some more stuff next to SIP, I decided to modify the open source Android App Sipdroid, which uses MjSip 1.6, until it fits my demands.

  1. To do so, first get the code.

  2. Import the project into Eclipse: File -> Import -> Existing Android Code Into Workspace.

  3. Create a new Android project that meets your demands considering API Level and so on.

  4. Add <uses-permission android:name="android.permission.INTERNET" /> to the Manifest of your project.

  5. Copy all packages but the following from the Sipdroid project to your project:

    • org.sipdroid.codecs and org.sipdroid.media (which I don't need yet, maybe later)
    • org.sipdroid.sipua and subpackages.
  6. Delete or comment broken references.

  7. See the code below to send a REGISTER to a server.

  8. Fix the Exeptions that are thrown by the Log mechanism by using android.util.Log instead of the given code. Finally, delete or comment the flush command that triggers a NullPointerException.

That's it.

import org.zoolu.sip.address.NameAddress;
import org.zoolu.sip.message.Message;
import org.zoolu.sip.message.MessageFactory;
import org.zoolu.sip.provider.SipProvider;
import org.zoolu.sip.provider.SipStack;
import org.zoolu.sip.transaction.TransactionClient;
import org.zoolu.sip.transaction.TransactionClientListener;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;

public class MainActivity extends Activity implements TransactionClientListener{

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    new Thread(new Runnable(){

        @Override
        public void run() {
            try{
                SipStack.init();

                SipProvider sipProvider = new SipProvider(
                        "192.168.0.198", 5060, new String[]{"udp"}, null);
                NameAddress toAddress = new NameAddress(
                        "sip:192.168.0.195:9876");
                NameAddress fromAddress = new NameAddress(
                        "sip:192.168.0.198:9876");

                Message message = MessageFactory.createRegisterRequest(
                        sipProvider, 
                        toAddress, 
                        fromAddress, 
                        fromAddress, 
                        null, 
                        null);

                TransactionClient t = new TransactionClient(
                        sipProvider, 
                        message,
                        MainActivity.this);

                t.request();

            }catch(Exception e){
                Log.d("MYSIP", Log.getStackTraceString(e));
            }
        }}).start();
}

// Interface methods

}

OTHER TIPS

Instead of fetching localIPAddress as:

String localIP = InetAddress.getLocalHost().getHostAddress();

Fetch the IP Address using NetworkInterface or WifiManager.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top