├── .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 allData = new ArrayList(); 96 | allData.addAll(regionList); 97 | allData.addAll(cameraList); 98 | 99 | if (callback != null) { 100 | callback.onMsg(responseFlag ? MsgIds.GET_SUB_F_R_SUC : MsgIds.GET_SUB_F_R_FAILED, allData); 101 | } 102 | } 103 | 104 | /** 105 | * 从控制中心获取下一级资源列表 106 | * 107 | * @param pId 父控制中心id 108 | */ 109 | private void requestSubResFromCtrlUnit(int pId) { 110 | 111 | boolean responseFlag = false; 112 | 113 | String servAddr = Config.getIns().getServerAddr(); 114 | ServInfo loginData = TempData.getIns().getLoginData(); 115 | if(loginData == null){ 116 | Log.i(Constants.LOG_TAG, "requestSubResFromCtrlUnit loginData:" + loginData); 117 | return; 118 | } 119 | String sessionID = loginData.getSessionID(); 120 | int controlUnitID = pId;// 控制中心id 121 | int numPerPage = 10000;// 此处取10000,表示每页获取的数量,这个数值可以根据实际情况进行修改 122 | int curPage = 1;// 当前获取的数据是第几页 123 | List ctrlUnitList = new ArrayList(); 124 | 125 | // 1.从控制中心获取控制中心 126 | boolean ret = VMSNetSDK.getInstance().getControlUnitList(servAddr, sessionID, String.valueOf(controlUnitID), numPerPage, 127 | curPage, ctrlUnitList); 128 | Log.i(Constants.LOG_TAG, "getControlUnitList ret:" + ret); 129 | responseFlag = responseFlag || ret; 130 | 131 | if (!ret) { 132 | Log.e(Constants.LOG_TAG, "Invoke VMSNetSDK.getControlUnitList failed:" + errDesc()); 133 | } 134 | List regionList = new ArrayList(); 135 | // 2.从控制中心获取区域列表 136 | ret = VMSNetSDK.getInstance().getRegionListFromCtrlUnit(servAddr, sessionID, String.valueOf(controlUnitID), numPerPage, 137 | curPage, regionList); 138 | Log.i(Constants.LOG_TAG, "getRegionListFromCtrlUnit ret:" + ret); 139 | responseFlag = responseFlag || ret; 140 | if (!ret) { 141 | Log.e(Constants.LOG_TAG, "Invoke VMSNetSDK.getRegionListFromCtrlUnit failed:" + errDesc()); 142 | } 143 | 144 | List cameraList = new ArrayList(); 145 | // 3.从控制中心获取摄像头列表 146 | ret = VMSNetSDK.getInstance().getCameraListFromCtrlUnit(servAddr, sessionID, String.valueOf(controlUnitID), numPerPage, 147 | curPage, cameraList); 148 | Log.i(Constants.LOG_TAG, "getCameraListFromCtrlUnit ret:" + ret); 149 | responseFlag = responseFlag || ret; 150 | if (!ret) { 151 | Log.e(Constants.LOG_TAG, "Invoke VMSNetSDK.getCameraListFromCtrlUnit failed:" + errDesc()); 152 | } 153 | 154 | List allData = new ArrayList(); 155 | allData.addAll(ctrlUnitList); 156 | allData.addAll(regionList); 157 | allData.addAll(cameraList); 158 | 159 | Log.i(Constants.LOG_TAG, "allData size is " + allData.size()); 160 | if (callback != null) { 161 | callback.onMsg(responseFlag ? MsgIds.GET_SUB_F_C_SUC : MsgIds.GET_SUB_F_C_FAIL, allData); 162 | } 163 | } 164 | 165 | /** 166 | * 第一次请求资源列表 167 | */ 168 | private void requestFirstList() { 169 | String servAddr = Config.getIns().getServerAddr(); 170 | ServInfo loginData = TempData.getIns().getLoginData(); 171 | if (loginData == null) { 172 | Log.i(Constants.LOG_TAG, "requestFirstList loginData:" + loginData); 173 | return; 174 | } 175 | String sessionID = loginData.getSessionID(); 176 | int controlUnitID = 0;// 首次获取数据,表示根目录 177 | int numPerPage = 10000;// 此处传10000,由于实际不可能有那么多,表示获取所有数据 178 | int curPage = 1; 179 | List ctrlUnitList = new ArrayList(); 180 | // 获取控制中心列表 181 | boolean ret = VMSNetSDK.getInstance().getControlUnitList(servAddr, sessionID, String.valueOf(controlUnitID), numPerPage, 182 | curPage, ctrlUnitList); 183 | Log.i(Constants.LOG_TAG, "getControlUnitList ret:" + ret); 184 | if (ctrlUnitList != null && !ctrlUnitList.isEmpty()) { 185 | for (ControlUnitInfo info : ctrlUnitList) { 186 | Log.i(Constants.LOG_TAG, "name:" + info.getName() + ",controlUnitID:" + info.getControlUnitID() + ",parentID:" 187 | + info.getParentID()); 188 | } 189 | } 190 | Log.i(Constants.LOG_TAG, "allData size is " + ctrlUnitList.size()); 191 | if (!ret) { 192 | Log.e(Constants.LOG_TAG, "Invoke VMSNetSDK.getControlUnitList failed:" + errDesc()); 193 | } 194 | if (callback != null) { 195 | callback.onMsg(ret ? MsgIds.GET_C_F_NONE_SUC : MsgIds.GET_C_F_NONE_FAIL, ctrlUnitList); 196 | } 197 | 198 | } 199 | 200 | /** 201 | * 错误描述 202 | * 203 | * @return 204 | */ 205 | private String errDesc() { 206 | return "errorDesc:" + VMSNetSDK.getInstance().getLastErrorDesc() + ",errorCode:" 207 | + VMSNetSDK.getInstance().getLastErrorCode(); 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /app/src/main/java/com/demo/sdk6x/resource/ResourceListActivity.java: -------------------------------------------------------------------------------- 1 | package com.demo.sdk6x.resource; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.demo.sdk6x.R; 7 | import com.demo.sdk6x.callback.MsgCallback; 8 | import com.demo.sdk6x.callback.MsgIds; 9 | import com.demo.sdk6x.constants.Constants; 10 | import com.demo.sdk6x.data.TempData; 11 | import com.demo.sdk6x.listviewlayout.ListViewForScrollView; 12 | import com.demo.sdk6x.live.LiveActivity; 13 | import com.demo.sdk6x.playback.PlayBackActivity; 14 | import com.demo.sdk6x.utils.UIUtil; 15 | import com.hikvision.vmsnetsdk.CameraInfo; 16 | import com.hikvision.vmsnetsdk.ControlUnitInfo; 17 | import com.hikvision.vmsnetsdk.RegionInfo; 18 | 19 | import android.annotation.SuppressLint; 20 | import android.app.Activity; 21 | import android.app.AlertDialog; 22 | import android.app.Dialog; 23 | import android.content.DialogInterface; 24 | import android.content.Intent; 25 | import android.os.Bundle; 26 | import android.os.Handler; 27 | import android.os.Message; 28 | import android.util.Log; 29 | import android.view.View; 30 | import android.widget.AdapterView; 31 | import android.widget.AdapterView.OnItemClickListener; 32 | 33 | public class ResourceListActivity extends Activity implements MsgCallback,OnItemClickListener{ 34 | 35 | /** 36 | * 资源列表 37 | */ 38 | private ListViewForScrollView resourceListView; 39 | private List mList; 40 | private ResourceListAdapter mAdapter; 41 | // private ScrollView sv; 42 | /** 43 | * 父节点资源类型,TYPE_UNKNOWN表示首次获取资源列表 44 | */ 45 | private int pResType = Constants.Resource.TYPE_UNKNOWN; 46 | /** 47 | * 父控制中心的id,只有当parentResType为TYPE_CTRL_UNIT才有用 48 | */ 49 | private int pCtrlUnitId; 50 | /** 51 | * 父区域的id,只有当parentResType为TYPE_REGION才有用 52 | */ 53 | private int pRegionId; 54 | /** 55 | * 消息处理Handler 56 | */ 57 | private MsgHandler handler; 58 | /** 59 | * 获取资源逻辑控制类 60 | */ 61 | private ResourceControl rc; 62 | private Dialog mDialog; 63 | 64 | private static final int GOTO_LIVE_OR_PLAYBACK = 0x0b; 65 | 66 | @Override 67 | protected void onCreate(Bundle savedInstanceState) { 68 | // TODO Auto-generated method stub 69 | super.onCreate(savedInstanceState); 70 | setContentView(R.layout.resource_list_activity); 71 | 72 | resourceListView = (ListViewForScrollView) findViewById(R.id.ctrlunit_list); 73 | 74 | resourceListView.setOnItemClickListener(this); 75 | // sv = (ScrollView) findViewById(R.id.mScrollView); 76 | // sv.smoothScrollTo(0, 0); 77 | mList = new ArrayList(); 78 | handler = new MsgHandler(); 79 | rc = new ResourceControl(); 80 | rc.setCallback(this); 81 | // initData(); 82 | 83 | mAdapter = new ResourceListAdapter(ResourceListActivity.this ,mList); 84 | resourceListView.setAdapter(mAdapter); 85 | 86 | reqResList(); 87 | } 88 | 89 | // private void setListViewHeightBasedOnChildren(ListView listView) { 90 | // ListAdapter listAdapter = listView.getAdapter(); 91 | // if (listAdapter == null) { 92 | // return; 93 | // } 94 | // 95 | // int totalHeight = 0; 96 | // for (int i = 0; i < listAdapter.getCount(); i++) { 97 | // View listItem = listAdapter.getView(i, null, listView); 98 | // listItem.measure(0, 0); 99 | // totalHeight += listItem.getMeasuredHeight(); 100 | // } 101 | // 102 | // ViewGroup.LayoutParams params = listView.getLayoutParams(); 103 | // params.height = totalHeight 104 | // + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); 105 | // listView.setLayoutParams(params); 106 | // } 107 | 108 | // /** 109 | // * 初始化数据 110 | // */ 111 | // private void initData() { 112 | // Intent intent = getIntent(); 113 | // if (intent.hasExtra(Constants.IntentKey.CONTROL_UNIT_ID)) { 114 | // pResType = Constants.Resource.TYPE_CTRL_UNIT; 115 | // pCtrlUnitId = intent 116 | // .getIntExtra(Constants.IntentKey.CONTROL_UNIT_ID, 0); 117 | // Log.i(Constants.LOG_TAG, 118 | // "Getting resource from ctrlunit.parent id is " 119 | // + pCtrlUnitId); 120 | // } else if (intent.hasExtra(Constants.IntentKey.REGION_ID)) { 121 | // pResType = Constants.Resource.TYPE_REGION; 122 | // pRegionId = intent.getIntExtra(Constants.IntentKey.REGION_ID, 0); 123 | // Log.i(Constants.LOG_TAG, 124 | // "Getting resource from region. parent id is " + pRegionId); 125 | // } else { 126 | // pResType = Constants.Resource.TYPE_UNKNOWN; 127 | // Log.i(Constants.LOG_TAG, "Getting resource for the first time."); 128 | // } 129 | // } 130 | 131 | /** 132 | * 请求资源列表 133 | */ 134 | private void reqResList() { 135 | 136 | new Thread(new Runnable() { 137 | @Override 138 | public void run() { 139 | int pId = 0; 140 | if (Constants.Resource.TYPE_CTRL_UNIT == pResType) { 141 | pId = pCtrlUnitId; 142 | } else if (Constants.Resource.TYPE_REGION == pResType) { 143 | pId = pRegionId; 144 | } 145 | rc.reqResList(pResType, pId); 146 | } 147 | }).start(); 148 | } 149 | 150 | 151 | @SuppressLint("HandlerLeak") 152 | private final class MsgHandler extends Handler { 153 | @Override 154 | public void handleMessage(Message msg) { 155 | super.handleMessage(msg); 156 | switch (msg.what) { 157 | 158 | // 获取控制中心列表成功 159 | case MsgIds.GET_C_F_NONE_SUC: 160 | 161 | // 从控制中心获取下级资源列表成功 162 | case MsgIds.GET_SUB_F_C_SUC: 163 | 164 | // 从区域获取下级列表成功 165 | case MsgIds.GET_SUB_F_R_SUC: 166 | refreshResList((List)msg.obj); 167 | break; 168 | 169 | // 获取控制中心列表失败 170 | case MsgIds.GET_C_F_NONE_FAIL: 171 | 172 | // 调用getControlUnitList失败 173 | case MsgIds.GET_CU_F_CU_FAIL: 174 | 175 | // 调用getRegionListFromCtrlUnit失败 176 | case MsgIds.GET_R_F_C_FAIL: 177 | 178 | // 调用getCameraListFromCtrlUnit失败 179 | case MsgIds.GET_C_F_C_FAIL: 180 | 181 | // 从控制中心获取下级资源列表成失败 182 | case MsgIds.GET_SUB_F_C_FAIL: 183 | 184 | // 调用getRegionListFromRegion失败 185 | case MsgIds.GET_R_F_R_FAIL: 186 | 187 | // 调用getCameraListFromRegion失败 188 | case MsgIds.GET_C_F_R_FAIL: 189 | 190 | // 从区域获取下级列表失败 191 | case MsgIds.GET_SUB_F_R_FAILED: 192 | onGetResListFailed(); 193 | break; 194 | case GOTO_LIVE_OR_PLAYBACK: 195 | CameraInfo cInfo = (CameraInfo)msg.obj; 196 | 197 | gotoLiveorPlayBack(cInfo); 198 | break; 199 | default: 200 | break; 201 | } 202 | } 203 | } 204 | 205 | /** 206 | * 调用接口失败时,界面弹出提示 207 | */ 208 | private void onGetResListFailed() { 209 | UIUtil.showToast(this, 210 | getString(R.string.fetch_reslist_failed, UIUtil.getErrorDesc())); 211 | } 212 | 213 | /** 214 | * 获取数据成功后刷新列表 215 | * 216 | * @param data 217 | */ 218 | private void refreshResList(List data) { 219 | if (data == null || data.isEmpty()) { 220 | UIUtil.showToast(this, R.string.no_data_tip); 221 | return; 222 | } 223 | UIUtil.showToast(this, R.string.fetch_resource_suc); 224 | // if(mAdapter != null){ 225 | mAdapter.setData(data); 226 | // } 227 | } 228 | 229 | @Override 230 | public void onMsg(int msgId, Object data) { 231 | // TODO Auto-generated method stub 232 | Message msg = Message.obtain(); 233 | msg.what = msgId; 234 | msg.obj = data; 235 | handler.sendMessage(msg); 236 | } 237 | 238 | @Override 239 | public void onItemClick(AdapterView parent, View view, int position, 240 | long id) { 241 | // TODO Auto-generated method stub 242 | 243 | final Object itemData = mAdapter.getItem(position); 244 | // String itemName = getItemName(itemData); 245 | 246 | new Thread(new Runnable() { 247 | @Override 248 | public void run() { 249 | 250 | if (itemData instanceof CameraInfo) { 251 | CameraInfo info = (CameraInfo) itemData; 252 | //得到摄像头,进行预览或者回放 253 | Log.i(Constants.LOG_TAG,"get Camera:" + info.getName() + "---" + info.getDeviceID()); 254 | onMsg(GOTO_LIVE_OR_PLAYBACK,info); 255 | }else{ 256 | int pId = 0; 257 | if (itemData instanceof ControlUnitInfo) { 258 | ControlUnitInfo info = (ControlUnitInfo) itemData; 259 | pResType = Constants.Resource.TYPE_CTRL_UNIT; 260 | pId = Integer.parseInt(info.getControlUnitID()); 261 | } 262 | 263 | if (itemData instanceof RegionInfo) { 264 | RegionInfo info = (RegionInfo) itemData; 265 | pResType = Constants.Resource.TYPE_REGION; 266 | pId = Integer.parseInt(info.getRegionID()); 267 | } 268 | 269 | rc.reqResList(pResType, pId); 270 | } 271 | 272 | } 273 | 274 | 275 | }).start(); 276 | } 277 | 278 | private void gotoLiveorPlayBack(final CameraInfo info) { 279 | // TODO Auto-generated method stub 280 | String[] datas = new String[]{"预览","回放"}; 281 | mDialog = new AlertDialog.Builder(ResourceListActivity.this).setSingleChoiceItems(datas, 0, new DialogInterface.OnClickListener() { 282 | 283 | @Override 284 | public void onClick(DialogInterface dialog, int which) { 285 | mDialog.dismiss(); 286 | switch (which) { 287 | case 0: 288 | gotoLive(info); 289 | break; 290 | case 1: 291 | gotoPlayback(info); 292 | break; 293 | default: 294 | break; 295 | } 296 | } 297 | 298 | }).create(); 299 | mDialog.show(); 300 | } 301 | 302 | /**实时预览 303 | * @param info 304 | */ 305 | private void gotoLive(CameraInfo info) { 306 | // TODO Auto-generated method stub 307 | if(info == null){ 308 | Log.e(Constants.LOG_TAG,"gotoLive():: fail"); 309 | return; 310 | } 311 | Intent intent = new Intent(ResourceListActivity.this, LiveActivity.class); 312 | intent.putExtra(Constants.IntentKey.CAMERA_ID, info.getId()); 313 | TempData.getIns().setCameraInfo(info); 314 | ResourceListActivity.this.startActivity(intent); 315 | } 316 | 317 | /**远程回放 318 | * @param info 319 | */ 320 | private void gotoPlayback(CameraInfo info) { 321 | // TODO Auto-generated method stub 322 | if(info == null){ 323 | Log.e(Constants.LOG_TAG,"gotoPlayback():: fail"); 324 | return; 325 | } 326 | Intent intent = new Intent(ResourceListActivity.this, PlayBackActivity.class); 327 | intent.putExtra(Constants.IntentKey.CAMERA_ID, info.getId()); 328 | ResourceListActivity.this.startActivity(intent); 329 | } 330 | 331 | 332 | } 333 | -------------------------------------------------------------------------------- /app/src/main/java/com/demo/sdk6x/resource/ResourceListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.demo.sdk6x.resource; 2 | 3 | import java.util.List; 4 | 5 | import com.demo.sdk6x.R; 6 | import com.hikvision.vmsnetsdk.CameraInfo; 7 | import com.hikvision.vmsnetsdk.ControlUnitInfo; 8 | import com.hikvision.vmsnetsdk.RegionInfo; 9 | 10 | import android.content.Context; 11 | import android.view.LayoutInflater; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.widget.BaseAdapter; 15 | import android.widget.TextView; 16 | 17 | public class ResourceListAdapter extends BaseAdapter { 18 | 19 | private Context mContext = null; 20 | private List mList = null; 21 | private LayoutInflater mListContainer = null; 22 | 23 | 24 | public ResourceListAdapter(Context context, List list) { 25 | mContext = context; 26 | mList = list; 27 | // 创建视图容器并设置上下文 28 | mListContainer = LayoutInflater.from(context); 29 | } 30 | 31 | @Override 32 | public int getCount() { 33 | if (mList == null) { 34 | return 0; 35 | } 36 | return mList.size(); 37 | } 38 | 39 | @Override 40 | public Object getItem(int position) { 41 | if (mList == null) { 42 | return null; 43 | } 44 | return mList.get(position); 45 | } 46 | 47 | @Override 48 | public long getItemId(int position) { 49 | // TODO Auto-generated method stub 50 | return position; 51 | } 52 | 53 | @Override 54 | public View getView(int position, View convertView, ViewGroup parent) { 55 | ViewHolder viewHolder; 56 | if(convertView == null){ 57 | viewHolder = new ViewHolder(); 58 | // 获取list_item布局文件的视图 59 | convertView = mListContainer.inflate(R.layout.resource_item_layout, null); 60 | // 获取控件对象 61 | viewHolder.tv = (TextView) convertView.findViewById(R.id.item_txt); 62 | convertView.setTag(viewHolder); 63 | }else{ 64 | viewHolder = (ViewHolder)convertView.getTag(); 65 | } 66 | // 67 | Object itemData = getItem(position); 68 | String itemName = getItemName(itemData); 69 | viewHolder.tv.setText(itemName); 70 | 71 | return convertView; 72 | } 73 | 74 | //获得资源列表名称 75 | private String getItemName(Object itemData) { 76 | if (itemData instanceof ControlUnitInfo) { 77 | ControlUnitInfo info = (ControlUnitInfo) itemData; 78 | return info.getName(); 79 | } 80 | 81 | if (itemData instanceof RegionInfo) { 82 | RegionInfo info = (RegionInfo) itemData; 83 | return info.getName(); 84 | } 85 | 86 | if (itemData instanceof CameraInfo) { 87 | CameraInfo info = (CameraInfo) itemData; 88 | return info.getName(); 89 | } 90 | 91 | return null; 92 | } 93 | 94 | public void setData(List data) { 95 | this.mList = data; 96 | notifyDataSetChanged(); 97 | } 98 | 99 | class ViewHolder { 100 | TextView tv = null; 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /app/src/main/java/com/demo/sdk6x/utils/Base64Utils.java: -------------------------------------------------------------------------------- 1 | package com.demo.sdk6x.utils; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.io.UnsupportedEncodingException; 6 | 7 | /** 8 | * @author Mr.Zheng 9 | * @date 2014��8��22�� ����9:50:28 10 | */ 11 | public class Base64Utils { 12 | private static char[] base64EncodeChars = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 13 | 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 14 | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', 15 | '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; 16 | private static byte[] base64DecodeChars = new byte[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 18 | -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 19 | 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 20 | 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, 21 | -1, -1, -1 }; 22 | 23 | /** 24 | * ���� 25 | * 26 | * @param data 27 | * @return 28 | */ 29 | public static String encode(byte[] data) { 30 | if (data == null) { 31 | return ""; 32 | } 33 | StringBuffer sb = new StringBuffer(); 34 | int len = data.length; 35 | int i = 0; 36 | int b1, b2, b3; 37 | while (i < len) { 38 | b1 = data[i++] & 0xff; 39 | if (i == len) { 40 | sb.append(base64EncodeChars[b1 >>> 2]); 41 | sb.append(base64EncodeChars[(b1 & 0x3) << 4]); 42 | sb.append("=="); 43 | break; 44 | } 45 | b2 = data[i++] & 0xff; 46 | if (i == len) { 47 | sb.append(base64EncodeChars[b1 >>> 2]); 48 | sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]); 49 | sb.append(base64EncodeChars[(b2 & 0x0f) << 2]); 50 | sb.append("="); 51 | break; 52 | } 53 | b3 = data[i++] & 0xff; 54 | sb.append(base64EncodeChars[b1 >>> 2]); 55 | sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]); 56 | sb.append(base64EncodeChars[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]); 57 | sb.append(base64EncodeChars[b3 & 0x3f]); 58 | } 59 | return sb.toString(); 60 | } 61 | 62 | /** 63 | * ���� 64 | * 65 | * @param str 66 | * @return 67 | */ 68 | public static byte[] decode(String str) { 69 | try { 70 | return decodePrivate(str); 71 | } catch (UnsupportedEncodingException e) { 72 | e.printStackTrace(); 73 | } 74 | return new byte[] {}; 75 | } 76 | 77 | private static byte[] decodePrivate(String str) throws UnsupportedEncodingException { 78 | if(TextUtils.isEmpty(str)){ 79 | return null; 80 | } 81 | StringBuffer sb = new StringBuffer(); 82 | byte[] data = null; 83 | data = str.getBytes("US-ASCII"); 84 | int len = data.length; 85 | int i = 0; 86 | int b1, b2, b3, b4; 87 | while (i < len) { 88 | 89 | do { 90 | b1 = base64DecodeChars[data[i++]]; 91 | } while (i < len && b1 == -1); 92 | if (b1 == -1) 93 | break; 94 | 95 | do { 96 | b2 = base64DecodeChars[data[i++]]; 97 | } while (i < len && b2 == -1); 98 | if (b2 == -1) 99 | break; 100 | sb.append((char) ((b1 << 2) | ((b2 & 0x30) >>> 4))); 101 | 102 | do { 103 | b3 = data[i++]; 104 | if (b3 == 61) 105 | return sb.toString().getBytes("iso8859-1"); 106 | b3 = base64DecodeChars[b3]; 107 | } while (i < len && b3 == -1); 108 | if (b3 == -1) 109 | break; 110 | sb.append((char) (((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2))); 111 | 112 | do { 113 | b4 = data[i++]; 114 | if (b4 == 61) 115 | return sb.toString().getBytes("iso8859-1"); 116 | b4 = base64DecodeChars[b4]; 117 | } while (i < len && b4 == -1); 118 | if (b4 == -1) 119 | break; 120 | sb.append((char) (((b3 & 0x03) << 6) | b4)); 121 | } 122 | return sb.toString().getBytes("iso8859-1"); 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /app/src/main/java/com/demo/sdk6x/utils/DebugLog.java: -------------------------------------------------------------------------------- 1 | package com.demo.sdk6x.utils; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * 打印日志类 7 | * @author huangweifeng 8 | * @Data 2013-10-15 9 | */ 10 | public class DebugLog { 11 | 12 | /** 13 | * 设置是否打印日志 14 | * @param isPrintLog 15 | * void 16 | * @since V1.0 17 | */ 18 | public static void setLogOption(boolean isPrintLog) { 19 | DEBUG = isPrintLog; 20 | } 21 | 22 | private static boolean DEBUG = true; 23 | 24 | private DebugLog() { 25 | } 26 | 27 | /** 28 | * 这里对方法做描述 29 | * @param tag 30 | * @param desc 31 | * void 32 | * @since V1.0 33 | */ 34 | public static void debug(String tag, String desc) { 35 | if (DEBUG) Log.d(tag, desc); 36 | } 37 | 38 | /** 39 | * 这里对方法做描述 40 | * @param tag 41 | * @param desc 42 | * void 43 | * @since V1.0 44 | */ 45 | public static void verbose(String tag, String desc) { 46 | if (DEBUG) Log.v(tag, desc); 47 | } 48 | 49 | /** 50 | * 这里对方法做描述 51 | * @param tag 52 | * @param desc 53 | * void 54 | * @since V1.0 55 | */ 56 | public static void warn(String tag, String desc) { 57 | if (DEBUG) Log.w(tag, desc); 58 | } 59 | 60 | /** 61 | * 这里对方法做描述 62 | * @param tag 63 | * @param desc 64 | * void 65 | * @since V1.0 66 | */ 67 | public static void info(String tag, String desc) { 68 | if (DEBUG) Log.i(tag, desc); 69 | } 70 | 71 | /** 72 | * 这里对方法做描述 73 | * @param tag 74 | * @param desc 75 | * void 76 | * @since V1.0 77 | */ 78 | public static void error(String tag, String desc) { 79 | if (DEBUG) Log.e(tag, desc); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/demo/sdk6x/utils/TimerUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * @ProjectName iVMS-5060_V3.0 3 | * @Copyright HangZhou Hikvision System Technology Co.,Ltd. All Right Reserved 4 | * 5 | * @FileName TimerUtil.java 6 | * @Description 这里对文件进行描述 7 | * 8 | * @author mlianghua 9 | * @data Jul 12, 2012 10 | * 11 | * @note 这里写本文件的详细功能描述和注释 12 | * @note 历史记录 13 | * 14 | * @warning 这里写本文件的相关警告 15 | */ 16 | package com.demo.sdk6x.utils; 17 | 18 | import java.text.SimpleDateFormat; 19 | import java.util.Calendar; 20 | import java.util.Date; 21 | import java.util.Locale; 22 | 23 | import com.demo.sdk6x.R; 24 | 25 | 26 | 27 | import android.content.Context; 28 | import android.os.Handler; 29 | import android.util.Log; 30 | 31 | /** 32 | * 在此对类做相应的描述 33 | * 34 | * @author mlianghua 35 | * @Data Jul 12, 2012 36 | */ 37 | public class TimerUtil { 38 | private static final String TAG = "TimerUtil"; 39 | 40 | private static Handler mTimeHandler = null; 41 | private static boolean mTimerMark = false; 42 | private static Runnable mTimerRunnable = null; 43 | private static int mUpdateTime = 0; 44 | 45 | private TimerUtil() { 46 | }; 47 | 48 | /** 49 | * 定时器开始定时 50 | * 51 | * @param doThing 定时器处理事情 52 | * @param updateTime 定时器时间 53 | * @since V1.0 54 | */ 55 | public static void startTime(Runnable doThing, int updateTime) { 56 | if (null == doThing || updateTime < 0) { 57 | return; 58 | } 59 | 60 | if (null == mTimeHandler) { 61 | mTimeHandler = new Handler(); 62 | mTimerRunnable = doThing; 63 | mUpdateTime = updateTime; 64 | mTimerMark = true; 65 | } 66 | 67 | if (mTimerMark) { 68 | mTimeHandler.postDelayed(mTimerRunnable, 0); 69 | } else { 70 | mTimeHandler.postDelayed(null, 0); 71 | } 72 | } 73 | 74 | /** 75 | * 定时器开始定时 76 | * 77 | * @param doThing 定时器处理事情 78 | * @param updateTime 定时器时间 79 | * @param mode 定时器模式 80 | * @since V1.0 81 | */ 82 | public static void startTime(Runnable doThing, int updateTime, boolean mode) { 83 | if (null == doThing || updateTime < 0) { 84 | return; 85 | } 86 | 87 | if (null == mTimeHandler) { 88 | mTimeHandler = new Handler(); 89 | mTimerRunnable = doThing; 90 | mUpdateTime = updateTime; 91 | mTimerMark = true; 92 | } 93 | 94 | if (mTimerMark) { 95 | if (mode) { 96 | mTimeHandler.postDelayed(mTimerRunnable, 0); 97 | } else { 98 | mTimeHandler.postDelayed(mTimerRunnable, updateTime); 99 | } 100 | } else { 101 | mTimeHandler.postDelayed(null, 0); 102 | } 103 | } 104 | 105 | /** 106 | * 这里对方法做描述 107 | * 108 | * @since V1.0 109 | */ 110 | public static void updataTime() { 111 | if (mTimerMark) { 112 | mTimeHandler.postDelayed(mTimerRunnable, mUpdateTime); 113 | } else { 114 | mTimeHandler.postDelayed(null, 0); 115 | } 116 | } 117 | 118 | /** 119 | * 这里对方法做描述 120 | * 121 | * @since V1.0 122 | */ 123 | public static void stopTime() { 124 | mTimerMark = false; 125 | if (null != mTimeHandler) { 126 | mTimeHandler.removeCallbacks(mTimerRunnable); 127 | mTimeHandler = null; 128 | } 129 | } 130 | 131 | /** 132 | * time格式 String型的日 如:昨天、今天、8月24日 15:30 133 | * @param ltime 134 | * @param context 135 | * @return 136 | * @since V1.0 137 | */ 138 | public synchronized static String getTime_FormatTime_MMDD(long ltime, Context context) { 139 | String time = ""; 140 | 141 | Calendar dateCalendar = Calendar.getInstance(); 142 | dateCalendar.setTimeInMillis(ltime); 143 | 144 | Calendar targetCalendar = Calendar.getInstance(); 145 | targetCalendar.set(Calendar.HOUR_OF_DAY, 0); 146 | targetCalendar.set(Calendar.MINUTE, 0); 147 | 148 | 149 | 150 | if (dateCalendar.after(targetCalendar)) { 151 | time = context.getString(R.string.today) +" "+ time; 152 | return time; 153 | } else { 154 | targetCalendar.add(Calendar.DATE, -1); 155 | if (dateCalendar.after(targetCalendar)) { 156 | time = context.getString(R.string.yesterday) +" "+ time; 157 | return time; 158 | } 159 | } 160 | 161 | String otherSDF = context.getString(R.string.mmdd); 162 | Date date = dateCalendar.getTime(); 163 | SimpleDateFormat sfd = new SimpleDateFormat(otherSDF); 164 | time = sfd.format(date); 165 | Log.d(TAG, "getTime_FormatTime_MMDD time:"+time); 166 | return time; 167 | } 168 | 169 | /** 170 | * time格式 String型的日 如:昨天、今天、8月24日 15:30 171 | * @param ltime 172 | * @param context 173 | * @return 174 | * @since V1.0 175 | */ 176 | public synchronized static String getTime_FormatTime_MMDDHHMM(long ltime, Context context) { 177 | String time = ""; 178 | 179 | Calendar dateCalendar = Calendar.getInstance(); 180 | dateCalendar.setTimeInMillis(ltime); 181 | 182 | int month = dateCalendar.get(Calendar.MONTH) + 1; 183 | int day = dateCalendar.get(Calendar.DAY_OF_MONTH); 184 | int hour = dateCalendar.get(Calendar.HOUR_OF_DAY); 185 | int minute = dateCalendar.get(Calendar.MINUTE); 186 | 187 | time = String.format("%02d:%02d", hour, minute); 188 | 189 | Calendar targetCalendar = Calendar.getInstance(); 190 | targetCalendar.set(Calendar.HOUR_OF_DAY, 0); 191 | targetCalendar.set(Calendar.MINUTE, 0); 192 | if (dateCalendar.after(targetCalendar)) { 193 | time = context.getString(R.string.today) +" "+ time; 194 | return time; 195 | } else { 196 | targetCalendar.add(Calendar.DATE, -1); 197 | if (dateCalendar.after(targetCalendar)) { 198 | time = context.getString(R.string.yesterday) +" "+ time; 199 | return time; 200 | } 201 | } 202 | 203 | time = String.format(Locale.ENGLISH,"%02d-%02d %02d:%02d", month, day, hour, minute); 204 | Log.d(TAG, "getTime_FormatTime_MMDDHHMM time:"+time); 205 | return time; 206 | } 207 | 208 | /** 209 | * 这里对方法做描述 210 | * 211 | * @return time格式 nnnn-mm-dd hh:mm:ss 212 | * @since V1.0 213 | */ 214 | public synchronized static String getTime_nnnnyydd(long t) { 215 | if (t == 0) { 216 | return ""; 217 | } 218 | 219 | Calendar cale = Calendar.getInstance(); 220 | cale.setTimeInMillis(t); 221 | int year = cale.get(Calendar.YEAR); 222 | int month = cale.get(Calendar.MONTH) + 1; 223 | int day = cale.get(Calendar.DAY_OF_MONTH); 224 | int hour = cale.get(Calendar.HOUR_OF_DAY); 225 | int minute = cale.get(Calendar.MINUTE); 226 | int second = cale.get(Calendar.SECOND); 227 | 228 | String time = String.format(Locale.ENGLISH, "%d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second); 229 | Log.d(TAG, "getTime_nnnnyydd time:"+time); 230 | return time; 231 | } 232 | 233 | /** 234 | * 这里对方法做描述 235 | * 236 | * @return time格式 nnnn-mm-dd hh:mm:ss 237 | * @since V1.0 238 | */ 239 | public synchronized static String getTime_nnnnyydd(Calendar cale) { 240 | if (cale == null) { 241 | return ""; 242 | } 243 | 244 | int year = cale.get(Calendar.YEAR); 245 | int month = cale.get(Calendar.MONTH) + 1; 246 | int day = cale.get(Calendar.DAY_OF_MONTH); 247 | int hour = cale.get(Calendar.HOUR_OF_DAY); 248 | int minute = cale.get(Calendar.MINUTE); 249 | int second = cale.get(Calendar.SECOND); 250 | String time = String.format(Locale.ENGLISH,"%d-%02d-%02d %02d:%02d:%02d", year,month,day, hour, minute, second); 251 | Log.d(TAG, "getTime_nnnnyydd time:" + time); 252 | return time; 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /app/src/main/java/com/demo/sdk6x/utils/UIUtil.java: -------------------------------------------------------------------------------- 1 | package com.demo.sdk6x.utils; 2 | 3 | import android.app.ProgressDialog; 4 | import android.content.Context; 5 | import android.widget.Toast; 6 | 7 | import com.hikvision.vmsnetsdk.VMSNetSDK; 8 | 9 | public final class UIUtil { 10 | private static ProgressDialog dialog; 11 | 12 | private UIUtil() { 13 | } 14 | 15 | public static void showToast(Context c, int resId) { 16 | Toast.makeText(c, resId, Toast.LENGTH_SHORT).show(); 17 | } 18 | 19 | public static void showToast(Context c, String desc) { 20 | Toast.makeText(c, desc, Toast.LENGTH_SHORT).show(); 21 | } 22 | 23 | public static void showProgressDialog(Context c, String msg) { 24 | dialog = ProgressDialog.show(c, "", msg); 25 | } 26 | 27 | public static void showProgressDialog(Context c, int resId) { 28 | dialog = ProgressDialog.show(c, "", c.getString(resId)); 29 | } 30 | 31 | public static void cancelProgressDialog() { 32 | if (dialog != null) { 33 | dialog.cancel(); 34 | dialog = null; 35 | } 36 | } 37 | 38 | public static String getErrorDesc() { 39 | int errorCode = VMSNetSDK.getInstance().getLastErrorCode(); 40 | String errorDesc = VMSNetSDK.getInstance().getLastErrorDesc(); 41 | return "errorCode:" + errorCode + ",errorDesc:" + errorDesc; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/demo/sdk6x/utils/UtilAudioPlay.java: -------------------------------------------------------------------------------- 1 | package com.demo.sdk6x.utils; 2 | 3 | import android.content.Context; 4 | import android.media.AudioManager; 5 | import android.media.SoundPool; 6 | import android.os.AsyncTask; 7 | import android.os.Handler; 8 | 9 | /** 10 | * 抓拍时的声音类 11 | * @author huangweifeng 12 | * @Data 2013-10-23 13 | */ 14 | public class UtilAudioPlay { 15 | 16 | private static SoundPool mSoundPool = null; 17 | private static UtilAudioPlay mPlayAudioTask = new UtilAudioPlay(); 18 | private static int mSoundId = -1; 19 | 20 | private UtilAudioPlay() { 21 | }; 22 | 23 | /** 24 | * 这里对方法做描述 25 | * 26 | * @param context 上下文 27 | * @param rawFile 音频文件 28 | * @since V1.0 29 | */ 30 | public synchronized static void playAudioFile(Context context, int rawFile) { 31 | 32 | if (null == mSoundPool) { 33 | mSoundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 100); 34 | mSoundId = mSoundPool.load(context, rawFile, 1); 35 | 36 | new Handler().postDelayed(mPlayAudioTask.new PlayAudioTask1(), 100); 37 | } else { 38 | if (-1 != mSoundId) 39 | mPlayAudioTask.new PlayAudioTask().execute(mSoundId); 40 | } 41 | } 42 | 43 | private class PlayAudioTask1 implements Runnable { 44 | @Override 45 | public void run() { 46 | mPlayAudioTask.new PlayAudioTask().execute(mSoundId); 47 | } 48 | } 49 | 50 | private class PlayAudioTask extends AsyncTask { 51 | @Override 52 | protected Void doInBackground(Integer... soundId) { 53 | mSoundPool.play(soundId[0], 1, 1, 1, 0, 1); 54 | return null; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/demo/sdk6x/utils/UtilFilePath.java: -------------------------------------------------------------------------------- 1 | package com.demo.sdk6x.utils; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | /** 6 | * 获取抓拍、录像路径类 7 | * 8 | * @author huangweifeng 9 | * @Data 2013-10-23 10 | */ 11 | public class UtilFilePath { 12 | 13 | /** 14 | * 获取图片目录 15 | * 16 | * @return Pictrue dir path. 17 | * @since V1.0 18 | */ 19 | public static File getPictureDirPath() { 20 | File SDFile = null; 21 | File mIVMSFolder = null; 22 | try { 23 | SDFile = android.os.Environment.getExternalStorageDirectory(); 24 | String path = SDFile.getAbsolutePath() + File.separator + "HIKVISION"; 25 | mIVMSFolder = new File(path); 26 | if ((null != mIVMSFolder) && (!mIVMSFolder.exists())) { 27 | mIVMSFolder.mkdir(); 28 | mIVMSFolder.createNewFile(); 29 | } 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | } 33 | return mIVMSFolder; 34 | } 35 | 36 | /** 37 | * 获取录像目录 38 | * 39 | * @return Video dir path. 40 | * @since V1.0 41 | */ 42 | public static File getVideoDirPath() { 43 | File SDFile = null; 44 | File mIVMSFolder = null; 45 | try { 46 | SDFile = android.os.Environment.getExternalStorageDirectory(); 47 | mIVMSFolder = new File(SDFile.getAbsolutePath() + File.separator + "HIKVISION"); 48 | if ((null != mIVMSFolder) && (!mIVMSFolder.exists())) { 49 | mIVMSFolder.mkdir(); 50 | mIVMSFolder.createNewFile(); 51 | } 52 | } catch (IOException e) { 53 | e.printStackTrace(); 54 | } 55 | return mIVMSFolder; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/demo/sdk6x/utils/UtilSDCard.java: -------------------------------------------------------------------------------- 1 | package com.demo.sdk6x.utils; 2 | 3 | import java.io.File; 4 | 5 | import android.os.Environment; 6 | import android.os.StatFs; 7 | 8 | /** 9 | * SDCard检测类 10 | * @author huangweifeng 11 | * @Data 2013-10-23 12 | */ 13 | public class UtilSDCard { 14 | 15 | /** 16 | * 获取SDCard 路径 17 | * 18 | * @return SDCard 路径 19 | * @since V1.0 20 | */ 21 | public static File getSDCardPath() { 22 | return android.os.Environment.getExternalStorageDirectory(); 23 | } 24 | 25 | /** 26 | * 获取SDCard剩下的大小 27 | * 28 | * @return SDCard剩下的大小 29 | * @since V1.0 30 | */ 31 | public static long getSDCardRemainSize() { 32 | StatFs statfs = new StatFs(Environment.getExternalStorageDirectory().getPath()); 33 | long blockSize = statfs.getBlockSize(); 34 | long availableBlocks = statfs.getAvailableBlocks(); 35 | return availableBlocks * blockSize; 36 | } 37 | 38 | /** 39 | * 获取SDCard的状态 40 | * 41 | * @return SDCard 可用的状态 42 | */ 43 | public static boolean isSDCardUsable() { 44 | boolean SDCardMounted = false; 45 | String sDStateString = android.os.Environment.getExternalStorageState(); 46 | if (sDStateString.equals(android.os.Environment.MEDIA_MOUNTED)) { 47 | SDCardMounted = true; 48 | } 49 | 50 | // 是否正在检测SD卡 51 | if (Environment.getExternalStorageState().equals(Environment.MEDIA_CHECKING) 52 | || Environment.getExternalStorageState().equals(Environment.MEDIA_NOFS)) { 53 | SDCardMounted = false; 54 | } 55 | 56 | // 检测是否插有SD卡 57 | if (Environment.getExternalStorageState().equals(Environment.MEDIA_REMOVED) 58 | || Environment.getExternalStorageState().equals(Environment.MEDIA_UNMOUNTED)) { 59 | SDCardMounted = false; 60 | } 61 | 62 | // 检测SD卡是否连接电脑共享 63 | if (Environment.getExternalStorageState().equals(Environment.MEDIA_SHARED)) { 64 | SDCardMounted = false; 65 | } 66 | 67 | return SDCardMounted; 68 | } 69 | } -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libCpuFeatures.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/src/main/jniLibs/armeabi/libCpuFeatures.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libMCRSDK.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/src/main/jniLibs/armeabi/libMCRSDK.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libPlayCtrl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/src/main/jniLibs/armeabi/libPlayCtrl.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libPlayCtrl_v5.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/src/main/jniLibs/armeabi/libPlayCtrl_v5.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libPlayCtrl_v7.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/src/main/jniLibs/armeabi/libPlayCtrl_v7.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libSystemTransform.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/src/main/jniLibs/armeabi/libSystemTransform.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libgnustl_shared.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/src/main/jniLibs/armeabi/libgnustl_shared.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libstlport_shared.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/src/main/jniLibs/armeabi/libstlport_shared.so -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghostsf/hikvision-android/396e3a3f2125918614b80e2d28ccbcc3663788b3/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/layout/live_activity.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | 17 | 21 | 22 | 28 | 29 | 30 | 35 | 36 |