androidvoiplinphone

Linphone Android not receiving calls


Recently I have been creating a new Android app to make/receive VoIP calls using Linphone lib. The first version of the app worked almost ok, I updated the lib and decided to do some code arrange, and for some reason, the app does not longer receive calls.

All the VoIP functionality is inside an android service:

package com.test.voice.linphone;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.os.Binder;
import android.os.IBinder;
import android.os.PowerManager;
import android.util.Log;

import com.test.voice.voice.R;

import org.linphone.core.AVPFMode;
import org.linphone.core.Address;
import org.linphone.core.AuthInfo;
import org.linphone.core.AuthMethod;
import org.linphone.core.Call;
import org.linphone.core.CallLog;
import org.linphone.core.CallStats;
import org.linphone.core.ChatMessage;
import org.linphone.core.ChatRoom;
import org.linphone.core.ConfiguringState;
import org.linphone.core.Content;
import org.linphone.core.Core;
import org.linphone.core.CoreException;
import org.linphone.core.CoreListener;
import org.linphone.core.EcCalibratorStatus;
import org.linphone.core.Event;
import org.linphone.core.Factory;
import org.linphone.core.Friend;
import org.linphone.core.FriendList;
import org.linphone.core.GlobalState;
import org.linphone.core.InfoMessage;
import org.linphone.core.PayloadType;
import org.linphone.core.PresenceModel;
import org.linphone.core.ProxyConfig;
import org.linphone.core.PublishState;
import org.linphone.core.Reason;
import org.linphone.core.RegistrationState;
import org.linphone.core.SubscriptionState;
import org.linphone.core.Transports;
import org.linphone.core.VersionUpdateCheckResult;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Timer;
import java.util.TimerTask;

public class LinphoneService extends Service {

    // *************************************** CONSTANTS *************************************** //

    private static final String TAG = "linphone_service";
    private static final String WAKE_LOG_TAG = ":voicewakelock";

    private static final String LIN_TAG = "libcore";
    private static final String USER_AGENT = "VoiceAgent";

    private static final long TIME_ITERATE = 200;

    // ****************************************** VARS ***************************************** //

    private final IBinder mBinder = new LocalBinder();
    private PowerManager.WakeLock mWakeLock;
    private Core mCore;
    private String mLpConfig = null;
    private String mConfigFactoryFile = null;
    public String mLinphoneConfigFile = null;
    private String mRootCaFile = null;
    private String mRingSoundFile = null;
    private String mRingBackSoundFile = null;
    private String mPauseSoundFile = null;
    private AuthInfo mAuthInfo;
    private ProxyConfig mProxyConfig;
    private Timer mIterateTimer;
    private LinphoneCallback mCallback;
    private RegistrationState mRegistrationState = RegistrationState.None;

    // ************************************* INNER CLASSES ************************************* //

    public class LocalBinder extends Binder {
        public LinphoneService getService() {
            return LinphoneService.this;
        }
    }

    // *************************************** LIFECYCLE *************************************** //

    @Override
    public void onCreate() {
        super.onCreate();

        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOG_TAG);
        mWakeLock.acquire();

        String basePath = getFilesDir().getAbsolutePath();
        mLpConfig = basePath + "/lpconfig.xsd";
        mConfigFactoryFile = basePath + "/linphonerc";
        mLinphoneConfigFile = basePath + "/.linphonerc";
        mRootCaFile = basePath + "/rootca.pem";
        mRingSoundFile = basePath + "/oldphone_mono.wav";
        mRingBackSoundFile = basePath + "/ringback.wav";
        mPauseSoundFile = basePath + "/toy_mono.wav";
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mWakeLock.release();

