Ошибка при получении входящего звонка в Linphone Call SDK для Android?

Я уже некоторое время реализую функцию VoIP Calling в приложении для Android, большая часть работы выполнена, но когда пользователь звонит другому пользователю через приложение, большую часть времени тот же человек получает звонок от того места, где он был инициализируется.

Например, есть два пользователя ABC и CBA. Когда ABC выполняет вызов в CBA, это делается правильно, но когда дело меняется на обратное, то есть когда CBA выполняет вызов ABC, во входящем методе Linphone он получает имя удаленного пользователя в виде CBA, что означает, что CBA получает вызовы сам.

Как решить эту проблему? Я применяю метод неправильно?

Я использовал SDK Linphone Calling для Android, даже не изменил методы.

Ниже приведен код для LinphoneService, который получает входящий вызов.

public final class LinphoneService extends Service {
    /* Listener needs to be implemented in the Service as it calls
     * setLatestEventInfo and startActivity() which needs a context.
     */
    public static final String START_LINPHONE_LOGS = " ==== Phone information dump ====";

    private static LinphoneService instance;

    private final static int NOTIF_ID = 1;
    private final static int INCALL_NOTIF_ID = 2;
    private final static int MESSAGE_NOTIF_ID = 3;
    private final static int SAS_NOTIF_ID = 6;

    public static boolean isReady() {
        return instance != null && instance.mTestDelayElapsed;
    }

    /**
     * @throws RuntimeException service not instantiated
     */
    public static LinphoneService instance() {
        if (isReady()) return instance;

        throw new RuntimeException("LinphoneService not instantiated yet");
    }

    public Handler mHandler = new Handler();

    //  private boolean mTestDelayElapsed; // add a timer for testing
    private boolean mTestDelayElapsed = true; // no timer
    private NotificationManager mNM;


    private String mNotificationTitle;
    private boolean mDisableRegistrationStatus;
    private LinphoneCoreListenerBase mListener;
    public static int notifcationsPriority = (Version.sdkAboveOrEqual(Version.API16_JELLY_BEAN_41) ? Notification.PRIORITY_MIN : 0);
    private WindowManager mWindowManager;

    private Application.ActivityLifecycleCallbacks activityCallbacks;


    /*Believe me or not, but knowing the application visibility state on Android is a nightmare.
    After two days of hard work I ended with the following class, that does the job more or less reliabily.
    */
    class ActivityMonitor implements Application.ActivityLifecycleCallbacks {
        private ArrayList<Activity> activities = new ArrayList<Activity>();
        private boolean mActive = false;
        private int mRunningActivities = 0;

        class InactivityChecker implements Runnable {
            private boolean isCanceled;

            public void cancel() {
                isCanceled = true;
            }

            @Override
            public void run() {
                synchronized (LinphoneService.this) {
                    if (!isCanceled) {
                        if (LinphoneService.ActivityMonitor.this.mRunningActivities == 0 && mActive) {
                            mActive = false;
                            LinphoneService.this.onBackgroundMode();
                        }
                    }
                }
            }
        }

        ;

        private LinphoneService.ActivityMonitor.InactivityChecker mLastChecker;

        @Override
        public synchronized void onActivityCreated(Activity activity, Bundle savedInstanceState) {
            Log.i("Activity created:" + activity);
            if (!activities.contains(activity))
                activities.add(activity);
        }

        @Override
        public void onActivityStarted(Activity activity) {
            Log.i("Activity started:" + activity);
        }

        @Override
        public synchronized void onActivityResumed(Activity activity) {
            Log.i("Activity resumed:" + activity);
            if (activities.contains(activity)) {
                mRunningActivities++;
                Log.i("runningActivities=" + mRunningActivities);
                checkActivity();
            }

        }

        @Override
        public synchronized void onActivityPaused(Activity activity) {
            Log.i("Activity paused:" + activity);
            if (activities.contains(activity)) {
                mRunningActivities--;
                Log.i("runningActivities=" + mRunningActivities);
                checkActivity();
            }

        }

        @Override
        public void onActivityStopped(Activity activity) {
            Log.i("Activity stopped:" + activity);
        }

        @Override
        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

        }

