├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── modules.xml
└── runConfigurations.xml
├── README.md
├── README_CN.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── xuchongyang
│ │ └── easylinphone
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── xuchongyang
│ │ │ └── easylinphone
│ │ │ ├── LoginActivity.java
│ │ │ ├── MainActivity.java
│ │ │ └── VideoActivity.java
│ └── res
│ │ ├── layout
│ │ ├── activity_login.xml
│ │ ├── activity_main.xml
│ │ └── activity_video.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── xuchongyang
│ └── easylinphone
│ └── ExampleUnitTest.java
├── build.gradle
├── easylinphone
├── .gitignore
├── build.gradle
├── libs
│ └── liblinphone-android-sdk.aar
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── xuchongyang
│ │ └── easyphone
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── xuchongyang
│ │ │ └── easyphone
│ │ │ ├── EasyLinphone.java
│ │ │ ├── callback
│ │ │ ├── PhoneCallback.java
│ │ │ └── RegistrationCallback.java
│ │ │ ├── linphone
│ │ │ ├── KeepAliveHandler.java
│ │ │ ├── LinphoneManager.java
│ │ │ ├── LinphoneUtils.java
│ │ │ └── PhoneBean.java
│ │ │ └── service
│ │ │ └── LinphoneService.java
│ └── res
│ │ ├── raw
│ │ ├── incoming_chat.wav
│ │ ├── linphonerc_default
│ │ ├── linphonerc_factory
│ │ ├── lpconfig.xsd
│ │ ├── oldphone_mono.wav
│ │ ├── ringback.wav
│ │ ├── rootca.pem
│ │ └── toy_mono.wav
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── java
│ └── com
│ └── xuchongyang
│ └── easyphone
│ └── ExampleUnitTest.java
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # Intellij
36 | *.iml
37 | .idea/workspace.xml
38 | .idea/tasks.xml
39 | .idea/gradle.xml
40 | .idea/libraries
41 | .idea/misc.xml
42 | .idea/vcs.xml
43 | .idea/codeStyleSettings.xml
44 | .idea/dictionaries/
45 |
46 | # Keystore files
47 | *.jks
48 |
49 | # External native build folder generated in Android Studio 2.2 and later
50 | .externalNativeBuild
51 |
52 | # Google Services (e.g. APIs or Firebase)
53 | google-services.json
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EasyLinphone
2 | EasyLinphone make it easy to import Linphone Android SDK to your project.
3 |
4 | [中文文档](https://github.com/forever4313/EasyLinphone/blob/master/README_CN.md)
5 |
6 | ## Import
7 | Download the EasyLinphone aar at [Latest release](https://github.com/xcy396/EasyLinphone/releases), and the Linphone Android SDK at [Linphone offical website](http://www.linphone.org/technical-corner/liblinphone/downloads).
8 |
9 | Then
10 | copy EasyLinPhone aar and Linphone aar to your project's `libs` folder, and import them in your app buid.gradle as below:
11 |
12 | ```groovy
13 | android {
14 | ...
15 | repositories {
16 | flatDir {
17 | dirs 'libs' //this way we can find the .aar file in libs folder
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | ...
24 | compile(name:'liblinphone-android-sdk', ext:'aar')
25 | compile(name:'easylinphone-release', ext:'aar')
26 | }
27 | ```
28 |
29 | ## Usage
30 | ### 1. Init LinphoneService
31 |
32 | ```java
33 | // Start service
34 | EasyLinphone.startService(mContext);
35 | // Add callback
36 | EasyLinphone.addCallback(new RegistrationCallback() {
37 | @Override
38 | public void registrationOk() {
39 | super.registrationOk();
40 | // do something
41 | }
42 |
43 | @Override
44 | public void registrationFailed() {
45 | super.registrationFailed();
46 | // do something
47 | }
48 | }, new PhoneCallback() {
49 | @Override
50 | public void incomingCall(LinphoneCall linphoneCall) {
51 | super.incomingCall(linphoneCall);
52 | // do something
53 | }
54 |
55 | @Override
56 | public void callConnected() {
57 | super.callConnected();
58 | // do something
59 | }
60 |
61 | @Override
62 | public void callEnd() {
63 | super.callEnd();
64 | // do something
65 | }
66 | });
67 | ```
68 |
69 | You can add registrationCallback and phoneCallback in different place in your project, this depending on your logic.
70 |
71 | ### 2. Login
72 |
73 | ```java
74 | // Configure sip account
75 | EasyLinphone.setAccount("1003", "123456", "192.168.9.60");
76 | // Register to sip server
77 | EasyLinphone.login();
78 | ```
79 |
80 | ### 3. Manage the voice call
81 |
82 | ```java
83 | // Make a call
84 | EasyLinphone.callTo("1001");
85 | // Hang up the current call
86 | EasyLinphone.hangUp();
87 | // Answer the current call
88 | EasyLinphone.acceptCall();
89 | // Toggle the mute function
90 | EasyLinphone.toggleMicro(!EasyLinphone.getLC().isMicMuted());
91 | // Toggle the handsfree function
92 | EasyLinphone.toggleSpeaker(!EasyLinphone.getLC().isSpeakerEnabled());
93 | ```
94 |
95 | ### 4. Manage the video call
96 |
97 | Your video call activity or fragment may like below:
98 |
99 | ```java
100 | public class VideoActivity extends AppCompatActivity {
101 | @BindView(R.id.video_rendering) SurfaceView mRenderingView;
102 | @BindView(R.id.video_preview) SurfaceView mPreviewView;
103 |
104 | @Override
105 | protected void onCreate(Bundle savedInstanceState) {
106 | super.onCreate(savedInstanceState);
107 | setContentView(R.layout.activity_video);
108 | ButterKnife.bind(this);
109 | EasyLinphone.setAndroidVideoWindow(new SurfaceView[]{mRenderingView}, new SurfaceView[]{mPreviewView});
110 | }
111 |
112 | @Override
113 | protected void onResume() {
114 | super.onResume();
115 | EasyLinphone.onResume();
116 | }
117 |
118 | @Override
119 | protected void onPause() {
120 | super.onPause();
121 | EasyLinphone.onPause();
122 | }
123 |
124 | @Override
125 | protected void onDestroy() {
126 | super.onDestroy();
127 | EasyLinphone.onDestroy();
128 | }
129 |
130 | @OnClick(R.id.video_hang)
131 | public void hang() {
132 | EasyLinphone.hangUp();
133 | finish();
134 | }
135 | }
136 | ```
137 |
138 | That's all, Enjoy it!
139 |
--------------------------------------------------------------------------------
/README_CN.md:
--------------------------------------------------------------------------------
1 | # EasyLinphone
2 | EasyLinphone 可以帮助你在项目中很轻松的使用 Linphone Android SDK。
3 |
4 | [English document](https://github.com/forever4313/EasyLinphone/blob/master/README.md)
5 |
6 | ## 导入
7 | * 在 [Release](https://github.com/forever4313/EasyLinphone/releases) 页面下载最新的 EasyLinphone aar 包
8 | * 在 [Linphone 官网](http://www.linphone.org/technical-corner/liblinphone/downloads) 下载最新的 LinPhone Android aar 包
9 | * 将刚才下载的两个 aar 包放到项目 app 的 libs 文件夹下,在 app 的 build.gradle 添加以下引用:
10 |
11 | ```groovy
12 | android {
13 | ...
14 | repositories {
15 | flatDir {
16 | dirs 'libs' //this way we can find the .aar file in libs folder
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | ...
23 | compile(name:'liblinphone-android-sdk', ext:'aar')
24 | compile(name:'easylinphone-release', ext:'aar')
25 | }
26 | ```
27 |
28 | ## 使用
29 | ### 1. 初始化 LinphoneService
30 |
31 | ```java
32 | // 开启服务
33 | EasyLinphone.startService(mContext);
34 | // 添加登录状态回调和通话回调
35 | EasyLinphone.addCallback(new RegistrationCallback() {
36 | @Override
37 | public void registrationOk() {
38 | super.registrationOk();
39 | // do something
40 | }
41 |
42 | @Override
43 | public void registrationFailed() {
44 | super.registrationFailed();
45 | // do something
46 | }
47 | }, new PhoneCallback() {
48 | @Override
49 | public void incomingCall(LinphoneCall linphoneCall) {
50 | super.incomingCall(linphoneCall);
51 | // do something
52 | }
53 |
54 | @Override
55 | public void callConnected() {
56 | super.callConnected();
57 | // do something
58 | }
59 |
60 | @Override
61 | public void callEnd() {
62 | super.callEnd();
63 | // do something
64 | }
65 | });
66 | ```
67 |
68 | 可以根据实际情况,在不同的地方分别添加登录状态回调和通话状态回调。
69 |
70 | ### 2. 登录
71 |
72 | ```java
73 | // 配置 Sip 账户信息
74 | EasyLinphone.setAccount("1003", "123456", "192.168.9.60");
75 | // 注册到 Sip 服务器
76 | EasyLinphone.login();
77 | ```
78 |
79 | ### 3. 管理音频通话
80 |
81 | ```java
82 | // 呼叫指定号码
83 | EasyLinphone.callTo("1001");
84 | // 挂断当前通话
85 | EasyLinphone.hangUp();
86 | // 接听当前来电
87 | EasyLinphone.acceptCall();
88 | // 切换静音
89 | EasyLinphone.toggleMicro(!EasyLinphone.getLC().isMicMuted());
90 | // 切换免提
91 | EasyLinphone.toggleSpeaker(!EasyLinphone.getLC().isSpeakerEnabled());
92 | ```
93 |
94 | ### 4. 管理视频通话
95 |
96 | 视频通话示例如下:
97 |
98 | ```java
99 | public class VideoActivity extends AppCompatActivity {
100 | @BindView(R.id.video_rendering) SurfaceView mRenderingView;
101 | @BindView(R.id.video_preview) SurfaceView mPreviewView;
102 |
103 | @Override
104 | protected void onCreate(Bundle savedInstanceState) {
105 | super.onCreate(savedInstanceState);
106 | setContentView(R.layout.activity_video);
107 | ButterKnife.bind(this);
108 | EasyLinphone.setAndroidVideoWindow(new SurfaceView[]{mRenderingView}, new SurfaceView[]{mPreviewView});
109 | }
110 |
111 | @Override
112 | protected void onResume() {
113 | super.onResume();
114 | EasyLinphone.onResume();
115 | }
116 |
117 | @Override
118 | protected void onPause() {
119 | super.onPause();
120 | EasyLinphone.onPause();
121 | }
122 |
123 | @Override
124 | protected void onDestroy() {
125 | super.onDestroy();
126 | EasyLinphone.onDestroy();
127 | }
128 |
129 | @OnClick(R.id.video_hang)
130 | public void hang() {
131 | EasyLinphone.hangUp();
132 | finish();
133 | }
134 | }
135 | ```
136 |
137 | 可以看到,通过本库可以很简单的使用 Linphone Android SDK。代码质量不高,还有很多疵漏之处,还请大家多多指教。
138 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.3"
6 | defaultConfig {
7 | applicationId "com.xuchongyang.easylinphone"
8 | minSdkVersion 19
9 | targetSdkVersion 22
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | lintOptions {
21 | checkReleaseBuilds false
22 | // Or, if you prefer, you can continue to check for errors in release builds,
23 | // but continue the build even when errors are found:
24 | abortOnError false
25 | }
26 | }
27 |
28 |
29 | dependencies {
30 | compile fileTree(include: ['*.jar'], dir: 'libs')
31 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
32 | exclude group: 'com.android.support', module: 'support-annotations'
33 | })
34 | compile project(':easylinphone')
35 | compile 'com.android.support:appcompat-v7:25.3.1'
36 | compile 'com.android.support.constraint:constraint-layout:1.0.2'
37 | compile 'com.jakewharton:butterknife:8.8.1'
38 | testCompile 'junit:junit:4.12'
39 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
40 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/markxu/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/xuchongyang/easylinphone/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easylinphone;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.xuchongyang.easylinphone", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xuchongyang/easylinphone/LoginActivity.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easylinphone;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.util.Log;
7 | import android.widget.EditText;
8 | import android.widget.Toast;
9 |
10 | import com.xuchongyang.easyphone.EasyLinphone;
11 | import com.xuchongyang.easyphone.callback.RegistrationCallback;
12 | import com.xuchongyang.easyphone.service.LinphoneService;
13 |
14 | import butterknife.BindView;
15 | import butterknife.ButterKnife;
16 | import butterknife.OnClick;
17 |
18 | public class LoginActivity extends AppCompatActivity {
19 | private static final String TAG = "LoginActivity";
20 | @BindView(R.id.sip_account) EditText mAccount;
21 | @BindView(R.id.sip_password) EditText mPassword;
22 | @BindView(R.id.sip_server) EditText mServer;
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_login);
28 | ButterKnife.bind(this);
29 |
30 | if (!LinphoneService.isReady()) {
31 | EasyLinphone.startService(this);
32 | EasyLinphone.addCallback(new RegistrationCallback() {
33 | @Override
34 | public void registrationOk() {
35 | super.registrationOk();
36 | Log.e(TAG, "registrationOk: ");
37 | Toast.makeText(LoginActivity.this, "登录成功!", Toast.LENGTH_SHORT).show();
38 | goToMainActivity();
39 | }
40 |
41 | @Override
42 | public void registrationFailed() {
43 | super.registrationFailed();
44 | Log.e(TAG, "registrationFailed: ");
45 | Toast.makeText(LoginActivity.this, "登录失败!", Toast.LENGTH_SHORT).show();
46 | }
47 | }, null);
48 | } else {
49 | goToMainActivity();
50 | }
51 | }
52 |
53 | @OnClick(R.id.press_login)
54 | public void login() {
55 | String account = mAccount.getText().toString();
56 | String password = mPassword.getText().toString();
57 | String serverIP = mServer.getText().toString();
58 | EasyLinphone.setAccount(account, password, serverIP);
59 | EasyLinphone.login();
60 | }
61 |
62 | private void goToMainActivity() {
63 | startActivity(new Intent(LoginActivity.this, MainActivity.class));
64 | finish();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xuchongyang/easylinphone/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easylinphone;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.util.Log;
9 | import android.view.View;
10 | import android.widget.Button;
11 | import android.widget.EditText;
12 |
13 | import com.xuchongyang.easyphone.EasyLinphone;
14 | import com.xuchongyang.easyphone.callback.PhoneCallback;
15 |
16 | import org.linphone.core.LinphoneCall;
17 |
18 | import butterknife.BindView;
19 | import butterknife.ButterKnife;
20 | import butterknife.OnClick;
21 |
22 | public class MainActivity extends AppCompatActivity {
23 | private static final String TAG = "MainActivity";
24 | @BindView(R.id.dial_num) EditText mDialNum;
25 | @BindView(R.id.hang_up) Button mHangUp;
26 | @BindView(R.id.accept_call) Button mCallIn;
27 | @BindView(R.id.toggle_speaker) Button mToggleSpeaker;
28 | @BindView(R.id.toggle_mute) Button mToggleMute;
29 |
30 | @Override
31 | protected void onCreate(Bundle savedInstanceState) {
32 | super.onCreate(savedInstanceState);
33 | setContentView(R.layout.activity_main);
34 | ButterKnife.bind(this);
35 |
36 | EasyLinphone.addCallback(null, new PhoneCallback() {
37 | @Override
38 | public void incomingCall(LinphoneCall linphoneCall) {
39 | super.incomingCall(linphoneCall);
40 | // 开启铃声免提
41 | EasyLinphone.toggleSpeaker(true);
42 | mCallIn.setVisibility(View.VISIBLE);
43 | mHangUp.setVisibility(View.VISIBLE);
44 | }
45 |
46 | @Override
47 | public void outgoingInit() {
48 | super.outgoingInit();
49 | mHangUp.setVisibility(View.VISIBLE);
50 | }
51 |
52 | @Override
53 | public void callConnected() {
54 | super.callConnected();
55 | // 视频通话默认免提,语音通话默认非免提
56 | EasyLinphone.toggleSpeaker(EasyLinphone.getVideoEnabled());
57 | // 所有通话默认非静音
58 | EasyLinphone.toggleMicro(false);
59 | mCallIn.setVisibility(View.GONE);
60 | mToggleSpeaker.setVisibility(View.VISIBLE);
61 | mToggleMute.setVisibility(View.VISIBLE);
62 | }
63 |
64 | @Override
65 | public void callEnd() {
66 | super.callEnd();
67 | sendBroadcast(new Intent(VideoActivity.RECEIVE_FINISH_VIDEO_ACTIVITY));
68 | mCallIn.setVisibility(View.GONE);
69 | mHangUp.setVisibility(View.GONE);
70 | mToggleMute.setVisibility(View.GONE);
71 | mToggleSpeaker.setVisibility(View.GONE);
72 | }
73 | });
74 | }
75 |
76 | @OnClick(R.id.audio_call)
77 | public void audioCall() {
78 | String dialNum = mDialNum.getText().toString();
79 | EasyLinphone.callTo(dialNum, false);
80 | }
81 |
82 | @OnClick(R.id.video_call)
83 | public void videoCall() {
84 | String dialNum = mDialNum.getText().toString();
85 | EasyLinphone.callTo(dialNum, true);
86 | startActivity(new Intent(MainActivity.this, VideoActivity.class));
87 | }
88 |
89 | @OnClick(R.id.hang_up)
90 | public void hangUp() {
91 | EasyLinphone.hangUp();
92 | }
93 |
94 | @OnClick(R.id.accept_call)
95 | public void acceptCall() {
96 | EasyLinphone.acceptCall();
97 | if (EasyLinphone.getVideoEnabled()) {
98 | startActivity(new Intent(MainActivity.this, VideoActivity.class));
99 | }
100 | }
101 |
102 | @OnClick(R.id.toggle_mute)
103 | public void toggleMute() {
104 | EasyLinphone.toggleMicro(!EasyLinphone.getLC().isMicMuted());
105 | }
106 |
107 | @OnClick(R.id.toggle_speaker)
108 | public void toggleSpeaker() {
109 | EasyLinphone.toggleSpeaker(!EasyLinphone.getLC().isSpeakerEnabled());
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xuchongyang/easylinphone/VideoActivity.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easylinphone;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.IntentFilter;
7 | import android.os.Bundle;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.view.SurfaceView;
10 |
11 | import com.xuchongyang.easyphone.EasyLinphone;
12 |
13 | import butterknife.BindView;
14 | import butterknife.ButterKnife;
15 | import butterknife.OnClick;
16 |
17 | public class VideoActivity extends AppCompatActivity {
18 | @BindView(R.id.video_rendering) SurfaceView mRenderingView;
19 | @BindView(R.id.video_preview) SurfaceView mPreviewView;
20 |
21 | private FinishVideoActivityReceiver mReceiver;
22 | public static final String RECEIVE_FINISH_VIDEO_ACTIVITY = "receive_finish_video_activity";
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_video);
28 | ButterKnife.bind(this);
29 | IntentFilter intentFilter = new IntentFilter(RECEIVE_FINISH_VIDEO_ACTIVITY);
30 | mReceiver = new FinishVideoActivityReceiver();
31 | registerReceiver(mReceiver, intentFilter);
32 | EasyLinphone.setAndroidVideoWindow(new SurfaceView[]{mRenderingView}, new SurfaceView[]{mPreviewView});
33 | }
34 |
35 | @Override
36 | protected void onResume() {
37 | super.onResume();
38 | EasyLinphone.onResume();
39 | }
40 |
41 | @Override
42 | protected void onPause() {
43 | super.onPause();
44 | EasyLinphone.onPause();
45 | }
46 |
47 | @Override
48 | protected void onDestroy() {
49 | super.onDestroy();
50 | if (mReceiver != null) {
51 | unregisterReceiver(mReceiver);
52 | }
53 | EasyLinphone.onDestroy();
54 | }
55 |
56 | @OnClick(R.id.video_hang)
57 | public void hang() {
58 | EasyLinphone.hangUp();
59 | finish();
60 | }
61 |
62 | @OnClick(R.id.video_mute)
63 | public void mute() {
64 | EasyLinphone.toggleMicro(!EasyLinphone.getLC().isMicMuted());
65 | }
66 |
67 | @OnClick(R.id.video_speaker)
68 | public void speaker() {
69 | EasyLinphone.toggleSpeaker(!EasyLinphone.getLC().isSpeakerEnabled());
70 | }
71 |
72 | public class FinishVideoActivityReceiver extends BroadcastReceiver {
73 | @Override
74 | public void onReceive(Context context, Intent intent) {
75 | VideoActivity.this.finish();
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_login.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
25 |
26 |
34 |
35 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
24 |
25 |
30 |
36 |
37 |
44 |
45 |
53 |
54 |
55 |
62 |
63 |
67 |
75 |
76 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_video.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
16 |
17 |
24 |
25 |
33 |
34 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | EasyLinphone
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/xuchongyang/easylinphone/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easylinphone;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.3.3'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 |
19 | flatDir {
20 | // 由于Library module中引用了 gif 库的 aar,在多 module 的情况下,
21 | // 其他的module编译会报错,所以需要在所有工程的repositories
22 | // 下把Library module中的libs目录添加到依赖关系中
23 | dirs project(':easylinphone').file('libs')
24 | }
25 | }
26 | }
27 |
28 | task clean(type: Delete) {
29 | delete rootProject.buildDir
30 | }
31 |
--------------------------------------------------------------------------------
/easylinphone/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/easylinphone/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 25
5 | buildToolsVersion "25.0.3"
6 |
7 | defaultConfig {
8 | minSdkVersion 17
9 | targetSdkVersion 25
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | repositories {
23 | flatDir {
24 | dirs 'libs' //this way we can find the .aar file in libs folder
25 | }
26 | }
27 | android {
28 | lintOptions {
29 | abortOnError false
30 | }
31 | }
32 | }
33 |
34 | dependencies {
35 | compile fileTree(dir: 'libs', include: ['*.jar'])
36 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
37 | exclude group: 'com.android.support', module: 'support-annotations'
38 | })
39 | compile 'com.android.support:appcompat-v7:25.3.1'
40 | testCompile 'junit:junit:4.12'
41 | compile(name:'liblinphone-android-sdk', ext:'aar')
42 | }
--------------------------------------------------------------------------------
/easylinphone/libs/liblinphone-android-sdk.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/easylinphone/libs/liblinphone-android-sdk.aar
--------------------------------------------------------------------------------
/easylinphone/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/markxu/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/easylinphone/src/androidTest/java/com/xuchongyang/easyphone/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easyphone;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.xuchongyang.easyphone.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/easylinphone/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/easylinphone/src/main/java/com/xuchongyang/easyphone/EasyLinphone.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easyphone;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.opengl.GLSurfaceView;
6 | import android.view.SurfaceView;
7 |
8 | import com.xuchongyang.easyphone.callback.PhoneCallback;
9 | import com.xuchongyang.easyphone.callback.RegistrationCallback;
10 | import com.xuchongyang.easyphone.linphone.LinphoneManager;
11 | import com.xuchongyang.easyphone.linphone.LinphoneUtils;
12 | import com.xuchongyang.easyphone.linphone.PhoneBean;
13 | import com.xuchongyang.easyphone.service.LinphoneService;
14 |
15 | import org.linphone.core.LinphoneCallParams;
16 | import org.linphone.core.LinphoneCore;
17 | import org.linphone.core.LinphoneCoreException;
18 | import org.linphone.mediastream.video.AndroidVideoWindowImpl;
19 |
20 | import static java.lang.Thread.sleep;
21 |
22 | /**
23 | * Created by Mark Xu on 2017/9/20.
24 | * Site: http://xuchongyang.com
25 | */
26 |
27 | public class EasyLinphone {
28 | private static ServiceWaitThread mServiceWaitThread;
29 | private static String mUsername, mPassword, mServerIP;
30 | private static AndroidVideoWindowImpl mAndroidVideoWindow;
31 | private static SurfaceView mRenderingView, mPreviewView;
32 |
33 | /**
34 | * 开启服务
35 | * @param context 上下文
36 | */
37 | public static void startService(Context context) {
38 | if (!LinphoneService.isReady()) {
39 | Intent intent = new Intent(Intent.ACTION_MAIN);
40 | intent.setClass(context, LinphoneService.class);
41 | context.startService(intent);
42 | }
43 | }
44 |
45 | /**
46 | * 设置 sip 账户信息
47 | * @param username sip 账户
48 | * @param password 密码
49 | * @param serverIP sip 服务器
50 | */
51 | public static void setAccount(String username, String password, String serverIP) {
52 | mUsername = username;
53 | mPassword = password;
54 | mServerIP = serverIP;
55 | }
56 |
57 | /**
58 | * 添加注册状态、通话状态回调
59 | * @param phoneCallback 通话回调
60 | * @param registrationCallback 注册状态回调
61 | */
62 | public static void addCallback(RegistrationCallback registrationCallback,
63 | PhoneCallback phoneCallback) {
64 | if (LinphoneService.isReady()) {
65 | LinphoneService.addRegistrationCallback(registrationCallback);
66 | LinphoneService.addPhoneCallback(phoneCallback);
67 | } else {
68 | mServiceWaitThread = new ServiceWaitThread(registrationCallback, phoneCallback);
69 | mServiceWaitThread.start();
70 | }
71 | }
72 |
73 | /**
74 | * 登录到 SIP 服务器
75 | */
76 | public static void login() {
77 | new Thread(new Runnable() {
78 | @Override
79 | public void run() {
80 | while (!LinphoneService.isReady()) {
81 | try {
82 | sleep(80);
83 | } catch (InterruptedException e) {
84 | e.printStackTrace();
85 | }
86 | }
87 | loginToServer();
88 | }
89 | }).start();
90 | }
91 |
92 | /**
93 | * 呼叫指定号码
94 | * @param num 呼叫号码
95 | */
96 | public static void callTo(String num, boolean isVideoCall) {
97 | if (!LinphoneService.isReady() || !LinphoneManager.isInstanceiated()) {
98 | return;
99 | }
100 | if (!num.equals("")) {
101 | PhoneBean phone = new PhoneBean();
102 | phone.setUserName(num);
103 | phone.setHost(mServerIP);
104 | LinphoneUtils.getInstance().startSingleCallingTo(phone, isVideoCall);
105 | }
106 | }
107 |
108 | /**
109 | * 接听来电
110 | */
111 | public static void acceptCall() {
112 | try {
113 | LinphoneManager.getLc().acceptCall(LinphoneManager.getLc().getCurrentCall());
114 | } catch (LinphoneCoreException e) {
115 | e.printStackTrace();
116 | }
117 | }
118 |
119 | /**
120 | * 挂断当前通话
121 | */
122 | public static void hangUp() {
123 | LinphoneUtils.getInstance().hangUp();
124 | }
125 |
126 | /**
127 | * 切换静音
128 | * @param isMicMuted 是否静音
129 | */
130 | public static void toggleMicro(boolean isMicMuted) {
131 | LinphoneUtils.getInstance().toggleMicro(isMicMuted);
132 | }
133 |
134 | /**
135 | * 切换免提
136 | * @param isSpeakerEnabled 是否免提
137 | */
138 | public static void toggleSpeaker(boolean isSpeakerEnabled) {
139 | LinphoneUtils.getInstance().toggleSpeaker(isSpeakerEnabled);
140 | }
141 |
142 | private static class ServiceWaitThread extends Thread {
143 | private PhoneCallback mPhoneCallback;
144 | private RegistrationCallback mRegistrationCallback;
145 |
146 | ServiceWaitThread(RegistrationCallback registrationCallback, PhoneCallback phoneCallback) {
147 | mRegistrationCallback = registrationCallback;
148 | mPhoneCallback = phoneCallback;
149 | }
150 |
151 | @Override
152 | public void run() {
153 | super.run();
154 | while (!LinphoneService.isReady()) {
155 | try {
156 | sleep(80);
157 | } catch (InterruptedException e) {
158 | throw new RuntimeException("waiting thread sleep() has been interrupted");
159 | }
160 | }
161 | LinphoneService.addPhoneCallback(mPhoneCallback);
162 | LinphoneService.addRegistrationCallback(mRegistrationCallback);
163 | mServiceWaitThread = null;
164 | }
165 | }
166 |
167 | /**
168 | * 登录 SIP 服务器
169 | */
170 | private static void loginToServer() {
171 | try {
172 | if (mUsername == null || mPassword == null || mServerIP == null) {
173 | throw new RuntimeException("The sip account is not configured.");
174 | }
175 | LinphoneUtils.getInstance().registerUserAuth(mUsername, mPassword, mServerIP);
176 | } catch (LinphoneCoreException e) {
177 | e.printStackTrace();
178 | }
179 | }
180 |
181 | public static boolean getVideoEnabled() {
182 | LinphoneCallParams remoteParams = LinphoneManager.getLc().getCurrentCall().getRemoteParams();
183 | return remoteParams != null && remoteParams.getVideoEnabled();
184 | }
185 |
186 | /**
187 | * 设置 SurfaceView
188 | * @param renderingView 远程 SurfaceView
189 | * @param previewView 本地 SurfaceView
190 | */
191 | public static void setAndroidVideoWindow(final SurfaceView[] renderingView, final SurfaceView[] previewView) {
192 | mRenderingView = renderingView[0];
193 | mPreviewView = previewView[0];
194 | fixZOrder(mRenderingView, mPreviewView);
195 | mAndroidVideoWindow = new AndroidVideoWindowImpl(renderingView[0], previewView[0], new AndroidVideoWindowImpl.VideoWindowListener() {
196 | @Override
197 | public void onVideoRenderingSurfaceReady(AndroidVideoWindowImpl androidVideoWindow, SurfaceView surfaceView) {
198 | setVideoWindow(androidVideoWindow);
199 | renderingView[0] = surfaceView;
200 | }
201 |
202 | @Override
203 | public void onVideoRenderingSurfaceDestroyed(AndroidVideoWindowImpl androidVideoWindow) {
204 | removeVideoWindow();
205 | }
206 |
207 | @Override
208 | public void onVideoPreviewSurfaceReady(AndroidVideoWindowImpl androidVideoWindow, SurfaceView surfaceView) {
209 | mPreviewView = surfaceView;
210 | setPreviewWindow(mPreviewView);
211 | }
212 |
213 | @Override
214 | public void onVideoPreviewSurfaceDestroyed(AndroidVideoWindowImpl androidVideoWindow) {
215 | removePreviewWindow();
216 | }
217 | });
218 | }
219 |
220 | /**
221 | * onResume
222 | */
223 | public static void onResume() {
224 | if (mRenderingView != null) {
225 | ((GLSurfaceView) mRenderingView).onResume();
226 | }
227 |
228 | if (mAndroidVideoWindow != null) {
229 | synchronized (mAndroidVideoWindow) {
230 | LinphoneManager.getLc().setVideoWindow(mAndroidVideoWindow);
231 | }
232 | }
233 | }
234 |
235 | /**
236 | * onPause
237 | */
238 | public static void onPause() {
239 | if (mAndroidVideoWindow != null) {
240 | synchronized (mAndroidVideoWindow) {
241 | LinphoneManager.getLc().setVideoWindow(null);
242 | }
243 | }
244 |
245 | if (mRenderingView != null) {
246 | ((GLSurfaceView) mRenderingView).onPause();
247 | }
248 | }
249 |
250 | /**
251 | * onDestroy
252 | */
253 | public static void onDestroy() {
254 | mPreviewView = null;
255 | mRenderingView = null;
256 |
257 | if (mAndroidVideoWindow != null) {
258 | mAndroidVideoWindow.release();
259 | mAndroidVideoWindow = null;
260 | }
261 | }
262 |
263 | private static void fixZOrder(SurfaceView rendering, SurfaceView preview) {
264 | rendering.setZOrderOnTop(false);
265 | preview.setZOrderOnTop(true);
266 | preview.setZOrderMediaOverlay(true); // Needed to be able to display control layout over
267 | }
268 |
269 | private static void setVideoWindow(Object o) {
270 | LinphoneManager.getLc().setVideoWindow(o);
271 | }
272 |
273 | private static void removeVideoWindow() {
274 | LinphoneCore linphoneCore = LinphoneManager.getLc();
275 | if (linphoneCore != null) {
276 | linphoneCore.setVideoWindow(null);
277 | }
278 | }
279 |
280 | private static void setPreviewWindow(Object o) {
281 | LinphoneManager.getLc().setPreviewWindow(o);
282 | }
283 |
284 | private static void removePreviewWindow() {
285 | LinphoneManager.getLc().setPreviewWindow(null);
286 | }
287 |
288 | /**
289 | * 获取 LinphoneCore
290 | * @return LinphoneCore
291 | */
292 | public static LinphoneCore getLC() {
293 | return LinphoneManager.getLc();
294 | }
295 | }
296 |
--------------------------------------------------------------------------------
/easylinphone/src/main/java/com/xuchongyang/easyphone/callback/PhoneCallback.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easyphone.callback;
2 |
3 | import org.linphone.core.LinphoneCall;
4 |
5 | /**
6 | * Created by Mark Xu on 17/3/13.
7 | * 状态回调
8 | */
9 |
10 | public abstract class PhoneCallback {
11 | /**
12 | * 来电状态
13 | * @param linphoneCall
14 | */
15 | public void incomingCall(LinphoneCall linphoneCall) {}
16 |
17 | /**
18 | * 呼叫初始化
19 | */
20 | public void outgoingInit() {}
21 |
22 | /**
23 | * 电话接通
24 | */
25 | public void callConnected() {}
26 |
27 | /**
28 | * 电话挂断
29 | */
30 | public void callEnd() {}
31 |
32 | /**
33 | * 释放通话
34 | */
35 | public void callReleased() {}
36 |
37 | /**
38 | * 连接失败
39 | */
40 | public void error() {}
41 | }
42 |
--------------------------------------------------------------------------------
/easylinphone/src/main/java/com/xuchongyang/easyphone/callback/RegistrationCallback.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easyphone.callback;
2 |
3 | /**
4 | * Created by Mark Xu on 2017/9/21.
5 | * Site: http://xuchongyang.com
6 | */
7 |
8 | public abstract class RegistrationCallback {
9 | public void registrationNone() {}
10 |
11 | public void registrationProgress() {}
12 |
13 | public void registrationOk() {}
14 |
15 | public void registrationCleared() {}
16 |
17 | public void registrationFailed() {}
18 | }
19 |
--------------------------------------------------------------------------------
/easylinphone/src/main/java/com/xuchongyang/easyphone/linphone/KeepAliveHandler.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easyphone.linphone;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.util.Log;
7 |
8 |
9 | /**
10 | * Created by Mark Xu on 17/3/13.
11 | * KeepAliveHandler
12 | */
13 |
14 | public class KeepAliveHandler extends BroadcastReceiver {
15 | private static final String TAG = "KeepAliveHandler";
16 | @Override
17 | public void onReceive(Context context, Intent intent) {
18 | if (LinphoneManager.getLcIfManagerNotDestroyOrNull() != null) {
19 | LinphoneManager.getLc().refreshRegisters();
20 | // SPUtils.save(context, "keepAlive", true);
21 | try {
22 | Thread.sleep(2000);
23 | } catch (InterruptedException e) {
24 | Log.e(TAG, "Cannot sleep for 2s");
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/easylinphone/src/main/java/com/xuchongyang/easyphone/linphone/LinphoneManager.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easyphone.linphone;
2 |
3 | import android.content.Context;
4 | import android.content.pm.PackageManager;
5 | import android.os.Handler;
6 | import android.os.Looper;
7 |
8 | import com.xuchongyang.easyphone.R;
9 |
10 | import org.linphone.core.LinphoneAddress;
11 | import org.linphone.core.LinphoneAuthInfo;
12 | import org.linphone.core.LinphoneCall;
13 | import org.linphone.core.LinphoneCallStats;
14 | import org.linphone.core.LinphoneChatMessage;
15 | import org.linphone.core.LinphoneChatRoom;
16 | import org.linphone.core.LinphoneContent;
17 | import org.linphone.core.LinphoneCore;
18 | import org.linphone.core.LinphoneCoreException;
19 | import org.linphone.core.LinphoneCoreFactory;
20 | import org.linphone.core.LinphoneCoreListener;
21 | import org.linphone.core.LinphoneEvent;
22 | import org.linphone.core.LinphoneFriend;
23 | import org.linphone.core.LinphoneFriendList;
24 | import org.linphone.core.LinphoneInfoMessage;
25 | import org.linphone.core.LinphoneProxyConfig;
26 | import org.linphone.core.PayloadType;
27 | import org.linphone.core.PublishState;
28 | import org.linphone.core.SubscriptionState;
29 | import org.linphone.core.ToneID;
30 | import org.linphone.mediastream.Log;
31 |
32 | import java.io.File;
33 | import java.io.IOException;
34 | import java.nio.ByteBuffer;
35 | import java.util.Timer;
36 | import java.util.TimerTask;
37 |
38 | /**
39 | * Created by Mark Xu on 17/3/11.
40 | * Linphone 管理器
41 | */
42 |
43 | public class LinphoneManager implements LinphoneCoreListener {
44 | private static final String TAG = "LinphoneManager";
45 | private static LinphoneManager instance;
46 | private Context mServiceContext;
47 | private LinphoneCore mLc;
48 | private Timer mTimer;
49 | private static boolean sExited;
50 |
51 | private String mLPConfigXsd = null;
52 | private String mLinphoneFactoryConfigFile = null;
53 | public String mLinphoneConfigFile = null;
54 | private String mLinphoneRootCaFile = null;
55 | private String mRingSoundFile = null;
56 | private String mRingBackSoundFile = null;
57 | private String mPauseSoundFile = null;
58 | private String mChatDatabaseFile = null;
59 | // private String mErrorToneFile = null;
60 |
61 | public LinphoneManager(Context serviceContext) {
62 | mServiceContext = serviceContext;
63 | LinphoneCoreFactory.instance().setDebugMode(true, "huanyutong");
64 | sExited = false;
65 |
66 | String basePath = mServiceContext.getFilesDir().getAbsolutePath();
67 | mLPConfigXsd = basePath + "/lpconfig.xsd";
68 | mLinphoneFactoryConfigFile = basePath + "/linphonerc";
69 | mLinphoneConfigFile = basePath + "/.linphonerc";
70 | mLinphoneRootCaFile = basePath + "/rootca.pem";
71 | mRingSoundFile = basePath + "/oldphone_mono.wav";
72 | mRingBackSoundFile = basePath + "/ringback.wav";
73 | mPauseSoundFile = basePath + "/toy_mono.wav";
74 | mChatDatabaseFile = basePath + "/linphone-history.db";
75 | // mErrorToneFile = basePath + "/error.wav";
76 | }
77 |
78 | public synchronized static final LinphoneManager createAndStart(Context context) {
79 | if (instance != null) {
80 | throw new RuntimeException("Linphone Manager is already initialized");
81 | }
82 | instance = new LinphoneManager(context);
83 | instance.startLibLinphone(context);
84 | return instance;
85 | }
86 |
87 | public static synchronized LinphoneCore getLcIfManagerNotDestroyOrNull() {
88 | if (sExited || instance == null) {
89 | Log.e("Trying to get linphone core while LinphoneManager already destroyed or not created");
90 | return null;
91 | }
92 | return getLc();
93 | }
94 |
95 | public static final boolean isInstanceiated() {
96 | return instance != null;
97 | }
98 |
99 | public static synchronized final LinphoneCore getLc() {
100 | return getInstance().mLc;
101 | }
102 |
103 | public static synchronized final LinphoneManager getInstance() {
104 | if (instance != null) {
105 | return instance;
106 | }
107 | if (sExited) {
108 | throw new RuntimeException("Linphone Manager was already destroyed. "
109 | + "Better use getLcIfManagerNotDestroyed and check returned value");
110 | }
111 | throw new RuntimeException("Linphone Manager should be created before accessed");
112 | }
113 |
114 | private synchronized void startLibLinphone(Context context) {
115 | try {
116 | copyAssetsFromPackage();
117 | mLc = LinphoneCoreFactory.instance().createLinphoneCore(this, mLinphoneConfigFile,
118 | mLinphoneFactoryConfigFile, null, context);
119 | mLc.addListener((LinphoneCoreListener)context);
120 |
121 | try {
122 | initLibLinphone();
123 | } catch (LinphoneCoreException e) {
124 | Log.e(e);
125 | }
126 |
127 | TimerTask task = new TimerTask() {
128 | @Override
129 | public void run() {
130 | new Handler(Looper.getMainLooper()).post(new Runnable() {
131 | @Override
132 | public void run() {
133 | if (mLc != null) {
134 | mLc.iterate();
135 | }
136 | }
137 | });
138 | }
139 | };
140 | mTimer = new Timer("Linphone Scheduler");
141 | mTimer.schedule(task, 0, 20);
142 | } catch (Exception e) {
143 | e.printStackTrace();
144 | Log.e(TAG, "startLibLinphone: cannot start linphone");
145 | }
146 | }
147 |
148 | private synchronized void initLibLinphone() throws LinphoneCoreException {
149 | mLc.setContext(mServiceContext);
150 | setUserAgent();
151 | mLc.setRemoteRingbackTone(mRingSoundFile);
152 | mLc.setTone(ToneID.CallWaiting, mRingSoundFile);
153 | mLc.setRing(mRingSoundFile);
154 | mLc.setRootCA(mLinphoneRootCaFile);
155 | mLc.setPlayFile(mPauseSoundFile);
156 | mLc.setChatDatabasePath(mChatDatabaseFile);
157 | // mLc.setCallErrorTone(Reason.NotFound, mErrorToneFile);//设置呼叫错误播放的铃声
158 |
159 | setBackCamAsDefault();
160 |
161 | int availableCores = Runtime.getRuntime().availableProcessors();
162 | Log.w(TAG, "MediaStreamer : " + availableCores + " cores detected and configured");
163 | mLc.setCpuCount(availableCores);
164 |
165 | int migrationResult = getLc().migrateToMultiTransport();
166 | Log.d(TAG, "Migration to multi transport result = " + migrationResult);
167 |
168 | mLc.setNetworkReachable(true);
169 |
170 | //回声消除
171 | // boolean isEchoCancellation = (boolean) SPUtils.get(mServiceContext, "echo_cancellation", true);
172 | mLc.enableEchoCancellation(true);
173 |
174 | //自适应码率控制
175 | // boolean isAdaptiveRateControl = (boolean) SPUtils.get(mServiceContext, "adaptive_rate_control", true);
176 | mLc.enableAdaptiveRateControl(true);
177 |
178 | //audio 码率设置
179 | LinphoneUtils.getConfig(mServiceContext).setInt("audio", "codec_bitrate_limit", 36);
180 |
181 | mLc.setPreferredVideoSizeByName("720p");
182 | mLc.setUploadBandwidth(1536);
183 | mLc.setDownloadBandwidth(1536);
184 |
185 | mLc.setVideoPolicy(mLc.getVideoAutoInitiatePolicy(), true);
186 | mLc.setVideoPolicy(true, mLc.getVideoAutoAcceptPolicy());
187 | mLc.enableVideo(true, true);
188 |
189 | // 设置编码格式
190 | setCodecMime();
191 |
192 | // IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
193 | // filter.addAction(Intent.ACTION_SCREEN_OFF);
194 | // mServiceContext.registerReceiver(mKeepAliveReceiver, filter);
195 | }
196 |
197 | private void setCodecMime() {
198 | for (PayloadType payloadType : mLc.getAudioCodecs()) {
199 | try {
200 | mLc.enablePayloadType(payloadType, true);
201 | } catch (LinphoneCoreException e) {
202 | e.printStackTrace();
203 | }
204 | // android.util.Log.e(TAG, "setCodecMime = " + payloadType.getMime() + " Rate " + payloadType.getRate() + " receviceFmtp " + payloadType.getRecvFmtp());
205 | // if (payloadType.getMime().equals("PCMA") && payloadType.getRate() == 8000) {
206 | // try {
207 | // android.util.Log.e(TAG, "setCodecMime: " + payloadType.getMime() + " " + payloadType.getRate());
208 | // mLc.enablePayloadType(payloadType, true);
209 | // } catch (LinphoneCoreException e) {
210 | // android.util.Log.e(TAG, "setCodecMime: " + e);
211 | // }
212 | // } else {
213 | // try {
214 | // mLc.enablePayloadType(payloadType, false);
215 | // } catch (LinphoneCoreException e) {
216 | // e.printStackTrace();
217 | // }
218 | // }
219 | }
220 | for (PayloadType payloadType : mLc.getVideoCodecs()) {
221 | try {
222 | android.util.Log.e(TAG, "setCodecMime: mime: " + payloadType.getMime() + " rate: " + payloadType.getRate());
223 | mLc.enablePayloadType(payloadType, true);
224 | } catch (LinphoneCoreException e) {
225 | e.printStackTrace();
226 | }
227 | }
228 | }
229 |
230 | private void copyAssetsFromPackage() throws IOException {
231 | LinphoneUtils.copyIfNotExist(mServiceContext, R.raw.oldphone_mono, mRingSoundFile);
232 | LinphoneUtils.copyIfNotExist(mServiceContext, R.raw.ringback, mRingBackSoundFile);
233 | LinphoneUtils.copyIfNotExist(mServiceContext, R.raw.toy_mono, mPauseSoundFile);
234 | LinphoneUtils.copyIfNotExist(mServiceContext, R.raw.linphonerc_default, mLinphoneConfigFile);
235 | LinphoneUtils.copyIfNotExist(mServiceContext, R.raw.linphonerc_factory, new File(mLinphoneFactoryConfigFile).getName());
236 | LinphoneUtils.copyIfNotExist(mServiceContext, R.raw.lpconfig, mLPConfigXsd);
237 | LinphoneUtils.copyIfNotExist(mServiceContext, R.raw.rootca, mLinphoneRootCaFile);
238 | }
239 |
240 | private void setUserAgent() {
241 | try {
242 | String versionName = mServiceContext.getPackageManager().getPackageInfo(mServiceContext.getPackageName(),
243 | 0).versionName;
244 | if (versionName == null) {
245 | versionName = String.valueOf(mServiceContext.getPackageManager().getPackageInfo(mServiceContext.getPackageName(), 0).versionCode);
246 | }
247 | mLc.setUserAgent("Hunayutong", versionName);
248 | } catch (PackageManager.NameNotFoundException e) {
249 | e.printStackTrace();
250 | }
251 | }
252 |
253 | public static synchronized void destroy() {
254 | if (instance == null) {
255 | return;
256 | }
257 | sExited = true;
258 | instance.doDestroy();
259 | }
260 |
261 | private void doDestroy() {
262 | try {
263 | mTimer.cancel();
264 | mLc.destroy();
265 | } catch (RuntimeException e) {
266 | e.printStackTrace();
267 | } finally {
268 | mLc = null;
269 | instance = null;
270 | }
271 | }
272 |
273 | @Override
274 | public void authInfoRequested(LinphoneCore linphoneCore, String s, String s1, String s2) {
275 |
276 | }
277 |
278 | @Override
279 | public void authenticationRequested(LinphoneCore linphoneCore, LinphoneAuthInfo linphoneAuthInfo, LinphoneCore.AuthMethod authMethod) {
280 |
281 | }
282 |
283 | @Override
284 | public void callStatsUpdated(LinphoneCore linphoneCore, LinphoneCall linphoneCall, LinphoneCallStats linphoneCallStats) {
285 |
286 | }
287 |
288 | @Override
289 | public void newSubscriptionRequest(LinphoneCore linphoneCore, LinphoneFriend linphoneFriend, String s) {
290 |
291 | }
292 |
293 | @Override
294 | public void notifyPresenceReceived(LinphoneCore linphoneCore, LinphoneFriend linphoneFriend) {
295 |
296 | }
297 |
298 | @Override
299 | public void dtmfReceived(LinphoneCore linphoneCore, LinphoneCall linphoneCall, int i) {
300 |
301 | }
302 |
303 | @Override
304 | public void notifyReceived(LinphoneCore linphoneCore, LinphoneCall linphoneCall, LinphoneAddress linphoneAddress, byte[] bytes) {
305 |
306 | }
307 |
308 | @Override
309 | public void transferState(LinphoneCore linphoneCore, LinphoneCall linphoneCall, LinphoneCall.State state) {
310 |
311 | }
312 |
313 | @Override
314 | public void infoReceived(LinphoneCore linphoneCore, LinphoneCall linphoneCall, LinphoneInfoMessage linphoneInfoMessage) {
315 |
316 | }
317 |
318 | @Override
319 | public void subscriptionStateChanged(LinphoneCore linphoneCore, LinphoneEvent linphoneEvent, SubscriptionState subscriptionState) {
320 |
321 | }
322 |
323 | @Override
324 | public void publishStateChanged(LinphoneCore linphoneCore, LinphoneEvent linphoneEvent, PublishState publishState) {
325 |
326 | }
327 |
328 | @Override
329 | public void show(LinphoneCore linphoneCore) {
330 |
331 | }
332 |
333 | @Override
334 | public void displayStatus(LinphoneCore linphoneCore, String s) {
335 |
336 | }
337 |
338 | @Override
339 | public void displayMessage(LinphoneCore linphoneCore, String s) {
340 |
341 | }
342 |
343 | @Override
344 | public void displayWarning(LinphoneCore linphoneCore, String s) {
345 |
346 | }
347 |
348 | @Override
349 | public void fileTransferProgressIndication(LinphoneCore linphoneCore, LinphoneChatMessage linphoneChatMessage, LinphoneContent linphoneContent, int i) {
350 |
351 | }
352 |
353 | @Override
354 | public void fileTransferRecv(LinphoneCore linphoneCore, LinphoneChatMessage linphoneChatMessage, LinphoneContent linphoneContent, byte[] bytes, int i) {
355 |
356 | }
357 |
358 | @Override
359 | public int fileTransferSend(LinphoneCore linphoneCore, LinphoneChatMessage linphoneChatMessage, LinphoneContent linphoneContent, ByteBuffer byteBuffer, int i) {
360 | return 0;
361 | }
362 |
363 | @Override
364 | public void callEncryptionChanged(LinphoneCore linphoneCore, LinphoneCall linphoneCall, boolean b, String s) {
365 |
366 | }
367 |
368 | @Override
369 | public void callState(LinphoneCore linphoneCore, LinphoneCall linphoneCall, LinphoneCall.State state, String s) {
370 |
371 | }
372 |
373 | @Override
374 | public void isComposingReceived(LinphoneCore linphoneCore, LinphoneChatRoom linphoneChatRoom) {
375 |
376 | }
377 |
378 | @Override
379 | public void ecCalibrationStatus(LinphoneCore linphoneCore, LinphoneCore.EcCalibratorStatus ecCalibratorStatus, int i, Object o) {
380 |
381 | }
382 |
383 | @Override
384 | public void globalState(LinphoneCore linphoneCore, LinphoneCore.GlobalState globalState, String s) {
385 |
386 | }
387 |
388 | @Override
389 | public void uploadProgressIndication(LinphoneCore linphoneCore, int i, int i1) {
390 |
391 | }
392 |
393 | @Override
394 | public void uploadStateChanged(LinphoneCore linphoneCore, LinphoneCore.LogCollectionUploadState logCollectionUploadState, String s) {
395 |
396 | }
397 |
398 | @Override
399 | public void friendListCreated(LinphoneCore linphoneCore, LinphoneFriendList linphoneFriendList) {
400 |
401 | }
402 |
403 | @Override
404 | public void friendListRemoved(LinphoneCore linphoneCore, LinphoneFriendList linphoneFriendList) {
405 |
406 | }
407 |
408 | @Override
409 | public void networkReachableChanged(LinphoneCore linphoneCore, boolean b) {
410 |
411 | }
412 |
413 | @Override
414 | public void messageReceived(LinphoneCore linphoneCore, LinphoneChatRoom linphoneChatRoom, LinphoneChatMessage linphoneChatMessage) {
415 |
416 | }
417 |
418 | @Override
419 | public void messageReceivedUnableToDecrypted(LinphoneCore linphoneCore, LinphoneChatRoom linphoneChatRoom, LinphoneChatMessage linphoneChatMessage) {
420 |
421 | }
422 |
423 | @Override
424 | public void notifyReceived(LinphoneCore linphoneCore, LinphoneEvent linphoneEvent, String s, LinphoneContent linphoneContent) {
425 |
426 | }
427 |
428 | @Override
429 | public void registrationState(LinphoneCore linphoneCore, LinphoneProxyConfig linphoneProxyConfig, LinphoneCore.RegistrationState registrationState, String s) {
430 |
431 | }
432 |
433 | @Override
434 | public void configuringStatus(LinphoneCore linphoneCore, LinphoneCore.RemoteProvisioningState remoteProvisioningState, String s) {
435 |
436 | }
437 |
438 | private void setBackCamAsDefault() {
439 | // int camId = 0;
440 | // AndroidCameraConfiguration.AndroidCamera[] cameras = AndroidCameraConfiguration.retrieveCameras();
441 | // for (AndroidCameraConfiguration.AndroidCamera androidCamera :
442 | // cameras) {
443 | // if (!androidCamera.frontFacing) {
444 | // camId = androidCamera.id;
445 | // }
446 | // }
447 | // android.util.Log.e(TAG, "setBackCamAsDefault: cameraId is " + camId);
448 | mLc.setVideoDevice(0);
449 | }
450 | }
451 |
--------------------------------------------------------------------------------
/easylinphone/src/main/java/com/xuchongyang/easyphone/linphone/LinphoneUtils.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easyphone.linphone;
2 |
3 | import android.content.Context;
4 | import android.util.Log;
5 |
6 | import org.linphone.core.LinphoneAddress;
7 | import org.linphone.core.LinphoneAuthInfo;
8 | import org.linphone.core.LinphoneCall;
9 | import org.linphone.core.LinphoneCallParams;
10 | import org.linphone.core.LinphoneCore;
11 | import org.linphone.core.LinphoneCoreException;
12 | import org.linphone.core.LinphoneCoreFactory;
13 | import org.linphone.core.LinphoneProxyConfig;
14 | import org.linphone.core.LpConfig;
15 |
16 | import java.io.File;
17 | import java.io.FileOutputStream;
18 | import java.io.IOException;
19 | import java.io.InputStream;
20 |
21 | /**
22 | * Created by Mark Xu on 17/3/13.
23 | * 语音通话工具类
24 | */
25 |
26 | public class LinphoneUtils {
27 | private static final String TAG = "LinphoneUtils";
28 | private static volatile LinphoneUtils sLinphoneUtils;
29 | private LinphoneCore mLinphoneCore = null;
30 |
31 | public static LinphoneUtils getInstance() {
32 | if (sLinphoneUtils == null) {
33 | synchronized (LinphoneUtils.class) {
34 | if (sLinphoneUtils == null) {
35 | sLinphoneUtils = new LinphoneUtils();
36 | }
37 | }
38 | }
39 | return sLinphoneUtils;
40 | }
41 |
42 | private LinphoneUtils() {
43 | mLinphoneCore = LinphoneManager.getLc();
44 | mLinphoneCore.enableEchoCancellation(true);
45 | mLinphoneCore.enableEchoLimiter(true);
46 | }
47 |
48 | /**
49 | * 注册到服务器
50 | * @param name
51 | * @param password
52 | * @param host
53 | * @throws LinphoneCoreException
54 | */
55 | public void registerUserAuth(String name, String password, String host) throws LinphoneCoreException {
56 | Log.e(TAG, "registerUserAuth name = " + name);
57 | Log.e(TAG, "registerUserAuth pw = " + password);
58 | Log.e(TAG, "registerUserAuth host = " + host);
59 | String identify = "sip:" + name + "@" + host;
60 | String proxy = "sip:" + host;
61 | LinphoneAddress proxyAddr = LinphoneCoreFactory.instance().createLinphoneAddress(proxy);
62 | LinphoneAddress identifyAddr = LinphoneCoreFactory.instance().createLinphoneAddress(identify);
63 | LinphoneAuthInfo authInfo = LinphoneCoreFactory.instance().createAuthInfo(name, null, password,
64 | null, null, host);
65 | LinphoneProxyConfig prxCfg = mLinphoneCore.createProxyConfig(identifyAddr.asString(),
66 | proxyAddr.asStringUriOnly(), proxyAddr.asStringUriOnly(), true);
67 | prxCfg.enableAvpf(false);
68 | prxCfg.setAvpfRRInterval(0);
69 | prxCfg.enableQualityReporting(false);
70 | prxCfg.setQualityReportingCollector(null);
71 | prxCfg.setQualityReportingInterval(0);
72 | prxCfg.enableRegister(true);
73 | mLinphoneCore.addProxyConfig(prxCfg);
74 | mLinphoneCore.addAuthInfo(authInfo);
75 | mLinphoneCore.setDefaultProxyConfig(prxCfg);
76 | }
77 |
78 | public LinphoneCall startSingleCallingTo(PhoneBean bean, boolean isVideoCall) {
79 | LinphoneAddress address;
80 | LinphoneCall call = null;
81 | try {
82 | address = mLinphoneCore.interpretUrl(bean.getUserName() + "@" + bean.getHost());
83 | } catch (LinphoneCoreException e) {
84 | e.printStackTrace();
85 | return null;
86 | }
87 | address.setDisplayName(bean.getDisplayName());
88 | LinphoneCallParams params = mLinphoneCore.createCallParams(null);
89 | if (isVideoCall) {
90 | params.setVideoEnabled(true);
91 | params.enableLowBandwidth(false);
92 | } else {
93 | params.setVideoEnabled(false);
94 | }
95 | try {
96 | call = mLinphoneCore.inviteAddressWithParams(address, params);
97 | } catch (LinphoneCoreException e) {
98 | e.printStackTrace();
99 | }
100 | return call;
101 | }
102 |
103 | /**
104 | * 挂断电话
105 | */
106 | public void hangUp() {
107 | LinphoneCall currentCall = mLinphoneCore.getCurrentCall();
108 | if (currentCall != null) {
109 | mLinphoneCore.terminateCall(currentCall);
110 | } else if (mLinphoneCore.isInConference()) {
111 | mLinphoneCore.terminateConference();
112 | } else {
113 | mLinphoneCore.terminateAllCalls();
114 | }
115 | }
116 |
117 | /**
118 | * 是否静音
119 | * @param isMicMuted
120 | */
121 | public void toggleMicro(boolean isMicMuted) {
122 | mLinphoneCore.muteMic(isMicMuted);
123 | }
124 |
125 | /**
126 | * 是否外放
127 | * @param isSpeakerEnabled
128 | */
129 | public void toggleSpeaker(boolean isSpeakerEnabled) {
130 | mLinphoneCore.enableSpeaker(isSpeakerEnabled);
131 | }
132 |
133 | public static void copyIfNotExist(Context context, int resourceId, String target) throws IOException {
134 | File fileToCopy = new File(target);
135 | if (!fileToCopy.exists()) {
136 | copyFromPackage(context, resourceId, fileToCopy.getName());
137 | }
138 | }
139 |
140 | public static void copyFromPackage(Context context, int resourceId, String target) throws IOException {
141 | FileOutputStream outputStream = context.openFileOutput(target, 0);
142 | InputStream inputStream = context.getResources().openRawResource(resourceId);
143 | int readByte;
144 | byte[] buff = new byte[8048];
145 | while ((readByte = inputStream.read(buff)) != -1) {
146 | outputStream.write(buff, 0, readByte);
147 | }
148 | outputStream.flush();
149 | outputStream.close();
150 | inputStream.close();
151 | }
152 |
153 | public static LpConfig getConfig(Context context) {
154 | LinphoneCore lc = getLc();
155 | if (lc != null) {
156 | return lc.getConfig();
157 | }
158 |
159 | if (LinphoneManager.isInstanceiated()) {
160 | org.linphone.mediastream.Log.w("LinphoneManager not instanciated yet...");
161 | return LinphoneCoreFactory.instance().createLpConfig(context.getFilesDir().getAbsolutePath() + "/.linphonerc");
162 | }
163 |
164 | return LinphoneCoreFactory.instance().createLpConfig(LinphoneManager.getInstance().mLinphoneConfigFile);
165 | }
166 |
167 | public static void sleep(int time) {
168 | try {
169 | Thread.sleep(time);
170 | } catch (InterruptedException e) {
171 | e.printStackTrace();
172 | }
173 | }
174 |
175 | private static LinphoneCore getLc() {
176 | if (!LinphoneManager.isInstanceiated()) {
177 | return null;
178 | }
179 | return LinphoneManager.getLcIfManagerNotDestroyOrNull();
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/easylinphone/src/main/java/com/xuchongyang/easyphone/linphone/PhoneBean.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easyphone.linphone;
2 |
3 | /**
4 | * Created by Mark Xu on 17/3/14.
5 | * sip 账号信息
6 | */
7 |
8 | public class PhoneBean {
9 | private String displayName;
10 | private String userName;
11 | private String host;
12 | private String password;
13 |
14 | public String getDisplayName() {
15 | return displayName;
16 | }
17 |
18 | public void setDisplayName(String displayName) {
19 | this.displayName = displayName;
20 | }
21 |
22 | public String getUserName() {
23 | return userName;
24 | }
25 |
26 | public void setUserName(String userName) {
27 | this.userName = userName;
28 | }
29 |
30 | public String getHost() {
31 | return host;
32 | }
33 |
34 | public void setHost(String host) {
35 | this.host = host;
36 | }
37 |
38 | public String getPassword() {
39 | return password;
40 | }
41 |
42 | public void setPassword(String password) {
43 | this.password = password;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/easylinphone/src/main/java/com/xuchongyang/easyphone/service/LinphoneService.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easyphone.service;
2 |
3 | import android.app.AlarmManager;
4 | import android.app.PendingIntent;
5 | import android.app.Service;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.os.IBinder;
9 | import android.os.SystemClock;
10 | import android.support.annotation.Nullable;
11 | import android.util.Log;
12 |
13 | import com.xuchongyang.easyphone.callback.PhoneCallback;
14 | import com.xuchongyang.easyphone.callback.RegistrationCallback;
15 | import com.xuchongyang.easyphone.linphone.KeepAliveHandler;
16 | import com.xuchongyang.easyphone.linphone.LinphoneManager;
17 |
18 | import org.linphone.core.LinphoneAddress;
19 | import org.linphone.core.LinphoneAuthInfo;
20 | import org.linphone.core.LinphoneCall;
21 | import org.linphone.core.LinphoneCallStats;
22 | import org.linphone.core.LinphoneChatMessage;
23 | import org.linphone.core.LinphoneChatRoom;
24 | import org.linphone.core.LinphoneContent;
25 | import org.linphone.core.LinphoneCore;
26 | import org.linphone.core.LinphoneCoreFactoryImpl;
27 | import org.linphone.core.LinphoneCoreListener;
28 | import org.linphone.core.LinphoneEvent;
29 | import org.linphone.core.LinphoneFriend;
30 | import org.linphone.core.LinphoneFriendList;
31 | import org.linphone.core.LinphoneInfoMessage;
32 | import org.linphone.core.LinphoneProxyConfig;
33 | import org.linphone.core.PublishState;
34 | import org.linphone.core.SubscriptionState;
35 |
36 | import java.nio.ByteBuffer;
37 |
38 |
39 | /**
40 | * Created by Mark Xu on 17/3/13.
41 | * LinphoneService
42 | */
43 |
44 | public class LinphoneService extends Service implements LinphoneCoreListener {
45 | private static final String TAG = "LinphoneService";
46 | private PendingIntent mKeepAlivePendingIntent;
47 | private static LinphoneService instance;
48 | private static PhoneCallback sPhoneCallback;
49 | private static RegistrationCallback sRegistrationCallback;
50 | // private PowerManager.WakeLock mWakeLock;
51 |
52 | public static boolean isReady() {
53 | return instance != null;
54 | }
55 |
56 | @Override
57 | public void onCreate() {
58 | super.onCreate();
59 | LinphoneCoreFactoryImpl.instance();
60 | LinphoneManager.createAndStart(LinphoneService.this);
61 | instance = this;
62 | Intent intent = new Intent(this, KeepAliveHandler.class);
63 | mKeepAlivePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
64 | ((AlarmManager)this.getSystemService(Context.ALARM_SERVICE)).setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
65 | SystemClock.elapsedRealtime() + 60000, 60000, mKeepAlivePendingIntent);
66 |
67 | // PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
68 | // mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Linphone");
69 | // mWakeLock.acquire();
70 | }
71 |
72 | @Override
73 | public void onDestroy() {
74 | super.onDestroy();
75 | Log.e(TAG, "LinphoneService onDestroy execute");
76 | removeAllCallback();
77 | LinphoneManager.getLc().destroy();
78 | LinphoneManager.destroy();
79 | // if (mWakeLock != null) {
80 | // mWakeLock.release();
81 | // mWakeLock = null;
82 | // }
83 | ((AlarmManager)this.getSystemService(Context.ALARM_SERVICE)).cancel(mKeepAlivePendingIntent);
84 | }
85 |
86 | @Nullable
87 | @Override
88 | public IBinder onBind(Intent intent) {
89 | return null;
90 | }
91 |
92 | public static void addPhoneCallback(PhoneCallback phoneCallback) {
93 | sPhoneCallback = phoneCallback;
94 | }
95 |
96 | public static void removePhoneCallback() {
97 | if (sPhoneCallback != null) {
98 | sPhoneCallback = null;
99 | }
100 | }
101 |
102 | public static void addRegistrationCallback(RegistrationCallback registrationCallback) {
103 | sRegistrationCallback = registrationCallback;
104 | }
105 |
106 | public static void removeRegistrationCallback() {
107 | if (sRegistrationCallback != null) {
108 | sRegistrationCallback = null;
109 | }
110 | }
111 |
112 | public void removeAllCallback() {
113 | removePhoneCallback();
114 | removeRegistrationCallback();
115 | }
116 |
117 | @Override
118 | public void registrationState(LinphoneCore linphoneCore, LinphoneProxyConfig linphoneProxyConfig,
119 | LinphoneCore.RegistrationState registrationState, String s) {
120 | String state = registrationState.toString();
121 | if (sRegistrationCallback != null && state.equals(LinphoneCore.RegistrationState.RegistrationNone.toString())) {
122 | sRegistrationCallback.registrationNone();
123 | } else if (state.equals(LinphoneCore.RegistrationState.RegistrationProgress.toString())) {
124 | sRegistrationCallback.registrationProgress();
125 | } else if (state.equals(LinphoneCore.RegistrationState.RegistrationOk.toString())) {
126 | sRegistrationCallback.registrationOk();
127 | } else if (state.equals(LinphoneCore.RegistrationState.RegistrationCleared.toString())) {
128 | sRegistrationCallback.registrationCleared();
129 | } else if (state.equals(LinphoneCore.RegistrationState.RegistrationFailed.toString())) {
130 | sRegistrationCallback.registrationFailed();
131 | }
132 | }
133 |
134 | @Override
135 | public void callState(final LinphoneCore linphoneCore, final LinphoneCall linphoneCall, LinphoneCall.State state, String s) {
136 | Log.e(TAG, "callState: " + state.toString());
137 | if (state == LinphoneCall.State.IncomingReceived && sPhoneCallback != null) {
138 | sPhoneCallback.incomingCall(linphoneCall);
139 | }
140 |
141 | if (state == LinphoneCall.State.OutgoingInit && sPhoneCallback != null) {
142 | sPhoneCallback.outgoingInit();
143 | }
144 |
145 | if (state == LinphoneCall.State.Connected && sPhoneCallback != null) {
146 | sPhoneCallback.callConnected();
147 | }
148 |
149 | if (state == LinphoneCall.State.Error && sPhoneCallback != null) {
150 | sPhoneCallback.error();
151 | }
152 |
153 | if (state == LinphoneCall.State.CallEnd && sPhoneCallback != null) {
154 | sPhoneCallback.callEnd();
155 | }
156 |
157 | if (state == LinphoneCall.State.CallReleased && sPhoneCallback != null) {
158 | sPhoneCallback.callReleased();
159 | }
160 | }
161 |
162 | /**
163 | * 呼叫指定频道
164 | * @param channel 频道
165 | */
166 | private void callThroughMobile(String channel) {
167 | // mChannel = channel;
168 | // if (LinphoneManager.getLc().isIncall()) {
169 | // LinphoneUtils.getInstance().hangUp();
170 | // MediaUtils.stop();
171 | // }
172 | // SPUtils.save(this, "channel", mChannel);
173 | // callNowChannel();
174 | }
175 |
176 | /**
177 | * 呼叫当前所在频道
178 | */
179 | private void callNowChannel() {
180 | // if (!LinphoneManager.getLc().isIncall()) {
181 | // if (!mChannel.equals("")) {
182 | // PhoneBean phone = new PhoneBean();
183 | // phone.setUserName(mChannel);
184 | // phone.setHost("115.159.84.73");
185 | // LinphoneUtils.getInstance().startSingleCallingTo(phone);
186 | // }
187 | // }
188 | }
189 |
190 | @Override
191 | public void authInfoRequested(LinphoneCore linphoneCore, String s, String s1, String s2) {
192 |
193 | }
194 |
195 | @Override
196 | public void authenticationRequested(LinphoneCore linphoneCore, LinphoneAuthInfo linphoneAuthInfo, LinphoneCore.AuthMethod authMethod) {
197 |
198 | }
199 |
200 | @Override
201 | public void callStatsUpdated(LinphoneCore linphoneCore, LinphoneCall linphoneCall, LinphoneCallStats linphoneCallStats) {
202 |
203 | }
204 |
205 | @Override
206 | public void newSubscriptionRequest(LinphoneCore linphoneCore, LinphoneFriend linphoneFriend, String s) {
207 |
208 | }
209 |
210 | @Override
211 | public void notifyPresenceReceived(LinphoneCore linphoneCore, LinphoneFriend linphoneFriend) {
212 |
213 | }
214 |
215 | @Override
216 | public void dtmfReceived(LinphoneCore linphoneCore, LinphoneCall linphoneCall, int i) {
217 |
218 | }
219 |
220 | @Override
221 | public void notifyReceived(LinphoneCore linphoneCore, LinphoneCall linphoneCall, LinphoneAddress linphoneAddress, byte[] bytes) {
222 |
223 | }
224 |
225 | @Override
226 | public void transferState(LinphoneCore linphoneCore, LinphoneCall linphoneCall, LinphoneCall.State state) {
227 |
228 | }
229 |
230 | @Override
231 | public void infoReceived(LinphoneCore linphoneCore, LinphoneCall linphoneCall, LinphoneInfoMessage linphoneInfoMessage) {
232 |
233 | }
234 |
235 | @Override
236 | public void subscriptionStateChanged(LinphoneCore linphoneCore, LinphoneEvent linphoneEvent, SubscriptionState subscriptionState) {
237 |
238 | }
239 |
240 | @Override
241 | public void publishStateChanged(LinphoneCore linphoneCore, LinphoneEvent linphoneEvent, PublishState publishState) {
242 |
243 | }
244 |
245 | @Override
246 | public void show(LinphoneCore linphoneCore) {
247 |
248 | }
249 |
250 | @Override
251 | public void displayStatus(LinphoneCore linphoneCore, String s) {
252 |
253 | }
254 |
255 | @Override
256 | public void displayMessage(LinphoneCore linphoneCore, String s) {
257 |
258 | }
259 |
260 | @Override
261 | public void displayWarning(LinphoneCore linphoneCore, String s) {
262 |
263 | }
264 |
265 | @Override
266 | public void fileTransferProgressIndication(LinphoneCore linphoneCore, LinphoneChatMessage linphoneChatMessage, LinphoneContent linphoneContent, int i) {
267 |
268 | }
269 |
270 | @Override
271 | public void fileTransferRecv(LinphoneCore linphoneCore, LinphoneChatMessage linphoneChatMessage, LinphoneContent linphoneContent, byte[] bytes, int i) {
272 |
273 | }
274 |
275 | @Override
276 | public int fileTransferSend(LinphoneCore linphoneCore, LinphoneChatMessage linphoneChatMessage, LinphoneContent linphoneContent, ByteBuffer byteBuffer, int i) {
277 | return 0;
278 | }
279 |
280 | @Override
281 | public void callEncryptionChanged(LinphoneCore linphoneCore, LinphoneCall linphoneCall, boolean b, String s) {
282 |
283 | }
284 |
285 | @Override
286 | public void isComposingReceived(LinphoneCore linphoneCore, LinphoneChatRoom linphoneChatRoom) {
287 |
288 | }
289 |
290 | @Override
291 | public void ecCalibrationStatus(LinphoneCore linphoneCore, LinphoneCore.EcCalibratorStatus ecCalibratorStatus, int i, Object o) {
292 |
293 | }
294 |
295 | @Override
296 | public void globalState(LinphoneCore linphoneCore, LinphoneCore.GlobalState globalState, String s) {
297 |
298 | }
299 |
300 | @Override
301 | public void uploadProgressIndication(LinphoneCore linphoneCore, int i, int i1) {
302 |
303 | }
304 |
305 | @Override
306 | public void uploadStateChanged(LinphoneCore linphoneCore, LinphoneCore.LogCollectionUploadState logCollectionUploadState, String s) {
307 |
308 | }
309 |
310 | @Override
311 | public void friendListCreated(LinphoneCore linphoneCore, LinphoneFriendList linphoneFriendList) {
312 |
313 | }
314 |
315 | @Override
316 | public void friendListRemoved(LinphoneCore linphoneCore, LinphoneFriendList linphoneFriendList) {
317 |
318 | }
319 |
320 | @Override
321 | public void networkReachableChanged(LinphoneCore linphoneCore, boolean b) {
322 |
323 | }
324 |
325 | @Override
326 | public void messageReceived(LinphoneCore linphoneCore, LinphoneChatRoom linphoneChatRoom, LinphoneChatMessage linphoneChatMessage) {
327 |
328 | }
329 |
330 | @Override
331 | public void messageReceivedUnableToDecrypted(LinphoneCore linphoneCore, LinphoneChatRoom linphoneChatRoom, LinphoneChatMessage linphoneChatMessage) {
332 |
333 | }
334 |
335 | @Override
336 | public void notifyReceived(LinphoneCore linphoneCore, LinphoneEvent linphoneEvent, String s, LinphoneContent linphoneContent) {
337 |
338 | }
339 |
340 | @Override
341 | public void configuringStatus(LinphoneCore linphoneCore, LinphoneCore.RemoteProvisioningState remoteProvisioningState, String s) {
342 |
343 | }
344 | }
345 |
--------------------------------------------------------------------------------
/easylinphone/src/main/res/raw/incoming_chat.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/easylinphone/src/main/res/raw/incoming_chat.wav
--------------------------------------------------------------------------------
/easylinphone/src/main/res/raw/linphonerc_default:
--------------------------------------------------------------------------------
1 | [net]
2 | download_bw=380
3 | upload_bw=380
4 |
5 | [sip]
6 | contact="Linphone Android"
7 | use_info=0
8 | use_ipv6=0
9 | keepalive_period=30000
10 |
11 | [video]
12 | size=qvga
13 |
14 | [app]
15 | sharing_server=https://www.linphone.org:444/lft.php
16 | tunnel=disabled
17 |
18 | [tunnel]
19 | host=
20 | port=443
21 |
--------------------------------------------------------------------------------
/easylinphone/src/main/res/raw/linphonerc_factory:
--------------------------------------------------------------------------------
1 | [net]
2 | mtu=1300
3 |
4 | [sip]
5 | guess_hostname=1
6 | inc_timeout=15
7 | register_only_when_network_is_up=1
8 | auto_net_state_mon=0
9 | auto_answer_replacing_calls=1
10 | media_encryption_mandatory=0
11 | ping_with_options=0
12 | root_ca=/data/data/org.linphone/files/rootca.pem
13 |
14 | [rtp]
15 | audio_rtp_port=7076
16 | video_rtp_port=9078
17 | audio_jitt_comp=60
18 | video_jitt_comp=60
19 | nortp_timeout=30
20 | disable_upnp=1
21 |
22 | [sound]
23 | playback_dev_id=
24 | ringer_dev_id=
25 | capture_dev_id=
26 | remote_ring=/data/data/org.linphone/files/ringback.wav
27 | local_ring=/data/data/org.linphone/files/oldphone_mono.wav
28 | dtmf_player_amp=0.1
29 |
30 | [misc]
31 | max_calls=10
32 | log_collection_upload_server_url=https://www.linphone.org:444/lft.php
33 | user_certificates_path=/data/data/org.linphone/files
--------------------------------------------------------------------------------
/easylinphone/src/main/res/raw/lpconfig.xsd:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/easylinphone/src/main/res/raw/oldphone_mono.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/easylinphone/src/main/res/raw/oldphone_mono.wav
--------------------------------------------------------------------------------
/easylinphone/src/main/res/raw/ringback.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/easylinphone/src/main/res/raw/ringback.wav
--------------------------------------------------------------------------------
/easylinphone/src/main/res/raw/toy_mono.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/easylinphone/src/main/res/raw/toy_mono.wav
--------------------------------------------------------------------------------
/easylinphone/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | EasyPhone
3 |
4 |
--------------------------------------------------------------------------------
/easylinphone/src/test/java/com/xuchongyang/easyphone/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.xuchongyang.easyphone;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forever4313/EasyLinphone/6cfcbd161ccfe0790e3d4ab470b6b530da6bce75/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Sep 20 10:38:18 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':easylinphone'
2 |
--------------------------------------------------------------------------------