        cancelIterateTimer();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    // ************************************* PUBLIC METHODS ************************************ //

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        return START_NOT_STICKY;
    }

    /**
     * Set a {@link LinphoneCallback} to receive event callbacks.
     *
     * @param callback {@link LinphoneCallback} to set.
     */
    public void setCallback(LinphoneCallback callback) {
        mCallback = callback;
    }

    /**
     * Initiate Linphone library, set configuration.
     *
     * @throws Exception
     */
    public void initLibrary() throws Exception {

        copyAssetsFromPackage();

        Factory.instance().setDebugMode(true, LIN_TAG);
        mCore = Factory.instance().createCore(
                mLinphoneConfigFile, mConfigFactoryFile, this);
        mCore.addListener(getCoreListener());
        mCore.enableIpv6(false);
        PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
        mCore.setUserAgent(USER_AGENT, packageInfo.versionName);
        mCore.setRemoteRingbackTone(mRingSoundFile);
        mCore.setRing(mRingSoundFile);
        mCore.setRootCa(mRootCaFile);
        mCore.setPlayFile(mPauseSoundFile);
        mCore.setNetworkReachable(true);
        mCore.enableEchoCancellation(true);
        mCore.enableEchoLimiter(true);
        mCore.enableAdaptiveRateControl(true);
        mCore.clearAllAuthInfo();
        mCore.clearProxyConfig();

        enablePayloads();

        startIterateTimer();

    }

    /**
     * Login agains the VoIP server.
     *
     * @param name     Username.
     * @param password Password.
     * @param host     Server.
     * @param tcpPort  Specify the TCP port to use, only TCP available.
     * @throws CoreException
     */
    public void login(String name, String password, String host, int tcpPort)
            throws CoreException {

        String identity = "sip:" + name + "@" + host;
        String proxy = "sip:" + host;

        Address proxyAddress = Factory.instance().createAddress(proxy);
        Address identityAddress = Factory.instance().createAddress(identity);
        if (proxyAddress == null || identityAddress == null) {
            throw new CoreException("Proxy or Identity address is null.");
        }

        mProxyConfig = mCore.createProxyConfig();
        mProxyConfig.setIdentityAddress(identityAddress);
        mProxyConfig.setServerAddr(proxyAddress.asStringUriOnly());
        mProxyConfig.setAvpfMode(AVPFMode.Disabled);
        mProxyConfig.setAvpfRrInterval(0);
        mProxyConfig.enableQualityReporting(false);
        mProxyConfig.setQualityReportingCollector(null);
        mProxyConfig.setQualityReportingInterval(0);
        //        mProxyConfig.setRoute(proxyAddress.asStringUriOnly());
        mProxyConfig.enableRegister(true);

        mAuthInfo = Factory.instance().createAuthInfo(
                name, null, password, null, null, host);

        Transports transports = mCore.getTransports();
        transports.setUdpPort(-1);
        transports.setTlsPort(-1);
        transports.setTcpPort(tcpPort);
        mCore.setTransports(transports);

        mCore.addProxyConfig(mProxyConfig);
        mCore.addAuthInfo(mAuthInfo);
        mCore.setDefaultProxyConfig(mProxyConfig);

    }

    /**
     * Disconnect from remote VoIP server.
     */
    public void logout() {
        if (mProxyConfig != null) {
            mProxyConfig.edit();
            mProxyConfig.enableRegister(false);
            mProxyConfig.done();
        }
    }

    /**
     * Accept incoming call.
     */
    public void acceptCall() {
        mCore.acceptCall(mCore.getCurrentCall());
    }

    /**
     * Decline current call.
     */
    public void declineCall() {
        mCore.declineCall(mCore.getCurrentCall(), Reason.Declined);
    }

    /**
     * Hang up the current call.
     */
    public void hangUp() {
        Call currentCall = mCore.getCurrentCall();
        if (currentCall != null) {
            mCore.terminateCall(currentCall);
        } else if (mCore.isInConference()) {
            mCore.terminateConference();
        } else {
            mCore.terminateAllCalls();
        }
    }

    // ************************************ PRIVATE METHODS ************************************ //

    /**
     * Copy resource files.
     *
     * @throws IOException If an I/O error occurrs.
     */
    private void copyAssetsFromPackage() throws IOException {
        copyIfNotExist(this, R.raw.oldphone_mono, mRingSoundFile);
        copyIfNotExist(this, R.raw.ringback, mRingBackSoundFile);
        copyIfNotExist(this, R.raw.toy_mono, mPauseSoundFile);
        copyIfNotExist(this, R.raw.linphonerc_default, mLinphoneConfigFile);
        copyIfNotExist(this, R.raw.linphonerc_factory, (
                new File(this.mConfigFactoryFile)).getName());
        copyIfNotExist(this, R.raw.lpconfig, mLpConfig);
        copyIfNotExist(this, R.raw.rootca, mRootCaFile);
    }

    private void copyIfNotExist(Context context, int resourceId, String target) throws IOException {
        File fileToCopy = new File(target);
        if (!fileToCopy.exists()) {
            copyFromPackage(context, resourceId, fileToCopy.getName());
        }
    }

    private void copyFromPackage(Context context, int resourceId, String target) throws
            IOException {
        FileOutputStream outputStream = context.openFileOutput(target, 0);
        InputStream inputStream = context.getResources().openRawResource(resourceId);
        byte[] buff = new byte[8048];

        int readByte;
        while ((readByte = inputStream.read(buff)) != -1) {
            outputStream.write(buff, 0, readByte);
        }

        outputStream.flush();
        outputStream.close();
        inputStream.close();
    }

    /**
     * Get the {@link CoreListener}.
     *
     * @return Instance of {@link CoreListener}.
     */
    private CoreListener getCoreListener() {
        return new CoreListener() {
            @Override
            public void onGlobalStateChanged(Core core, GlobalState globalState, String s) {
                Log.d(TAG, "Core listener - Global State Changed: " + s);
                mCallback.onGlobalStateChanged(globalState);
            }

            @Override
            public void onRegistrationStateChanged(Core core, ProxyConfig proxyConfig,
                                                   RegistrationState registrationState,
                                                   String state) {
                Log.d(TAG, "Core listener - On Registration State Changed: " +
                        state);
                if (registrationState != mRegistrationState) {
                    mCallback.onRegistrationStateChanged(registrationState);
                }
                mRegistrationState = registrationState;
            }

            @Override
            public void onCallStateChanged(Core core, Call call, Call.State state, String s) {
                Log.d(TAG, "Core listener - On Call State Changed");
                mCallback.onCallStateChanged(call, state);
            }

            @Override
            public void onNotifyPresenceReceived(Core core, Friend friend) {
                Log.d(TAG, "Core listener - On Notify Presence Received");
            }

            @Override
            public void onNotifyPresenceReceivedForUriOrTel(Core core, Friend friend, String s,
                                                            PresenceModel presenceModel) {
                Log.d(TAG, "Core listener - On Notify Presence Received For Uri Or Tel");
            }

            @Override
            public void onNewSubscriptionRequested(Core core, Friend friend, String s) {
                Log.d(TAG, "Core listener - On New Subscription Requested");
            }

            @Override
            public void onAuthenticationRequested(Core core, AuthInfo authInfo, AuthMethod
                    authMethod) {
                Log.d(TAG, "Core listener - On Authentication Requested");
            }

            @Override
            public void onCallLogUpdated(Core core, CallLog callLog) {
                Log.d(TAG, "Core listener - On Call Log Updated");
            }

            @Override
            public void onMessageReceived(Core core, ChatRoom chatRoom, ChatMessage chatMessage) {
                Log.d(TAG, "Core listener - On Message Received");
            }

            @Override
            public void onMessageReceivedUnableDecrypt(Core core, ChatRoom chatRoom, ChatMessage
                    chatMessage) {
                Log.d(TAG, "Core listener - On Message Received Unable Decrypt");
            }

            @Override
            public void onIsComposingReceived(Core core, ChatRoom chatRoom) {
                Log.d(TAG, "Core listener - On Is Composing Received");
            }

            @Override
            public void onDtmfReceived(Core core, Call call, int i) {
                Log.d(TAG, "Core listener - On Dtmf Received");
            }

            @Override
            public void onReferReceived(Core core, String s) {
                Log.d(TAG, "Core listener - On Refer Received");
            }

            @Override
            public void onCallEncryptionChanged(Core core, Call call, boolean b, String s) {
                Log.d(TAG, "Core listener - On Call Encrypted Changed");
            }

            @Override
            public void onTransferStateChanged(Core core, Call call, Call.State state) {
                Log.d(TAG, "Core listener - On Transfer State Changed");
            }

            @Override
            public void onBuddyInfoUpdated(Core core, Friend friend) {
                Log.d(TAG, "Core listener - On Buddy Info Updated");
            }

            @Override
            public void onCallStatsUpdated(Core core, Call call, CallStats callStats) {
                Log.d(TAG, "Core listener - On Call Stats Updated");
            }

            @Override
            public void onInfoReceived(Core core, Call call, InfoMessage infoMessage) {
                Log.d(TAG, "Core listener - On Info Received");
            }

            @Override
            public void onSubscriptionStateChanged(Core core, Event event, SubscriptionState
                    subscriptionState) {
                Log.d(TAG, "Core listener - On Subscription State Changed");
            }

            @Override
            public void onNotifyReceived(Core core, Event event, String s, Content content) {
                Log.d(TAG, "Core listener - On Notify Received");
            }

            @Override
            public void onSubscribeReceived(Core core, Event event, String s, Content content) {
                Log.d(TAG, "Core listener - On Subscribe Received");
            }

            @Override
            public void onPublishStateChanged(Core core, Event event, PublishState publishState) {
                Log.d(TAG, "Core listener - On Publish State Changed");
            }

            @Override
            public void onConfiguringStatus(Core core, ConfiguringState configuringState, String
                    s) {
                Log.d(TAG, "Core listener - On Configuring Status");
            }

            @Override
            public void onNetworkReachable(Core core, boolean b) {
                Log.d(TAG, "Core listener - On Network Reachable");
            }

            @Override
            public void onLogCollectionUploadStateChanged(Core core, Core
                    .LogCollectionUploadState logCollectionUploadState, String s) {
                Log.d(TAG, "Core listener - On Log Collection Upload StateChanged");
            }

            @Override
            public void onLogCollectionUploadProgressIndication(Core core, int i, int i1) {
                Log.d(TAG, "Core listener - On Log Collection Upload ProgressIndication");
            }

            @Override
            public void onFriendListCreated(Core core, FriendList friendList) {
                Log.d(TAG, "Core listener - On Friend List Created");
            }

            @Override
            public void onFriendListRemoved(Core core, FriendList friendList) {
                Log.d(TAG, "Core listener - On Friend List Removed");
            }

            @Override
            public void onCallCreated(Core core, Call call) {
                Log.d(TAG, "Core listener - On Call Created");
            }

            @Override
            public void onVersionUpdateCheckResultReceived(Core core, VersionUpdateCheckResult
                    versionUpdateCheckResult, String s, String s1) {
                Log.d(TAG, "Core listener - On Version Update Check ResultReceived");
            }

            @Override
            public void onChatRoomStateChanged(Core core, ChatRoom chatRoom, ChatRoom.State state) {
                Log.d(TAG, "Core listener - On Chat Room State Changed");
            }

            @Override
            public void onQrcodeFound(Core core, String s) {
                Log.d(TAG, "Core listener - On QR Code Found");
            }

            @Override
            public void onEcCalibrationResult(Core core, EcCalibratorStatus ecCalibratorStatus,
                                              int i) {
                Log.d(TAG, "Core listener - On EC Calibration Result");
            }

            @Override
            public void onEcCalibrationAudioInit(Core core) {
                Log.d(TAG, "Core listener - On EC Calibration Audio Init");
            }

            @Override
            public void onEcCalibrationAudioUninit(Core core) {
                Log.d(TAG, "Core listener - On EC Calibration Audio Uninit");
            }

        };
    }

    private void startIterateTimer() {
        cancelIterateTimer();
        mIterateTimer = new Timer();
        mIterateTimer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                if (mCore != null) mCore.iterate();
            }
        }, 0, TIME_ITERATE);
    }

    /**
     * Remove iterate timer.
     */
    private void cancelIterateTimer() {
        if (mIterateTimer != null) mIterateTimer.cancel();
        mIterateTimer = null;
    }

    private void enablePayloads() {
        PayloadType[] audioPayloads = mCore.getAudioPayloadTypes();

        for (int i = 0; i < audioPayloads.length; ++i) {
            PayloadType payloadType = audioPayloads[i];

            payloadType.enable(true);
        }

        mCore.setAudioPayloadTypes(audioPayloads);
    }
}

All the configurations and audio files are ok since they were working in the first implementation, but I guess I am doing something wrong on this class.

Any help?


Solution

  • Finally I solved the issue, I was missing Core.start():

    /**
     * Initiate Linphone library, set configuration.
     *
     * @throws Exception
     */
    public void initLibrary() throws Exception {
    
        copyAssetsFromPackage();
    
        Factory.instance().setDebugMode(false, LIN_TAG);
        mCore = Factory.instance().createCore(
                mLinphoneConfigFile, mConfigFactoryFile, this);
        mCore.addListener(getCoreListener());
        mCore.start();
        mCore.enableIpv6(false);
        PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
        mCore.setUserAgent(USER_AGENT, packageInfo.versionName);
        mCore.setRemoteRingbackTone(mRingSoundFile);
        mCore.setRing(mRingSoundFile);
        mCore.setRootCa(mRootCaFile);
        mCore.setPlayFile(mPauseSoundFile);
        mCore.setNetworkReachable(true);
        mCore.enableEchoCancellation(true);
        mCore.enableEchoLimiter(true);
        mCore.enableAdaptiveRateControl(true);
        mCore.clearAllAuthInfo();
        mCore.clearProxyConfig();
    
        enablePayloads();
    
        startIterateTimer();
    
    }