        @Override
        public synchronized void onActivityDestroyed(Activity activity) {
            Log.i("Activity destroyed:" + activity);
            if (activities.contains(activity)) {
                activities.remove(activity);
            }
        }

        void startInactivityChecker() {
            if (mLastChecker != null) mLastChecker.cancel();
            LinphoneService.this.mHandler.postDelayed(
                    (mLastChecker = new LinphoneService.ActivityMonitor.InactivityChecker()), 2000);
        }

        void checkActivity() {

            if (mRunningActivities == 0) {
                if (mActive) startInactivityChecker();
            } else if (mRunningActivities > 0) {
                if (!mActive) {
                    mActive = true;
                    LinphoneService.this.onForegroundMode();
                }
                if (mLastChecker != null) {
                    mLastChecker.cancel();
                    mLastChecker = null;
                }
            }
        }
    }

    protected void onBackgroundMode() {
        Log.i("App has entered background mode");
        if (LinphonePreferences.instance() != null && LinphonePreferences.instance().isFriendlistsubscriptionEnabled()) {
            if (LinphoneManager.isInstanciated())
                LinphoneManager.getInstance().subscribeFriendList(false);
        }
    }

    protected void onForegroundMode() {
        Log.i("App has left background mode");
        if (LinphonePreferences.instance() != null && LinphonePreferences.instance().isFriendlistsubscriptionEnabled()) {
            if (LinphoneManager.isInstanciated())
                LinphoneManager.getInstance().subscribeFriendList(true);
        }
    }

    private void setupActivityMonitor() {
        if (activityCallbacks != null) return;
        getApplication().registerActivityLifecycleCallbacks(activityCallbacks = new LinphoneService.ActivityMonitor());
    }



    @SuppressWarnings("unchecked")
    @Override
    public void onCreate() {
        super.onCreate();

        setupActivityMonitor();
        // In case restart after a crash. Main in LinphoneActivity
        mNotificationTitle = getString(R.string.service_name);

        // Needed in order for the two next calls to succeed, libraries must have been loaded first
        LinphonePreferences.instance().setContext(getBaseContext());
        LinphoneCoreFactory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath());
        boolean isDebugEnabled = LinphonePreferences.instance().isDebugEnabled();
        LinphoneCoreFactory.instance().enableLogCollection(isDebugEnabled);
        LinphoneCoreFactory.instance().setDebugMode(isDebugEnabled, getString(R.string.app_name));

        // Dump some debugging information to the logs
        Log.i(START_LINPHONE_LOGS);
        dumpDeviceInformation();
        dumpInstalledLinphoneInformation();

        //Disable service notification for Android O
        if ((Version.sdkAboveOrEqual(Version.API26_O_80))) {
            LinphonePreferences.instance().setServiceNotificationVisibility(false);
            mDisableRegistrationStatus = true;
        }

        mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        mNM.cancel(INCALL_NOTIF_ID); // in case of crash the icon is not removed



        if (!LinphoneManager.isInstanciated())
        LinphoneManager.createAndStart(LinphoneService.this);

        instance = this; // instance is ready once linphone manager has been created
        incomingReceivedActivityName = LinphonePreferences.instance().getActivityToLaunchOnIncomingReceived();

        android.util.Log.d("linphoneCalling", "Service Strated");
        LinphoneManager.getLc().addListener(mListener = new LinphoneCoreListenerBase() {
            @Override
            public void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message) {
                if (instance == null) {
                    Log.i("Service not ready, discarding call state change to ", state.toString());
                    return;
                }

                if (state == LinphoneCall.State.IncomingReceived) {
                    android.util.Log.d("ServiceStarted", "IncomingCall  Status");
                    onIncomingReceived2(call);
                }

                if (state == State.CallEnd || state == State.CallReleased || state == State.Error) {
                    if (LinphoneManager.isInstanciated() && LinphoneManager.getLc() != null && LinphoneManager.getLc().getCallsNb() == 0) {

                    }
                }

                if (state == State.CallEnd && call.getCallLog().getStatus() == CallStatus.Missed) {
                    int missedCallCount = LinphoneManager.getLcIfManagerNotDestroyedOrNull().getMissedCallsCount();
                    String body;
                    if (missedCallCount > 1) {
                        body = getString(R.string.missed_calls_notif_body).replace("%i", String.valueOf(missedCallCount));
                    } else {
                        LinphoneAddress address = call.getRemoteAddress();
                        body = address.getDisplayName();
                        if (body == null) {
                            body = address.asStringUriOnly();
                        }

                    }

                }

                if (state == State.StreamsRunning) {
                    // Workaround bug current call seems to be updated after state changed to streams running
                    if (getResources().getBoolean(R.bool.enable_call_notification))
                        refreshIncallIcon(call);
                } else {
                    if (getResources().getBoolean(R.bool.enable_call_notification))
                        refreshIncallIcon(LinphoneManager.getLc().getCurrentCall());
                }
            }

            @Override
            public void globalState(LinphoneCore lc, LinphoneCore.GlobalState state, String message) {

            }

            @Override
            public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, LinphoneCore.RegistrationState state, String smessage) {
            }
        });


        try {
            mStartForeground = getClass().getMethod("startForeground", mStartFgSign);
            mStopForeground = getClass().getMethod("stopForeground", mStopFgSign);
        } catch (NoSuchMethodException e) {
            Log.e(e, "Couldn't find startForeground or stopForeground");
        }



    /*  if (displayServiceNotification()) {
            startForegroundCompat(NOTIF_ID, mNotif);
        }*/

        if (!mTestDelayElapsed) {
            // Only used when testing. Simulates a 5 seconds delay for launching service
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mTestDelayElapsed = true;
                }
            }, 5000);
        }

        //make sure the application will at least wakes up every 10 mn

        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
    }




    private enum IncallIconState {INCALL, PAUSE, VIDEO, IDLE}

    private LinphoneService.IncallIconState mCurrentIncallIconState = LinphoneService.IncallIconState.IDLE;


    public void refreshIncallIcon(LinphoneCall currentCall) {
        LinphoneCore lc = LinphoneManager.getLc();

    }


    public void removeSasNotification() {
        mNM.cancel(SAS_NOTIF_ID);
    }

    private static final Class<?>[] mSetFgSign = new Class[]{boolean.class};
    private static final Class<?>[] mStartFgSign = new Class[]{
            int.class, Notification.class};
    private static final Class<?>[] mStopFgSign = new Class[]{boolean.class};

    private Method mSetForeground;
    private Method mStartForeground;
    private Method mStopForeground;
    private Object[] mSetForegroundArgs = new Object[1];
    private Object[] mStartForegroundArgs = new Object[2];
    private Object[] mStopForegroundArgs = new Object[1];
    private String incomingReceivedActivityName;

    void invokeMethod(Method method, Object[] args) {
        try {
            method.invoke(this, args);
        } catch (InvocationTargetException e) {
            // Should not happen.
            Log.w(e, "Unable to invoke method");
        } catch (IllegalAccessException e) {
            // Should not happen.
            Log.w(e, "Unable to invoke method");
        }
    }

    /**
     * This is a wrapper around the new startForeground method, using the older
     * APIs if it is not available.
     */
    void startForegroundCompat(int id, Notification notification) {
        // If we have the new startForeground API, then use it.
        if (mStartForeground != null) {
            mStartForegroundArgs[0] = Integer.valueOf(id);
            mStartForegroundArgs[1] = notification;
            invokeMethod(mStartForeground, mStartForegroundArgs);
            return;
        }

        // Fall back on the old API.
        if (mSetForeground != null) {
            mSetForegroundArgs[0] = Boolean.TRUE;
            invokeMethod(mSetForeground, mSetForegroundArgs);
            // continue
        }

        notifyWrapper(id, notification);
    }

    /**
     * This is a wrapper around the new stopForeground method, using the older
     * APIs if it is not available.
     */
    void stopForegroundCompat(int id) {
        // If we have the new stopForeground API, then use it.
        if (mStopForeground != null) {
            mStopForegroundArgs[0] = Boolean.TRUE;
            invokeMethod(mStopForeground, mStopForegroundArgs);
            return;
        }

        // Fall back on the old API.  Note to cancel BEFORE changing the
        // foreground state, since we could be killed at that point.
        mNM.cancel(id);
        if (mSetForeground != null) {
            mSetForegroundArgs[0] = Boolean.FALSE;
            invokeMethod(mSetForeground, mSetForegroundArgs);
        }
    }

    private void dumpDeviceInformation() {
        StringBuilder sb = new StringBuilder();
        sb.append("DEVICE=").append(Build.DEVICE).append("\n");
        sb.append("MODEL=").append(Build.MODEL).append("\n");
        sb.append("MANUFACTURER=").append(Build.MANUFACTURER).append("\n");
        sb.append("SDK=").append(Build.VERSION.SDK_INT).append("\n");
        sb.append("Supported ABIs=");
        for (String abi : Version.getCpuAbis()) {
            sb.append(abi + ", ");
        }
        sb.append("\n");
        Log.i(sb.toString());
    }

    private void dumpInstalledLinphoneInformation() {
        PackageInfo info = null;
        try {
            info = getPackageManager().getPackageInfo(getPackageName(), 0);
        } catch (NameNotFoundException nnfe) {
        }

        if (info != null) {
            Log.i("Linphone version is ", info.versionName + " (" + info.versionCode + ")");
        } else {
            Log.i("Linphone version is unknown");
        }
    }


    /**
     * Wrap notifier to avoid setting the linphone icons while the service
     * is stopping. When the (rare) bug is triggered, the linphone icon is
     * present despite the service is not running. To trigger it one could
     * stop linphone as soon as it is started. Transport configured with TLS.
     */
    private synchronized void notifyWrapper(int id, Notification notification) {
        if (instance != null && notification != null) {
            mNM.notify(id, notification);
        } else {
            Log.i("Service not ready, discarding notification");
        }
    }

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


    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        android.util.Log.d("TaskRemoved","True");
        if (getResources().getBoolean(R.bool.kill_service_with_task_manager)) {
            Log.d("Task removed, stop service");

            // If push is enabled, don't unregister account, otherwise do unregister
            if (LinphonePreferences.instance().isPushNotificationEnabled()) {
                LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
                if (lc != null) lc.setNetworkReachable(false);
            }
           stopSelf();
        }
        super.onTaskRemoved(rootIntent);
    }

    @Override
    public synchronized void onDestroy() {

        if (activityCallbacks != null) {
            getApplication().unregisterActivityLifecycleCallbacks(activityCallbacks);
            activityCallbacks = null;
        }

        LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
        if (lc != null) {
            lc.removeListener(mListener);
        }

        instance = null;
        LinphoneManager.destroy();

        // Make sure our notification is gone.
        stopForegroundCompat(NOTIF_ID);
        mNM.cancel(INCALL_NOTIF_ID);
        mNM.cancel(MESSAGE_NOTIF_ID);

        super.onDestroy();
    }


    private void onIncomingReceived2(LinphoneCall call) {
        String name = call.getRemoteAddress().asString().substring(call.getRemoteAddress().asString().indexOf("\"")+1,call.getRemoteAddress().asString().lastIndexOf("\""));
        String myname = MyApplication.getInstance().getPrefManager().getUserName()+" "+MyApplication.getInstance().getPrefManager().getUserLastName();
        android.util.Log.d("ServiceStarted", " Values  "+ name+"   "+myname + call.getUserData());
        if (!name.equals(myname)) {
            Intent intent = new Intent(getApplicationContext(), TwilioIncomingCallActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        }

    }

При поступлении любого входящего вызова слушатель в службе инициализируется по имени LinphoneManager.getLc().addListener в этом он прослушивает входящий вызов, где оператор If упоминается как

if (state == LinphoneCall.State.IncomingReceived) {
                    android.util.Log.d("ServiceStarted", "IncomingCall  Status");
                    onIncomingReceived2(call);
                }

Теперь внизу кода есть метод onIncomingReceived2(LinphoneCall call), Поэтому, когда я проверил из метода по умолчанию, т.е. call.getRemoteAddress (), я получаю то же имя пользователя, от которого был вызван вызов Initialized.

Поэтому, когда я звоню, он принимается на том же устройстве. Буду очень признателен, если кто-нибудь может помочь в этом. Заранее спасибо.

0 ответов

Другие вопросы по тегам