Android集成Linphone

demo地址:https://gitee.com/me_project_share/linphone-demo

1、项目级build.gradle引入库

buildscript {
    repositories {
        google()
        jcenter()
        maven { url 'https://linphone.org/releases/maven_repository/' }
    }
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.3"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31"
    }
}
allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://linphone.org/releases/maven_repository/' }
    }
}

2、app级build.gradle引入

implementation('org.linphone:linphone-sdk-android:5.0.0')
implementation 'androidx.media:media:1.4.0'//响铃

3、添加权限

<uses-permission android:name="android.permission.INTERNET" />//网络权限
<uses-permission android:name="android.permission.CAMERA"
     tools:ignore="PermissionImpliesUnsupportedChromeOsHardware" />//摄像头权限
<uses-permission android:name="android.permission.READ_PHONE_STATE" />//手机状态权限

<uses-permission android:name="android.permission.RECORD_AUDIO" />//麦克风权限
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />//麦克风设置权限

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />//网络状态权限

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />//读取本地权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />//写入本地权限

4、AndroidManifest.xml加入Linphone Service

<service
   android:name="org.linphone.core.tools.service.CoreService"
   android:foregroundServiceType="phoneCall|camera|microphone"
   android:label="@string/library_name"
   android:stopWithTask="false" />

5、初始化Linphone

LinphoneManager.getInstance()
                .init(this)
                .start();

6、登录Linphone

LinphoneManager.getInstance().Login("账号","密码","ip","端口");

7、拨号

LinphoneManager.getInstance().startCall(number, false/*是否是视频通话*/);

 其他api参考下面文件或者下载demo


需要的文件

LinphoneManager文件:

public class LinphoneManager {
    private static LinphoneManager INSTANCE = null;
    private Call.State previousCallState = Call.State.Idle;
    private Context mContext;
    private CorePreferences corePreferences;
    private Core core;
    private RegistrationCallback registrationCallback;
    private boolean gsmCallActive = false;
//    private PhoneCallback phoneCallback;
    private boolean coreIsStart = false;
    private Call currentCall;

    public LinphoneManager() {

    }

    public static LinphoneManager getInstance() {
        if (INSTANCE == null) {
            synchronized (LinphoneUtils.class) {
                if (INSTANCE == null) {
                    INSTANCE = new LinphoneManager();
                }
            }
        }
        return INSTANCE;
    }

    public LinphoneManager init(Context context) {
        mContext = context.getApplicationContext();

        //开启日志
        Factory.instance().enableLogCollection(LogCollectionState.Enabled);
        Factory.instance().enableLogcatLogs(true);

        corePreferences = new CorePreferences(mContext);
        corePreferences.copyAssetsFromPackage();

        core = Factory.instance().createCoreWithConfig(corePreferences.getConfig(), mContext);
        return this;
    }

    /**
     * 登录到服务器
     *
     * @param username 账号名
     * @param password 密码
     * @param ip       IP地址
     * @param port     端口号
     */
    public void Login(@NonNull String username, @NonNull String password, @NonNull String ip, @NonNull String port) {
        core.clearProxyConfig();
        String domain = ip + ":" + port;
        AccountCreator accountCreator = core.createAccountCreator(corePreferences.getXmlrpcUrl());
        accountCreator.setLanguage(Locale.getDefault().getLanguage());
        accountCreator.reset();

        accountCreator.setUsername(username);//账号
        accountCreator.setPassword(password);//密码
        accountCreator.setDisplayName(username);//显示名称
        accountCreator.setDomain(domain);//域名
        accountCreator.setTransport(TransportType.Udp);//传输类型

        accountCreator.createProxyConfig();
    }

    public LinphoneManager registrationCallback(RegistrationCallback registrationCallback) {
        this.registrationCallback = registrationCallback;
        return this;
    }

    public LinphoneManager registerPhoneCallback(PhoneCallback phoneCallback) {
//        this.phoneCallback = phoneCallback;
        return this;
    }

