1
zhanghua
2024-09-26 c775c6953d9759e70f08acbfa8f6d7490aaae3d1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
package com.netsdk.demo.customize;
 
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Toolkit;
 
import javax.swing.JWindow;
 
import com.netsdk.demo.util.CaseMenu;
import com.netsdk.lib.NetSDKLib;
import com.netsdk.lib.ToolKits;
import com.netsdk.lib.NetSDKLib.*;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
 
public class VTOTalk {
    static NetSDKLib netsdkApi     = NetSDKLib.NETSDK_INSTANCE;
    static NetSDKLib configApi     = NetSDKLib.CONFIG_INSTANCE;
    
    private NetSDKLib.NET_DEVICEINFO_Ex deviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex();
    
    // 登录句柄
    private static LLong loginHandle = new LLong(0);
    
    // 语音对讲句柄
    public static LLong m_hTalkHandle = new LLong(0);   
    
    private static boolean m_bRecordStatus    = false;
    
    private static LLong m_hRealPlayHandle = new LLong(0);
    
    private static JWindow wnd = new JWindow();
 
    String address             = "172.23.30.60"; // 172.26.6.104
    int    port             = 37777;
    String username         = "admin";
    String password         = "admin123";
    
    private static class DisconnectCallback implements NetSDKLib.fDisConnect {
        private static DisconnectCallback instance = new DisconnectCallback();
        private DisconnectCallback() {}
        public static DisconnectCallback getInstance() { 
            return instance;
        }
        
        public void invoke(LLong lLoginID, String pchDVRIP, int nDVRPort, Pointer dwUser){
            System.out.printf("Device[%s:%d] Disconnect!\n" , pchDVRIP , nDVRPort);
        }
    }
    
    private static class HaveReconnectCallback implements NetSDKLib.fHaveReConnect {
        private static HaveReconnectCallback instance = new HaveReconnectCallback();
        private HaveReconnectCallback() {}
        public static HaveReconnectCallback getInstance() { 
            return instance;
        }
        
        public void invoke(LLong lLoginID, String pchDVRIP, int nDVRPort, Pointer dwUser){
            System.out.printf("Device[%s:%d] HaveReconnected!\n" , pchDVRIP , nDVRPort);
        }
    }
    
    public void EndTest() {
        System.out.println("End Test");
        if( loginHandle.longValue() != 0)
        {
            netsdkApi.CLIENT_Logout(loginHandle);
        }
        System.out.println("See You...");
 
        netsdkApi.CLIENT_Cleanup();
        System.exit(0);
    }
 
    public void InitTest() {
        //初始化SDK库
        netsdkApi.CLIENT_Init(DisconnectCallback.getInstance(), null);
        
        //设置断线自动重练功能
        netsdkApi.CLIENT_SetAutoReconnect(HaveReconnectCallback.getInstance(), null);
        
        // 向设备登入
        int nSpecCap = 0;
        IntByReference nError = new IntByReference(0);
        loginHandle = netsdkApi.CLIENT_LoginEx2(address, port, username,
                password, nSpecCap, null, deviceInfo, nError);
        
        if(loginHandle.longValue() == 0) {
            System.err.printf("Login Device [%s:%d] Failed ! Last Error[%x]\n", address, port, netsdkApi.CLIENT_GetLastError());
            // 释放SDK资源,在关闭工程时调用
            EndTest();
            return;
        }
 
        System.out.printf("Login Device [%s:%d] Success. \n", address, port);    
    }
    
