AndroidネットワークベースVoIP電話の実現linphone
35865 ワード
Linphoneはネットワーク電話またはIP音声電話であり、直接ネットワーク機器を通じて電話をかけることができる.簡単に使って、直接コードをつけます!1.カスタムサービスlinphoneの関連操作のステータスをリスニングし、LinphoneManagerを初期化します.
カスタム管理クラスLinphoneManager、linphoneを初期化
ステータスリスニング用のカスタム抽象クラス
linphoneをカプセル化するツールクラスPhoneVoiceUtilsは、ログイン、ログイン、ダイヤルアップ、サイレント、外付け機能の統合を含む
まずサービスをオンにし、オンが完了した後、登録操作を行い、登録に成功すれば電話のダイヤルを行うことができます.
登録に成功すれば、電話を直接呼び出すことができます.PhoneVoiceUtilsの電話を直接呼び出す方法
通話傍受を追加し、異なる状態で対応する操作を行います.
電話を切る
これで、通話の簡単な流れが完了します.
public class LinphoneService extends Service implements LinphoneCoreListener {
private static final String TAG = "LinphoneService";
private PendingIntent mKeepAlivePendingIntent;
private static LinphoneService instance;
private static PhoneServiceCallback sPhoneServiceCallback;
private LinphoneCore mLinphoneCore;
private LinphoneCall mLinphoneCall;
public static void addCallback(PhoneServiceCallback phoneServiceCallback) {
sPhoneServiceCallback = phoneServiceCallback;
}
@Override
public void onCreate() {
super.onCreate();
EventBus.getDefault().register(this);
LinphoneCoreFactoryImpl.instance();
LinphoneManager.createAndStart(LinphoneService.this);
instance = this;
Intent intent = new Intent(this, KeepAliveHandler.class);
mKeepAlivePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
((AlarmManager)this.getSystemService(Context.ALARM_SERVICE)).setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 600000,
600000,
mKeepAlivePendingIntent);
}
public static boolean isReady() {
return instance != null;
}
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
LinphoneManager.destroy();
((AlarmManager)this.getSystemService(Context.ALARM_SERVICE)).cancel(mKeepAlivePendingIntent);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
/*
*
*/
@Subscribe
public void refuseCall(RefuseCallEvent event) {
mLinphoneCore.declineCall(mLinphoneCall, Reason.None);
}
/*
*
*/
@Override
public void callState(final LinphoneCore linphoneCore, final LinphoneCall linphoneCall, LinphoneCall.State state, String s) {
Log.e(TAG, "callState: " + state.toString());
if(state == LinphoneCall.State.OutgoingEarlyMedia){//
if(sPhoneServiceCallback != null){
sPhoneServiceCallback.callStart();
}
}
if (state == LinphoneCall.State.Connected) {//
if (sPhoneServiceCallback != null) {
sPhoneServiceCallback.callConnected();
}
}
if (state == LinphoneCall.State.CallEnd || state == LinphoneCall.State.CallReleased || state == LinphoneCall.State.Error) {
//CallEnd CallReleased Error
//
if (sPhoneServiceCallback != null) {
sPhoneServiceCallback.callReleased();
}
}
}
/*
*
*/
@Override
public void registrationState(LinphoneCore linphoneCore, LinphoneProxyConfig linphoneProxyConfig, LinphoneCore.RegistrationState registrationState, String s) {
Log.e(TAG, "registrationState: = " + registrationState.toString());
if(registrationState == LinphoneCore.RegistrationState.RegistrationOk){
//
EventBus.getDefault().post(new LoginOk());
}
}
}
カスタム管理クラスLinphoneManager、linphoneを初期化
public class LinphoneManager implements LinphoneCoreListener {
private static final String TAG = "LinphoneManager";
private static LinphoneManager instance;
private Context mServiceContext;
private LinphoneCore mLc;
private Timer mTimer;
private LinphoneCall mCall;
private static boolean sExited;
private Resources mR;
private String mLPConfigXsd = null;
private String mLinphoneFactoryConfigFile = null;
public String mLinphoneConfigFile = null;
private String mLinphoneRootCaFile = null;
private String mRingSoundFile = null;
private String mRingBackSoundFile = null;
private String mPauseSoundFile = null;
private String mChatDatabaseFile = null;
private BroadcastReceiver mKeepAliveReceiver = new KeepAliveReceiver();
public LinphoneManager(Context serviceContext) {
mServiceContext = serviceContext;
LinphoneCoreFactory.instance().setDebugMode(true, "huanyutong");
sExited = false;
String basePath = mServiceContext.getFilesDir().getAbsolutePath();
mLPConfigXsd = basePath + "/lpconfig.xsd";
mLinphoneFactoryConfigFile = basePath + "/linphonerc";
mLinphoneConfigFile = basePath + "/.linphonerc";
mLinphoneRootCaFile = basePath + "/rootca.pem";
mRingSoundFile = basePath + "/oldphone_mono.wav";
mRingBackSoundFile = basePath + "/ringback.wav";
mPauseSoundFile = basePath + "/toy_mono.wav";
mChatDatabaseFile = basePath + "/linphone-history.db";
// mErrorToneFile = basePath + "/error.wav";
mR = serviceContext.getResources();
}
public synchronized static final LinphoneManager createAndStart(Context context) {
if (instance != null) {
throw new RuntimeException("Linphone Manager is already initialized");
}
instance = new LinphoneManager(context);
instance.startLibLinphone(context);
return instance;
}
public static synchronized LinphoneCore getLcIfManagerNotDestroyOrNull() {
if (sExited || instance == null) {
Log.e("Trying to get linphone core while LinphoneManager already destroyed or not created");
return null;
}
return getLc();
}
public static final boolean isInstanceiated() {
return instance != null;
}
public static synchronized final LinphoneCore getLc() {
return getInstance().mLc;
}
public static synchronized final LinphoneManager getInstance() {
if (instance != null) {
return instance;
}
if (sExited) {
throw new RuntimeException("Linphone Manager was already destroyed. "
+ "Better use getLcIfManagerNotDestroyed and check returned value");
}
throw new RuntimeException("Linphone Manager should be created before accessed");
}
private synchronized void startLibLinphone(Context context) {
try {
copyAssetsFromPackage();
mLc = LinphoneCoreFactory.instance().createLinphoneCore(this, mLinphoneConfigFile,
mLinphoneFactoryConfigFile, null, context);
mLc.addListener((LinphoneCoreListener)context);
try {
initLibLinphone();
} catch (LinphoneCoreException e) {
Log.e(e);
}
TimerTask task = new TimerTask() {
@Override
public void run() {
UIThreadDispatcher.dispatch(new Runnable() {
@Override
public void run() {
if (mLc != null) {
mLc.iterate();
}
}
});
}
};
mTimer = new Timer("Linphone Scheduler");
mTimer.schedule(task, 0, 20);
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "startLibLinphone: cannot start linphone");
}
}
private synchronized void initLibLinphone() throws LinphoneCoreException {
mLc.setContext(mServiceContext);
setUserAgent();
mLc.setRemoteRingbackTone(mRingSoundFile);
mLc.setTone(ToneID.CallWaiting, mRingSoundFile);
mLc.setRing(mRingSoundFile);
mLc.setRootCA(mLinphoneRootCaFile);
mLc.setPlayFile(mPauseSoundFile);
mLc.setChatDatabasePath(mChatDatabaseFile);
// mLc.setCallErrorTone(Reason.NotFound, mErrorToneFile);//
int availableCores = Runtime.getRuntime().availableProcessors();
Log.w(TAG, "MediaStreamer : " + availableCores + " cores detected and configured");
mLc.setCpuCount(availableCores);
int migrationResult = getLc().migrateToMultiTransport();
Log.d(TAG, "Migration to multi transport result = " + migrationResult);
mLc.setNetworkReachable(true);
//
boolean isEchoCancellation = true;
mLc.enableEchoCancellation(isEchoCancellation);
//
boolean isAdaptiveRateControl = true;
mLc.enableAdaptiveRateControl(isAdaptiveRateControl);
//audio
LinphoneUtils.getConfig(mServiceContext).setInt("audio", "codec_bitrate_limit", 128);
mLc.setPreferredVideoSizeByName("720p");
mLc.setUploadBandwidth(1536);
mLc.setDownloadBandwidth(1536);
mLc.setVideoPolicy(mLc.getVideoAutoInitiatePolicy(), true);
mLc.setVideoPolicy(true, mLc.getVideoAutoAcceptPolicy());
mLc.enableVideo(true, true);
setCodecMime();
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
mServiceContext.registerReceiver(mKeepAliveReceiver, filter);
}
private void setCodecMime()
{
for (final PayloadType pt : mLc.getVideoCodecs())
{
android.util.Log.i(TAG, "setCodecMime = " + pt.getMime());
if (!pt.getMime().equals("VP8"))
{
try
{
android.util.Log.i(TAG, "disable codec " + pt.getMime());
mLc.enablePayloadType(pt, false);
}
catch (LinphoneCoreException e)
{
Log.e(e);
}
}
}
}
private void copyAssetsFromPackage() throws IOException {
LinphoneUtils.copyIfNotExist(mServiceContext, R.raw.oldphone_mono, mRingSoundFile);
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);
}
private void setUserAgent() {
try {
String versionName = mServiceContext.getPackageManager().getPackageInfo(mServiceContext.getPackageName(),
0).versionName;
if (versionName == null) {
versionName = String.valueOf(mServiceContext.getPackageManager().getPackageInfo(mServiceContext.getPackageName(), 0).versionCode);
}
mLc.setUserAgent("Hunayutong", versionName);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
public static synchronized void destroy() {
if (instance == null) {
return;
}
sExited = true;
instance.doDestroy();
}
private void doDestroy() {
try {
mTimer.cancel();
mLc.destroy();
} catch (RuntimeException e) {
e.printStackTrace();
} finally {
mLc = null;
instance = null;
}
}
}
ステータスリスニング用のカスタム抽象クラス
public abstract class PhoneServiceCallback {
/**
*
* @param registrationState
*/
public void registrationState(LinphoneCore.RegistrationState registrationState) {}
/**
*
* @param registrationState
*/
public void unRegistrationState(LinphoneCore.RegistrationState registrationState) {}
/**
*
* @param linphoneCall
*/
public void incomingCall(LinphoneCall linphoneCall) {}
/**
*
*/
public void callConnected() {}
/**
*
*/
public void callReleased() {}
/**
*
*/
public void callStart() {}
}
linphoneをカプセル化するツールクラスPhoneVoiceUtilsは、ログイン、ログイン、ダイヤルアップ、サイレント、外付け機能の統合を含む
public class PhoneVoiceUtils {
private static final String TAG = "PhoneVoiceUtils";
private static volatile PhoneVoiceUtils sPhoneVoiceUtils;
private LinphoneCore mLinphoneCore = null;
public static PhoneVoiceUtils getInstance() {
if (sPhoneVoiceUtils == null) {
synchronized (PhoneVoiceUtils.class) {
if (sPhoneVoiceUtils == null) {
sPhoneVoiceUtils = new PhoneVoiceUtils();
}
}
}
return sPhoneVoiceUtils;
}
private PhoneVoiceUtils() {
mLinphoneCore = LinphoneManager.getLc();
mLinphoneCore.enableEchoCancellation(true);
mLinphoneCore.enableEchoLimiter(true);
}
/**
*
*
* @param name
* @param password
* @param host IP :
* @throws LinphoneCoreException
*/
public void registerUserAuth(String name, String password, String host) throws LinphoneCoreException {
Log.e(TAG, "registerUserAuth name = " + name);
Log.e(TAG, "registerUserAuth pw = " + password);
Log.e(TAG, "registerUserAuth host = " + host);
String identify = "sip:" + name + "@" + host;
String proxy = "sip:" + host;
LinphoneAddress proxyAddr = LinphoneCoreFactory.instance().createLinphoneAddress(proxy);
LinphoneAddress identifyAddr = LinphoneCoreFactory.instance().createLinphoneAddress(identify);
LinphoneAuthInfo authInfo = LinphoneCoreFactory.instance().createAuthInfo(name, null, password,
null, null, host);
LinphoneProxyConfig prxCfg = mLinphoneCore.createProxyConfig(identifyAddr.asString(),
proxyAddr.asStringUriOnly(), proxyAddr.asStringUriOnly(), true);
prxCfg.enableAvpf(false);
prxCfg.setAvpfRRInterval(0);
prxCfg.enableQualityReporting(false);
prxCfg.setQualityReportingCollector(null);
prxCfg.setQualityReportingInterval(0);
prxCfg.enableRegister(true);
mLinphoneCore.addProxyConfig(prxCfg);
mLinphoneCore.addAuthInfo(authInfo);
mLinphoneCore.setDefaultProxyConfig(prxCfg);
LinphoneService.addCallback(new PhoneServiceCallback() {
@Override
public void registrationState(LinphoneCore.RegistrationState registrationState) {
super.registrationState(registrationState);
}
});
}
//
public void unRegisterUserAuth() {
mLinphoneCore = LinphoneManager.getLc();
mLinphoneCore.clearAuthInfos();
}
/**
*
* @param phone
*/
public LinphoneCall startSingleCallingTo(String phone) {
LinphoneAddress address;
LinphoneCall call = null;
try {
address = mLinphoneCore.interpretUrl(phone);
} catch (LinphoneCoreException e) {
e.printStackTrace();
Log.e("startSingleCallingTo", " LinphoneCoreException0:" + e.toString());
return null;
}
LinphoneCallParams params = mLinphoneCore.createCallParams(null);
params.setVideoEnabled(false);
try {
call = mLinphoneCore.inviteAddressWithParams(address, params);
} catch (LinphoneCoreException e) {
e.printStackTrace();
Log.e("startSingleCallingTo", " LinphoneCoreException1:" + e.toString());
}
return call;
}
/**
*
*/
public void hangUp() {
if(mLinphoneCore == null)
mLinphoneCore = LinphoneManager.getLc();
LinphoneCall currentCall = mLinphoneCore.getCurrentCall();
if (currentCall != null) {
mLinphoneCore.terminateCall(currentCall);
} else if (mLinphoneCore.isInConference()) {
mLinphoneCore.terminateConference();
} else {
mLinphoneCore.terminateAllCalls();
}
}
/**
*
*
* @param isMicMuted
*/
public void toggleMicro(boolean isMicMuted) {
if(mLinphoneCore == null)
mLinphoneCore = LinphoneManager.getLc();
mLinphoneCore.muteMic(isMicMuted);
}
/**
*
*
* @param isSpeakerEnabled
*/
public void toggleSpeaker(boolean isSpeakerEnabled) {
if(mLinphoneCore == null)
mLinphoneCore = LinphoneManager.getLc();
mLinphoneCore.enableSpeaker(isSpeakerEnabled);
}
}
まずサービスをオンにし、オンが完了した後、登録操作を行い、登録に成功すれば電話のダイヤルを行うことができます.
// VoIP
public void registerVoip(String sipAccount) {
if (LinphoneService.isReady()) {// service
registerCall(sipAccount);
} else {
mServiceWaitThread = new ServiceWaitThread();
mServiceWaitThread.start();
}
}
private ServiceWaitThread mServiceWaitThread;
private class ServiceWaitThread extends Thread {
@Override
public void run() {
super.run();
while (!LinphoneService.isReady()) {
try {
startService(new Intent(Intent.ACTION_MAIN).setClass(getApplicationContext(), LinphoneService.class));
sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException("waiting thread sleep() has been interrupted");
}
}
EventBus.getDefault().postSticky(new LinphoneServiceStartEvent());
mServiceWaitThread = null;
}
}
// VoIP
public void registerCall(String sipAccount) {
try {
PhoneVoiceUtils.getInstance().registerUserAuth(sipAccount, AppString.SIPPASSWORD, AppString.SIPSERVER);
} catch (LinphoneCoreException e) {
e.printStackTrace();
}
}
登録に成功すれば、電話を直接呼び出すことができます.PhoneVoiceUtilsの電話を直接呼び出す方法
PhoneVoiceUtils.getInstance().startSingleCallingTo(number);
通話傍受を追加し、異なる状態で対応する操作を行います.
LinphoneService.addCallback(new PhoneServiceCallback() {
@Override
public void callConnected() {
//
}
@Override
public void callStart() {
//
}
@Override
public void callReleased() {
//
}
});
電話を切る
PhoneVoiceUtils.getInstance().hangUp();
これで、通話の簡単な流れが完了します.