    /**
     * 启动linphone
     */
    public void start() {
        if (!coreIsStart) {
            Log.i(mContext.getString(R.string.library_name), "[LinphoneManager] starting Linphone");
            coreIsStart = true;
            initLinphone();
            core.addListener(mCoreListener);
            core.start();

            TelephonyManager telephonyManager =
                    (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
            Log.i(mContext.getString(R.string.library_name), "[LinphoneManager] 注册 phone state listener");
            telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
        }
    }

    /***
     * 初始化设置
     */
    private void initLinphone() {
        configureCore();
//        initUserCertificates();
    }

    private void configureCore() {
        core.setNativeRingingEnabled(true);// 来电铃声
        core.setVibrationOnIncomingCallEnabled(true);// 来电振动
        core.enableEchoCancellation(true); //回声消除
        core.enableAdaptiveRateControl(true); //自适应码率控制
    }

    /***
     * 设置存放用户x509证书的目录路径
     */
    private void initUserCertificates() {
        String userCertsPath = corePreferences.userCertificatesPath;
        File f = new File(userCertsPath);
        if (!f.exists()) {
            if (!f.mkdir()) {
                Log.e(mContext.getString(R.string.library_name), "[LinphoneManager] " + userCertsPath + "不能创建");
            }
        }
        core.setUserCertificatesPath(userCertsPath);
    }

    /**
     * 拨打电话
     *
     * @param toPhoneNum  String
     * @param isVideoCall Boolean
     */
    public void startCall(@NonNull String toPhoneNum, @NonNull boolean isVideoCall) {
        if (toPhoneNum.trim().isEmpty()) {
            Toast.makeText(mContext, "请输入正确的呼叫号码", Toast.LENGTH_LONG).show();
            return;
        }
        try {
            Address addressToCall = core.interpretUrl(toPhoneNum);
            if (addressToCall != null) {
                addressToCall.setDisplayName(toPhoneNum);
            }

            CallParams params = core.createCallParams(null);
            if (params != null) {
                //启用通话录音
//            params.setRecordFile(LinphoneUtils.getRecordingFilePathForAddress(mContext, addressToCall));
                //启动低宽带模式
                if (LinphoneUtils.checkIfNetworkHasLowBandwidth(mContext)) {
                    Log.w(mContext.getString(R.string.library_name), "[LinphoneManager] Enabling low bandwidth mode!");
                    params.enableLowBandwidth(true);
                }
                if (isVideoCall) {
                    params.enableVideo(true);
                    core.enableVideoCapture(true);
                    core.enableVideoDisplay(true);
                } else {
                    params.enableVideo(false);
                }
                core.inviteAddressWithParams(addressToCall, params);
            } else {
                core.inviteAddress(addressToCall);
            }


        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 接听来电
     */
    public int answerCall(Call call) {
        Log.i(mContext.getString(R.string.library_name), "[LinphoneManager] 接听来电 " + call);
        CallParams params = core.createCallParams(call);
        if (params != null) {
            //启用通话录音
//        params.setRecordFile(LinphoneUtils.getRecordingFilePathForAddress(mContext, call.getRemoteAddress()));
            if (LinphoneUtils.checkIfNetworkHasLowBandwidth(mContext)) {
                Log.w(mContext.getString(R.string.library_name), "[LinphoneManager] 启用低带宽模式!");
                params.enableLowBandwidth(true);
            }
            params.enableVideo(isVideoCall(call));
            return call.acceptWithParams(params);
        } else {
            return -1;
        }
    }

    /**
     * 拒接电话
     *
     * @param call Call
     */
    public int declineCall(Call call) {
        String voiceMailUri = corePreferences.getVoiceMailUri();
        if (voiceMailUri != null && corePreferences.isRedirectDeclinedCallToVoiceMail()) {
            Address voiceMailAddress = core.interpretUrl(voiceMailUri);
            if (voiceMailAddress != null) {
                Log.i(mContext.getString(R.string.library_name), "[LinphoneManager] 重定向 call " + call +" 语音信箱URI: " + voiceMailUri);
                return call.redirectTo(voiceMailAddress);
            }
        } else {
            Log.i(mContext.getString(R.string.library_name), "[LinphoneManager] 拒接电话"+call);
            return call.decline(Reason.Declined);
        }
        return -1;
    }

    /**
     * 挂断电话
     */
    public int terminateCall(Call call) {
        Log.i(mContext.getString(R.string.library_name), "[LinphoneManager] 挂断电话 " + call);
        return call.terminate();
    }

    /***
     * 麦克风是否开启
     * @return
     */
    public boolean micEnabled() {
        return core.micEnabled();
    }

    /***
     * 扬声器是否开启
     * @return
     */
    public boolean speakerEnabled() {
        return core.getOutputAudioDevice().getType() == AudioDevice.Type.Speaker;
    }

    /**
     * 启动麦克风
     *
     * @param micEnabled Boolean
     */
    public void enableMic(Boolean micEnabled) {
        if (core != null) {
            core.enableMic(micEnabled);
        }
    }

    /**
     * 扬声器或听筒
     *
     * @param SpeakerEnabled Boolean
     */
    public void enableSpeaker(boolean SpeakerEnabled) {
        if (core != null) {
            if (SpeakerEnabled) {
                AudioRouteUtils.routeAudioToSpeaker(core);
            } else {
                AudioRouteUtils.routeAudioToEarpiece(core);
            }
        }
    }

    /**
     * 是否是视频电话
     *
     * @return Boolean
     */
    public boolean isVideoCall(Call call) {
        CallParams remoteParams = call.getRemoteParams();
        return remoteParams != null && remoteParams.videoEnabled();
    }

    /**
     * 设置视频界面
     *
     * @param videoRendering TextureView 对方界面
     * @param videoPreview   CaptureTextureView 自己界面
     */
    public void setVideoWindowId(TextureView videoRendering, TextureView videoPreview) {
        if (core != null) {
            core.setNativeVideoWindowId(videoRendering);
            core.setNativePreviewWindowId(videoPreview);
        }
    }

    /**
     * 停止linphone
     */
    private void stop() {
        coreIsStart = false;
        TelephonyManager telephonyManager =
                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);

        Log.i(mContext.getString(R.string.library_name), "[LinphoneManager] 注销 phone state listener");
        telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);

        core.removeListener(mCoreListener);
        core.stop();
    }

    /**
     * 注销登录
     */
    public void loginOut() {
        if (core != null) {
            core.clearProxyConfig();
        }
    }

    public Call getCurrentCall() {
        return (currentCall != null) ? currentCall : null;
    }

    public void getLoginState() {
        if (core != null && core.getDefaultAccount() != null){
            Intent intent = new Intent("com.okcis.siplibrary.LoginState");
            intent.putExtra("LoginState", core.getDefaultAccount().getState().toInt());
            mContext.sendBroadcast(intent);
        }
    }

    CoreListenerStub mCoreListener = new CoreListenerStub() {
        @Override
        public void onRegistrationStateChanged(@NonNull Core core, @NonNull ProxyConfig proxyConfig, RegistrationState state, @NonNull String message) {
            super.onRegistrationStateChanged(core, proxyConfig, state, message);
            Intent intent = new Intent("com.okcis.siplibrary.LoginState");
            switch (state) {
                case None:
                    intent.putExtra("LoginState", RegistrationState.None.toInt());
                    mContext.sendBroadcast(intent);
//                    registrationCallback.registrationNone();
                    break;
                case Progress:
                    intent.putExtra("LoginState", RegistrationState.Progress.toInt());
                    mContext.sendBroadcast(intent);
//                    registrationCallback.registrationProgress();
                    break;
                case Ok:
                    intent.putExtra("LoginState", RegistrationState.Ok.toInt());
                    mContext.sendBroadcast(intent);
//                    registrationCallback.registrationOk();
                    break;
                case Cleared:
                    intent.putExtra("LoginState", RegistrationState.Cleared.toInt());
                    mContext.sendBroadcast(intent);
//                    registrationCallback.registrationClear();
                    break;
                case Failed:
                    intent.putExtra("LoginState", RegistrationState.Failed.toInt());
                    mContext.sendBroadcast(intent);
//                    registrationCallback.registrationFailed();
                    break;
            }
        }


        @Override
        public void onCallStateChanged(@NonNull Core core, @NonNull Call call, Call.State state, @NonNull String message) {
            super.onCallStateChanged(core, call, state, message);
            Log.e(mContext.getString(R.string.library_name), "[LinphoneManager] Call state changed " + state + "     " + core.getCallsNb());
            if (!gsmCallActive) {
                currentCall = call;
            }
            Intent intent = new Intent("com.okcis.siplibrary.CallState");
            intent.setPackage(mContext.getPackageName());
            switch (state) {
                case IncomingReceived:
                case IncomingEarlyMedia:
                    if (gsmCallActive) {
                        Log.w(mContext.getString(R.string.library_name), "[LinphoneManager] Refusing the call with reason busy because a GSM call is active");
                        call.decline(Reason.Busy);
                        return;
                    }
                    intent.putExtra("CallState", Call.State.IncomingReceived.toInt());
                    mContext.sendBroadcast(intent);
//                    phoneCallback.incomingCall(currentCall);
                    gsmCallActive = true;
                    //自动接听
                    if (corePreferences.isAutoAnswerEnabled()) {
                        int autoAnswerDelay = corePreferences.getAutoAnswerTime();
                        if (autoAnswerDelay == 0) {
                            Log.w(mContext.getString(R.string.library_name), "[LinphoneManager] 立即自动接听来电");
                            answerCall(currentCall);
                        } else {
                            Log.i(mContext.getString(R.string.library_name), "[LinphoneManager] " + autoAnswerDelay + "ms后自动接听来电");
                            Handler mainThreadHandler = new Handler(Looper.getMainLooper());
                            mainThreadHandler.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    Log.w(mContext.getString(R.string.library_name), "[LinphoneManager] Auto answering call");
                                    answerCall(currentCall);
                                }
                            }, autoAnswerDelay);
                        }
                    }
                    break;
                case OutgoingInit:
                    if (core.getCallsNb() == 1 && !gsmCallActive) {
                        intent.putExtra("CallState", Call.State.OutgoingInit.toInt());
                        mContext.sendBroadcast(intent);
//                        phoneCallback.outgoingInit(currentCall);
                        gsmCallActive = true;
                    }
                    break;
                case OutgoingProgress:
                    if (core.getCallsNb() == 1 && corePreferences.isRouteAudioToBluetoothIfAvailable()) {
                        AudioRouteUtils.routeAudioToBluetooth(core, currentCall);
                    }
                    break;
                case Connected:
                    intent.putExtra("CallState", Call.State.Connected.toInt());
                    mContext.sendBroadcast(intent);
//                    phoneCallback.callConnected(currentCall);
                    break;
                case StreamsRunning:
                    if (core.getCallsNb() == 1) {
                        // 只有第一次呼叫在StreamsRunning时才尝试连接蓝牙或耳机
                        if (previousCallState == Call.State.Connected) {
                            Log.i(mContext.getString(R.string.library_name), "[LinphoneManager] 第一次进入StreamsRunning状态,尝试将音频路由到可用的耳机或蓝牙设备");
                            if (AudioRouteUtils.isHeadsetAudioRouteAvailable(core)) {
                                AudioRouteUtils.routeAudioToHeadset(core, currentCall);
                            } else if (corePreferences.isRouteAudioToBluetoothIfAvailable() && AudioRouteUtils.isBluetoothAudioRouteAvailable(core)) {
                                AudioRouteUtils.routeAudioToBluetooth(core, currentCall);
                            }
                        }
                    }

                    if (corePreferences.isRouteAudioToSpeakerWhenVideoIsEnabled() && currentCall.getCurrentParams().videoEnabled()) {
                        // 如果使用耳机或蓝牙,在启用视频时不打开扬声器
                        if (!AudioRouteUtils.isHeadsetAudioRouteAvailable(core) &&
                                !AudioRouteUtils.isBluetoothAudioRouteCurrentlyUsed(core, currentCall)
                        ) {
                            Log.i(mContext.getString(R.string.library_name), "[LinphoneManager] 视频通话,没有有线耳机,没有使用蓝牙,音频路由到扬声器");
                            AudioRouteUtils.routeAudioToSpeaker(core);
                        }
                    }
                    break;
                case End:
                    if (core.getCallsNb() == 0) {
                        intent.putExtra("CallState", Call.State.End.toInt());
                        mContext.sendBroadcast(intent);
//                        phoneCallback.callEnd(currentCall);
                        gsmCallActive = false;
                    }
                    break;
                case Released:
                    if (core.getCallsNb() == 0) {
                        intent.putExtra("CallState", Call.State.Released.toInt());
                        mContext.sendBroadcast(intent);
//                        phoneCallback.callReleased(currentCall);
                        gsmCallActive = false;
                    }
                    break;
                case Error:
                    if (core.getCallsNb() == 0) {
                        int msgId;
                        switch (currentCall.getErrorInfo().getReason()) {
                            case Busy:
                                msgId = R.string.call_error_user_busy;
                                break;
                            case IOError:
                                msgId = R.string.call_error_io_error;
                                break;
                            case NotAcceptable:
                                msgId = R.string.call_error_incompatible_media_params;
                                break;
                            case NotFound:
                                msgId = R.string.call_error_user_not_found;
                                break;
                            case Forbidden:
                                msgId = R.string.call_error_forbidden;
                                break;
                            default:
                                msgId = R.string.call_error_unknown;
                                break;
                        }
                        intent.putExtra("CallState", Call.State.Error.toInt());
                        mContext.sendBroadcast(intent);
//                        phoneCallback.error(mContext.getString(msgId));
                        gsmCallActive = false;
                    }
                    break;

            }
            previousCallState = state;
        }
    };

    PhoneStateListener phoneStateListener = new PhoneStateListener() {
        @Override
        public void onCallStateChanged(int state, String phoneNumber) {
            super.onCallStateChanged(state, phoneNumber);
            Log.i(mContext.getString(R.string.library_name), "[LinphoneManager] 手机状态 " + state);
            switch (state) {
                case TelephonyManager.CALL_STATE_OFFHOOK:
                case TelephonyManager.CALL_STATE_RINGING:
                    gsmCallActive = true;
                    break;
                default:
                    gsmCallActive = false;
                    break;
            }
        }
    };


}