    /**
     * 获取接口错误码
     * @return
     */
    public static String getErrorCode() {
        return " { error code: ( 0x80000000|" + (netsdkApi.CLIENT_GetLastError() & 0x7fffffff) +" ). 参考  NetSDKLib.java }";
    }
 
    
    /**
     * \if ENGLISH_LANG
     * Start Talk
     * \else
     * 开始通话
     * \endif
     */
    public static boolean startTalk() {
    
        // 设置语音对讲编码格式
        NetSDKLib.NETDEV_TALKDECODE_INFO talkEncode = new NetSDKLib.NETDEV_TALKDECODE_INFO();
        talkEncode.encodeType = NetSDKLib.NET_TALK_CODING_TYPE.NET_TALK_PCM;
        talkEncode.dwSampleRate = 8000;
        talkEncode.nAudioBit = 16;
        talkEncode.nPacketPeriod = 25;
        talkEncode.write();
        if(netsdkApi.CLIENT_SetDeviceMode(loginHandle, NetSDKLib.EM_USEDEV_MODE.NET_TALK_ENCODE_TYPE, talkEncode.getPointer())) {
            System.out.println("Set Talk Encode Type Succeed!");
        } else {
            System.err.println("Set Talk Encode Type Failed!" + getErrorCode());
            return false;
        }
        
        // 设置客户端对讲方式
        if (netsdkApi.CLIENT_SetDeviceMode(loginHandle, NetSDKLib.EM_USEDEV_MODE.NET_TALK_CLIENT_MODE, null)) {
            System.out.println("Set Talk Client Mode Succeed!");
        } else {
            System.err.println("Set Talk Client Mode Failed!" + getErrorCode());
            return false;
        }
        
        // 设置对讲模式
        NetSDKLib.NET_SPEAK_PARAM speak = new NetSDKLib.NET_SPEAK_PARAM();
        speak.nMode = 0;
        speak.bEnableWait = false;
        speak.write();
        
        if (netsdkApi.CLIENT_SetDeviceMode(loginHandle, NetSDKLib.EM_USEDEV_MODE.NET_TALK_SPEAK_PARAM, speak.getPointer())) {
            System.out.println("Set Talk Speak Mode Succeed!");
        } else {
            System.err.println("Set Talk Speak Mode Failed!" + getErrorCode());
            return false;
        }
        
        m_hTalkHandle = netsdkApi.CLIENT_StartTalkEx(loginHandle, AudioDataCB.getInstance(), null);
        
        if(m_hTalkHandle.longValue() == 0) {
              System.err.println("Start Talk Failed!" + getErrorCode());
              return false;
        } else {
              System.out.println("Start Talk Success");
            if(netsdkApi.CLIENT_RecordStart()){
                System.out.println("Start Record Success");
                m_bRecordStatus = true;
            } else {
                System.err.println("Start Local Record Failed!" + getErrorCode());
                stopTalk();
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * \if ENGLISH_LANG
     * Stop Talk
     * \else
     * 结束通话
     * \endif
     */
    public static void stopTalk() {
        if(m_hTalkHandle.longValue() == 0) {
            return;
        }
        
        if (m_bRecordStatus){
            netsdkApi.CLIENT_RecordStop();
            m_bRecordStatus = false;
        }
        
        if(netsdkApi.CLIENT_StopTalkEx(m_hTalkHandle)) {
            m_hTalkHandle.setValue(0);
        }else {
            System.err.println("Stop Talk Failed!" + getErrorCode());
        }
    }
    
    /**
     * \if ENGLISH_LANG
     * Audio Data Callback
     * \else
     * 语音对讲的数据回调
     * \endif
     */
    private static class AudioDataCB implements NetSDKLib.pfAudioDataCallBack {
        
        private AudioDataCB() {}
        private static AudioDataCB audioCallBack = new AudioDataCB();
        
        public static AudioDataCB getInstance() {
            return audioCallBack;
        }
        
        public void invoke(LLong lTalkHandle, Pointer pDataBuf, int dwBufSize, byte byAudioFlag, Pointer dwUser){
            
            if(lTalkHandle.longValue() != m_hTalkHandle.longValue()) {
                return;
            }
            
            /**
             * 0:本地录音库采集的音频数据
             * 1:收到的设备发过来的音频数据
             * 2:对讲呼叫响应数据
             * 3:收到的设备发过来的视频数据
             */
            if (byAudioFlag == 0) { // 将收到的本地PC端检测到的声卡数据发送给设备端
                
                LLong lSendSize = netsdkApi.CLIENT_TalkSendData(m_hTalkHandle, pDataBuf, dwBufSize);
                if(lSendSize.longValue() != (long)dwBufSize) {
                    System.err.println("send incomplete" + lSendSize.longValue() + ":" + dwBufSize);
                } else {
                    System.out.println("本地音频发送给设备");
                }
            } else if (byAudioFlag == 1 || byAudioFlag == 3) { // 将收到的设备端发送过来的语音数据传给SDK解码播放
                netsdkApi.CLIENT_AudioDecEx(m_hTalkHandle, pDataBuf, dwBufSize);
                System.out.println("设备发送过来数据解码播放");
            } else if(byAudioFlag == 2) {
                System.out.println("device responded...");
            }
        }
    }
    
    /**
     * 实时预览
     */
    public void RealPlay() {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        screenSize.height /= 2;
        screenSize.width /= 2;
        wnd.setSize(screenSize);
        centerWindow(wnd);
        wnd.setVisible(true);
        
        m_hRealPlayHandle = netsdkApi.CLIENT_RealPlayEx(loginHandle, 0, Native.getComponentPointer(wnd), 0);
        if (m_hRealPlayHandle.longValue() == 0) {
            System.err.println("实时预览失败, " + getErrorCode());
            return;
        } else {
            System.out.println("实时预览成功!");
        }
        
        // dwFlag   数据类型 
        // 1         原始数据标志
        // 2        带有帧信息的数据标志
        // 4         YUV 数据标志 
        // 8        PCM 音频数据标志
        int dwFlag = 1;
        if(netsdkApi.CLIENT_SetRealDataCallBackEx(m_hRealPlayHandle, RealDataCallBack.getInstance(), null, dwFlag)) {
            System.out.println("设置预览回调成功!");
        } else {
            System.err.println("设置预览回调失败!" + netsdkApi.CLIENT_GetLastError());
        }
    }
    
    // 实时预览数据回调函数
    private static class RealDataCallBack implements NetSDKLib.fRealDataCallBackEx {
        private RealDataCallBack() {}
        
        private static class RealDataCallBackHolder {
            private static RealDataCallBack instance = new RealDataCallBack();
        }
        
        public static RealDataCallBack getInstance() {
            return RealDataCallBackHolder.instance;
        }
        
        @Override
        public void invoke(LLong lRealHandle, int dwDataType,
                Pointer pBuffer, int dwBufSize, int param, Pointer dwUser) {        
            // dwDataType   数据类型 
            // 0             原始数据 
            // 1             带有帧信息的数据 
            // 2            yuv数据 
            // 3             pcm音频数据 
            System.out.println("dwDataType:" + dwDataType);
            
            // 视频数据, 可以根据需要的  dwDataType 过滤, 具体需要哪种数据, 在 CLIENT_SetRealDataCallBackEx 里设置
            byte[] data = pBuffer.getByteArray(0, dwBufSize);
            System.out.println(new String(data).trim());
        }
    }
    
    public static void centerWindow(Container window) {
        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
        int w = window.getSize().width;
        int h = window.getSize().height;
        int x = (dim.width - w) / 2;
        int y = (dim.height - h) / 2;
        window.setLocation(x, y);
    }
    
    public void stopRealPlay() {
        if(m_hRealPlayHandle.longValue() != 0) {
            netsdkApi.CLIENT_StopRealPlayEx(m_hRealPlayHandle);
            m_hRealPlayHandle.setValue(0);
            
            wnd.setVisible(false);
        }
    }
    
    
    /**
     * 设置二维码的解码信息
     */
    public void SetQrcode() {
        int emtype = NET_EM_ACCESS_CTL_MANAGER.NET_EM_ACCESS_CTL_SET_QRCODEDECODE_INFO; 
        /*
         * 入参
         */
        NET_IN_SET_QRCODE_DECODE_INFO stIn = new NET_IN_SET_QRCODE_DECODE_INFO();
        
        // 加密方式
        stIn.emCipher = NET_ENUM_QRCODE_CIPHER.NET_ENUM_QRCODE_CIPHER_AES256;  
        
        // 秘钥, 必须32位,用户自己定义,用于二维码加密
        // 但是加密密钥变化的周期不能小于1天;因为访客拿到二维码的时候,最长可能会使用二维码一天的,所以如果变化,最少一天以上再变
        String key = "0123456789ABCDEF0123456789ABCDEF";
        System.arraycopy(key.getBytes(), 0, stIn.szKey, 0, key.getBytes().length);
        
        /*
         * 出参
         */
        NET_OUT_SET_QRCODE_DECODE_INFO stOut = new NET_OUT_SET_QRCODE_DECODE_INFO();
        
        stIn.write();
        stOut.write();
        boolean bRet = netsdkApi.CLIENT_OperateAccessControlManager(loginHandle, emtype, stIn.getPointer(), stOut.getPointer(), 5000);
        stIn.read();
        stOut.read();
        
        if(bRet) {        
            System.out.println("设置二维码的解码信息成功.");
        } else {
            System.err.println("设置二维码的解码信息失败, " + getErrorCode());
        }
    }
    
    /**
     * 二维码加密
     */
    public void EncryptString() {
        /*
         * 入参
         */
        NET_IN_ENCRYPT_STRING stIn = new NET_IN_ENCRYPT_STRING();
        // 卡号
        String card = "B56E78BD";
        System.arraycopy(card.getBytes(), 0, stIn.szCard, 0, card.getBytes().length);
        
        // 秘钥, 必须32位,要跟SetQrcode()里的密钥一样
        String key = "0123456789ABCDEF0123456789ABCDEF";
        System.arraycopy(key.getBytes(), 0, stIn.szKey, 0, key.getBytes().length);
        
        /*
         * 出参
         */
        NET_OUT_ENCRYPT_STRING stOut = new NET_OUT_ENCRYPT_STRING();
        
        if(netsdkApi.CLIENT_EncryptString(stIn, stOut, 4000)) {
            System.out.println("加密后的字符串:" + new String(stOut.szEncryptString).trim());
        }
    }
    
    /**
     * 订阅报警信息
     * @return
     */
    public void startListen() {        
        // 设置报警回调函数
        netsdkApi.CLIENT_SetDVRMessCallBack(fAlarmDataCB.getCallBack(), null);
        
        // 订阅报警
        boolean bRet = netsdkApi.CLIENT_StartListenEx(loginHandle);
        if (!bRet) {
            System.err.println("订阅报警失败! LastError = 0x%x\n" + netsdkApi.CLIENT_GetLastError());
        }
        else {
            System.out.println("订阅报警成功.");
        }
    }
    
    /**
     * 取消订阅报警信息
     * @return
     */
    public void stopListen() {
        // 停止订阅报警
        boolean bRet = netsdkApi.CLIENT_StopListen(loginHandle);
           if (bRet) {
               System.out.println("取消订阅报警信息.");
           }    
    }
    
    /**
     * 报警信息回调函数原形,建议写成单例模式
     */
    private static class fAlarmDataCB implements NetSDKLib.fMessCallBack{
        private fAlarmDataCB(){}
        
        private static class fAlarmDataCBHolder {
            private static fAlarmDataCB callback = new fAlarmDataCB();
        }
        
        public static fAlarmDataCB getCallBack() {
            return fAlarmDataCBHolder.callback;
        }
        
          public boolean invoke(int lCommand, LLong lLoginID, Pointer pStuEvent, int dwBufLen, String strDeviceIP,  NativeLong nDevicePort, Pointer dwUser){
              System.out.printf("command = %x\n", lCommand);
              switch (lCommand)
              {
                  case NetSDKLib.NET_ALARM_TALKING_INVITE : //  设备请求对方发起对讲事件
                  {
                      NetSDKLib.ALARM_TALKING_INVITE_INFO msg = new NetSDKLib.ALARM_TALKING_INVITE_INFO();
                      ToolKits.GetPointerData(pStuEvent, msg);
                      
                      System.out.println("呼叫的房间号 :" + new String(msg.szCallID).trim());
                      
                      break;
                  }
              }
              
              return true;
          }
    }
    
    public void RunTest() {
        CaseMenu menu = new CaseMenu();    
        
        menu.addItem(new CaseMenu.Item(this , "设置二维码的解码信息", "SetQrcode"));    
        menu.addItem(new CaseMenu.Item(this , "二维码加密", "EncryptString"));    
        
        menu.addItem(new CaseMenu.Item(this , "对讲", "startTalk"));    
        menu.addItem(new CaseMenu.Item(this , "停止对讲", "stopTalk"));  
        
        menu.addItem(new CaseMenu.Item(this , "预览", "RealPlay"));    
        menu.addItem(new CaseMenu.Item(this , "停止预览", "stopRealPlay"));  
        
        menu.addItem(new CaseMenu.Item(this , "报警订阅", "startListen"));    
        menu.addItem(new CaseMenu.Item(this , "取消报警订阅", "stopListen"));  
        
        menu.run();
    }
 
    
    public static void main(String[]args) {    
        VTOTalk demo = new VTOTalk();
        demo.InitTest();
        demo.RunTest();
        demo.EndTest();
    }
}