| | |
| | | package com.hdl.hdllinphonesdk.core.service; |
| | | |
| | | import android.app.AlarmManager; |
| | | import android.app.Notification; |
| | | import android.app.NotificationChannel; |
| | | import android.app.NotificationManager; |
| | | import android.app.PendingIntent; |
| | | import android.app.Service; |
| | | import android.content.Context; |
| | |
| | | import android.os.Handler; |
| | | import android.os.IBinder; |
| | | import android.os.SystemClock; |
| | | import android.support.v4.app.NotificationCompat; |
| | | |
| | | |
| | | import com.hdl.hdllinphonesdk.HDLLinphoneKit; |
| | | import com.hdl.hdllinphonesdk.R; |
| | | import com.hdl.hdllinphonesdk.core.callback.PhoneCallback; |
| | | import com.hdl.hdllinphonesdk.core.callback.RegistrationCallback; |
| | | import com.hdl.hdllinphonesdk.core.linphone.KeepAliveHandler; |
| | | import com.hdl.hdllinphonesdk.core.linphone.LinphoneUtils; |
| | | import com.hdl.hdllinphonesdk.utils.HDLLog; |
| | | |
| | | import org.linphone.core.Call; |
| | | import org.linphone.core.Core; |
| | |
| | | private PendingIntent mKeepAlivePendingIntent; |
| | | private static PhoneCallback sPhoneCallback;//通话状态回调 |
| | | private static RegistrationCallback sRegistrationCallback;//账号注册登录状态回调 |
| | | private String mRingSoundFile,mPauseSoundFile = null; |
| | | private String mRingSoundFile, mPauseSoundFile = null; |
| | | |
| | | private Handler mHandler; |
| | | private Timer mTimer; |
| | |
| | | } |
| | | |
| | | public static Core getCore() { |
| | | if(sInstance == null){ |
| | | return null; |
| | | } |
| | | return sInstance.mCore; |
| | | } |
| | | |
| | |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 添加通话状态回调 |
| | | * @param phoneCallback |
| | | */ |
| | | public static void addPhoneCallback(PhoneCallback phoneCallback) { |
| | | sPhoneCallback = phoneCallback; |
| | | } |
| | | |
| | | public static void removePhoneCallback() { |
| | | if (sPhoneCallback != null) { |
| | | sPhoneCallback = null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 添加注册状态回调 |
| | | * @param registrationCallback |
| | | */ |
| | | public static void addRegistrationCallback(RegistrationCallback registrationCallback) { |
| | | sRegistrationCallback = registrationCallback; |
| | | } |
| | | |
| | | public static void removeRegistrationCallback() { |
| | | if (sRegistrationCallback != null) { |
| | | sRegistrationCallback = null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 移除所以Callback |
| | | */ |
| | | public void removeAllCallback() { |
| | | removePhoneCallback(); |
| | | removeRegistrationCallback(); |
| | |
| | | @Override |
| | | public void onCreate() { |
| | | super.onCreate(); |
| | | |
| | | hdlStartForeground(); |
| | | initLinphone(); |
| | | |
| | | Intent intent = new Intent(this, KeepAliveHandler.class); |
| | | mKeepAlivePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); |
| | | ((AlarmManager) this.getSystemService(Context.ALARM_SERVICE)).setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, |
| | | SystemClock.elapsedRealtime() + 60000, 60000, mKeepAlivePendingIntent); |
| | | |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public int onStartCommand(Intent intent, int flags, int startId) { |
| | |
| | | @Override |
| | | public void onDestroy() { |
| | | removeAllCallback(); |
| | | |
| | | logout(); |
| | | mCore.removeListener(mCoreListener); |
| | | mTimer.cancel(); |
| | | mCore.stop(); |
| | |
| | | |
| | | ((AlarmManager) this.getSystemService(Context.ALARM_SERVICE)).cancel(mKeepAlivePendingIntent); |
| | | |
| | | hdlStopForeground(); |
| | | super.onDestroy(); |
| | | } |
| | | |
| | |
| | | * 初始化Linphone |
| | | */ |
| | | private void initLinphone() { |
| | | |
| | | String basePath = getFilesDir().getAbsolutePath(); |
| | | Factory.instance().setLogCollectionPath(basePath); |
| | | Factory.instance().enableLogCollection(LogCollectionState.Enabled); |
| | | Factory.instance().setDebugMode(false, getString(R.string.app_name)); |
| | | // Dump some useful information about the device we're running on |
| | | Log.i(START_LINPHONE_LOGS); |
| | | dumpDeviceInformation(); |
| | | dumpInstalledLinphoneInformation(); |
| | | // HDLLog.I(START_LINPHONE_LOGS); |
| | | // dumpDeviceInformation(); |
| | | // dumpInstalledLinphoneInformation(); |
| | | mHandler = new Handler(); |
| | | // This will be our main Core listener, it will change activities depending on events |
| | | initCoreListener(); |
| | | |
| | | copyAssetsFromPackage(basePath); |
| | | |
| | | // Create the Core and add our listener |
| | | mCore = Factory.instance() |
| | | .createCore(basePath + "/.linphonerc", basePath + "/linphonerc", this); |
| | |
| | | configureCore(); |
| | | } |
| | | |
| | | /** |
| | | * 初始化CoreListener监听 |
| | | */ |
| | | private void initCoreListener() { |
| | | mCoreListener = new CoreListenerStub() { |
| | | @Override |
| | | public void onCallStateChanged(Core core, Call linphoneCall, Call.State state, String message) { |
| | | Log.e(START_LINPHONE_LOGS, "callState: " + state.toString()); |
| | | HDLLog.e(START_LINPHONE_LOGS, "callState: " + state.toString()); |
| | | currentCallState = state; |
| | | if (sPhoneCallback != null) { |
| | | if (state == Call.State.IncomingReceived) { |
| | |
| | | |
| | | @Override |
| | | public void onRegistrationStateChanged(Core core, ProxyConfig proxyConfig, RegistrationState registrationState, String message) { |
| | | |
| | | String state = registrationState.toString(); |
| | | Log.i(START_LINPHONE_LOGS, "registrationState: " + state); |
| | | if (sRegistrationCallback != null) { |
| | | HDLLog.i(START_LINPHONE_LOGS, "registrationState: " + state); |
| | | |
| | | if (state.equals(RegistrationState.None.toString())) { |
| | | if (state.equals(RegistrationState.None.toString())) { |
| | | if (sRegistrationCallback != null){ |
| | | sRegistrationCallback.registrationNone(); |
| | | } else if (state.equals(RegistrationState.Progress.toString())) { |
| | | } |
| | | } else if (state.equals(RegistrationState.Progress.toString())) { |
| | | if (sRegistrationCallback != null){ |
| | | sRegistrationCallback.registrationProgress(); |
| | | } else if (state.equals(RegistrationState.Ok.toString())) { |
| | | } |
| | | } else if (state.equals(RegistrationState.Ok.toString())) { |
| | | if (sRegistrationCallback != null) { |
| | | sRegistrationCallback.registrationOk(); |
| | | } else if (state.equals(RegistrationState.Cleared.toString())) { |
| | | } |
| | | } else if (state.equals(RegistrationState.Cleared.toString())) { |
| | | removeProxyConfig(core, proxyConfig); |
| | | if (sRegistrationCallback != null) { |
| | | sRegistrationCallback.registrationCleared(); |
| | | } else if (state.equals(RegistrationState.Failed.toString())) { |
| | | } |
| | | } else if (state.equals(RegistrationState.Failed.toString())) { |
| | | if (sRegistrationCallback != null) { |
| | | sRegistrationCallback.registrationFailed(); |
| | | } |
| | | } |
| | |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * 收到注销成功后移除当前代理 |
| | | * @param core |
| | | * @param proxyConfig |
| | | */ |
| | | void removeProxyConfig(Core core, ProxyConfig proxyConfig) { |
| | | try { |
| | | HDLLog.i(START_LINPHONE_LOGS, "registrationState: 注销成功移除账号:" + proxyConfig.getIdentityAddress().getUsername()); |
| | | //收到注销成功后移除当前代理 |
| | | if (core != null) { |
| | | core.removeProxyConfig(proxyConfig); |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * mCore启动默认参数配置 |
| | | */ |
| | | private void configureCore() { |
| | | // We will create a directory for user signed certificates if needed |
| | | String basePath = getFilesDir().getAbsolutePath(); |
| | |
| | | File f = new File(userCerts); |
| | | if (!f.exists()) { |
| | | if (!f.mkdir()) { |
| | | Log.e(userCerts + " can't be created."); |
| | | HDLLog.E(userCerts + " can't be created."); |
| | | } |
| | | } |
| | | //设置UserAgent |
| | | setUserAgent(); |
| | | |
| | | mCore.setUserCertificatesPath(userCerts); |
| | | // mCore.setNativeRingingEnabled(true); |
| | | // |
| | | // mCore.setRemoteRingbackTone(mRingSoundFile); |
| | | // mCore.setTone(ToneID.CallWaiting, mRingSoundFile); |
| | | mCore.setRing(mRingSoundFile); |
| | | // mCore.setPlayFile(mPauseSoundFile); |
| | | |
| | | // mCore.enableVideoCapture(false);//禁用手机摄像头视频采集 |
| | | |
| | | mCore.setNetworkReachable(true); |
| | |
| | | mCore.enableEchoLimiter(true); |
| | | |
| | | //自适应码率控制 |
| | | // boolean isAdaptiveRateControl = (boolean) SPUtils.get(mServiceContext, "adaptive_rate_control", true); |
| | | mCore.enableAdaptiveRateControl(true); |
| | | //audio 码率设置 |
| | | mCore.getConfig().setInt("audio", "codec_bitrate_limit", 36); |
| | |
| | | setCodecMime(); |
| | | } |
| | | |
| | | /** |
| | | * 设置编码格式 |
| | | */ |
| | | private void setCodecMime() { |
| | | PayloadType[] ptList = mCore.getAudioPayloadTypes(); |
| | | for (PayloadType pt : ptList) { |
| | |
| | | mCore.setVideoPayloadTypes(ptVideoList); |
| | | } |
| | | |
| | | /** |
| | | * 设置是否启用铃声,目前发现设置无效待分析原因 |
| | | * @param use |
| | | */ |
| | | public void enableDeviceRingtone(boolean use) { |
| | | if (use) { |
| | | mCore.setRing(null); |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 设置UserAgent |
| | | */ |
| | | private void setUserAgent() { |
| | | try { |
| | | String versionName = this.getPackageManager().getPackageInfo(this.getPackageName(), |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 打印相关信息 |
| | | */ |
| | | private void dumpDeviceInformation() { |
| | | StringBuilder sb = new StringBuilder(); |
| | | sb.append("DEVICE=").append(Build.DEVICE).append("\n"); |
| | |
| | | sb.append(abi).append(", "); |
| | | } |
| | | sb.append("\n"); |
| | | Log.i(sb.toString()); |
| | | HDLLog.I(sb.toString()); |
| | | } |
| | | |
| | | /** |
| | | * 打印版本号信息 |
| | | */ |
| | | private void dumpInstalledLinphoneInformation() { |
| | | PackageInfo info = null; |
| | | try { |
| | |
| | | } |
| | | |
| | | if (info != null) { |
| | | Log.i( |
| | | HDLLog.i( |
| | | "[Service] Linphone version is ", |
| | | info.versionName + " (" + info.versionCode + ")"); |
| | | } else { |
| | | Log.i("[Service] Linphone version is unknown"); |
| | | HDLLog.I("[Service] Linphone version is unknown"); |
| | | } |
| | | } |
| | | |
| | |
| | | // The factory config is used to override any other setting, let's copy it each time |
| | | copyFromPackage(R.raw.linphonerc_factory, "linphonerc"); |
| | | mRingSoundFile = basePath + "/oldphone_mono.wav"; |
| | | copyIfNotExist(R.raw.oldphone_mono, basePath + "/oldphone_mono.wav"); |
| | | copyIfNotExist(R.raw.oldphone_mono, basePath + "/oldphone_mono.wav"); |
| | | copyIfNotExist(R.raw.ringback, basePath + "/ringback.wav"); |
| | | mPauseSoundFile = basePath + "/toy_mono.wav"; |
| | | copyIfNotExist( R.raw.toy_mono, basePath + "/toy_mono.wav"); |
| | | |
| | | // LinphoneUtils.copyIfNotExist(mServiceContext, R.raw.ringback, mRingBackSoundFile); |
| | | // LinphoneUtils.copyIfNotExist(mServiceContext, R.raw.toy_mono, mPauseSoundFile); |
| | | // LinphoneUtils.copyIfNotExist(mServiceContext, R.raw.linphonerc_default, mLinphoneConfigFile); |
| | | // LinphoneUtils.copyIfNotExist(mServiceContext, R.raw.linphonerc_factory, new File(mLinphoneFactoryConfigFile).getName()); |
| | | // LinphoneUtils.copyIfNotExist(mServiceContext, R.raw.lpconfig, mLPConfigXsd); |
| | | // LinphoneUtils.copyIfNotExist(mServiceContext, R.raw.rootca, mLinphoneRootCaFile); |
| | | |
| | | copyIfNotExist(R.raw.toy_mono, basePath + "/toy_mono.wav"); |
| | | |
| | | } catch (IOException ioe) { |
| | | Log.e(ioe); |
| | |
| | | |
| | | } |
| | | |
| | | /** |
| | | * copyIfNotExist |
| | | * @param ressourceId |
| | | * @param target |
| | | * @throws IOException |
| | | */ |
| | | private void copyIfNotExist(int ressourceId, String target) throws IOException { |
| | | File lFileToCopy = new File(target); |
| | | if (!lFileToCopy.exists()) { |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * copyFromPackage |
| | | * @param ressourceId |
| | | * @param target |
| | | * @throws IOException |
| | | */ |
| | | private void copyFromPackage(int ressourceId, String target) throws IOException { |
| | | FileOutputStream lOutputStream = openFileOutput(target, 0); |
| | | InputStream lInputStream = getResources().openRawResource(ressourceId); |
| | |
| | | public Call.State getCurrentCallState() { |
| | | return currentCallState; |
| | | } |
| | | |
| | | /** |
| | | * 注销所有账号 |
| | | */ |
| | | void logout() { |
| | | try { |
| | | if (mCore != null) { |
| | | ProxyConfig[] configs = mCore.getProxyConfigList(); |
| | | for (ProxyConfig config : configs) { |
| | | if (config != null) { |
| | | config.edit(); |
| | | config.enableRegister(false); |
| | | config.done(); |
| | | } |
| | | } |
| | | HDLLog.E("注销所有账号"); |
| | | // core.clearAllAuthInfo(); |
| | | // core.clearProxyConfig(); |
| | | } |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | //通知ID |
| | | public static final int NOTIFICATION_ID = 2; |
| | | /** |
| | | * 解决android8.0以上无法启动服务的问题 |
| | | */ |
| | | void hdlStartForeground() { |
| | | |
| | | } |
| | | /** |
| | | * stopForeground |
| | | */ |
| | | void hdlStopForeground() { |
| | | // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
| | | // stopForeground(true); |
| | | // } |
| | | } |
| | | } |