CorePreferences文件

public class CorePreferences {

    private Context mContext;
    public Config config;
    public String basePath;
    public String configPath;
    public String factoryConfigPath;
    public String linphoneDefaultValuesPath;
    public String defaultValuesPath;
    public String userCertificatesPath;

    public CorePreferences(Context context) {
        mContext = context;
        basePath = mContext.getFilesDir().getAbsolutePath();
        configPath = basePath + "/.linphonerc";
        factoryConfigPath = basePath + "/linphonerc";
        linphoneDefaultValuesPath = basePath + "/assistant_linphone_default_values";
        defaultValuesPath = basePath + "/assistant_default_values";
        userCertificatesPath = basePath + "/user-certs";

        config = Factory.instance().createConfigWithFactory(
                configPath,
                factoryConfigPath
        );
        String TagName = mContext.getString(R.string.library_name);
        Factory.instance().setDebugMode(isDebugEnabled(), TagName);

    }

    public Config getConfig(){
        return (config != null)? config:null;
    }

    /***
     * 是否开启debug
     * @return
     */
    public boolean isDebugEnabled() {
        if (config == null) return false;
        return config.getBool("app", "debug", false);
    }

    public CorePreferences enabledDebug(boolean enabled) {
        if (config == null) return null;
        config.setBool("app", "debug", enabled);
        return this;
    }

