├── .gitignore
├── README.md
├── app
├── .DS_Store
├── .gitignore
├── build.gradle
├── libs
│ ├── MCRSDK.jar
│ ├── PlayerSDK.jar
│ ├── vmsnetsdk.jar
│ └── xUtils-2.6.14.jar
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── demo
│ │ └── sdk6x
│ │ ├── app
│ │ └── DemoApp.java
│ │ ├── callback
│ │ ├── MsgCallback.java
│ │ └── MsgIds.java
│ │ ├── constants
│ │ └── Constants.java
│ │ ├── data
│ │ ├── Config.java
│ │ ├── LiveCameraInfo.java
│ │ └── TempData.java
│ │ ├── listviewlayout
│ │ └── ListViewForScrollView.java
│ │ ├── live
│ │ ├── ConstantLive.java
│ │ ├── LiveActivity.java
│ │ ├── LiveCallBack.java
│ │ ├── LiveControl.java
│ │ ├── TalkCallInfo.java
│ │ ├── TalkControl.java
│ │ └── TalkState.java
│ │ ├── login
│ │ └── LoginActivity.java
│ │ ├── playback
│ │ ├── ConstantPlayBack.java
│ │ ├── PlayBackActivity.java
│ │ ├── PlayBackCallBack.java
│ │ ├── PlayBackControl.java
│ │ └── PlayBackParams.java
│ │ ├── resource
│ │ ├── ResourceControl.java
│ │ ├── ResourceListActivity.java
│ │ └── ResourceListAdapter.java
│ │ └── utils
│ │ ├── Base64Utils.java
│ │ ├── DebugLog.java
│ │ ├── TimerUtil.java
│ │ ├── UIUtil.java
│ │ ├── UtilAudioPlay.java
│ │ ├── UtilFilePath.java
│ │ └── UtilSDCard.java
│ ├── jniLibs
│ └── armeabi
│ │ ├── libCpuFeatures.so
│ │ ├── libMCRSDK.so
│ │ ├── libPlayCtrl.so
│ │ ├── libPlayCtrl_v5.so
│ │ ├── libPlayCtrl_v7.so
│ │ ├── libSystemTransform.so
│ │ ├── libgnustl_shared.so
│ │ └── libstlport_shared.so
│ └── res
│ ├── drawable-hdpi
│ └── ic_launcher.png
│ ├── drawable-mdpi
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ ├── live_activity.xml
│ ├── login_activity.xml
│ ├── playback_activity.xml
│ ├── resource_item_layout.xml
│ └── resource_list_activity.xml
│ ├── menu
│ └── login.xml
│ ├── raw
│ └── paizhao.mp3
│ ├── values-sw600dp
│ └── dimens.xml
│ ├── values-sw720dp-land
│ └── dimens.xml
│ ├── values-v11
│ └── styles.xml
│ ├── values-v14
│ └── styles.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── doc
└── Android 4.0取流播放获取资源SDK使用说明书.docx
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── import-summary.txt
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Android template
3 | # Built application files
4 | *.apk
5 | *.ap_
6 |
7 | # Files for the ART/Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 | out/
17 |
18 | # Gradle files
19 | .gradle/
20 | build/
21 |
22 | # Local configuration file (sdk path, etc)
23 | local.properties
24 |
25 | # Proguard folder generated by Eclipse
26 | proguard/
27 |
28 | # Log Files
29 | *.log
30 |
31 | # Android Studio Navigation editor temp files
32 | .navigation/
33 |
34 | # Android Studio captures folder
35 | captures/
36 |
37 | # IntelliJ
38 | *.iml
39 | .idea
40 | .idea/workspace.xml
41 | .idea/tasks.xml
42 | .idea/gradle.xml
43 | .idea/dictionaries
44 | .idea/libraries
45 |
46 | # Keystore files
47 | # Uncomment the following line if you do not want to check your keystore files in.
48 | #*.jks
49 |
50 | # External native build folder generated in Android Studio 2.2 and later
51 | .externalNativeBuild
52 |
53 | # Google Services (e.g. APIs or Firebase)
54 | google-services.json
55 |
56 | # Freeline
57 | freeline.py
58 | freeline/
59 | freeline_project_description.json
60 |
61 | # fastlane
62 | fastlane/report.xml
63 | fastlane/Preview.html
64 | fastlane/screenshots
65 | fastlane/test_output
66 | fastlane/readme.md
67 |
68 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # hikvision-android
2 | > hikvision android sdk,海康威视安卓二次开发sdk
3 |
4 | 具体说明详见:
5 | [海康威视hikvision SDK二次开发](https://ghostsf.com/hikvision)
--------------------------------------------------------------------------------
/app/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/.DS_Store
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | release
3 | debug
4 | *.iml
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 19
5 | buildToolsVersion '26.0.2'
6 |
7 | defaultConfig {
8 | applicationId "com.demo.sdk6x"
9 | minSdkVersion 8
10 | targetSdkVersion 18
11 | }
12 |
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile 'com.android.support:support-v4:19.1.0'
23 | compile files('libs/MCRSDK.jar')
24 | compile files('libs/PlayerSDK.jar')
25 | compile files('libs/vmsnetsdk.jar')
26 | compile files('libs/xUtils-2.6.14.jar')
27 | }
28 |
--------------------------------------------------------------------------------
/app/libs/MCRSDK.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/libs/MCRSDK.jar
--------------------------------------------------------------------------------
/app/libs/PlayerSDK.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/libs/PlayerSDK.jar
--------------------------------------------------------------------------------
/app/libs/vmsnetsdk.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/libs/vmsnetsdk.jar
--------------------------------------------------------------------------------
/app/libs/xUtils-2.6.14.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/libs/xUtils-2.6.14.jar
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
49 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
62 |
65 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/app/DemoApp.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.app;
2 |
3 | import com.hik.mcrsdk.MCRSDK;
4 | import com.hik.mcrsdk.rtsp.RtspClient;
5 | import com.hikvision.vmsnetsdk.VMSNetSDK;
6 |
7 | import android.app.Application;
8 | import android.content.Context;
9 | import android.net.wifi.WifiManager;
10 |
11 | /**
12 | * Application 类
13 | * @author zhoudaihui
14 | *
15 | */
16 | public class DemoApp extends Application {
17 | private static DemoApp ins;
18 |
19 | @Override
20 | public void onCreate() {
21 | super.onCreate();
22 | ins = this;
23 | System.loadLibrary("gnustl_shared");
24 | MCRSDK.init();
25 | RtspClient.initLib();
26 | MCRSDK.setPrint(1, null);
27 | VMSNetSDK.getInstance().openLog(true);
28 | }
29 |
30 | public static DemoApp getIns() {
31 | return ins;
32 | }
33 |
34 | /**
35 | * 获取登录设备mac地址
36 | *
37 | * @return
38 | */
39 | public String getMacAddr()
40 | {
41 | WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
42 | String mac = wm.getConnectionInfo().getMacAddress();
43 | return mac == null ? "" : mac;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/callback/MsgCallback.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package com.demo.sdk6x.callback;
5 |
6 | /**
7 | * 消息回调接口
8 | * @author zhoudaihui
9 | *
10 | */
11 | public interface MsgCallback {
12 | /**
13 | * @param msgId 消息id
14 | * @param data 回调返回的数据
15 | */
16 | void onMsg(int msgId, Object data);
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/callback/MsgIds.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package com.demo.sdk6x.callback;
5 |
6 | /**
7 | * 消息id常量类
8 | *
9 | * @author zhoudaihui
10 | *
11 | */
12 | public interface MsgIds {
13 | /**
14 | * 获取控制中心列表成功
15 | */
16 | int GET_C_F_NONE_SUC = 0x00;
17 | /**
18 | * 获取控制中心列表失败
19 | */
20 | int GET_C_F_NONE_FAIL = 0x01;
21 | /**
22 | * 调用getControlUnitList失败
23 | */
24 | int GET_CU_F_CU_FAIL = 0x02;
25 | /**
26 | * 调用getRegionListFromCtrlUnit失败
27 | */
28 | int GET_R_F_C_FAIL = 0x03;
29 | /**
30 | * 调用getCameraListFromCtrlUnit失败
31 | */
32 | int GET_C_F_C_FAIL = 0x04;
33 | /**
34 | * 从控制中心获取下级资源列表成功
35 | */
36 | int GET_SUB_F_C_SUC = 0x05;
37 | /**
38 | * 从控制中心获取下级资源列表成失败
39 | */
40 | int GET_SUB_F_C_FAIL = 0x06;
41 | /**
42 | * 调用getRegionListFromRegion失败
43 | */
44 | int GET_R_F_R_FAIL = 0x07;
45 | /**
46 | * 调用getCameraListFromRegion失败
47 | */
48 | int GET_C_F_R_FAIL = 0x08;
49 | /**
50 | * 从区域获取下级列表成功
51 | */
52 | int GET_SUB_F_R_SUC = 0x09;
53 | /**
54 | * 从区域获取下级列表失败
55 | */
56 | int GET_SUB_F_R_FAILED = 0x0A;
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/constants/Constants.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.constants;
2 |
3 | public final class Constants {
4 | private Constants() {
5 | }
6 |
7 | /**
8 | * 日志tag名
9 | */
10 | public static String LOG_TAG = "TFNTEST";
11 |
12 | /**
13 | * Intent key常量
14 | */
15 | public static interface IntentKey {
16 | /**
17 | * 控制中心id
18 | */
19 | String CONTROL_UNIT_ID = "control_unit_id";
20 | /**
21 | * 区域id
22 | */
23 | String REGION_ID = "region_id";
24 | /**
25 | * 监控点id
26 | */
27 | String CAMERA_ID = "camera_id";
28 | /** 设备ID*/
29 | String DEVICE_ID = "device_id";
30 | }
31 |
32 | public static interface Resource {
33 | /**
34 | * 控制中心
35 | */
36 | int TYPE_CTRL_UNIT = 1;
37 | /**
38 | * 区域
39 | */
40 | int TYPE_REGION = 2;
41 | /**
42 | * 未知
43 | */
44 | int TYPE_UNKNOWN = 3;
45 | }
46 |
47 | /**
48 | * 登录逻辑相关常量
49 | */
50 | public static interface Login {
51 |
52 | /**
53 | * 显示进度
54 | */
55 | int SHOW_LOGIN_PROGRESS = 2;
56 | /**
57 | * 取消进度提示
58 | */
59 | int CANCEL_LOGIN_PROGRESS = 3;
60 |
61 | /**
62 | * 登录成功
63 | */
64 | int LOGIN_SUCCESS = 4;
65 | /**
66 | * 登录失败
67 | */
68 | int LOGIN_FAILED = 5;
69 | /**
70 | * 登录失败,携带原因码
71 | */
72 | int LOGIN_FAIL_WITH_CODE = 6;
73 | /**
74 | * 需要显示验证码
75 | */
76 | int LOGIN_NEED_VERIFCODE = 7;
77 | /**
78 | * 验证码错误
79 | */
80 | int LOGIN_CHECK_FAIL_VERIFYCODE_ERR = 8;
81 | /**
82 | * 验证码无效
83 | */
84 | int LOGIN_CHECK_FAIL_VERIFYCODE_INVALIDE = 9;
85 | }
86 |
87 |
88 | public interface LoginCode{
89 | int SUCCESS_LOGIN = 200;
90 | int SUCCESS_CODE_FIRST_LOGIN = 20030;
91 | int SUCCESS_CODE_PWD_WEAK = 20031;
92 | int SUCCESS_CODE_PWD_STALE = 20032;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/data/Config.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.data;
2 |
3 | import com.demo.sdk6x.app.DemoApp;
4 |
5 | import android.content.Context;
6 | import android.content.SharedPreferences;
7 |
8 | public final class Config {
9 | private static Config ins = null;
10 | private SharedPreferences sp;
11 | /**
12 | * 配置文件文件名
13 | */
14 | private static final String CONFIG_FILE_NAME = "demo_conf";
15 | /**
16 | * 服务器地址
17 | */
18 | private static final String SERVER_ADDR = "server_addr";
19 |
20 | /**
21 | * 默认登录地址,这个地址是我们公司测试地址,开发者可以根据实际情况进行修改
22 | */
23 | private static final String DEF_SERVER = "http://60.191.94.170:8086";
24 |
25 | private Config() {
26 | sp = DemoApp.getIns().getSharedPreferences(CONFIG_FILE_NAME, Context.MODE_PRIVATE);
27 | }
28 |
29 | public static Config getIns() {
30 | if (null == ins) {
31 | ins = new Config();
32 | }
33 | return ins;
34 | }
35 |
36 | /**
37 | * 设置服务器地址
38 | *
39 | * @param serverAdrr
40 | * @since V1.0
41 | */
42 | public void setServerAddr(String serverAdrr) {
43 | sp.edit().putString(SERVER_ADDR, serverAdrr).commit();
44 | }
45 |
46 | /**
47 | * 获取服务器地址
48 | *
49 | * @return
50 | * @since V1.0
51 | */
52 | public String getServerAddr() {
53 | return sp.getString(SERVER_ADDR, DEF_SERVER);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/data/LiveCameraInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @ProjectName iVMS-5060_V3.0
3 | * @Copyright HangZhou Hikvision System Technology Co.,Ltd. All Right Reserved
4 | *
5 | * @FileName CameraID.java
6 | * @Description 这里对文件进行描述
7 | *
8 | * @author mlianghua
9 | * @data Jun 28, 2012
10 | *
11 | * @note 这里写本文件的详细功能描述和注释
12 | * @note 历史记录
13 | *
14 | * @warning 这里写本文件的相关警告
15 | */
16 | package com.demo.sdk6x.data;
17 |
18 | import com.hikvision.vmsnetsdk.CameraInfoEx;
19 | import com.hikvision.vmsnetsdk.RealPlayURL;
20 |
21 | /**
22 | * 在此对类做相应的描述
23 | *
24 | * @author mlianghua
25 | * @Data Jun 28, 2012
26 | */
27 | public class LiveCameraInfo {
28 |
29 | /**
30 | * 监控点ID
31 | */
32 | private String mCameraId = "";
33 |
34 | /**
35 | * 监控点名字
36 | */
37 | private String mCameraName = "";
38 |
39 | /**
40 | * 设备ID
41 | */
42 | private String mDeviceId = "";
43 |
44 | /**
45 | * 监控点RtspUrl
46 | */
47 | private RealPlayURL mRtspUrl = null;
48 |
49 | /**
50 | * 云台端口
51 | */
52 | private int mPTZPort = 0;
53 |
54 | /**
55 | * 云台服务器地址
56 | */
57 | private String mPTZServer = "";
58 |
59 | /**
60 | * 级联标识,0-非级联,1-级联
61 | */
62 | private int cascadeFlag = 0;
63 |
64 | /**
65 | * 设备的网域ID
66 | */
67 | private int deviceNetID = 0;
68 |
69 | /**
70 | * 获取监控点Rtsp Url.
71 | *
72 | * @return the mRtspUrl
73 | */
74 | public RealPlayURL getmRtspUrl() {
75 | return mRtspUrl;
76 | }
77 |
78 | /**
79 | * 设置监控点Rtsp Url.
80 | *
81 | * @param rtspUrl the mRtspUrl to set.
82 | */
83 | public void setmRtspUrl(RealPlayURL rtspUrl) {
84 | mRtspUrl = rtspUrl;
85 | }
86 |
87 | /**
88 | * 获取监控点 Name.
89 | *
90 | * @return the mCameraID
91 | */
92 | public String getmCameraId() {
93 | return mCameraId;
94 | }
95 |
96 | /**
97 | * 设置监控点 Name.
98 | *
99 | * @param cameraId the mCameraID to set
100 | */
101 | public void setmCameraId(String cameraId) {
102 | mCameraId = cameraId;
103 | }
104 |
105 | /**
106 | * 获取监控点 Name.
107 | *
108 | * @return the mCameraName
109 | */
110 | public String getmCameraName() {
111 | return mCameraName;
112 | }
113 |
114 | /**
115 | * 设置监控点 Name.
116 | *
117 | * @param cameraName the mCameraName to set
118 | */
119 | public void setmCameraName(String cameraName) {
120 | mCameraName = cameraName;
121 | }
122 |
123 | public String getDeviceId() {
124 | return mDeviceId;
125 | }
126 |
127 | public void setDeviceId(String mDeviceId) {
128 | this.mDeviceId = mDeviceId;
129 | }
130 |
131 | public void setPTZPort(int ptzPort) {
132 | mPTZPort = ptzPort;
133 | }
134 |
135 | public int getPTZPort() {
136 | return mPTZPort;
137 | }
138 |
139 | public void setPTZServer(String ptzServer) {
140 | mPTZServer = ptzServer;
141 | }
142 |
143 | public String getPTZServer() {
144 | return mPTZServer;
145 | }
146 |
147 | public int getCascadeFlag() {
148 | return cascadeFlag;
149 | }
150 |
151 | public void setCascadeFlag(int cascadeFlag) {
152 | this.cascadeFlag = cascadeFlag;
153 | }
154 |
155 | public int getDeviceNetID() {
156 | return deviceNetID;
157 | }
158 |
159 | public void setDeviceNetID(int deviceNetID) {
160 | this.deviceNetID = deviceNetID;
161 | }
162 |
163 | /**
164 | * 设置参数
165 | *
166 | * @param cameraInfoEx
167 | */
168 | public void setParams(CameraInfoEx cameraInfoEx) {
169 | // TODO Auto-generated method stub
170 | setmCameraId(cameraInfoEx.getId());
171 | setmCameraName(cameraInfoEx.getName());
172 | setDeviceId(cameraInfoEx.getDeviceId());
173 | setPTZPort(cameraInfoEx.getAcsPort());
174 | setPTZServer(cameraInfoEx.getAcsIP());
175 | setCascadeFlag(cameraInfoEx.getCascadeFlag());
176 | setDeviceNetID(cameraInfoEx.getDeviceNetId());
177 | }
178 |
179 | }
180 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/data/TempData.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.data;
2 |
3 | import com.hikvision.vmsnetsdk.CameraInfo;
4 | import com.hikvision.vmsnetsdk.CameraInfoEx;
5 | import com.hikvision.vmsnetsdk.ServInfo;
6 | import com.hikvision.vmsnetsdk.netLayer.msp.cameraInfo.CameraDetailInfo;
7 |
8 | public final class TempData {
9 | private static TempData ins = new TempData();
10 | public static TempData getIns() {
11 | return ins;
12 | }
13 | /**
14 | * 登录返回的数据
15 | */
16 | private ServInfo loginData;
17 |
18 | /**
19 | * 监控点信息,用作临时传递数据用
20 | */
21 | private CameraInfo cameraInfo;
22 |
23 | private CameraInfoEx cameraInfoEx;
24 |
25 | public static TempData getInstance() {
26 | return ins;
27 | }
28 |
29 | /**
30 | * 设置登录成功返回的信息
31 | * @param loginData
32 | * @since V1.0
33 | */
34 | public void setLoginData(ServInfo loginData) {
35 | this.loginData = loginData;
36 | }
37 |
38 | /**
39 | * 获取登录成功返回的信息
40 | * @return
41 | * @since V1.0
42 | */
43 | public ServInfo getLoginData() {
44 | return loginData;
45 | }
46 |
47 | /**
48 | * 保存监控点信息
49 | * @param cameraInfo
50 | * @since V1.0
51 | */
52 | public void setCameraInfo(CameraInfo cameraInfo) {
53 | this.cameraInfo = cameraInfo;
54 | }
55 |
56 | /**
57 | * 获取监控点信息
58 | * @return
59 | * @since V1.0
60 | */
61 | public CameraInfo getCameraInfo() {
62 | return cameraInfo;
63 | }
64 |
65 |
66 | public void setCameraInfoEx(CameraInfoEx cameraInfoEx) {
67 | this.cameraInfoEx = cameraInfoEx;
68 | }
69 |
70 | public CameraInfoEx getCameraInfoEx() {
71 | return cameraInfoEx;
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/listviewlayout/ListViewForScrollView.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.listviewlayout;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.ListView;
6 |
7 | public class ListViewForScrollView extends ListView {
8 |
9 | public ListViewForScrollView(Context context) {
10 | super(context);
11 | // TODO Auto-generated constructor stub
12 | }
13 |
14 | public ListViewForScrollView(Context context, AttributeSet attrs,
15 | int defStyle) {
16 | super(context, attrs, defStyle);
17 | // TODO Auto-generated constructor stub
18 | }
19 |
20 | public ListViewForScrollView(Context context, AttributeSet attrs) {
21 | super(context, attrs);
22 | // TODO Auto-generated constructor stub
23 | }
24 |
25 | @Override
26 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
27 | // TODO Auto-generated method stub
28 | int mExpandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
29 | super.onMeasure(widthMeasureSpec, mExpandSpec);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/live/ConstantLive.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.live;
2 |
3 | /**
4 | * 预览模块用到的常量
5 | *
6 | * @author huangweifeng
7 | * @Data 2013-10-21
8 | */
9 | public class ConstantLive {
10 |
11 | private static final int ERR_BASE = 10000;
12 | /**
13 | * 取流成功
14 | * */
15 | public static final int RTSP_SUCCESS = ERR_BASE;
16 | /**
17 | * 启动播放失败
18 | **/
19 | public static final int START_OPEN_FAILED = ERR_BASE + 1;
20 | /**
21 | * 播放成功
22 | * */
23 | public static final int PLAY_DISPLAY_SUCCESS = ERR_BASE + 2;
24 | /**
25 | * 停止成功
26 | * */
27 | public static final int STOP_SUCCESS = ERR_BASE + 3;
28 | /**
29 | * 播放库句柄不可用
30 | * */
31 | public static final int PLAYER_HANDLE_NULL = ERR_BASE + 4;
32 | /**
33 | * 播放库端口不可用
34 | * */
35 | public static final int PLAYER_PORT_UNAVAILABLE = ERR_BASE + 5;
36 | /**
37 | * RTSP链接失败
38 | * */
39 | public static final int RTSP_FAIL = ERR_BASE + 6;
40 | /**
41 | * 获取OSD时间失败
42 | * */
43 | public static final int GET_OSD_TIME_FAIL = ERR_BASE + 7;
44 | /**
45 | * SD卡不可用
46 | * */
47 | public static final int SD_CARD_UN_USEABLE = ERR_BASE + 8;
48 | /**
49 | * SD卡空间不足
50 | * */
51 | public static final int SD_CARD_SIZE_NOT_ENOUGH = ERR_BASE + 9;
52 | /**
53 | * 非播放状态不能抓拍
54 | */
55 | public static final int CAPTURE_FAILED_NPLAY_STATE = ERR_BASE + 10;
56 | /**
57 | * 非播放状态不能录像
58 | */
59 | public static final int RECORD_FAILED_NPLAY_STATE = ERR_BASE + 11;
60 | /**
61 | * 非播放状态不能开启音频
62 | */
63 | public static final int AUDIO_START_FAILED_NPLAY_STATE = ERR_BASE + 12;
64 | /**
65 | * 非播放状态不能关闭音频
66 | */
67 | public static final int AUDIO_STOP_FAILED_NPLAY_STATE = ERR_BASE + 13;
68 | /**
69 | * 从MAG取流标签
70 | * */
71 | public static final int MAG = 2;
72 | /**
73 | * 主码流标签
74 | */
75 | public static final int MAIN_STREAM = 0;
76 | /**
77 | * 子码流标签
78 | * */
79 | public static final int SUB_STREAM = 1;
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/live/LiveActivity.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.live;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Activity;
5 | import android.app.AlertDialog;
6 | import android.content.DialogInterface;
7 | import android.os.Bundle;
8 | import android.os.Handler;
9 | import android.os.Message;
10 | import android.text.TextUtils;
11 | import android.util.Log;
12 | import android.view.SurfaceHolder;
13 | import android.view.SurfaceHolder.Callback;
14 | import android.view.SurfaceView;
15 | import android.view.View;
16 | import android.view.View.OnClickListener;
17 | import android.widget.Button;
18 | import android.widget.ProgressBar;
19 | import android.widget.RadioGroup;
20 | import android.widget.RadioGroup.OnCheckedChangeListener;
21 | import android.widget.RelativeLayout;
22 |
23 | import com.demo.sdk6x.R;
24 | import com.demo.sdk6x.constants.Constants;
25 | import com.demo.sdk6x.data.Config;
26 | import com.demo.sdk6x.data.TempData;
27 | import com.demo.sdk6x.utils.DebugLog;
28 | import com.demo.sdk6x.utils.UIUtil;
29 | import com.demo.sdk6x.utils.UtilAudioPlay;
30 | import com.demo.sdk6x.utils.UtilFilePath;
31 | import com.hik.mcrsdk.rtsp.LiveInfo;
32 | import com.hik.mcrsdk.rtsp.RtspClient;
33 | import com.hikvision.vmsnetsdk.CameraInfo;
34 | import com.hikvision.vmsnetsdk.CameraInfoEx;
35 | import com.hikvision.vmsnetsdk.RealPlayURL;
36 | import com.hikvision.vmsnetsdk.ServInfo;
37 | import com.hikvision.vmsnetsdk.VMSNetSDK;
38 | import com.hikvision.vmsnetsdk.netLayer.msp.deviceInfo.DeviceInfo;
39 |
40 | import java.util.ArrayList;
41 | import java.util.List;
42 | import java.util.Random;
43 |
44 | /**
45 | * 预览
46 | *
47 | * @author xiadaidai
48 | * @Data 2015-06-03
49 | */
50 | public class LiveActivity extends Activity implements OnClickListener, OnCheckedChangeListener, Callback, LiveCallBack
51 | {
52 | private static final String TAG = "LiveActivity";
53 |
54 | /**
55 | * 开始播放按钮
56 | */
57 | private Button mStartBtn;
58 |
59 | /**
60 | * 停止播放按钮
61 | */
62 | private Button mStopBtn;
63 |
64 | /**
65 | * 抓拍按钮
66 | */
67 | private Button mCaptureBtn;
68 |
69 | /**
70 | * 录像按钮
71 | */
72 | private Button mRecordBtn;
73 |
74 | /**
75 | * 音频按钮
76 | */
77 | private Button mAudioBtn;
78 |
79 | /**
80 | * 码流切换
81 | */
82 | private RadioGroup mRadioGroup;
83 |
84 | /**
85 | * 码流类型
86 | */
87 | private int mStreamType = -1;
88 |
89 | /**
90 | * 通过VMSNetSDK返回的预览地址对象
91 | */
92 | private RealPlayURL mRealPlayURL;
93 |
94 | /**
95 | * 登录设备的用户名
96 | */
97 | private String mName;
98 |
99 | /**
100 | * 登录设备的密码
101 | */
102 | private String mPassword;
103 |
104 | /**
105 | * 控制层对象
106 | */
107 | private LiveControl mLiveControl;
108 |
109 | /**
110 | * 播放视频的控件对象
111 | */
112 | private SurfaceView mSurfaceView;
113 |
114 | /**
115 | * 创建取流等待bar
116 | */
117 | private ProgressBar mProgressBar;
118 |
119 | /**
120 | * 创建消息对象
121 | */
122 | private Handler mMessageHandler = new MyHandler();
123 |
124 | /**
125 | * 音频是否开启
126 | */
127 | private boolean mIsAudioOpen = false;
128 |
129 | /**
130 | * 是否正在录像
131 | */
132 | private boolean mIsRecord;
133 |
134 | /**
135 | * 播放流量
136 | */
137 | private long mStreamRate = 0;
138 |
139 | /**
140 | * 监控点信息对象
141 | */
142 | private CameraInfo cameraInfo;
143 |
144 | /**
145 | * 云台控制界面布局区域
146 | */
147 | private RelativeLayout cloudCtrlArea;
148 |
149 | /**
150 | * 云台控制按钮
151 | */
152 | private Button startCtrlBtn;
153 |
154 | /**
155 | * 停止云台控制按钮
156 | */
157 | private Button stopCtrlBtn;
158 |
159 | /**
160 | * 云台控制对话框
161 | */
162 | private AlertDialog mDialog;
163 |
164 | private String mDeviceID = "";
165 |
166 | private VMSNetSDK mVmsNetSDK = null;
167 |
168 | private ServInfo mServInfo;
169 |
170 | private String mCameraID = null;
171 |
172 | private CameraInfoEx cameraInfoEx;
173 |
174 | /** RTSP sdk句柄 */
175 | private RtspClient mRtspHandle = null;
176 |
177 | /**
178 | * 获取监控点详情结果
179 | */
180 | private boolean getCameraDetailInfoResult = false;
181 |
182 | /**
183 | * 获取设备详情结果
184 | */
185 | private boolean getDeviceInfoResult = false;
186 |
187 | /** 服务器校验时的token */
188 | private String mToken = null;
189 |
190 | private DeviceInfo deviceInfo;
191 |
192 | /**
193 | * 用户能力集,1--预览 2--回放 3--地理位置矫正 4--云台控制
194 | */
195 | private List mUserCap;
196 |
197 | /**
198 | * 云台控制
199 | */
200 | private static final int PTZ_CONTROL = 4;
201 |
202 | @Override
203 | protected void onCreate(Bundle savedInstanceState)
204 | {
205 | super.onCreate(savedInstanceState);
206 | setContentView(R.layout.live_activity);
207 |
208 | initData();
209 |
210 | initUI();
211 |
212 | }
213 |
214 | /**
215 | * 初始化网络库和控制层对象
216 | *
217 | * @since V1.0
218 | */
219 | private void initData()
220 | {
221 | mServInfo = TempData.getIns().getLoginData();
222 |
223 | mRealPlayURL = new RealPlayURL();
224 |
225 | mLiveControl = new LiveControl();
226 | mLiveControl.setLiveCallBack(this);
227 |
228 | cameraInfo = TempData.getIns().getCameraInfo();
229 |
230 | mCameraID = cameraInfo.getId();
231 |
232 | cameraInfoEx = new CameraInfoEx();
233 | cameraInfoEx.setId(mCameraID);
234 |
235 | mVmsNetSDK = VMSNetSDK.getInstance();
236 | if (mVmsNetSDK == null)
237 | {
238 | Log.e(Constants.LOG_TAG, "mVmsNetSDK is null");
239 | return;
240 | }
241 |
242 | String serAddr = Config.getIns().getServerAddr();
243 | String sessionid = mServInfo.getSessionID();
244 |
245 | getCameraDetailInfo(serAddr, sessionid);
246 |
247 | // liveCameraInfo.setParams(cameraInfoEx);
248 | // RTSP SDK
249 | mRtspHandle = RtspClient.getInstance();
250 | if (null == mRtspHandle)
251 | {
252 | Log.e(Constants.LOG_TAG, "initialize:" + "RealPlay mRtspHandle is null!");
253 | return;
254 | }
255 |
256 | }
257 |
258 | /**
259 | * 获取监控点详情方法
260 | *
261 | * @param serAddr 服务器地址
262 | * @param sessionid 会话ID
263 | */
264 | private void getCameraDetailInfo(final String serAddr, final String sessionid)
265 | {
266 | new Thread(new Runnable()
267 | {
268 | @Override
269 | public void run()
270 | {
271 | getCameraDetailInfoResult =
272 | LiveActivity.this.mVmsNetSDK.getCameraInfoEx(serAddr, sessionid, mCameraID, cameraInfoEx);
273 | Log.i(Constants.LOG_TAG, "result is :" + getCameraDetailInfoResult);
274 |
275 | mDeviceID = cameraInfoEx.getDeviceId();
276 | Log.i(Constants.LOG_TAG, "mDeviceID is :" + mDeviceID);
277 | deviceInfo = new DeviceInfo();
278 |
279 | // 获取设备信息
280 | getDeviceInfoResult =
281 | LiveActivity.this.mVmsNetSDK.getDeviceInfo(serAddr, sessionid, mDeviceID, deviceInfo);
282 | if (!getDeviceInfoResult || null == deviceInfo || TextUtils.isEmpty(deviceInfo.getLoginName())
283 | || TextUtils.isEmpty(deviceInfo.getLoginPsw()))
284 | {
285 | deviceInfo.setLoginName("admin");
286 | deviceInfo.setLoginPsw("12345");
287 | }
288 | mName = deviceInfo.getLoginName();
289 | mPassword = deviceInfo.getLoginPsw();
290 |
291 | DebugLog.info(Constants.LOG_TAG,
292 | "ret is :" + getDeviceInfoResult + "----------------" + deviceInfo.getDeviceName() + "--------"
293 | + "deviceLoginName is " + mName + "---" + "deviceLoginPassword is " + mPassword + "-----"
294 | + "deviceID is " + mDeviceID);
295 | }
296 | }).start();
297 |
298 | }
299 |
300 | /**
301 | * 初始化控件
302 | *
303 | * @since V1.0
304 | */
305 | private void initUI()
306 | {
307 | mStartBtn = (Button)findViewById(R.id.liveStartBtn);
308 | mStartBtn.setOnClickListener(this);
309 | mStopBtn = (Button)findViewById(R.id.liveStopBtn);
310 | mStopBtn.setOnClickListener(this);
311 | mCaptureBtn = (Button)findViewById(R.id.liveCaptureBtn);
312 | mCaptureBtn.setOnClickListener(this);
313 |
314 | mRecordBtn = (Button)findViewById(R.id.liveRecordBtn);
315 | mRecordBtn.setOnClickListener(this);
316 |
317 | mAudioBtn = (Button)findViewById(R.id.liveAudioBtn);
318 | mAudioBtn.setOnClickListener(this);
319 |
320 | mRadioGroup = (RadioGroup)findViewById(R.id.radioGroup);
321 | mRadioGroup.setOnCheckedChangeListener(this);
322 | mRadioGroup.check(R.id.subRadio);
323 | mStreamType = ConstantLive.SUB_STREAM;
324 |
325 | mSurfaceView = (SurfaceView)findViewById(R.id.surfaceView);
326 | mSurfaceView.getHolder().addCallback(this);
327 |
328 | mProgressBar = (ProgressBar)findViewById(R.id.liveProgressBar);
329 | mProgressBar.setVisibility(View.INVISIBLE);
330 |
331 | cloudCtrlArea = (RelativeLayout)findViewById(R.id.cloud_area);
332 | // 云台控制需要根据权限来显示
333 | mUserCap = new ArrayList();
334 | mUserCap = cameraInfo.getUserCapability();
335 | if (mUserCap.contains(PTZ_CONTROL))
336 | {
337 | cloudCtrlArea.setVisibility(View.VISIBLE);
338 |
339 | startCtrlBtn = (Button)findViewById(R.id.start_ctrl);
340 | stopCtrlBtn = (Button)findViewById(R.id.stop_ctrl);
341 | startCtrlBtn.setOnClickListener(this);
342 | stopCtrlBtn.setOnClickListener(this);
343 | }
344 | else
345 | {
346 | cloudCtrlArea.setVisibility(View.GONE);
347 | }
348 | }
349 |
350 | @Override
351 | public void onCheckedChanged(RadioGroup group, int checkedId)
352 | {
353 | if (group.getId() == R.id.radioGroup)
354 | {
355 | switch (group.getCheckedRadioButtonId())
356 | {
357 | case R.id.mainRadio:
358 | mStreamType = ConstantLive.MAIN_STREAM;
359 | break;
360 |
361 | case R.id.subRadio:
362 | mStreamType = ConstantLive.SUB_STREAM;
363 | break;
364 |
365 | case R.id.magRadio:
366 | mStreamType = ConstantLive.MAG;
367 | break;
368 | }
369 | }
370 | }
371 |
372 | @Override
373 | public void onClick(View v)
374 | {
375 | switch (v.getId())
376 | {
377 | case R.id.liveStartBtn:
378 | startBtnOnClick();
379 | break;
380 |
381 | case R.id.liveStopBtn:
382 | stopBtnOnClick();
383 | break;
384 |
385 | case R.id.liveCaptureBtn:
386 | captureBtnOnClick();
387 | break;
388 |
389 | case R.id.liveRecordBtn:
390 | recordBtnOnClick();
391 | break;
392 |
393 | case R.id.liveAudioBtn:
394 | audioBtnOnClick();
395 | break;
396 | case R.id.start_ctrl:
397 | startCloudCtrl();
398 | break;
399 | case R.id.stop_ctrl:
400 | stopCloudCtrl();
401 | break;
402 | default:
403 | break;
404 | }
405 | }
406 |
407 | /**
408 | * 开始云台控制,弹出控制界面
409 | */
410 | private void startCloudCtrl()
411 | {
412 |
413 | final int[] gestureIDs = {1, 2, 3, 4, 11, 12, 13, 14, 7, 8, 9, 10};
414 | String[] datas =
415 | {"云台转上", "云台转下", "云台转左", "云台转右", "云台左上", "云台右上", "云台左下", "云台右下", "镜头拉近", "镜头拉远", "镜头近焦", "镜头远焦"};
416 | mDialog = new AlertDialog.Builder(this).setSingleChoiceItems(datas, 0, new DialogInterface.OnClickListener()
417 | {
418 |
419 | @Override
420 | public void onClick(DialogInterface dialog, int which)
421 | {
422 | mDialog.dismiss();
423 | sendCtrlCmd(gestureIDs[which]);
424 | }
425 | }).create();
426 | mDialog.show();
427 | }
428 |
429 | /**
430 | * 发送云台控制命令
431 | *
432 | * @param gestureID 1-云台转上 、2-云台转下 、3-云台转左 、4-云台转右、 11-云台左上 、12-云台右上 13-云台左下 、14-云台右下、7-镜头拉近、8-镜头拉远、9-镜头近焦、10-镜头远焦
433 | */
434 | private void sendCtrlCmd(final int gestureID)
435 | {
436 | new Thread(new Runnable()
437 | {
438 |
439 | @Override
440 | public void run()
441 | {
442 | String sessionID = mServInfo.getSessionID();
443 | // 云台控制速度 取值范围(1-10)
444 | int speed = 5;
445 | Log.i(Constants.LOG_TAG, "ip:" + cameraInfoEx.getAcsIP() + ",port:" + cameraInfoEx.getAcsPort()
446 | + ",isPTZControl:" + mUserCap.contains(PTZ_CONTROL));
447 | // 发送控制命令
448 | boolean ret =
449 | LiveActivity.this.mVmsNetSDK.sendStartPTZCmd(cameraInfoEx.getAcsIP(),
450 | cameraInfoEx.getAcsPort(),
451 | sessionID,
452 | mCameraID,
453 | gestureID,
454 | speed,
455 | 600,cameraInfoEx.getCascadeFlag()+"");
456 | Log.i(Constants.LOG_TAG, "sendStartPTZCmd ret:" + ret);
457 | }
458 | }).start();
459 | }
460 |
461 | /**
462 | * 停止云台控制
463 | */
464 | private void stopCloudCtrl()
465 | {
466 | new Thread(new Runnable()
467 | {
468 |
469 | @Override
470 | public void run()
471 | {
472 | String sessionID = mServInfo.getSessionID();
473 | boolean ret =
474 | LiveActivity.this.mVmsNetSDK.sendStopPTZCmd(cameraInfoEx.getAcsIP(),
475 | cameraInfoEx.getAcsPort(),
476 | sessionID,
477 | mCameraID,cameraInfoEx.getCascadeFlag()+"");
478 | Log.i(Constants.LOG_TAG, "stopPtzCmd sent,ret:" + ret);
479 | }
480 | }).start();
481 | }
482 |
483 | /**
484 | * 启动播放 void
485 | *
486 | * @since V1.0
487 | */
488 | private void startBtnOnClick()
489 | {
490 | mProgressBar.setVisibility(View.VISIBLE);
491 | new Thread()
492 | {
493 | @Override
494 | public void run()
495 | {
496 | super.run();
497 | mLiveControl.setLiveParams(getPlayUrl(mStreamType), mName, mPassword);
498 |
499 | if (mLiveControl.LIVE_PLAY == mLiveControl.getLiveState())
500 | {
501 | mLiveControl.stop();
502 | }
503 |
504 | if (mLiveControl.LIVE_INIT == mLiveControl.getLiveState())
505 | {
506 | mLiveControl.startLive(mSurfaceView);
507 | }
508 | }
509 | }.start();
510 | }
511 |
512 | /**
513 | * 该方法是获取播放地址的,当mStreamType=2时,获取的是MAG,当mStreamType =1时获取的子码流,当mStreamType = 0时获取的是主码流
514 | * 由于该方法中部分参数是监控点的属性,所以需要先获取监控点信息,具体获取监控点信息的方法见resourceActivity。
515 | *
516 | * @param streamType 2、表示MAG取流方式;1、表示子码流取流方式;0、表示主码流取流方式;
517 | * @return String 播放地址 :2、表示返回的是MAG的播放地址;1、表示返回的是子码流的播放地址;0、表示返回的是主码流的播放地址。
518 | * @since V1.0
519 | */
520 | private String getPlayUrl(int streamType)
521 | {
522 | String url = "";
523 |
524 | if (mRealPlayURL == null)
525 | {
526 | return null;
527 | }
528 |
529 | // 获取播放Token
530 | if(mServInfo.isTokenVerify()){
531 | mToken = LiveActivity.this.mVmsNetSDK.getPlayToken(mServInfo.getSessionID());
532 | DebugLog.info(Constants.LOG_TAG, "mToken is :" + mToken);
533 | }
534 | Log.d(Constants.LOG_TAG, "generateLiveUrl MagStreamSerAddr:" + mServInfo.getMagServer().getMagStreamSerAddr());
535 | Log.d(Constants.LOG_TAG, "generateLiveUrl MagStreamSerPort:" + mServInfo.getMagServer().getMagStreamSerPort());
536 | Log.d(Constants.LOG_TAG, "generateLiveUrl cameraId:" + cameraInfoEx.getId());
537 | Log.d(Constants.LOG_TAG, "generateLiveUrl token:" + mToken);
538 | Log.d(Constants.LOG_TAG, "generateLiveUrl streamType:" + streamType);
539 | Log.d(Constants.LOG_TAG, "generateLiveUrl appNetId:" + mServInfo.getAppNetId());
540 | Log.d(Constants.LOG_TAG, "generateLiveUrl deviceNetID:" + cameraInfoEx.getDeviceNetId());
541 | Log.d(Constants.LOG_TAG, "generateLiveUrl userAuthority:" + mServInfo.getUserAuthority());
542 | Log.d(Constants.LOG_TAG, "generateLiveUrl cascadeFlag:" + cameraInfoEx.getCascadeFlag());
543 | Log.d(Constants.LOG_TAG, "generateLiveUrl internet:" + mServInfo.isInternet());
544 |
545 | LiveInfo liveInfo = new LiveInfo();
546 | liveInfo.setMagIp(mServInfo.getMagServer().getMagStreamSerAddr());
547 | liveInfo.setMagPort(mServInfo.getMagServer().getMagStreamSerPort());
548 | liveInfo.setCameraIndexCode(cameraInfoEx.getId());
549 | if(mServInfo.isTokenVerify()){
550 | liveInfo.setToken(mToken);
551 | }else{
552 | liveInfo.setToken(null);
553 | }
554 |
555 | // 转码不区分主子码流
556 | liveInfo.setStreamType(streamType);
557 | liveInfo.setMcuNetID(mServInfo.getAppNetId());
558 | liveInfo.setDeviceNetID(cameraInfoEx.getDeviceNetId());
559 | liveInfo.setiPriority(mServInfo.getUserAuthority());
560 | liveInfo.setCascadeFlag(cameraInfoEx.getCascadeFlag());
561 |
562 | if (deviceInfo != null)
563 | {
564 | if (cameraInfoEx.getCascadeFlag() == LiveInfo.CASCADE_TYPE_YES)
565 | {
566 | deviceInfo.setLoginName("admin");
567 | deviceInfo.setLoginPsw("12345");
568 | }
569 | }
570 |
571 | if (mServInfo.isInternet())
572 | {
573 | liveInfo.setIsInternet(LiveInfo.NETWORK_TYPE_INTERNET);
574 | // 获取不转码地址
575 | liveInfo.setbTranscode(false);
576 | mRealPlayURL.setUrl1(mRtspHandle.generateLiveUrl(liveInfo));
577 |
578 | // 获取转码地址
579 | // 使用默认转码参数cif 128 15 h264 ps
580 | liveInfo.setbTranscode(true);
581 | mRealPlayURL.setUrl2(mRtspHandle.generateLiveUrl(liveInfo));
582 | }
583 | else
584 | {
585 | liveInfo.setIsInternet(LiveInfo.NETWORK_TYPE_LOCAL);
586 | liveInfo.setbTranscode(false);
587 | // 内网不转码
588 | mRealPlayURL.setUrl1(mRtspHandle.generateLiveUrl(liveInfo));
589 | mRealPlayURL.setUrl2("");
590 | }
591 |
592 | Log.d(Constants.LOG_TAG, "url1:" + mRealPlayURL.getUrl1());
593 | Log.d(Constants.LOG_TAG, "url2:" + mRealPlayURL.getUrl2());
594 |
595 | url = mRealPlayURL.getUrl1();
596 | if (streamType == 2 && mRealPlayURL.getUrl2() != null && mRealPlayURL.getUrl2().length() > 0)
597 | {
598 | url = mRealPlayURL.getUrl2();
599 | }
600 | Log.i(Constants.LOG_TAG, "mRTSPUrl" + url);
601 |
602 | return url;
603 | }
604 |
605 | /**
606 | * 停止播放 void
607 | *
608 | * @since V1.0
609 | */
610 | private void stopBtnOnClick()
611 | {
612 | if (null != mLiveControl)
613 | {
614 | mLiveControl.stop();
615 | }
616 | }
617 |
618 | /**
619 | * 抓拍 void
620 | *
621 | * @since V1.0
622 | */
623 | private void captureBtnOnClick()
624 | {
625 | if (null != mLiveControl)
626 | {
627 | // 随即生成一个1到10000的数字,用于抓拍图片名称的一部分,区分图片,开发者可以根据实际情况修改区分图片名称的方法
628 | int recordIndex = new Random().nextInt(10000);
629 | boolean ret =
630 | mLiveControl.capture(UtilFilePath.getPictureDirPath().getAbsolutePath(), "Picture" + recordIndex
631 | + ".jpg");
632 | if (ret)
633 | {
634 | UIUtil.showToast(LiveActivity.this, "抓拍成功");
635 | UtilAudioPlay.playAudioFile(LiveActivity.this, R.raw.paizhao);
636 | }
637 | else
638 | {
639 | UIUtil.showToast(LiveActivity.this, "抓拍失败");
640 | DebugLog.error(TAG, "captureBtnOnClick():: 抓拍失败");
641 | }
642 | }
643 | }
644 |
645 | /**
646 | * 录像 void
647 | *
648 | * @since V1.0
649 | */
650 | private void recordBtnOnClick()
651 | {
652 | if (null != mLiveControl)
653 | {
654 | if (!mIsRecord)
655 | {
656 | // 随即生成一个1到10000的数字,用于录像名称的一部分,区分图片,开发者可以根据实际情况修改区分录像名称的方法
657 | int recordIndex = new Random().nextInt(10000);
658 | boolean ret =
659 | mLiveControl.startRecord(UtilFilePath.getVideoDirPath().getAbsolutePath(), "Video" + recordIndex
660 | + ".mp4");
661 | if (ret)
662 | {
663 | UIUtil.showToast(LiveActivity.this, "启动录像成功");
664 | mIsRecord = true;
665 | mRecordBtn.setText("停止录像");
666 | }
667 | else
668 | {
669 | UIUtil.showToast(LiveActivity.this, "启动录像失败");
670 | DebugLog.error(Constants.LOG_TAG, "recordBtnOnClick():: 启动录像失败");
671 | }
672 | }
673 | else
674 | {
675 | mLiveControl.stopRecord();
676 | mIsRecord = false;
677 | UIUtil.showToast(LiveActivity.this, "停止录像成功");
678 | mRecordBtn.setText("开始录像");
679 | }
680 | }
681 | }
682 |
683 | /**
684 | * 音频 void
685 | *
686 | * @since V1.0
687 | */
688 | private void audioBtnOnClick()
689 | {
690 | if (null != mLiveControl)
691 | {
692 | if (mIsAudioOpen)
693 | {
694 | mLiveControl.stopAudio();
695 | mIsAudioOpen = false;
696 | UIUtil.showToast(LiveActivity.this, "关闭音频");
697 | mAudioBtn.setText("开启音频");
698 | }
699 | else
700 | {
701 | boolean ret = mLiveControl.startAudio();
702 | if (!ret)
703 | {
704 | mIsAudioOpen = false;
705 | UIUtil.showToast(LiveActivity.this, "开启音频失败");
706 | mAudioBtn.setText("音频");
707 | }
708 | else
709 | {
710 | mIsAudioOpen = true;
711 | // 开启音频成功,并不代表一定有声音,需要设备开启声音。
712 | UIUtil.showToast(LiveActivity.this, "开启音频成功");
713 | mAudioBtn.setText("关闭音频");
714 | }
715 | }
716 | }
717 |
718 | }
719 |
720 | @Override
721 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
722 | {
723 |
724 | }
725 |
726 | @Override
727 | public void surfaceCreated(SurfaceHolder holder)
728 | {
729 |
730 | }
731 |
732 | @Override
733 | public void surfaceDestroyed(SurfaceHolder holder)
734 | {
735 | if (null != mLiveControl)
736 | {
737 | if (mIsRecord)
738 | {
739 | mRecordBtn.setText("开始录像");
740 | mLiveControl.stopRecord();
741 | mIsRecord = false;
742 | }
743 | mLiveControl.stop();
744 | }
745 | }
746 |
747 | @Override
748 | public void onMessageCallback(int messageID)
749 | {
750 | sendMessageCase(messageID);
751 | }
752 |
753 | /**
754 | * 返回已经播放的流量 void
755 | *
756 | * @return long
757 | * @since V1.0
758 | */
759 | public long getStreamRate()
760 | {
761 | return mStreamRate;
762 | }
763 |
764 | /**
765 | * 发送消息
766 | *
767 | * @param i void
768 | * @since V1.0
769 | */
770 | private void sendMessageCase(int i)
771 | {
772 | if (null != mMessageHandler)
773 | {
774 | Message msg = Message.obtain();
775 | msg.arg1 = i;
776 | mMessageHandler.sendMessage(msg);
777 | }
778 | }
779 |
780 | /**
781 | * 消息类
782 | *
783 | * @author huangweifeng
784 | * @Data 2013-10-23
785 | */
786 | @SuppressLint("HandlerLeak")
787 | private final class MyHandler extends Handler
788 | {
789 | public void handleMessage(Message msg)
790 | {
791 | switch (msg.arg1)
792 | {
793 | case ConstantLive.RTSP_SUCCESS:
794 | UIUtil.showToast(LiveActivity.this, "启动取流成功");
795 | break;
796 |
797 | case ConstantLive.STOP_SUCCESS:
798 | UIUtil.showToast(LiveActivity.this, "停止成功");
799 | break;
800 |
801 | case ConstantLive.START_OPEN_FAILED:
802 | UIUtil.showToast(LiveActivity.this, "开启播放库失败");
803 | if (null != mProgressBar)
804 | {
805 | mProgressBar.setVisibility(View.GONE);
806 | }
807 | break;
808 |
809 | case ConstantLive.PLAY_DISPLAY_SUCCESS:
810 | UIUtil.showToast(LiveActivity.this, "播放成功");
811 | if (null != mProgressBar)
812 | {
813 | mProgressBar.setVisibility(View.GONE);
814 | }
815 | break;
816 |
817 | case ConstantLive.RTSP_FAIL:
818 | UIUtil.showToast(LiveActivity.this, "RTSP链接失败");
819 | if (null != mProgressBar)
820 | {
821 | mProgressBar.setVisibility(View.GONE);
822 | }
823 | if (null != mLiveControl)
824 | {
825 | mLiveControl.stop();
826 | }
827 | break;
828 |
829 | case ConstantLive.GET_OSD_TIME_FAIL:
830 | UIUtil.showToast(LiveActivity.this, "获取OSD时间失败");
831 | break;
832 |
833 | case ConstantLive.SD_CARD_UN_USEABLE:
834 | UIUtil.showToast(LiveActivity.this, "SD卡不可用");
835 | break;
836 |
837 | case ConstantLive.SD_CARD_SIZE_NOT_ENOUGH:
838 | UIUtil.showToast(LiveActivity.this, "SD卡空间不足");
839 | break;
840 | case ConstantLive.CAPTURE_FAILED_NPLAY_STATE:
841 | UIUtil.showToast(LiveActivity.this, "非播放状态不能抓拍");
842 | break;
843 | case ConstantLive.RECORD_FAILED_NPLAY_STATE:
844 | UIUtil.showToast(LiveActivity.this, "非播放状态不能录像");
845 | break;
846 | case ConstantLive.AUDIO_START_FAILED_NPLAY_STATE:
847 | UIUtil.showToast(LiveActivity.this, "非播放状态不能开启音频");
848 | break;
849 | }
850 | }
851 | }
852 | }
853 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/live/LiveCallBack.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.live;
2 |
3 | /**
4 | * 预览回调接口
5 | * @author huangweifeng
6 | * @Data 2013-10-21
7 | */
8 | public interface LiveCallBack {
9 | /**
10 | * 播放引擎消息回调接口
11 | *
12 | * @param message 消息
13 | * @since V1.0
14 | */
15 | public void onMessageCallback(int message);
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/live/LiveControl.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.live;
2 |
3 | import java.io.File;
4 | import java.io.FileOutputStream;
5 | import java.io.IOException;
6 | import java.nio.ByteBuffer;
7 | import java.util.Calendar;
8 | import org.MediaPlayer.PlayM4.Player;
9 | import org.MediaPlayer.PlayM4.Player.MPSystemTime;
10 | import org.MediaPlayer.PlayM4.PlayerCallBack.PlayerDisplayCB;
11 | import android.os.SystemClock;
12 | import android.util.Log;
13 | import android.view.SurfaceHolder;
14 | import android.view.SurfaceView;
15 |
16 | import com.demo.sdk6x.utils.DebugLog;
17 | import com.demo.sdk6x.utils.UtilSDCard;
18 | import com.hik.mcrsdk.rtsp.RtspClient;
19 | import com.hik.mcrsdk.rtsp.RtspClientCallback;
20 |
21 | /**
22 | * 预览控制层
23 | *
24 | * @author huangweifeng
25 | * @Data 2013-10-21
26 | */
27 | public class LiveControl implements RtspClientCallback, PlayerDisplayCB {
28 | private final String TAG = this.getClass().getSimpleName();
29 | /**
30 | * 创建播放库句柄对象
31 | */
32 | private Player mPlayerHandler;
33 | /**
34 | * 创建RTSP取流库句柄对象
35 | */
36 | private RtspClient mRtspHandler;
37 | /**
38 | * 播放库播放端口
39 | */
40 | private int mPlayerPort = -1;
41 | /**
42 | * 初始化阶段
43 | */
44 | public final int LIVE_INIT = 0;
45 | /**
46 | * 取流阶段
47 | */
48 | public final int LIVE_STREAM = 1;
49 | /**
50 | * 播放阶段
51 | */
52 | public final int LIVE_PLAY = 2;
53 | /**
54 | * 释放资源阶段
55 | */
56 | public final int LIVE_RELEASE = 3;
57 | /**
58 | * 预览状态
59 | */
60 | private int mLiveState = LIVE_INIT;
61 | /**
62 | * 播放地址的URL,支持MAG或者流媒体
63 | */
64 | private String mUrl = "";
65 | /**
66 | * 播放使用的SurfaceView对象
67 | */
68 | private SurfaceView mSurfaceView;
69 | /**
70 | * 创建RTSP引擎索引
71 | */
72 | private int mRtspEngineIndex = RtspClient.RTSPCLIENT_INVALIDATE_ENGINEID;
73 | private LiveCallBack mLiveCallBack = null;
74 | private int connectNum = 0;
75 | /**
76 | * 抓拍图片文件
77 | */
78 | private File mPictureFile = null;
79 | /**
80 | * 录像文件
81 | */
82 | private File mRecordFile = null;
83 | /**
84 | * 是否正在录像
85 | */
86 | private boolean mIsRecord = true;
87 | /**
88 | * 数据流
89 | */
90 | private ByteBuffer mStreamHeadDataBuffer;
91 | /**
92 | * 文件输出流
93 | */
94 | private FileOutputStream mRecordFileOutputStream;
95 | /**
96 | * 播放流量
97 | */
98 | private long mStreamRate = 0;
99 | /**
100 | * 设置SD卡使用限度,当小于256M时,提示SD卡内存不足,根据具体情况可以修改
101 | */
102 | private int mSDCardSize = 256 * 1024 * 1024;
103 | /**
104 | * 转封装状态
105 | */
106 | private int mTransState = -1;
107 | private String mDeviceUserName = "";
108 | private String mDevicePassword = "";
109 |
110 | /**
111 | * 构造函数
112 | *
113 | * @param context
114 | */
115 | public LiveControl() {
116 | init();
117 | }
118 |
119 | /**
120 | * 控制层初始化方法 void
121 | *
122 | * @since V1.0
123 | */
124 | public void init() {
125 | mPlayerHandler = Player.getInstance();
126 | mRtspHandler = RtspClient.getInstance();
127 | mLiveState = LIVE_INIT;
128 | }
129 |
130 | /**
131 | * 设置预览参数
132 | *
133 | * @param url 播放地址(过MAG/流媒体)
134 | * @param name 登录设备的用户名
135 | * @param password 登录设备的密码 void
136 | * @since V1.0
137 | */
138 | public void setLiveParams(String url, String name, String password) {
139 | mUrl = url;
140 | mDeviceUserName = name;
141 | mDevicePassword = password;
142 | }
143 |
144 | /**
145 | * 设置控制层回调接口
146 | *
147 | * @param liveCallBack
148 | * @since V1.0
149 | */
150 | public void setLiveCallBack(LiveCallBack liveCallBack) {
151 | mLiveCallBack = liveCallBack;
152 | }
153 |
154 | /**
155 | * 启动控制层播放
156 | *
157 | * @param surfaceView
158 | * @since V1.0
159 | */
160 | public void startLive(SurfaceView surfaceView) {
161 | if (null == surfaceView) {
162 | DebugLog.error(TAG, "startLive():: surfaceView is null");
163 | return;
164 | }
165 | mSurfaceView = surfaceView;
166 |
167 | if (LIVE_STREAM == mLiveState) {
168 | DebugLog.error(TAG, "startLive():: is palying");
169 | }
170 | startRtsp();
171 | }
172 |
173 | /**
174 | * 获取当前播放状态
175 | *
176 | * @return LIVE_INIT初始化、LIVE_STREAM取流、LIVE_PLAY播放、LIVE_RELEASE释放资源
177 | * @since V1.0
178 | */
179 | public int getLiveState() {
180 | return mLiveState;
181 | }
182 |
183 | /**
184 | * 启动RTSP开始取流
185 | *
186 | * @since V1.0
187 | */
188 | private void startRtsp() {
189 | if (null == mRtspHandler) {
190 | DebugLog.error(TAG, "startRtsp():: mRtspHandler is null");
191 | return;
192 | }
193 | mRtspEngineIndex = mRtspHandler.createRtspClientEngine(this, RtspClient.RTPRTSP_TRANSMODE);
194 | if (mRtspEngineIndex < 0) {
195 | int errorCode = mRtspHandler.getLastError();
196 | DebugLog.error("AAA", "startRtsp():: errorCode is R" + errorCode);
197 | if (null != mLiveCallBack) {
198 | mLiveCallBack.onMessageCallback(ConstantLive.RTSP_FAIL);
199 | }
200 | return;
201 | }
202 | Log.d(TAG,"mRtspEngineIndex: "+ mRtspEngineIndex + "mUrl: " + mUrl +"mDeviceUserName: " + mDeviceUserName +
203 | "mDevicePassword: " + mDevicePassword);
204 | boolean ret = mRtspHandler.startRtspProc(mRtspEngineIndex, mUrl, mDeviceUserName, mDevicePassword);
205 | if (!ret) {
206 | int errorCode = mRtspHandler.getLastError();
207 | DebugLog.error(TAG, "startRtsp():: errorCode is R" + errorCode);
208 | mRtspHandler.releaseRtspClientEngineer(mRtspEngineIndex);
209 | if (null != mLiveCallBack) {
210 | mLiveCallBack.onMessageCallback(ConstantLive.RTSP_FAIL);
211 | }
212 | return;
213 | }
214 | mLiveState = LIVE_STREAM;
215 | if (null != mLiveCallBack) {
216 | mLiveCallBack.onMessageCallback(ConstantLive.RTSP_SUCCESS);
217 | }
218 | }
219 |
220 | /**
221 | * 停止预览方法
222 | *
223 | * @since V1.0
224 | */
225 | public void stop() {
226 | if (LIVE_INIT == mLiveState) {
227 | return;
228 | }
229 |
230 | if (mIsRecord) {
231 | stopRecord();
232 | mIsRecord = false;
233 | }
234 |
235 | stopRtsp();
236 | closePlayer();
237 | if (null != mLiveCallBack) {
238 | mLiveCallBack.onMessageCallback(ConstantLive.STOP_SUCCESS);
239 | }
240 |
241 | mLiveState = LIVE_INIT;
242 | }
243 |
244 | /**
245 | * 停止RTSP
246 | *
247 | * @since V1.0
248 | */
249 | private void stopRtsp() {
250 | if (null != mRtspHandler) {
251 | if (RtspClient.RTSPCLIENT_INVALIDATE_ENGINEID != mRtspEngineIndex) {
252 | mRtspHandler.stopRtspProc(mRtspEngineIndex);
253 | mRtspHandler.releaseRtspClientEngineer(mRtspEngineIndex);
254 | mRtspEngineIndex = RtspClient.RTSPCLIENT_INVALIDATE_ENGINEID;
255 | }
256 | }
257 | }
258 |
259 | /**
260 | * 关闭播放库 void
261 | *
262 | * @since V1.0
263 | */
264 | private void closePlayer() {
265 | if (null != mPlayerHandler) {
266 | if (-1 != mPlayerPort) {
267 | boolean ret = mPlayerHandler.stop(mPlayerPort);
268 | if (!ret) {
269 | DebugLog.error(
270 | TAG,
271 | "closePlayer(): Player stop failed! errorCode is P"
272 | + mPlayerHandler.getLastError(mPlayerPort));
273 | }
274 |
275 | ret = mPlayerHandler.closeStream(mPlayerPort);
276 | if (!ret) {
277 | DebugLog.error(TAG, "closePlayer(): Player closeStream failed!");
278 | }
279 |
280 | ret = mPlayerHandler.freePort(mPlayerPort);
281 | if (!ret) {
282 | DebugLog.error(TAG, "closePlayer(): Player freePort failed!");
283 | }
284 | mPlayerPort = -1;
285 | }
286 | }
287 | }
288 |
289 | /*
290 | * handle - - 引擎id dataType - - 数据类型,决定data数据的类型,包括DATATYPE_HEADER和DATATYPE_STREAM两种类型 data -
291 | * -回调数据,分为:header数据和stream数据,由datatype作区分,header用于初始化播放库 length - - data 数据的长度 timeStamp - - 时间戳(保留) packetNo -
292 | * -rtp包号(保留) useId - - 用户数据,默认就是引擎id与handle相同
293 | */
294 |
295 | @Override
296 | public void onDataCallBack(int handle, int dataType, byte[] data, int length, int timeStamp, int packetNo, int useId) {
297 | if (mStreamRate + length >= Long.MAX_VALUE) {
298 | mStreamRate = 0;
299 | }
300 | mStreamRate += length;
301 |
302 | switch (dataType) {
303 | case RtspClient.DATATYPE_HEADER:
304 | boolean ret = processStreamHeader(data, length);
305 | if (!ret) {
306 | if (null != mLiveCallBack) {
307 | mLiveCallBack.onMessageCallback(ConstantLive.START_OPEN_FAILED);
308 | return;
309 | } else {
310 | DebugLog.error(TAG, "onDataCallBack():: mLiveCallBack is null");
311 | }
312 | } else {
313 | DebugLog.error(TAG, "MediaPlayer Header success!");
314 | }
315 | break;
316 | default:
317 | processStreamData(data, length);
318 | break;
319 | }
320 | processRecordData(dataType, data, length);
321 | }
322 |
323 | /**
324 | * 录像数据处理
325 | *
326 | * @param dataType 数据流
327 | * @param dataBuffer 数据缓存
328 | * @param dataLength 数据长度
329 | */
330 | private void processRecordData(int dataType, byte[] dataBuffer, int dataLength) {
331 | if (null == dataBuffer || dataLength == 0) {
332 | return;
333 | }
334 | if (mIsRecord) {
335 | if (RtspClient.DATATYPE_HEADER == dataType) {
336 | mStreamHeadDataBuffer = ByteBuffer.allocate(dataLength);
337 | for (int i = 0; i < dataLength; i++) {
338 | mStreamHeadDataBuffer.put(dataBuffer[i]);
339 | }
340 | } else if (RtspClient.DATATYPE_STREAM == dataType) {
341 | writeStreamData(dataBuffer, dataLength);
342 | }
343 | } else {
344 | if (-1 != mTransState) {
345 | mTransState = -1;
346 | }
347 | }
348 | }
349 |
350 | /**
351 | * 录像数据写到文件
352 | *
353 | * @param recordData 录像数据
354 | * @param length 录像数据长度
355 | * @since V1.0
356 | */
357 | private boolean writeStreamData(byte[] recordData, int length) {
358 | if (null == recordData || length <= 0) {
359 | return false;
360 | }
361 |
362 | if (null == mRecordFile) {
363 | return false;
364 | }
365 |
366 | try {
367 | if (null == mRecordFileOutputStream) {
368 | mRecordFileOutputStream = new FileOutputStream(mRecordFile);
369 | }
370 | mRecordFileOutputStream.write(recordData, 0, length);
371 | DebugLog.error(TAG, "writeStreamData() success");
372 | } catch (Exception e) {
373 | e.printStackTrace();
374 | return false;
375 | }
376 |
377 | return true;
378 | }
379 |
380 | /**
381 | * 处理数据流头
382 | *
383 | * @param data
384 | * @param len
385 | * @return boolean
386 | * @since V1.0
387 | */
388 | private boolean processStreamHeader(byte[] data, int len) {
389 | if (-1 != mPlayerPort) {
390 | closePlayer();
391 | }
392 |
393 | boolean ret = startPlayer(data, len);
394 | return ret;
395 | }
396 |
397 | /**
398 | * 开启播放库方法
399 | *
400 | * @param data
401 | * @param len
402 | * @return boolean
403 | * @since V1.0
404 | */
405 | private boolean startPlayer(byte[] data, int len) {
406 | if (null == data || 0 == len) {
407 | DebugLog.error(TAG, "startPlayer() Stream data error data is null or len is 0");
408 | return false;
409 | }
410 |
411 | if (null == mPlayerHandler) {
412 | DebugLog.error(TAG, "startPlayer(): mPlayerHandler is null!");
413 | return false;
414 | }
415 |
416 | mPlayerPort = mPlayerHandler.getPort();
417 | if (-1 == mPlayerPort) {
418 | DebugLog.error(TAG, "startPlayer(): mPlayerPort is -1");
419 | return false;
420 | }
421 |
422 | boolean ret = mPlayerHandler.setStreamOpenMode(mPlayerPort, Player.STREAM_REALTIME);
423 | if (!ret) {
424 | int tempErrorCode = mPlayerHandler.getLastError(mPlayerPort);
425 | mPlayerHandler.freePort(mPlayerPort);
426 | mPlayerPort = -1;
427 | DebugLog.error(TAG, "startPlayer(): Player setStreamOpenMode failed! errorCord is P" + tempErrorCode);
428 | return false;
429 | }
430 |
431 | ret = mPlayerHandler.openStream(mPlayerPort, data, len, 2 * 1024 * 1024);
432 | if (!ret) {
433 | DebugLog.error(TAG, "startPlayer() mPlayerHandle.openStream failed!" + "Port: " + mPlayerPort
434 | + "ErrorCode is P " + mPlayerHandler.getLastError(mPlayerPort));
435 | return false;
436 | }
437 |
438 | ret = mPlayerHandler.setDisplayCB(mPlayerPort, this);
439 | if (!ret) {
440 | DebugLog.error(
441 | TAG,
442 | "startPlayer() mPlayerHandle.setDisplayCB() failed errorCode is P"
443 | + mPlayerHandler.getLastError(mPlayerPort));
444 | return false;
445 | }
446 |
447 | if (null == mSurfaceView) {
448 | DebugLog.error(TAG, "startPlayer():: mSurfaceView is null");
449 | return false;
450 | }
451 |
452 | SurfaceHolder surfaceHolder = mSurfaceView.getHolder();
453 | if (null == surfaceHolder) {
454 | DebugLog.error(TAG, "startPlayer() mPlayer mainSurface is null!");
455 | return false;
456 | }
457 |
458 | ret = mPlayerHandler.play(mPlayerPort, surfaceHolder);
459 | if (!ret) {
460 | DebugLog.error(TAG,
461 | "startPlayer() mPlayerHandle.play failed!" + "Port: " + mPlayerPort + "PlayView Surface: "
462 | + surfaceHolder + "errorCode is P" + mPlayerHandler.getLastError(mPlayerPort));
463 | return false;
464 | }
465 |
466 | return true;
467 | }
468 |
469 | /**
470 | * 抓拍 void
471 | *
472 | * @param filePath 存放文件路径
473 | * @param picName 抓拍时文件的名称
474 | * @return true-抓拍成功,false-抓拍失败
475 | * @since V1.0
476 | */
477 | public boolean capture(String filePath, String picName) {
478 | if (!UtilSDCard.isSDCardUsable()) {
479 | if (null != mLiveCallBack) {
480 | mLiveCallBack.onMessageCallback(ConstantLive.SD_CARD_UN_USEABLE);
481 | }
482 | return false;
483 | }
484 |
485 | if (UtilSDCard.getSDCardRemainSize() <= mSDCardSize) {
486 | if (null != mLiveCallBack) {
487 | mLiveCallBack.onMessageCallback(ConstantLive.SD_CARD_SIZE_NOT_ENOUGH);
488 | }
489 | return false;
490 | }
491 |
492 | if (LIVE_PLAY != mLiveState) {
493 | mLiveCallBack.onMessageCallback(ConstantLive.CAPTURE_FAILED_NPLAY_STATE);
494 | return false;
495 | }
496 |
497 | byte[] pictureBuffer = getPictureOnJPEG();
498 | if (null == pictureBuffer || pictureBuffer.length == 0) {
499 | DebugLog.error(TAG, "capture():: pictureBuffer is null or length 0");
500 | return false;
501 | }
502 |
503 | boolean ret = createPictureFile(filePath, picName);
504 | if (!ret) {
505 | pictureBuffer = null;
506 | DebugLog.error(TAG, "capture():: createPictureFile() return false");
507 | return false;
508 | }
509 |
510 | ret = writePictureToFile(pictureBuffer, pictureBuffer.length);
511 | if (!ret) {
512 | pictureBuffer = null;
513 | removePictureFile();
514 | DebugLog.error(TAG, "capture():: writePictureToFile() return false");
515 | return false;
516 | }
517 | return true;
518 | }
519 |
520 | /**
521 | * 获取JPEG图片数据
522 | *
523 | * @return JPEG图片的数据.
524 | * @since V1.0
525 | */
526 | private byte[] getPictureOnJPEG() {
527 | if (null == mPlayerHandler) {
528 | DebugLog.error(TAG, "getPictureOnJPEG():: mPlayerHandler is null");
529 | return null;
530 | }
531 |
532 | if (-1 == mPlayerPort) {
533 | DebugLog.error(TAG, "getPictureOnJPEG():: mPlayerPort is Unavailable");
534 | return null;
535 | }
536 |
537 | int picSize = getPictureSize();
538 | if (picSize <= 0) {
539 | return null;
540 | }
541 |
542 | byte[] pictureBuffer = null;
543 | try {
544 | pictureBuffer = new byte[picSize];
545 | } catch (OutOfMemoryError e) {
546 | e.printStackTrace();
547 | pictureBuffer = null;
548 | return null;
549 | }
550 |
551 | Player.MPInteger jpgSize = new Player.MPInteger();
552 |
553 | boolean ret = mPlayerHandler.getJPEG(mPlayerPort, pictureBuffer, picSize, jpgSize);
554 | if (!ret) {
555 | DebugLog.error(TAG, "getPictureOnJPEG():: mPlayerHandler.getJPEG() return false");
556 | return null;
557 | }
558 |
559 | int jpegSize = jpgSize.value;
560 | if (jpegSize <= 0) {
561 | pictureBuffer = null;
562 | return null;
563 | }
564 |
565 | ByteBuffer jpgBuffer = ByteBuffer.wrap(pictureBuffer, 0, jpegSize);
566 | if (null == jpgBuffer) {
567 | pictureBuffer = null;
568 | return null;
569 | }
570 |
571 | return jpgBuffer.array();
572 | }
573 |
574 | /**
575 | * 创建图片文件
576 | *
577 | * @param path 图片路径
578 | * @param fileName 图片名字
579 | * @return true - 图片创建成功 or false - 图片创建失败
580 | * @since V1.0
581 | */
582 | private boolean createPictureFile(String path, String fileName) {
583 | if (null == path || null == fileName || path.equals("") || fileName.equals("")) {
584 | return false;
585 | }
586 |
587 | String dirPath = createFileDir(path);
588 | if (null == dirPath || dirPath.equals("")) {
589 | return false;
590 | }
591 |
592 | try {
593 | mPictureFile = new File(dirPath + File.separator + fileName);
594 | if ((null != mPictureFile) && (!mPictureFile.exists())) {
595 | mPictureFile.createNewFile();
596 | }
597 | } catch (Exception e) {
598 | e.printStackTrace();
599 | mPictureFile = null;
600 | return false;
601 | }
602 | return true;
603 | }
604 |
605 | /**
606 | * 抓拍图片写到SDCard
607 | *
608 | * @param picData 图片数据
609 | * @param length 图片数据长度
610 | * @since V1.0
611 | */
612 | private boolean writePictureToFile(byte[] picData, int length) {
613 | if (null == picData || length <= 0 || picData.length > length) {
614 | return false;
615 | }
616 |
617 | if (null == mPictureFile) {
618 | return false;
619 | }
620 |
621 | FileOutputStream fOut = null;
622 | try {
623 | if (!mPictureFile.exists()) {
624 | mPictureFile.createNewFile();
625 | }
626 | fOut = new FileOutputStream(mPictureFile);
627 | fOut.write(picData, 0, length);
628 | fOut.flush();
629 | fOut.close();
630 | fOut = null;
631 | } catch (Exception e) {
632 | e.printStackTrace();
633 | fOut = null;
634 | mPictureFile.delete();
635 | mPictureFile = null;
636 | return false;
637 | }
638 | return true;
639 | }
640 |
641 | /**
642 | * 删除图片文件
643 | *
644 | * @since V1.0
645 | */
646 | private void removePictureFile() {
647 | try {
648 | if (null == mPictureFile) {
649 | return;
650 | }
651 | mPictureFile.delete();
652 | } catch (Exception e) {
653 | e.printStackTrace();
654 | } finally {
655 | mPictureFile = null;
656 | }
657 | }
658 |
659 | /**
660 | * 创建文件夹
661 | *
662 | * @param path 文件路径
663 | * @return 文件夹路径
664 | * @since V1.0
665 | */
666 | private String createFileDir(String path) {
667 | if (null == path || path.equals("")) {
668 | return "";
669 | }
670 | File tempFile = null;
671 | try {
672 | tempFile = new File(path);
673 | if ((null != tempFile) && (!tempFile.exists())) {
674 | tempFile.mkdirs();
675 | }
676 | } catch (Exception e) {
677 | e.printStackTrace();
678 | tempFile = null;
679 | return "";
680 | }
681 | return tempFile.getAbsolutePath();
682 | }
683 |
684 | /**
685 | * 停止录像 void
686 | *
687 | * @since V1.0
688 | */
689 | public void stopRecord() {
690 | if (!mIsRecord) {
691 | return;
692 | }
693 |
694 | mIsRecord = false;
695 |
696 | stopWriteStreamData();
697 | }
698 |
699 | /**
700 | * 停止写入数据流
701 | *
702 | * @since V1.0
703 | */
704 | private void stopWriteStreamData() {
705 | if (null == mRecordFileOutputStream) {
706 | return;
707 | }
708 |
709 | try {
710 | mRecordFileOutputStream.flush();
711 | mRecordFileOutputStream.close();
712 | } catch (IOException e) {
713 | e.printStackTrace();
714 | } finally {
715 | mRecordFileOutputStream = null;
716 | mRecordFile = null;
717 | }
718 | }
719 |
720 | /**
721 | * 启动录像方法
722 | *
723 | * @param filePath 录像文件路径
724 | * @param fileName 录像文件名称
725 | * @param isRpmPackage 是否启用转封装
726 | * @return true-启动录像成功,false-启动录像失败
727 | * @since V1.0
728 | */
729 | public boolean startRecord(String filePath, String fileName) {
730 |
731 | if (!UtilSDCard.isSDCardUsable()) {
732 | if (null != mLiveCallBack) {
733 | mLiveCallBack.onMessageCallback(ConstantLive.SD_CARD_UN_USEABLE);
734 | }
735 | return false;
736 | }
737 |
738 | if (UtilSDCard.getSDCardRemainSize() <= mSDCardSize) {
739 | if (null != mLiveCallBack) {
740 | mLiveCallBack.onMessageCallback(ConstantLive.SD_CARD_SIZE_NOT_ENOUGH);
741 | }
742 | return false;
743 | }
744 |
745 | if (LIVE_PLAY != mLiveState) {
746 | DebugLog.error(TAG, "非播放状态不能录像");
747 | mLiveCallBack.onMessageCallback(ConstantLive.RECORD_FAILED_NPLAY_STATE);
748 | return false;
749 | }
750 |
751 | boolean ret = createRecordFile(filePath, fileName);
752 | if (!ret) {
753 | DebugLog.error(TAG, "createRecordFile() fail 创建录像文件失败");
754 | return false;
755 | }
756 |
757 | ret = writeStreamHead(mRecordFile);
758 | if (!ret) {
759 | DebugLog.error(TAG, "writeStreamHead() 写文件失败");
760 | removeRecordFile();
761 | return false;
762 | }
763 |
764 | mIsRecord = true;
765 | DebugLog.error(TAG, "启动录像成功");
766 | return true;
767 | }
768 |
769 | /**
770 | * 创建录像文件
771 | *
772 | * @param path 文件路径
773 | * @param fileName 文件名
774 | * @return true - 创建成功 or false - 创建失败
775 | * @since V1.0
776 | */
777 | private boolean createRecordFile(String path, String fileName) {
778 | if (null == path || path.equals("") || null == fileName || fileName.equals("")) {
779 | return false;
780 | }
781 |
782 | try {
783 | mRecordFile = new File(path + File.separator + fileName);
784 | if ((null != mRecordFile) && (!mRecordFile.exists())) {
785 | mRecordFile.createNewFile();
786 | }
787 | } catch (IOException e) {
788 | e.printStackTrace();
789 |
790 | mRecordFile = null;
791 | return false;
792 | }
793 |
794 | return true;
795 | }
796 |
797 | /**
798 | * 写流头文件
799 | *
800 | * @param file 写入的文件
801 | * @return true - 写入头文件成功. false - 写入头文件失败.
802 | * @since V1.0
803 | */
804 | private boolean writeStreamHead(File file) {
805 | if (null == file || null == mStreamHeadDataBuffer) {
806 | Log.e("AAA", "mStreamHeadDataBuffer is null!");
807 | return false;
808 | }
809 |
810 | byte[] tempByte = mStreamHeadDataBuffer.array();
811 | if (null == tempByte) {
812 | return false;
813 | }
814 | try {
815 | if (null == mRecordFileOutputStream) {
816 | mRecordFileOutputStream = new FileOutputStream(file);
817 | }
818 | mRecordFileOutputStream.write(tempByte, 0, tempByte.length);
819 | } catch (Exception e) {
820 | e.printStackTrace();
821 | if (mRecordFileOutputStream != null) {
822 | try {
823 | mRecordFileOutputStream.close();
824 | } catch (IOException e1) {
825 | e1.printStackTrace();
826 | }
827 | }
828 | mRecordFileOutputStream = null;
829 | mStreamHeadDataBuffer = null;
830 | tempByte = null;
831 | return false;
832 | }
833 |
834 | return true;
835 | }
836 |
837 | /**
838 | * 删除录像文件
839 | *
840 | * @since V1.0
841 | */
842 | private void removeRecordFile() {
843 | try {
844 | if (null == mRecordFile) {
845 | return;
846 | }
847 | mRecordFile.delete();
848 |
849 | } catch (Exception e) {
850 | e.printStackTrace();
851 | } finally {
852 | mRecordFile = null;
853 | }
854 | }
855 |
856 | /**
857 | * 开启音频
858 | *
859 | * @return boolean
860 | * @since V1.0
861 | */
862 | public boolean startAudio() {
863 | if (LIVE_PLAY != mLiveState) {
864 | DebugLog.error(TAG, "非播放状态不能开启音频");
865 | mLiveCallBack.onMessageCallback(ConstantLive.AUDIO_START_FAILED_NPLAY_STATE);
866 | return false;
867 | }
868 |
869 | if (null == mPlayerHandler) {
870 | return false;
871 | }
872 |
873 | boolean ret = mPlayerHandler.playSound(mPlayerPort);
874 | if (!ret) {
875 | return false;
876 | }
877 | return true;
878 | }
879 |
880 | /**
881 | * 关闭音频
882 | *
883 | * @return boolean
884 | * @since V1.0
885 | */
886 | public boolean stopAudio() {
887 | if (LIVE_PLAY != mLiveState) {
888 | DebugLog.error(TAG, "非播放状态不能关闭音频");
889 | return false;
890 | }
891 |
892 | if (null == mPlayerHandler) {
893 | return false;
894 | }
895 |
896 | boolean ret = mPlayerHandler.stopSound();
897 | if (!ret) {
898 | return false;
899 | }
900 | return true;
901 | }
902 |
903 | /**
904 | * 获取JPEG图片大小
905 | *
906 | * @return JPEG图片的大小.
907 | * @throws PlayerException
908 | * @throws MediaPlayerException MediaPlayer 异常
909 | * @since V1.0
910 | */
911 | private int getPictureSize() {
912 | Player.MPInteger width = new Player.MPInteger();
913 | Player.MPInteger height = new Player.MPInteger();
914 | boolean ret = mPlayerHandler.getPictureSize(mPlayerPort, width, height);
915 | if (!ret) {
916 | DebugLog.error(TAG, "getPictureSize():: mPlayerHandler.getPictureSize() return false,errorCode is P"
917 | + mPlayerHandler.getLastError(mPlayerPort));
918 | return 0;
919 | }
920 | int pictureSize = width.value * height.value * 3;
921 | return pictureSize;
922 | }
923 |
924 | /**
925 | * 向播放库塞数据
926 | *
927 | * @param data
928 | * @param len void
929 | * @since V1.0
930 | */
931 | private void processStreamData(byte[] data, int len) {
932 | if (null == data || 0 == len) {
933 | DebugLog.error(TAG, "processStreamData() Stream data is null or len is 0");
934 | return;
935 | }
936 | if (null != mPlayerHandler) {
937 | boolean ret = mPlayerHandler.inputData(mPlayerPort, data, len);
938 | if (!ret) {
939 | SystemClock.sleep(10);
940 | }
941 | }
942 | }
943 |
944 | /*
945 | * handle - - 引擎id opt - -回调消息,包括:RTSPCLIENT_MSG_PLAYBACK_FINISH,RTSPCLIENT_MSG_BUFFER_OVERFLOW
946 | * ,RTSPCLIENT_MSG_CONNECTION_EXCEPTION 三种 param1 - - 保留参数 param2 - - 保留参数 useId - - 用户数据,默认就是引擎id与handle相同
947 | */
948 |
949 | @Override
950 | public void onMessageCallBack(int handle, int opt, int param1, int param2, int useId) {
951 |
952 | if (opt == RtspClient.RTSPCLIENT_MSG_CONNECTION_EXCEPTION) {
953 | stop();
954 | DebugLog.error(TAG, "onMessageCallBack():: rtsp connection exception");
955 | if (connectNum > 3) {
956 | DebugLog.error(TAG, "onMessageCallBack():: rtsp connection more than three times");
957 | connectNum = 0;
958 | } else {
959 | startLive(mSurfaceView);
960 | connectNum++;
961 | }
962 | }
963 | }
964 |
965 | /**
966 | * 返回已经播放的流量 void
967 | *
968 | * @return long
969 | * @since V1.0
970 | */
971 | public long getStreamRate() {
972 | return mStreamRate;
973 | }
974 |
975 | /**
976 | * 清空流量统计 void
977 | *
978 | * @since V1.0
979 | */
980 | public void clearStreamRate() {
981 | mStreamRate = 0;
982 | }
983 |
984 | /**
985 | * 获取OSD时间
986 | *
987 | * @return Calendar
988 | * @since V1.0
989 | */
990 | public Calendar getOSDTime() {
991 | Calendar systemTime = Calendar.getInstance();
992 | if (null == mPlayerHandler) {
993 | DebugLog.error(TAG, "getOSDTime(): mPlayerHandler is null!");
994 | return null;
995 | }
996 |
997 | if (-1 == mPlayerPort) {
998 | DebugLog.error(TAG, "getOSDTime(): mPlayerPort is -1");
999 | return null;
1000 | }
1001 |
1002 | MPSystemTime time = new MPSystemTime();
1003 | boolean ret = mPlayerHandler.getSystemTime(mPlayerPort, time);
1004 | if (!ret) {
1005 | DebugLog.error(TAG,
1006 | "getOSDTime(): getSystemTime() fail errorCode is " + mPlayerHandler.getLastError(mPlayerPort));
1007 | mLiveCallBack.onMessageCallback(ConstantLive.GET_OSD_TIME_FAIL);
1008 | return systemTime;
1009 | }
1010 |
1011 | systemTime.set(Calendar.YEAR, time.year);
1012 | systemTime.set(Calendar.MONTH, time.month - 1);
1013 | systemTime.set(Calendar.DAY_OF_MONTH, time.day);
1014 | systemTime.set(Calendar.HOUR_OF_DAY, time.hour);
1015 | systemTime.set(Calendar.MINUTE, time.min);
1016 | systemTime.set(Calendar.SECOND, time.sec);
1017 | systemTime.set(Calendar.MILLISECOND, time.ms);
1018 |
1019 | return systemTime;
1020 | }
1021 |
1022 | @Override
1023 | public void onDisplay(int arg0, byte[] arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7) {
1024 | if (LIVE_PLAY != mLiveState) {
1025 | mLiveState = LIVE_PLAY;
1026 | if (null != mLiveCallBack) {
1027 | mLiveCallBack.onMessageCallback(ConstantLive.PLAY_DISPLAY_SUCCESS);
1028 | } else {
1029 | DebugLog.error(TAG, "onDisplay():: mLiveCallBack is null");
1030 | }
1031 |
1032 | }
1033 | }
1034 |
1035 | }
1036 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/live/TalkCallInfo.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.live;
2 |
3 | /**
4 | * 对讲信息
5 | * @author weilinfeng
6 | * @Data 2014-6-17
7 | */
8 | public class TalkCallInfo {
9 | /** 服务器IP,用MAG的IP */
10 | public String servIP;
11 | /** 注册服务器端口,MAG对讲端口 */
12 | public int servPort;
13 | /** 客户端UserID,用登陆MSP的SessionID表示 */
14 | public String userID;
15 | /** 接收方的UserID,使用对讲器的indexCode,用于对讲服务器对讲(目前接VAG可使用deviceIndexCode) */
16 | public String toUserID;
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/live/TalkControl.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.live;
2 |
3 | import android.os.AsyncTask;
4 | import android.os.Handler;
5 | import android.os.Message;
6 |
7 | import com.demo.sdk6x.utils.DebugLog;
8 | import com.hik.mcrsdk.talk.SDKTalkCallInfo;
9 | import com.hik.mcrsdk.talk.SDKTalkLoginInfo;
10 | import com.hik.mcrsdk.talk.TalkClientSDK;
11 | import com.hik.mcrsdk.talk.TalkErrorListener;
12 | import com.hik.mcrsdk.talk.TalkPCMDataLister;
13 | import com.hik.mcrsdk.talk.module.AudioStreamManager;
14 | import com.hik.mcrsdk.talk.module.AudioStreamManager.AudioCallBack;
15 | import com.hik.mcrsdk.talk.module.GatherParams;
16 |
17 | /**
18 | * 对讲控制层
19 | *
20 | * @author weilinfeng
21 | * @Data 2014-6-17
22 | */
23 | public class TalkControl {
24 | /** 变量/常量说明 */
25 | private static final String TAG = "TalkControl";
26 | /** 停止状态 */
27 | TalkState mTalkState = TalkState.stoped;
28 | /** 变量/常量说明 */
29 | private TalkClientSDK mTalkClientSDK = null;
30 | /** 变量/常量说明 */
31 | private AudioStreamManager mAudioStreamManager = null;
32 | /** 手机采集的PCM数据回调 */
33 | private AudioCallBack mAudioCallBack = new AudioCallBack() {
34 | @Override
35 | public void onPCMData(byte[] data, int length) {
36 | mTalkClientSDK.inputAudioData(data, length);
37 | }
38 | };
39 |
40 | /** TALKSDK的PCM数据回调 */
41 | private TalkPCMDataLister mTalkPCMDataLister = new TalkPCMDataLister() {
42 | @Override
43 | public void onTalkPCMDataListener(byte[] data,
44 | int len, long pUser) {
45 | // DebugLog.error(TAG, "onTalkPCMDataListener() data len:"+len);
46 | // TODO Auto-generated method stub
47 | mAudioStreamManager.inputPCMData(data, len);
48 |
49 | }
50 | };
51 |
52 | /** TALKSDK的错误回调 */
53 | private TalkErrorListener mTalkErrorListener = new TalkErrorListener() {
54 | @Override
55 | public void onTalkErrorListener(int errorCode, String describe,
56 | long pUser) {
57 | DebugLog.error(TAG, "onTalkPCMDataListener() errorCode:"
58 | + errorCode + " describe:" + describe);
59 |
60 | }
61 | };
62 |
63 | /**
64 | * 对讲控制层构造函数
65 | *
66 | * @param liveActivity
67 | */
68 | public TalkControl() {
69 | mTalkClientSDK = TalkClientSDK.getInstance();
70 | mAudioStreamManager = AudioStreamManager.getInstance();
71 | }
72 |
73 | /**
74 | * 这里对方法做描述
75 | *
76 | * @param talkInfo
77 | * @param userIndex
78 | * @return
79 | * @since V1.0
80 | */
81 | public boolean startTalk(TalkCallInfo talkInfo) {
82 | DebugLog.error(TAG, "startTalk()");
83 |
84 | if (mTalkState == TalkState.started) {
85 | DebugLog.error(TAG, "startTalk() be started");
86 | return true;
87 | }
88 |
89 | if (mTalkState != TalkState.stoped) {
90 | DebugLog.error(TAG, "startTalk() no stop state");
91 | return false;
92 | }
93 |
94 | // 开始对讲
95 | mTalkState = TalkState.starting;
96 |
97 | new AsyncTask() {
98 |
99 | @Override
100 | protected Boolean doInBackground(TalkCallInfo... params) {
101 | DebugLog.error(TAG, "startTalk() doInBackground");
102 | if (params == null) {
103 | DebugLog.error(TAG, "startTalk() doInBackground params == null");
104 | return false;
105 | }
106 |
107 | final SDKTalkLoginInfo sdkLoginInfo = getSDKTalkLoginInfo(params[0]);
108 | if (sdkLoginInfo == null) {
109 | DebugLog.error(TAG, "startTalk() getSDKTalkLoginInfo fail");
110 | return false;
111 | }
112 |
113 | final SDKTalkCallInfo sdkTalkInfo = getSDKTalkCallInfo(params[0]);
114 | if (sdkTalkInfo == null) {
115 | DebugLog.error(TAG, "startTalk() getSDKTalkCallInfo fail");
116 | return false;
117 | }
118 |
119 | boolean bRet = login(sdkLoginInfo);
120 | if (!bRet) {
121 | DebugLog.error(TAG, "startTalk() login fail");
122 | return false;
123 | }
124 |
125 | bRet = startAudioTalk(sdkTalkInfo);
126 | if (!bRet) {
127 | DebugLog.error(TAG, "startTalk() startAudioTalk fail");
128 | logout();
129 | return false;
130 | }
131 |
132 | DebugLog.error(TAG, "startTalk() doInBackground success");
133 | return true;
134 | }
135 |
136 | protected void onPostExecute(Boolean result) {
137 | if (result) {
138 | // 开始对讲成功
139 | DebugLog.error(TAG, "startTalk() success");
140 | } else {
141 | // 开始对讲失败
142 | DebugLog.error(TAG, "startTalk() fail");
143 | }
144 |
145 | // 开始对讲完成
146 | mTalkState = TalkState.started;
147 | };
148 |
149 | }.execute(talkInfo);
150 |
151 | DebugLog.error(TAG, "startTalk() complete");
152 | return true;
153 | }
154 |
155 | public boolean stopTalk() {
156 | DebugLog.error(TAG, "stopTalk()");
157 | if (mTalkState == TalkState.stoped) {
158 | DebugLog.error(TAG, "startTalk() be stoped");
159 | return true;
160 | }
161 | else if (mTalkState != TalkState.started) {
162 | DebugLog.error(TAG, "startTalk() no started");
163 | return false;
164 | }
165 |
166 | mTalkState = TalkState.stoping;
167 |
168 | new AsyncTask() {
169 |
170 | @Override
171 | protected Boolean doInBackground(Void... params) {
172 | // 停止对讲
173 | stopAudioTalk();
174 |
175 | // 登出
176 | logout();
177 |
178 | return true;
179 | }
180 |
181 | protected void onPostExecute(Boolean result) {
182 | if (result) {
183 | // 停止对讲成功
184 | DebugLog.error(TAG, "stopTalk() success");
185 | }
186 | else {
187 | // 停止对讲失败
188 | DebugLog.error(TAG, "stopTalk() fail");
189 | }
190 |
191 | // 停止结束
192 | mTalkState = TalkState.stoped;
193 | };
194 |
195 | }.execute();
196 |
197 | DebugLog.error(TAG, "stopTalk() complete");
198 | return true;
199 | }
200 |
201 | /**
202 | * 重启对讲(不注销登录的情况下,停止上次对讲,开启本次对讲)
203 | *
204 | * @param talkInfo
205 | * @param userIndex
206 | * @return
207 | * @since V1.0
208 | */
209 | public boolean reStartTalk(TalkCallInfo talkInfo) {
210 | DebugLog.error(TAG, "reStartTalk()");
211 |
212 | if (mTalkState == TalkState.starting) {
213 | DebugLog.error(TAG, "reStartTalk() be starting");
214 | return false;
215 | }
216 |
217 | if (mTalkState == TalkState.stoping) {
218 | DebugLog.error(TAG, "reStartTalk() be stoping");
219 | return false;
220 | }
221 |
222 | // 开始对讲
223 | mTalkState = TalkState.starting;
224 |
225 | new AsyncTask() {
226 |
227 | @Override
228 | protected Boolean doInBackground(TalkCallInfo... params) {
229 | DebugLog.error(TAG, "startTalk() doInBackground");
230 | if (params == null) {
231 | DebugLog.error(TAG, "startTalk() doInBackground params == null");
232 | return false;
233 | }
234 |
235 | final SDKTalkLoginInfo sdkLoginInfo = getSDKTalkLoginInfo(params[0]);
236 | if (sdkLoginInfo == null) {
237 | DebugLog.error(TAG, "startTalk() doInBackground getSDKTalkLoginInfo fail");
238 | return false;
239 | }
240 |
241 | final SDKTalkCallInfo sdkTalkInfo = getSDKTalkCallInfo(params[0]);
242 | if (sdkTalkInfo == null) {
243 | DebugLog.error(TAG, "startTalk() doInBackground getSDKTalkCallInfo fail");
244 | return false;
245 | }
246 |
247 | // 停止音频对讲
248 | stopAudioTalk();
249 |
250 | logout();
251 |
252 | boolean bRet = login(sdkLoginInfo);
253 | if (!bRet) {
254 | DebugLog.error(TAG, "startTalk() doInBackground login fail");
255 | return false;
256 | }
257 |
258 | // 开启对讲
259 | bRet = startAudioTalk(sdkTalkInfo);
260 | if (!bRet) {
261 | DebugLog.error(TAG, "startTalk() doInBackground startAudioTalk fail");
262 | logout();
263 | return false;
264 | }
265 |
266 | DebugLog.error(TAG, "startTalk() doInBackground success");
267 | return true;
268 | }
269 |
270 | protected void onPostExecute(Boolean result) {
271 | if (result) {
272 | // 开始对讲成功
273 | DebugLog.error(TAG, "reStartTalk() success");
274 | } else {
275 | // 开始对讲失败
276 | DebugLog.error(TAG, "reStartTalk() fail");
277 | }
278 |
279 | // 开始对讲完成
280 | mTalkState = TalkState.started;
281 | };
282 |
283 | }.execute(talkInfo);
284 |
285 | DebugLog.error(TAG, "startTalk() complete");
286 | return true;
287 | }
288 |
289 |
290 | /**
291 | * 返回当前状态
292 | *
293 | * @return
294 | * @since V1.0
295 | */
296 | public TalkState getState() {
297 | return mTalkState;
298 | }
299 |
300 | /**
301 | * 登陆对讲服务器
302 | *
303 | * @return
304 | * @since V1.0
305 | */
306 | private boolean login(SDKTalkLoginInfo sdkLoginInfo) {
307 | DebugLog.error(TAG, "login()");
308 | if (sdkLoginInfo == null) {
309 | DebugLog.error(TAG, "login() sdkLoginInfo == null");
310 | return false;
311 | }
312 |
313 | // 设置错误回调
314 | boolean bRet = mTalkClientSDK.addTalkErrorListener(mTalkErrorListener);
315 | if (!bRet) {
316 | DebugLog.error(TAG, "login() mTalkClientSDK addTalkErrorListener fail" + mTalkClientSDK.getErrorCode());
317 | return false;
318 | }
319 |
320 | bRet = mTalkClientSDK.login(sdkLoginInfo, 1);
321 | if (!bRet) {
322 | DebugLog.error(TAG, "login() mTalkClientSDK login fail");
323 | return false;
324 | }
325 |
326 | DebugLog.error(TAG, "login() success");
327 | return true;
328 | }
329 |
330 | /**
331 | * 登出对讲服务器
332 | *
333 | * @since V1.0
334 | */
335 | private void logout() {
336 | mTalkClientSDK.logout();
337 | DebugLog.error(TAG, "logout() success");
338 | }
339 |
340 | /**
341 | * 开始对讲
342 | *
343 | * @return
344 | * @since V1.0
345 | */
346 | private boolean startAudioTalk(SDKTalkCallInfo sdkTalkInfo) {
347 | DebugLog.error(TAG, "startAudioTalk()");
348 |
349 | // 设置数据回调
350 | boolean bRet = mTalkClientSDK.addTalkPCMDataLister(mTalkPCMDataLister);
351 | if(!bRet) {
352 | DebugLog.error(TAG, "login() mTalkClientSDK addTalkPCMDataLister fail");
353 | return false;
354 | }
355 |
356 | bRet = mTalkClientSDK.startTalk(sdkTalkInfo);
357 | if(!bRet) {
358 | DebugLog.error(TAG, "startTalk() mTalkClientSDK startTalk fail");
359 | return false;
360 | }
361 |
362 | int encodeType = mTalkClientSDK.getDeviceEncodeType();
363 | if(encodeType == -1) {
364 | DebugLog.error(TAG, "startTalk() getDeviceEncodeType fail encodeType:"+encodeType);
365 | return false;
366 | }
367 | DebugLog.error(TAG, "startTalk() getDeviceEncodeType encodeType:"+encodeType);
368 |
369 | // 设置手机采集的PCM数据回调
370 | mAudioStreamManager.setCallBack(mAudioCallBack);
371 |
372 | GatherParams gatherParam = new GatherParams();
373 | if(encodeType == TalkClientSDK.TYPE_G711_A || encodeType == TalkClientSDK.TYPE_G711_U || encodeType == TalkClientSDK.TYPE_G726) {
374 | gatherParam.setSampleRate(GatherParams.SAMPLE_RATE_8000);
375 | }
376 | else if(encodeType == TalkClientSDK.TYPE_G722){
377 | gatherParam.setSampleRate(GatherParams.SAMPLE_RATE_16000);
378 | }
379 |
380 | gatherParam.setChannels(GatherParams.CHANNEL_MONO);
381 | gatherParam.setBitPerSample(GatherParams.PCM_16BIT);
382 | bRet = mAudioStreamManager.startGather(gatherParam);
383 | if(!bRet) {
384 | DebugLog.error(TAG, "startTalk() mAudioStreamManager startGather fail");
385 | return false;
386 | }
387 |
388 | GatherParams playParam = new GatherParams();
389 | if(encodeType == TalkClientSDK.TYPE_G711_A || encodeType == TalkClientSDK.TYPE_G711_U || encodeType == TalkClientSDK.TYPE_G726) {
390 | playParam.setSampleRate(GatherParams.SAMPLE_RATE_8000);
391 | }
392 | else if(encodeType == TalkClientSDK.TYPE_G722){
393 | playParam.setSampleRate(GatherParams.SAMPLE_RATE_16000);
394 | }
395 | else {
396 | DebugLog.error(TAG, "startTalk() mAudioStreamManager startGather fail");
397 | return false;
398 | }
399 |
400 | playParam.setChannels(GatherParams.CHANNEL_MONO);
401 | playParam.setBitPerSample(GatherParams.PCM_16BIT);
402 | bRet = mAudioStreamManager.startPlay(playParam);
403 | if(!bRet) {
404 | DebugLog.error(TAG, "startTalk() mAudioStreamManager startPlay fail");
405 | return false;
406 | }
407 |
408 | DebugLog.error(TAG, "startTalk() success");
409 | return true;
410 | }
411 |
412 | /**
413 | * 停止对讲
414 | *
415 | * @since V1.0
416 | */
417 | private void stopAudioTalk() {
418 | mTalkClientSDK.stopTalk();
419 |
420 | mAudioStreamManager.stopGather();
421 |
422 | mAudioStreamManager.stopPlay();
423 |
424 | DebugLog.error(TAG, "stopTalk() success");
425 | }
426 |
427 | /**
428 | * 获取对讲SDK登陆信息
429 | *
430 | * @param loginInfo
431 | * @return
432 | * @since V1.0
433 | */
434 | private SDKTalkLoginInfo getSDKTalkLoginInfo(TalkCallInfo talkInfo) {
435 | if (talkInfo == null) {
436 | DebugLog.error(TAG, "getSDKTalkLoginInfo() talkInfo == null");
437 | return null;
438 | }
439 |
440 | SDKTalkLoginInfo sdkLoginInfo = new SDKTalkLoginInfo();
441 | // 设备PUID,如果是cu,则传cuUserID
442 | sdkLoginInfo.puid = talkInfo.userID;
443 | // 服务器IP,用MAG的IP
444 | sdkLoginInfo.servIP = talkInfo.servIP;
445 | // 注册服务器端口,MAG对讲端口
446 | sdkLoginInfo.servPort = talkInfo.servPort;
447 | // 客户端UserID,用登陆MSP的SessionID表示
448 | sdkLoginInfo.userID = talkInfo.userID;
449 | // 登录对讲服务器的密码,暂时不用,可以为空或者12345
450 | sdkLoginInfo.password = "12345";
451 | // 终端类型,0:单兵;1:客户端(包括mpu);2:车载设
452 | sdkLoginInfo.type = TalkClientSDK.TYPE_CU;
453 | // 音频编码类型
454 | sdkLoginInfo.codecType = TalkClientSDK.TYPE_G711_A;
455 |
456 | return sdkLoginInfo;
457 | }
458 |
459 | /**
460 | * 获取对讲SDK呼叫信息
461 | *
462 | * @param talkInfo
463 | * @return
464 | * @since V1.0
465 | */
466 | private SDKTalkCallInfo getSDKTalkCallInfo(TalkCallInfo talkInfo) {
467 | if (talkInfo == null) {
468 | DebugLog.error(TAG, "getSDKTalkCallInfo() talkInfo == null");
469 | return null;
470 | }
471 |
472 | SDKTalkCallInfo sdkTalkCallInfo = new SDKTalkCallInfo();
473 | // 客户端UserID,用登陆MSP的SessionID表示
474 | sdkTalkCallInfo.fromUserID = talkInfo.userID;
475 | // 接收方的UserID,使用对讲器的indexCode,用于对讲服务器对讲(目前接VAG可使用deviceIndexCode)
476 | sdkTalkCallInfo.toUserID = talkInfo.toUserID;
477 | // 设备序列号,用于VAG对讲(目前接VAG可使用deviceIndexCode)
478 | sdkTalkCallInfo.deviceIndexCode = talkInfo.toUserID;
479 | // 设备类型,用于VAG对讲30000
480 | sdkTalkCallInfo.deviceType = 30000;
481 | // 对讲通道编号,用于VAG对讲,目前统一传1
482 | sdkTalkCallInfo.channelNum = 1;
483 |
484 | return sdkTalkCallInfo;
485 | }
486 |
487 | }
488 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/live/TalkState.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.live;
2 |
3 | public enum TalkState {
4 | /** 开始中 */
5 | starting,
6 | /** 开始成功 */
7 | started,
8 | /** 停止中 */
9 | stoping,
10 | /** 停止成功 */
11 | stoped
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/login/LoginActivity.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.login;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapFactory;
7 | import android.os.Bundle;
8 | import android.os.Handler;
9 | import android.os.Message;
10 | import android.text.TextUtils;
11 | import android.util.Log;
12 | import android.view.View;
13 | import android.view.View.OnClickListener;
14 | import android.widget.Button;
15 | import android.widget.EditText;
16 | import android.widget.ImageView;
17 |
18 | import com.demo.sdk6x.R;
19 | import com.demo.sdk6x.app.DemoApp;
20 | import com.demo.sdk6x.constants.Constants;
21 | import com.demo.sdk6x.data.Config;
22 | import com.demo.sdk6x.data.TempData;
23 | import com.demo.sdk6x.resource.ResourceListActivity;
24 | import com.demo.sdk6x.utils.Base64Utils;
25 | import com.demo.sdk6x.utils.UIUtil;
26 | import com.hikvision.vmsnetsdk.ServInfo;
27 | import com.hikvision.vmsnetsdk.ServerConfig;
28 | import com.hikvision.vmsnetsdk.VMSNetSDK;
29 |
30 | import java.util.concurrent.Executors;
31 |
32 | public class LoginActivity extends Activity {
33 | public static final String TAG = "LoginActivity";
34 |
35 | /**
36 | * 发送消息的对象
37 | */
38 | private MsgHandler handler;
39 |
40 | /**
41 | * 用户名输入框
42 | */
43 | private EditText username;
44 |
45 | /**
46 | * 密码输入框
47 | */
48 | private EditText passwd;
49 |
50 | /**
51 | * 验证码输入框
52 | */
53 | private EditText verifCode;
54 |
55 | /**
56 | * 验证码图片
57 | */
58 | private ImageView verifCodeImg;
59 |
60 | /**
61 | * 登录按钮
62 | */
63 | private Button loginBtn;
64 |
65 | /**
66 | * 登录平台地址
67 | */
68 | private String servAddr = "";
69 |
70 | /**
71 | * 登录返回的数据
72 | */
73 | private ServInfo servInfo;
74 |
75 | /**
76 | * 服务器地址输入框
77 | */
78 | private EditText serverAddrEt;
79 |
80 | /**
81 | * 是否需要验证码
82 | */
83 | private boolean isNeedVerifCode = false;
84 |
85 | @Override
86 | protected void onCreate(Bundle savedInstanceState) {
87 | super.onCreate(savedInstanceState);
88 | setContentView(R.layout.login_activity);
89 |
90 | initUI();
91 |
92 | initData();
93 | }
94 |
95 | /**
96 | * 初始化控件
97 | */
98 | private void initUI() {
99 | // TODO Auto-generated method stub
100 | username = (EditText) findViewById(R.id.username);
101 | passwd = (EditText) findViewById(R.id.passwd);
102 | loginBtn = (Button) findViewById(R.id.loginbtn);
103 | verifCode = (EditText) findViewById(R.id.verifCode);
104 | verifCodeImg = (ImageView) findViewById(R.id.iv_verifCode);
105 | serverAddrEt = (EditText) findViewById(R.id.server_addr_et);
106 |
107 | loginBtn.setOnClickListener(new OnClickListener() {
108 |
109 | @Override
110 | public void onClick(View v) {
111 | login();
112 | }
113 | });
114 |
115 | }
116 |
117 |
118 | @Override
119 | protected void onResume() {
120 | super.onResume();
121 | if (isNeedVerifCode) {
122 | refreshVerifCode();
123 | }
124 | }
125 |
126 | /**
127 | * 初始化数据
128 | */
129 | private void initData() {
130 | // TODO Auto-generated method stub
131 | handler = new MsgHandler();
132 | servInfo = new ServInfo();
133 |
134 | // 为了方便测试,设置默认用户名密码
135 | username.setText("admin");
136 | passwd.setText("Hik12345");
137 | // 登录平台地址
138 | servAddr = Config.getIns().getServerAddr();
139 | serverAddrEt.setText(servAddr);
140 | }
141 |
142 | protected void login() {
143 | // TODO Auto-generated method stub
144 | servAddr = serverAddrEt.getText().toString().trim();
145 | if (servAddr.length() <= 0) {
146 | UIUtil.showToast(this, R.string.serveraddr_empty_tip);
147 | return;
148 | }
149 | Config.getIns().setServerAddr(servAddr);
150 | final String userName = username.getText().toString().trim();
151 | final String password = passwd.getText().toString().trim();
152 | final String code = verifCode.getText().toString().trim();
153 |
154 | if (isNeedVerifCode && code.length() <= 0) {
155 | UIUtil.showToast(LoginActivity.this, R.string.verifCode_empty_tip);
156 | return;
157 | }
158 |
159 | if (userName.length() <= 0) {
160 | UIUtil.showToast(LoginActivity.this, R.string.username_empty_tip);
161 | return;
162 | }
163 | if (password.length() <= 0) {
164 | UIUtil.showToast(LoginActivity.this, R.string.password_empty_tip);
165 | return;
166 | }
167 |
168 | final String macAddress = DemoApp.getIns().getMacAddr();
169 | if (macAddress.length() == 0) {
170 | UIUtil.showToast(LoginActivity.this, R.string.macaddr_empty_tip);
171 | return;
172 | }
173 | final String mDomainAddress = clearDomainAddress(servAddr);
174 |
175 | handler.sendEmptyMessage(Constants.Login.SHOW_LOGIN_PROGRESS);
176 |
177 | // 新线程进行登录操作
178 | new Thread(new Runnable() {
179 | @Override
180 | public void run() {
181 | //1、先获取服务器配置信息ServerConfig
182 | ServerConfig serverConfig = new ServerConfig();
183 | boolean getServerConfigSuccess = VMSNetSDK.getInstance().getServerConfig(servAddr, serverConfig, false);
184 | if (getServerConfigSuccess) {
185 | boolean isSuccess = VMSNetSDK.getInstance().safeLoginNewPlatform(servAddr, userName, password,
186 | macAddress, 3, "5060", code, servInfo.getVerifCodeKey(), servInfo, serverConfig);
187 | if (servInfo != null) {
188 | TempData.getInstance().setLoginData(servInfo);
189 | }
190 | dealNewLoginResult(servInfo, isSuccess);
191 | } else {
192 | // 登录请求
193 | // boolean ret = VMSNetSDK.getInstance().login(servAddr, userName, password, macAddress, servInfo, mDomainAddress);
194 | boolean ret = VMSNetSDK.getInstance().login(servAddr, userName, password, macAddress, servInfo);
195 |
196 | if (ret) {
197 | TempData.getInstance().setLoginData(servInfo);
198 | handler.sendEmptyMessage(Constants.Login.LOGIN_SUCCESS);
199 | } else {
200 | handler.sendEmptyMessage(Constants.Login.LOGIN_FAILED);
201 | }
202 | }
203 | }
204 | }).start();
205 | }
206 |
207 | /**
208 | * 去掉请求协议头和端口
209 | *
210 | * @param domainAddress
211 | * @return 纯IP
212 | */
213 | private String clearDomainAddress(String domainAddress) {
214 | if (TextUtils.isEmpty(domainAddress)) {
215 | return null;
216 | }
217 | String ipAddress = "";
218 | //兼容http://开头的地址格式
219 | if (domainAddress.contains("http://") || domainAddress.contains("https://")) {
220 | String[] splits = domainAddress.split("//");
221 | if (splits.length >= 2) {
222 | domainAddress = splits[1];
223 | }
224 | }
225 | if (domainAddress.contains(":")) {//例:10.33.27.240:81或10.33.27.240:81/msp无法解析
226 | String[] str_address = domainAddress.split(":");
227 | ipAddress = str_address[0];
228 | return ipAddress;
229 | } else if (!domainAddress.contains(":") && domainAddress.contains("/")) {//例如10.33.27.240/msp无法解析
230 | String[] str_address = domainAddress.split("/");
231 | ipAddress = str_address[0];
232 | return ipAddress;
233 | }
234 | return domainAddress;
235 | }
236 |
237 | public void dealNewLoginResult(ServInfo servInfo, boolean isSuccess) {
238 | if (servInfo == null) {
239 | handler.sendEmptyMessage(Constants.Login.LOGIN_FAILED);
240 | return;
241 | }
242 |
243 | if (isSuccess) {
244 | int code = servInfo.getSrcCode();
245 | handleLoginSuccess(code, servInfo);
246 | TempData.getInstance().setLoginData(servInfo);
247 | } else {
248 | handler.sendEmptyMessage(Constants.Login.LOGIN_FAILED);
249 | }
250 | }
251 |
252 | private void handleLoginSuccess(int successCode, ServInfo servInfo) {
253 | String errorDec = "";
254 | switch (successCode) {
255 | case Constants.LoginCode.SUCCESS_LOGIN:
256 | case Constants.LoginCode.SUCCESS_CODE_FIRST_LOGIN:
257 | case Constants.LoginCode.SUCCESS_CODE_PWD_WEAK:
258 | case Constants.LoginCode.SUCCESS_CODE_PWD_STALE:
259 | handler.sendEmptyMessage(Constants.Login.LOGIN_SUCCESS);
260 | break;
261 | case VMSNetSDK.VMSNETSDK_MSP_USEER_HAS_LOCK:
262 | errorDec = getApplication().getResources().getString(R.string.login_user_has_lock);
263 | sendHandleMessage(Constants.Login.LOGIN_FAIL_WITH_CODE, successCode, errorDec);
264 | break;
265 | case VMSNetSDK.VMSNETSDK_MSP_NEED_VERIFCODE:
266 | isNeedVerifCode = true;
267 | sendHandleMessage(Constants.Login.LOGIN_NEED_VERIFCODE, successCode, servInfo);
268 | break;
269 | case VMSNetSDK.VMSNETSDK_MSP_VERIFCODE_ERR:
270 | isNeedVerifCode = true;
271 | sendHandleMessage(Constants.Login.LOGIN_CHECK_FAIL_VERIFYCODE_ERR, successCode, servInfo);
272 | break;
273 | case VMSNetSDK.VMSNETSDK_MSP_VERIFCODE_INVALIDE:
274 | isNeedVerifCode = true;
275 | sendHandleMessage(Constants.Login.LOGIN_CHECK_FAIL_VERIFYCODE_INVALIDE, successCode, servInfo);
276 | break;
277 | default:
278 | break;
279 | }
280 | }
281 |
282 | public void sendHandleMessage(int what, int arg1, Object obj) {
283 | if (null == handler) {
284 | Log.e(TAG, "the handler is null.");
285 | return;
286 | }
287 | Message message = Message.obtain();
288 | message.what = what;
289 | message.arg1 = arg1;
290 | message.obj = obj;
291 | handler.sendMessage(message);
292 | }
293 |
294 | /**
295 | * 登录失败
296 | */
297 | public void onLoginFailed() {
298 | cancelProgress();
299 | UIUtil.showToast(this, getString(R.string.login_failed, UIUtil.getErrorDesc()));
300 | }
301 |
302 | /**
303 | * 登录成功
304 | */
305 | public void onLoginSuccess() {
306 | cancelProgress();
307 | UIUtil.showToast(this, R.string.login_suc_tip);
308 | // 跳转到获取控制中心列表界面
309 | // gotoResourceListActivity();
310 | Intent intent = new Intent(LoginActivity.this, ResourceListActivity.class);
311 | startActivity(intent);
312 | }
313 |
314 | /**
315 | * 登录进度条
316 | */
317 | private void showLoginProgress() {
318 | UIUtil.showProgressDialog(this, R.string.login_process_tip);
319 | }
320 |
321 | /**
322 | * 取消进度条
323 | */
324 | private void cancelProgress() {
325 | UIUtil.cancelProgressDialog();
326 | }
327 |
328 |
329 | private final class MsgHandler extends Handler {
330 |
331 | @Override
332 | public void handleMessage(Message msg) {
333 | super.handleMessage(msg);
334 | switch (msg.what) {
335 | case Constants.Login.SHOW_LOGIN_PROGRESS:
336 | showLoginProgress();
337 | break;
338 | case Constants.Login.CANCEL_LOGIN_PROGRESS:
339 | cancelProgress();
340 | break;
341 | case Constants.Login.LOGIN_SUCCESS:
342 | // 登录成功
343 | onLoginSuccess();
344 | break;
345 | case Constants.Login.LOGIN_FAILED:
346 | // 登录失败
347 | onLoginFailed();
348 | break;
349 | case Constants.Login.LOGIN_FAIL_WITH_CODE:
350 | cancelProgress();
351 | UIUtil.showToast(LoginActivity.this, msg.obj.toString());
352 | break;
353 | case Constants.Login.LOGIN_NEED_VERIFCODE:
354 | cancelProgress();
355 | UIUtil.showToast(LoginActivity.this, R.string.login_user_password_error);
356 | passwd.setText("");//清空密码
357 | ServInfo servInfotemp = (ServInfo) msg.obj;
358 | if (TextUtils.isEmpty(servInfotemp.getVerifCode()) || TextUtils.isEmpty(servInfotemp.getVerifCodeKey())) {
359 | refreshVerifCode();
360 | } else {
361 | showVerifCode(servInfotemp);
362 | }
363 | break;
364 | case Constants.Login.LOGIN_CHECK_FAIL_VERIFYCODE_ERR:
365 | cancelProgress();
366 | UIUtil.showToast(LoginActivity.this, R.string.login_verifcode_err);
367 | passwd.setText("");//清空密码
368 | refreshVerifCode();
369 | break;
370 | case Constants.Login.LOGIN_CHECK_FAIL_VERIFYCODE_INVALIDE:
371 | cancelProgress();
372 | UIUtil.showToast(LoginActivity.this, R.string.login_verifcode_invalide);
373 | passwd.setText("");//清空密码
374 | refreshVerifCode();
375 | break;
376 | default:
377 | handler.sendEmptyMessage(Constants.Login.LOGIN_FAILED);
378 | break;
379 | }
380 |
381 | }
382 | }
383 |
384 | /**
385 | * 展示验证码
386 | *
387 | * @param servInfo
388 | */
389 | private void showVerifCode(ServInfo servInfo) {
390 | this.servInfo = servInfo;
391 |
392 | if (verifCode.getVisibility() != View.VISIBLE) {
393 | verifCode.setVisibility(View.VISIBLE);
394 | verifCodeImg.setVisibility(View.VISIBLE);
395 | } else {
396 | verifCode.setText("");
397 | }
398 | if (servInfo != null) {
399 | verifCodeImg.setImageBitmap(getBitmap(Base64Utils.decode(servInfo.getVerifCode())));
400 | }
401 | }
402 |
403 | /**
404 | * 刷新验证码
405 | */
406 | public void refreshVerifCode() {
407 | // 执行登录方法
408 | Executors.newCachedThreadPool().execute(new Runnable() {
409 | @Override
410 | public void run() {
411 | // TODO Auto-generated method stub
412 | final ServInfo servInfo = new ServInfo();
413 | if (VMSNetSDK.getInstance().getVerifCode(servAddr, servInfo)) {
414 | runOnUiThread(new Runnable() {
415 | @Override
416 | public void run() {
417 | showVerifCode(servInfo);
418 | }
419 | });
420 | } else {
421 | UIUtil.showToast(LoginActivity.this, R.string.verifcode_refresh_fail);
422 | }
423 | }
424 | });
425 | }
426 |
427 | private Bitmap getBitmap(byte[] decode) {
428 | if (decode == null) {
429 | return null;
430 | }
431 | return decode.length != 0 ? BitmapFactory.decodeByteArray(decode, 0, decode.length) : null;
432 | }
433 | }
434 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/playback/ConstantPlayBack.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.playback;
2 |
3 | /**
4 | * 回放中用到的常量
5 | *
6 | * @author huangweifeng
7 | * @Data 2013-10-28
8 | */
9 | public class ConstantPlayBack {
10 | private static final int ERR_BASE = 1000;
11 | /**
12 | * 启动取流失败
13 | * */
14 | public static final int START_RTSP_FAIL = ERR_BASE;
15 | /**
16 | * 启动取流成功
17 | * */
18 | public static final int START_RTSP_SUCCESS = ERR_BASE + 1;
19 | /**
20 | * 暂停失败
21 | * */
22 | public static final int PAUSE_FAIL = ERR_BASE + 2;
23 | /**
24 | * 暂停成功
25 | * */
26 | public static final int PAUSE_SUCCESS = ERR_BASE + 3;
27 | /**
28 | * 恢复播放失败
29 | * */
30 | public static final int RESUEM_FAIL = ERR_BASE + 4;
31 | /**
32 | * 恢复播放成功
33 | * */
34 | public static final int RESUEM_SUCCESS = ERR_BASE + 5;
35 | /**
36 | * 启动播放失败
37 | * */
38 | public static final int START_OPEN_FAILED = ERR_BASE + 6;
39 | /**
40 | * 回放成功
41 | * */
42 | public static final int PLAY_DISPLAY_SUCCESS = ERR_BASE + 7;
43 | /**
44 | * SD卡不可用
45 | * */
46 | public static final int SD_CARD_UN_USEABLE = ERR_BASE + 8;
47 | /**
48 | * SD卡空间不足
49 | * */
50 | public static final int SD_CARD_SIZE_NOT_ENOUGH = ERR_BASE + 9;
51 | /**
52 | * 非播放状态不能抓怕
53 | */
54 | public static final int CAPTURE_FAILED_NPLAY_STATE = ERR_BASE + 10;
55 | /**
56 | * 非播放状态不能暂停
57 | */
58 | public static final int PAUSE_FAIL_NPLAY_STATE = ERR_BASE + 11;
59 | /**
60 | * 非暂停状态不需要恢复
61 | */
62 | public static final int RESUEM_FAIL_NPAUSE_STATE = ERR_BASE + 12;
63 | /**
64 | * 非播放状态不能录像
65 | */
66 | public static final int RECORD_FAIL_NPLAY_STATE = ERR_BASE + 13;
67 | /**
68 | * 非播放状态不能开启音频
69 | */
70 | public static final int AUDIO_START_FAIL_NPLAY_STATE = ERR_BASE + 14;
71 | /**
72 | * 非播放状态不能关闭音频
73 | */
74 | public static final int AUDIO_STOP_FAIL_NPLAY_STATE = ERR_BASE + 15;
75 | /**
76 | * 获取录像文件成功
77 | */
78 | public static final int GET_RECORD_FILE_SUCCESS = ERR_BASE + 16;
79 | /**
80 | * 获取录像文件失败
81 | */
82 | public static final int GET_RECORD_FILE_FAIL = ERR_BASE + 17;
83 | /**
84 | * 停止成功
85 | */
86 | public static final int STOP_SUCCESS = ERR_BASE + 18;
87 | /**
88 | * 获取录像文件为空
89 | */
90 | public static final int GET_RECORD_FILE_NULL = ERR_BASE + 19;
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/playback/PlayBackCallBack.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.playback;
2 |
3 | /**
4 | * 回放回调接口
5 | * @author huangweifeng
6 | * @Data 2013-10-28
7 | */
8 | public interface PlayBackCallBack {
9 | /**
10 | * 播放引擎消息回调接口
11 | *
12 | * @param message 消息
13 | * @since V1.0
14 | */
15 | public void onMessageCallback(int message);
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/playback/PlayBackParams.java:
--------------------------------------------------------------------------------
1 | package com.demo.sdk6x.playback;
2 |
3 | import com.hik.mcrsdk.rtsp.ABS_TIME;
4 |
5 | import android.view.SurfaceView;
6 |
7 |
8 | /**
9 | * 回放时传递的参数类
10 | *
11 | * @author huangweifeng
12 | * @Data 2013-10-28
13 | */
14 | public class PlayBackParams {
15 | /**
16 | * 播放控件
17 | * */
18 | public SurfaceView surfaceView;
19 | /**
20 | * 回放地址
21 | * */
22 | public String url;
23 | /**
24 | * 登录设备的用户名
25 | * */
26 | public String name;
27 | /**
28 | * 登录设备的密码
29 | * */
30 | public String passwrod;
31 | /**
32 | * 回放开始时间
33 | * */
34 | public ABS_TIME startTime;
35 | /**
36 | * 回放结束时间
37 | * */
38 | public ABS_TIME endTime;
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/demo/sdk6x/resource/ResourceControl.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package com.demo.sdk6x.resource;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | import android.util.Log;
10 |
11 | import com.demo.sdk6x.callback.MsgCallback;
12 | import com.demo.sdk6x.callback.MsgIds;
13 | import com.demo.sdk6x.constants.Constants;
14 | import com.demo.sdk6x.data.Config;
15 | import com.demo.sdk6x.data.TempData;
16 | import com.hikvision.vmsnetsdk.CameraInfo;
17 | import com.hikvision.vmsnetsdk.ControlUnitInfo;
18 | import com.hikvision.vmsnetsdk.RegionInfo;
19 | import com.hikvision.vmsnetsdk.ServInfo;
20 | import com.hikvision.vmsnetsdk.VMSNetSDK;
21 |
22 | /**
23 | * 获取资源逻辑控制类
24 | *
25 | * @author zhoudaihui
26 | */
27 | public final class ResourceControl {
28 | private MsgCallback callback;
29 |
30 | public void setCallback(MsgCallback callback) {
31 | this.callback = callback;
32 | }
33 |
34 | /**
35 | * 请求下一级列表资源
36 | *
37 | * @param pType 父节点资源类型 TYPE_UNKNOWN-首次获取资源,父节点默认id为0 TYPE_CTRL_UNIT-父节点为控制中心,父节点资源id传控制中心id即可
38 | * TYPE_REGION-父节点为区域,父资源id传区域id即可
39 | * @param pId 父节点资源id
40 | */
41 | public void reqResList(int pType, int pId) {
42 | switch (pType) {
43 | case Constants.Resource.TYPE_UNKNOWN:// 第一次请求资源列表
44 | requestFirstList();
45 | break;
46 | case Constants.Resource.TYPE_CTRL_UNIT:// 从控制中心获取子资源列表
47 | requestSubResFromCtrlUnit(pId);
48 | break;
49 | case Constants.Resource.TYPE_REGION:// 从区域获取子资源列表
50 | requestSubResFromRegion(pId);
51 | break;
52 | default:
53 | break;
54 | }
55 | }
56 |
57 | /**
58 | * 从区域获取下一级资源列表
59 | *
60 | * @param pId 父区域id
61 | */
62 | private void requestSubResFromRegion(int pId) {
63 |
64 | boolean responseFlag = false;
65 |
66 | String servAddr = Config.getIns().getServerAddr();
67 | ServInfo loginData = TempData.getIns().getLoginData();
68 | if(loginData == null){
69 | Log.i(Constants.LOG_TAG, "getRegionListFromRegion loginData : " + loginData);
70 | return;
71 | }
72 | int numPerPage = 10000;
73 | int curPage = 1;
74 |
75 | List regionList = new ArrayList();
76 | // 1.从区域获取区域列表
77 | boolean ret = VMSNetSDK.getInstance().getRegionListFromRegion(servAddr, loginData.getSessionID()
78 | , String.valueOf(pId), numPerPage, curPage, regionList);
79 | Log.i(Constants.LOG_TAG, "getRegionListFromRegion ret : " + ret);
80 | responseFlag = responseFlag || ret;
81 | if (!ret) {
82 | Log.e(Constants.LOG_TAG, "Invoke VMSNetSDK.getRegionListFromRegion failed:" + errDesc());
83 | }
84 |
85 | List cameraList = new ArrayList();
86 | // 2.从区域获取监控点(摄像头)列表
87 | ret = VMSNetSDK.getInstance().getCameraListFromRegion(servAddr, loginData.getSessionID(), String.valueOf(pId), numPerPage, curPage,
88 | cameraList);
89 | Log.i(Constants.LOG_TAG, "getCameraListFromRegion ret : " + ret);
90 | responseFlag = responseFlag || ret;
91 | if (!ret) {
92 | Log.e(Constants.LOG_TAG, "Invoke VMSNetSDK.getCameraListFromRegion failed:" + errDesc());
93 | }
94 |
95 | List