    /***
     * 是否开启自动应答
     * @return
     */
    public boolean isAutoAnswerEnabled() {
        if (config == null) return false;
        return config.getBool("app", "auto_answer", false);
    }

    public CorePreferences enableAutoAnswer(boolean enable) {
        if (config == null) return null;
        config.setBool("app", "auto_answer", enable);
        return this;
    }

    /***
     * 自动应答时间
     * @return
     */
    public int getAutoAnswerTime() {
        if (config == null) return 0;
        return config.getInt("app", "auto_answer_delay", 0);
    }

    public CorePreferences setAutoAnswerTime(int time) {
        if (config == null) return null;
        config.setInt("app", "auto_answer_delay", time);
        return this;
    }

    /***
     * 获取语音箱地址
     * @return
     */
    public String getVoiceMailUri() {
        if (config == null) return null;
        return config.getString("app", "voice_mail", null);
    }

    public CorePreferences setVoiceMailUri(String uri) {
        if (config == null) return null;
        config.setString("app", "voice_mail", uri);
        return this;
    }

    /***
     * 是否开启:被拒绝通话转到语音箱
     * @return
     */
    public boolean isRedirectDeclinedCallToVoiceMail() {
        if (config == null) return false;
        return config.getBool("app", "redirect_declined_call_to_voice_mail", true);
    }

    public CorePreferences enabledRedirectDeclinedCallToVoiceMail(boolean value) {
        if (config == null) return null;
        config.setBool("app", "redirect_declined_call_to_voice_mail", value);
        return this;
    }

    /**
     * 是否获取可用蓝牙设备
     * @return
     */
    public boolean isRouteAudioToBluetoothIfAvailable() {
        if (config == null) return false;
        return config.getBool("app", "route_audio_to_bluetooth_if_available", true);
    }

    public CorePreferences enabledRouteAudioToBluetoothIfAvailable(boolean value) {
        if (config == null) return null;
        config.setBool("app", "route_audio_to_bluetooth_if_available", value);
        return this;
    }

    /***
     * 视频通话是否启用扬声器
     * @return
     */
    public boolean isRouteAudioToSpeakerWhenVideoIsEnabled() {
        if (config == null) return false;
        return config.getBool("app", "route_audio_to_speaker_when_video_enabled", true);
    }

    public CorePreferences enabledRouteAudioToSpeakerWhenVideoIsEnabled(boolean value) {
        if (config == null) return null;
        config.setBool("app", "route_audio_to_speaker_when_video_enabled", value);
        return this;
    }

    /***
     * 获取xmlrpc_url
     * @return
     */
    public String getXmlrpcUrl() {
        if (config == null) return null;
        return config.getString("assistant", "xmlrpc_url", null);
    }

    public void setXmlrpcUrl(String value) {
        if (config == null) return;
        config.setString("assistant", "xmlrpc_url", value);
    }

    public void copyAssetsFromPackage() {
        copy("linphonerc_default", configPath, false);
        copy("linphonerc_factory", factoryConfigPath, true);
        copy("assistant_linphone_default_values", linphoneDefaultValuesPath, true);
        copy("assistant_default_values", defaultValuesPath, true);

        move(basePath + "/linphone-log-history.db", basePath + "/call-history.db", false);
        move(basePath + "/zrtp_secrets", basePath + "/zrtp-secrets.db", false);
    }

    private void copy(String from, String to, boolean overrideIfExists) {
        File outFile = new File(to);
        if (outFile.exists()) {
            if (!overrideIfExists) {
                Log.i(mContext.getString(R.string.library_name), "[CorePreferences] copy文件" + from + "已经存在,路径:" + to);
                return;
            }
        }
        Log.i(mContext.getString(R.string.library_name), "[CorePreferences] 从assets copy" + from + "文件,路径:" + to);
        try {
            OutputStream outStream = new FileOutputStream(outFile);
            InputStream inFile = mContext.getAssets().open(from);
            byte[] buffer = new byte[1024];
            int length = inFile.read(buffer);

            while (length > 0) {
                outStream.write(buffer, 0, length);
                length = inFile.read(buffer);
            }
            inFile.close();
            outStream.flush();
            outStream.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    private void move(String from, String to, boolean overrideIfExists) {
        File inFile = new File(from);
        File outFile = new File(to);
        if (inFile.exists()) {
            if (outFile.exists() && !overrideIfExists) {
                Log.w(mContext.getString(R.string.library_name), "[CorePreferences] move文件" + from + "已经存在,路径:" + to);
            } else {
                try {
                    InputStream inStream = new FileInputStream(inFile);
                    OutputStream outStream = new FileOutputStream(outFile);

                    byte[] buffer = new byte[1024];
                    int len = 0;
                    while ((len = in.read(buffer)) != -1) {
                        outStream.write(buffer, 0, len);
                    }

                    inStream.close();
                    outStream.flush();
                    outStream.close();

                    inFile.delete();
                    Log.i(mContext.getString(R.string.library_name), "[CorePreferences] move文件" + from + "完成,路径:" + to);
                } catch (FileNotFoundException e) {
                    throw new RuntimeException(e);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

            }
        } else {
            Log.w(mContext.getString(R.string.library_name), "[CorePreferences] move" + from + "文件失败,没有文件资源");
        }
    }

}

AudioRouteUtils文件:

public class AudioRouteUtils {

    /***
     * 切换到听筒
     * @param core
     */
    public static void routeAudioToEarpiece(Core core) {
        if (core.getCallsNb() == 0) {
            Log.e("AudioRouteUtils","[Audio Route Helper] No call found, aborting earpiece audio route change");
            return;
        }
        Call call = core.getCurrentCall();
        if (call == null){
            call = core.getCalls()[0];
        }

        for (AudioDevice audioDevice: core.getAudioDevices()) {
            if (audioDevice.getType() == AudioDevice.Type.Earpiece) {
                Log.i("AudioRouteUtils","[Audio Route Helper Earpiece] 找到听筒音频设备 "+ audioDevice.getDeviceName());
                call.setOutputAudioDevice(audioDevice);
                return;
            }
        }
        Log.e("AudioRouteUtils","[Audio Route Helper] 找不到听筒音频设备");
    }

    /***
     * 切换到扬声器
     * @param core
     */
    public static void routeAudioToSpeaker(Core core) {
        if (core.getCallsNb() == 0) {
            Log.e("AudioRouteUtils","[Audio Route Helper] No call found, aborting speaker audio route change");
            return;
        }
        Call call = core.getCurrentCall();
        if (call == null){
            call = core.getCalls()[0];
        }

        for (AudioDevice audioDevice: core.getAudioDevices()) {
            if (audioDevice.getType() == AudioDevice.Type.Speaker) {
                Log.i("AudioRouteUtils","[Audio Route Helper Speaker] 找到扬声器音频设备 "+ audioDevice.getDeviceName());
                call.setOutputAudioDevice(audioDevice);
                return;
            }
        }
        Log.e("AudioRouteUtils","[Audio Route Helper] 找不到扬声器音频设备");
    }

    /***
     * 切换到蓝牙设备
     * @param core
     * @param call
     */
    public static void routeAudioToBluetooth(Core core, Call call) {
        if (core.getCallsNb() == 0) {
            Log.e("AudioRouteUtils", "[Audio Route Helper] No call found, aborting bluetooth audio route change");
            return;
        }
        Call currentCall;
        if (call == null){
            currentCall = core.getCurrentCall();
            if (currentCall == null){
                currentCall = core.getCalls()[0];
            }
        } else {
            currentCall = call;
        }

        for (AudioDevice audioDevice: core.getAudioDevices()) {
            if (audioDevice.getType() == AudioDevice.Type.Bluetooth) {
                if (audioDevice.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) {
                    Log.i("AudioRouteUtils","[Audio Route Helper] 找到蓝牙音频设备 " + audioDevice.getDeviceName());
                    currentCall.setOutputAudioDevice(audioDevice);
                    return;
                }
            }
        }
        Log.e("AudioRouteUtils","[Audio Route Helper] 找不到蓝牙音频设备");
    }


    /***
     * 切换到耳机
     * @param core
     * @param call
     */
    public static void routeAudioToHeadset(Core core, Call call) {
        if (core.getCallsNb() == 0) {
            Log.e("AudioRouteUtils","[Audio Route Helper] No call found, aborting headset audio route change");
            return;
        }
        Call currentCall;
        if (call == null){
            currentCall = core.getCurrentCall();
            if (currentCall == null){
                currentCall = core.getCalls()[0];
            }
        } else {
            currentCall = call;
        }

        for (AudioDevice audioDevice: core.getAudioDevices()) {
            if (audioDevice.getType() == AudioDevice.Type.Headphones || audioDevice.getType() == AudioDevice.Type.Headset) {
                if (audioDevice.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) {
                    Log.i("AudioRouteUtils","[Audio Route Helper] 找到有线耳机音频设备 " + audioDevice.getDeviceName());
                    currentCall.setOutputAudioDevice(audioDevice);
                    return;
                }
            }
        }
        Log.e("AudioRouteUtils","[Audio Route Helper] 找不到有线耳机音频设备");
    }

    /***
     * 耳机是否可用
     * @param core
     * @return
     */
    public static boolean isHeadsetAudioRouteAvailable(Core core) {
        for (AudioDevice audioDevice : core.getAudioDevices()) {
            if ((audioDevice.getType() == AudioDevice.Type.Headset || audioDevice.getType() == AudioDevice.Type.Headphones) &&
                    audioDevice.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) {
                Log.i("AudioRouteUtils","[Audio Route Helper] 找到耳机设备 " + audioDevice.getDeviceName());
                return true;
            }
        }
        return false;
    }

    /***
     * 当前是否在使用蓝牙设备
     * @param core
     * @param call
     * @return
     */
    public static boolean isBluetoothAudioRouteCurrentlyUsed(Core core,Call call) {
        if (core.getCallsNb() == 0) {
            Log.w("AudioRouteUtils","[Audio Route Helper] No call found, so bluetooth audio route isn't used");
            return false;
        }
        Call currentCall;
        if (call == null){
            currentCall = core.getCurrentCall();
            if (currentCall == null){
                currentCall = core.getCalls()[0];
            }
        } else {
            currentCall = call;
        }

        AudioDevice audioDevice = currentCall.getOutputAudioDevice();
        Log.i("AudioRouteUtils","[Audio Route Helper] 当前正在使用的音频设备是 " + audioDevice.getDeviceName());
        return audioDevice.getType() == AudioDevice.Type.Bluetooth;
    }

    /***
     * 蓝牙设备是否可用
     * @param core
     * @return
     */
    public static boolean isBluetoothAudioRouteAvailable(Core core) {
        for (AudioDevice audioDevice : core.getAudioDevices()) {
            if (audioDevice.getType() == AudioDevice.Type.Bluetooth &&
                    audioDevice.hasCapability(AudioDevice.Capabilities.CapabilityPlay)) {
                Log.i("AudioRouteUtils","[Audio Route Helper] 找到蓝牙音频设备 " + audioDevice.getDeviceName());
                return true;
            }
        }
        return false;
    }
}

FileUtils文件:

public class FileUtils {
    public static final String VFS_PLAIN_FILE_EXTENSION = ".bctbx_evfs_plain";

    public static String getDisplayName(Address address) {
        return (!address.getDisplayName().trim().isEmpty())? address.getUsername() : "";
    }


    public static File getFileStoragePath(Context context, String fileName) {
        File path = getFileStorageDir(context, isExtensionImage(fileName));
        File file = new File(path, fileName);

        int prefix = 1;
        while (file.exists()) {
            file = new File(path, prefix + "_" + fileName);
            prefix += 1;
        }
        return file;
    }

    public static File getFileStorageDir(Context context, Boolean isPicture) {
        File path = null;
        if (Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED) {
            String directory = Environment.DIRECTORY_DOWNLOADS;
            if (isPicture) {
                directory = Environment.DIRECTORY_PICTURES;
            }
            path = context.getExternalFilesDir(directory);
        }

        File returnPath = (path != null)? path: context.getFilesDir();

        return returnPath;
    }

    public static Boolean isExtensionImage(String path) {
        String extension = getExtensionFromFileName(path).toLowerCase(Locale.getDefault());
        String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
        return (type != null) && type.startsWith("image/") ? true : false;
    }

    public static String getExtensionFromFileName(String fileName) {
        String realFileName = "";
        if (fileName.endsWith(VFS_PLAIN_FILE_EXTENSION)) {
            realFileName = fileName.substring(0, fileName.length() - VFS_PLAIN_FILE_EXTENSION.length());
        } else {
            realFileName = fileName;
        }

        String extension = MimeTypeMap.getFileExtensionFromUrl(realFileName);
        if (extension != null && !extension.isEmpty()) {
            int i = realFileName.lastIndexOf('.');
            if (i > 0) {
                extension = realFileName.substring(i + 1);
            }
        }

        return extension;
    }
}

LinphoneUtils文件:

public class LinphoneUtils {

    /***
     * 检查网络带宽是否过低
     * @param context
     * @return
     */
    public static boolean checkIfNetworkHasLowBandwidth(Context context){
        ConnectivityManager connMgr =
                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
        if (networkInfo != null && networkInfo.isConnected()) {
            if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                if (networkInfo.getSubtype() == NETWORK_TYPE_EDGE
                        || networkInfo.getSubtype() == NETWORK_TYPE_GPRS
                        || networkInfo.getSubtype() == NETWORK_TYPE_IDEN){
                    return true;
                } else {
                    return false;
                }
            }
        }
        // In doubt return false
        return false;
    }

    /***
     * 录音文件地址
     * @param context
     * @param address
     * @return
     */
    public static String getRecordingFilePathForAddress(Context context, Address address) {
        String displayName = FileUtils.getDisplayName(address);
        DateFormat dateFormat = new SimpleDateFormat(
                "dd-MM-yyyy-HH-mm-ss",
                Locale.getDefault()
        );
        String fileName = displayName + "_" + dateFormat.format(new Date()) + ".mkv";
        return FileUtils.getFileStoragePath(context, fileName).getAbsolutePath();
    }


}

MyBroadcastReceiver文件:

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction() == "com.okcis.siplibrary.CallState"){
            int callState = intent.getIntExtra("CallState", -1);
            if (callState != -1){
                Activity currentActivity = BaseActivity.getCurrentActivity();
                if (callState == Call.State.IncomingReceived.toInt()){
                    Intent startIntent = new Intent(context, CallIncomingActivity.class);
                    startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    context.startActivity(startIntent);
                } else if (callState == Call.State.OutgoingInit.toInt()){
                    Intent startIntent = new Intent(context, CallOutgoingActivity.class);
                    startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    context.startActivity(startIntent);
                } else if (callState == Call.State.Connected.toInt()){
                    if (currentActivity instanceof CallOutgoingActivity){
                        currentActivity.finish();
                    } else if (currentActivity instanceof CallIncomingActivity){
                        currentActivity.finish();
                    }
                    Intent startIntent = new Intent(context, CallConnectActivity.class);
                    startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    context.startActivity(startIntent);
                } else if (callState == Call.State.End.toInt()){
                    if (currentActivity instanceof LinphoneMainActivity){

                    } else if (currentActivity instanceof CallOutgoingActivity){
                        currentActivity.finish();
                    } else if (currentActivity instanceof CallIncomingActivity){
                        currentActivity.finish();
                    } else if (currentActivity instanceof CallConnectActivity){
                        currentActivity.finish();
                    }

                } else if (callState == Call.State.Released.toInt()){
                    if (currentActivity instanceof LinphoneMainActivity){

                    } else if (currentActivity instanceof CallOutgoingActivity){
                        currentActivity.finish();
                    } else if (currentActivity instanceof CallIncomingActivity){
                        currentActivity.finish();
                    } else if (currentActivity instanceof CallConnectActivity){
                        currentActivity.finish();
                    }
                } else if (callState == Call.State.Error.toInt()){
                    if (currentActivity instanceof LinphoneMainActivity){

                    } else if (currentActivity instanceof CallOutgoingActivity){
                        currentActivity.finish();
                    } else if (currentActivity instanceof CallIncomingActivity){
                        currentActivity.finish();
                    } else if (currentActivity instanceof CallConnectActivity){
                        currentActivity.finish();
                    }
                }
            }
        }

    }
}

BaseActivity文件:

public class BaseActivity extends AppCompatActivity {
    private static List<Activity> currentActivityList = new LinkedList<>();

    public static synchronized Activity getCurrentActivity() {
        return (currentActivityList.size() > 0)?currentActivityList.get(currentActivityList.size() - 1):null;
    }

    public synchronized void setCurrentActivity(Activity activity) {
        currentActivityList.add(activity);
    }

    public synchronized void removeCurrentActivity(Activity activity){
        for (Activity currentActivity: currentActivityList){
            if (currentActivity == activity){
                currentActivityList.remove(activity);
            }
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值