sample code - “get Live view and OSD image with http”¶
usage:
p <1(Main),2(httpLV)> - set live view protocol
l - get live view
t - turn On OSD image
o - get OSD image
s <0(liveview),1(osd)> - streaming liveview/osd
k <1(U),2(D),3(L),4(R),5(Ent),6(Menu) - send key
This sample code is included in SimpleCli.
For Jetson environment, please add ‘target_link_libraries(${remotecli} PRIVATE “-pthread”)’ to CMakeLists.txt.
1// "get live view and OSD with http" sample
2#include "httplib.h" // https://github.com/yhirose/cpp-httplib
3
4#include <chrono>
5#include <cstdint>
6#include <cstdlib>
7#include <fstream>
8#include <future>
9#include <iostream>
10#include <mutex>
11#include <sstream>
12#include <stdexcept>
13#include <string>
14#include <thread>
15#include <vector>
16
17#if !defined(__APPLE__)
18 #if defined(USE_EXPERIMENTAL_FS) // for jetson
19 #include <experimental/filesystem>
20 namespace fs = std::experimental::filesystem;
21 #else
22 #include <filesystem>
23 namespace fs = std::filesystem;
24 #endif
25#endif
26
27#if defined(__APPLE__) || defined(__linux__)
28 #include <unistd.h>
29#endif
30
31// macro for multibyte character
32#if defined(_WIN32) || defined(_WIN64)
33 using CrString = std::wstring;
34 #define CRSTR(s) L ## s
35 #define CrCout std::wcout
36 #define DELIMITER CRSTR("\\")
37#else
38 using CrString = std::string;
39 #define CRSTR(s) s
40 #define CrCout std::cout
41 #define DELIMITER CRSTR("/")
42#endif
43
44
45#include "CrDeviceProperty.h"
46#include "CameraRemote_SDK.h"
47#include "IDeviceCallback.h"
48#include "CrDebugString.h" // use CrDebugString.cpp
49
50#define PrintError(msg, err) { fprintf(stderr, "Error in %s(%d):" msg ",%s\n", __FUNCTION__, __LINE__, (err ? CrErrorString(err).c_str():"")); }
51#define GotoError(msg, err) { PrintError(msg, err); goto Error; }
52
53bool m_connected = false;
54CrString m_modelId;
55int64_t m_device_handle = 0;
56
57std::mutex m_eventPromiseMutex;
58uint32_t m_setDPCode = 0;
59std::promise<void>* m_eventPromise = nullptr;
60void setEventPromise(std::promise<void>* dp)
61{
62 std::lock_guard<std::mutex> lock(m_eventPromiseMutex);
63 m_eventPromise = dp;
64}
65
66std::promise<void>* m_lvPromise = nullptr;
67std::mutex m_lvPromiseMutex;
68int lvType = 0;
69void setLvPromise(std::promise<void>* dp)
70{
71 std::lock_guard<std::mutex> lock(m_lvPromiseMutex);
72 m_lvPromise = dp;
73}
74
75SCRSDK::CrError _getDeviceProperty(int64_t device_handle, uint32_t code, SCRSDK::CrDeviceProperty* devProp)
76{
77 std::int32_t nprop = 0;
78 SCRSDK::CrDeviceProperty* prop_list = nullptr;
79 SCRSDK::CrError err = SCRSDK::GetSelectDeviceProperties(device_handle, 1, &code, &prop_list, &nprop);
80 if(err) GotoError("", err);
81 if(prop_list && nprop >= 1) {
82 *devProp = prop_list[0];
83 }
84Error:
85 if(prop_list) SCRSDK::ReleaseDeviceProperties(device_handle, prop_list);
86 return err;
87}
88
89SCRSDK::CrError _setDeviceProperty(int64_t device_handle, uint32_t code, uint64_t data, bool blocking=true)
90{
91 int result = SCRSDK::CrError_Generic_Unknown;
92 SCRSDK::CrError err = 0;
93 std::promise<void> eventPromise;
94 std::future<void> eventFuture = eventPromise.get_future();
95 std::future_status status;
96
97 SCRSDK::CrDeviceProperty devProp;
98
99 err = _getDeviceProperty(device_handle, code, &devProp);
100 if(err) GotoError("", err);
101 if (blocking && devProp.GetCurrentValue() == data) {
102 std::cout << "skipped\n";
103 return 0;
104 }
105
106 if(blocking) {
107 std::lock_guard<std::mutex> lock(m_eventPromiseMutex);
108 m_setDPCode = code;
109 m_eventPromise = &eventPromise;
110 }
111
112 devProp.SetCurrentValue(data);
113 err = SCRSDK::SetDeviceProperty(device_handle, &devProp);
114 if(err) GotoError("", err);
115
116 if(!blocking) return 0;
117
118 status = eventFuture.wait_for(std::chrono::milliseconds(3000));
119 if(status != std::future_status::ready) GotoError("timeout", 0);
120
121 try{
122 eventFuture.get();
123 } catch(const std::exception&) GotoError("", 0);
124 std::cout << "OK\n";
125
126 result = 0;
127Error:
128 setEventPromise(nullptr);
129 return result;
130}
131
132class DeviceCallback : public SCRSDK::IDeviceCallback
133{
134public:
135 DeviceCallback() {};
136 ~DeviceCallback() {};
137
138 void OnConnected(SCRSDK::DeviceConnectionVersioin version)
139 {
140 CrCout << "Connected to " << m_modelId << "\n";
141 m_connected = true;
142 std::lock_guard<std::mutex> lock(m_eventPromiseMutex);
143 if(m_eventPromise) {
144 m_eventPromise->set_value();
145 m_eventPromise = nullptr;
146 }
147 }
148
149 void OnError(CrInt32u error)
150 {
151 printf("Connection error:%s\n", CrErrorString(error).c_str());
152 std::lock_guard<std::mutex> lock(m_eventPromiseMutex);
153 if(m_eventPromise) {
154 m_eventPromise->set_exception(std::make_exception_ptr(std::runtime_error("error")));
155 m_eventPromise = nullptr;
156 }
157 }
158
159 void OnDisconnected(CrInt32u error)
160 {
161 CrCout << "Disconnected from " << m_modelId << "\n";
162 m_connected = false;
163 std::lock_guard<std::mutex> lock(m_eventPromiseMutex);
164 if(m_eventPromise) {
165 m_eventPromise->set_value();
166 m_eventPromise = nullptr;
167 }
168 }
169
170 void OnCompleteDownload(CrChar* filename, CrInt32u type )
171 {
172 CrCout << "OnCompleteDownload:" << filename << "\n";
173 }
174
175 void OnNotifyContentsTransfer(CrInt32u notify, SCRSDK::CrContentHandle contentHandle, CrChar* filename)
176 {
177 std::cout << "OnNotifyContentsTransfer.\n";
178 }
179
180 void OnWarning(CrInt32u warning)
181 {
182 if (warning == SCRSDK::CrWarning_Connect_Reconnecting) {
183 CrCout << "Reconnecting to " << m_modelId << "\n";
184 return;
185 }
186 }
187
188 void OnWarningExt(CrInt32u warning, CrInt32 param1, CrInt32 param2, CrInt32 param3) {}
189 void OnLvPropertyChanged() {}
190 void OnLvPropertyChangedCodes(CrInt32u num, CrInt32u* codes) {}
191 void OnPropertyChanged() {}
192 void OnPropertyChangedCodes(CrInt32u num, CrInt32u* codes)
193 {
194 std::cout << "OnPropertyChangedCodes:\n";
195 for(uint32_t i = 0; i < num; ++i) {
196 std::lock_guard<std::mutex> lock(m_eventPromiseMutex);
197 if(m_setDPCode && m_setDPCode == codes[i]) {
198 m_setDPCode = 0;
199 if(m_eventPromise) {
200 m_eventPromise->set_value();
201 m_eventPromise = nullptr;
202 }
203 }
204 }
205 }
206 void OnNotifyMonitorUpdated(CrInt32u type, CrInt32u frameNo)
207 {
208 if(type == lvType) {
209 // printf("%x", frameNo & 0xF);
210 std::lock_guard<std::mutex> lock(m_lvPromiseMutex);
211 if(m_lvPromise) {
212 m_lvPromise->set_value();
213 m_lvPromise = nullptr;
214 }
215 }
216 }
217
218};
219
220CrString _getModelId(const SCRSDK::ICrCameraObjectInfo* objInfo)
221{
222 CrString id;
223 if (CrString(objInfo->GetConnectionTypeName()) == CRSTR("IP")) {
224 id = CrString(objInfo->GetMACAddressChar());
225 } else {
226 id = CrString((CrChar*)objInfo->GetId());
227 }
228 return CrString(objInfo->GetModel()).append(CRSTR(" (")).append(id).append(CRSTR(")"));
229}
230
231SCRSDK::CrError _getIdPassword(SCRSDK::ICrCameraObjectInfo* objInfo, std::string& fingerprint, std::string& userId, std::string& userPassword)
232{
233 char fpBuff[128] = {0};
234 CrInt32u fpLen = 0;
235 SCRSDK::CrError err = SCRSDK::GetFingerprint(objInfo, fpBuff, &fpLen);
236 if(err) GotoError("", err);
237 fingerprint = std::string(fpBuff, fpLen);
238
239 std::cout << "fingerprint: " << fingerprint.c_str() << "\n";
240 std::cout << "id:"; std::getline(std::cin, userId);
241 std::cout << "password:"; std::getline(std::cin, userPassword);
242 return 0;
243Error:
244 return err;
245}
246
247SCRSDK::CrError _getLiveView(int64_t device_handle, CrString path)
248{
249 int result = SCRSDK::CrError_Generic_Unknown;
250 SCRSDK::CrError err = 0;
251 CrInt32 num = 0;
252 SCRSDK::CrLiveViewProperty* property = nullptr;
253 SCRSDK::CrImageInfo imageInfo;
254 SCRSDK::CrImageDataBlock image_data;
255 CrInt32u bufSize = 0;
256 CrInt8u* image_buff = nullptr;
257
258 err = SCRSDK::GetLiveViewProperties(device_handle, &property, &num); if(err) GotoError("", err);
259 SCRSDK::ReleaseLiveViewProperties(device_handle, property);
260
261 err = SCRSDK::GetLiveViewImageInfo(device_handle, &imageInfo); if(err) GotoError("", err);
262 bufSize = imageInfo.GetBufferSize();
263 if (bufSize <= 0) GotoError("", 0);
264
265 image_buff = new CrInt8u[bufSize];
266 if (!image_buff) GotoError("", 0);
267
268 image_data.SetData(image_buff);
269 image_data.SetSize(bufSize);
270
271 err = SCRSDK::GetLiveViewImage(device_handle, &image_data); if(err) GotoError("", err);
272 if (image_data.GetSize() <= 0) GotoError("", 0);
273
274 {
275 path.append(DELIMITER CRSTR("LiveView000000.JPG"));
276 std::ofstream file(path, std::ios::out | std::ios::binary);
277 if (file.bad()) GotoError("", 0);
278 file.write((char*)image_data.GetImageData(), image_data.GetImageSize());
279 file.close();
280 CrCout << path.data() << '\n';
281 }
282 result = 0;
283Error:
284 if(image_buff) delete[] image_buff;
285 return result;
286}
287
288SCRSDK::CrError _getOsdImage(int64_t device_handle, CrString path)
289{
290 int result = SCRSDK::CrError_Generic_Unknown;
291 SCRSDK::CrError err = 0;
292 SCRSDK::CrDeviceProperty devProp;
293 SCRSDK::CrOSDImageDataBlock image_data;
294 CrInt8u* image_buff = nullptr;
295
296 err = _getDeviceProperty(device_handle, SCRSDK::CrDeviceProperty_OSDImageMode, &devProp);
297 if(err) GotoError("", err);
298
299 if (devProp.GetCurrentValue() != SCRSDK::CrOSDImageMode_On)
300 GotoError("please turn on OSD image", 0);
301
302 image_buff = new CrInt8u[CR_OSD_IMAGE_MAX_SIZE]; if(!image_buff) GotoError("", 0);
303 image_data.SetData(image_buff);
304
305 err = SCRSDK::GetOSDImage(device_handle, &image_data); if(err) GotoError("", err);
306 if (image_data.GetImageSize() <= 0) GotoError("", 0);
307
308 {
309 path.append(DELIMITER CRSTR("OSDImage000000.PNG"));
310 std::ofstream file(path, std::ios::out | std::ios::binary);
311 if (file.bad()) GotoError("", 0)
312 file.write((char*)image_data.GetImageData(), image_data.GetImageSize());
313 file.close();
314 CrCout << path.data() << '\n';
315 }
316 result = 0;
317Error:
318 if(image_buff) delete[] image_buff;
319 return result;
320}
321
322//-------------------------------
323
324#include <atomic>
325
326std::atomic<bool> running(true);
327
328SCRSDK::CrError _getLiveView2(int64_t device_handle, CrInt8u** lv_image, CrInt32u* lv_size)
329{
330 int result = SCRSDK::CrError_Generic_Unknown;
331 SCRSDK::CrError err = 0;
332 CrInt32 num = 0;
333 SCRSDK::CrLiveViewProperty* property = nullptr;
334 SCRSDK::CrImageInfo imageInfo;
335 SCRSDK::CrImageDataBlock image_data;
336 CrInt32u bufSize = 0;
337 CrInt8u* image_buff = nullptr;
338
339 err = SCRSDK::GetLiveViewProperties(device_handle, &property, &num); if(err) GotoError("", err);
340 SCRSDK::ReleaseLiveViewProperties(device_handle, property);
341
342 err = SCRSDK::GetLiveViewImageInfo(device_handle, &imageInfo); if(err) GotoError("", err);
343 bufSize = imageInfo.GetBufferSize();
344 if (bufSize <= 0) GotoError("", 0);
345
346 image_buff = new CrInt8u[bufSize];
347 if (!image_buff) GotoError("", 0);
348
349 image_data.SetData(image_buff);
350 image_data.SetSize(bufSize);
351
352 err = SCRSDK::GetLiveViewImage(device_handle, &image_data); if(err) GotoError("", err);
353 if (image_data.GetSize() <= 0) GotoError("", 0);
354
355 *lv_size = image_data.GetImageSize();
356 *lv_image = new CrInt8u[*lv_size];
357 if(!*lv_image) GotoError("", 0);
358 memcpy(*lv_image, image_data.GetImageData(), *lv_size);
359 result = 0;
360Error:
361 if(image_buff) delete[] image_buff;
362 return result;
363}
364
365SCRSDK::CrError _getOsdImage2(int64_t device_handle, CrInt8u** lv_image, CrInt32u* lv_size)
366{
367 int result = SCRSDK::CrError_Generic_Unknown;
368 SCRSDK::CrError err = 0;
369 SCRSDK::CrDeviceProperty devProp;
370 SCRSDK::CrOSDImageDataBlock image_data;
371 CrInt8u* image_buff = nullptr;
372
373 err = _getDeviceProperty(device_handle, SCRSDK::CrDeviceProperty_OSDImageMode, &devProp);
374 if(err) GotoError("", err);
375
376 if (devProp.GetCurrentValue() != SCRSDK::CrOSDImageMode_On)
377 GotoError("please turn on OSD image", 0);
378
379 image_buff = new CrInt8u[CR_OSD_IMAGE_MAX_SIZE]; if(!image_buff) GotoError("", 0);
380 image_data.SetData(image_buff);
381
382 err = SCRSDK::GetOSDImage(device_handle, &image_data); if(err) GotoError("", err);
383 if (image_data.GetImageSize() <= 0) GotoError("", 0);
384
385 *lv_size = image_data.GetImageSize();
386 *lv_image = new CrInt8u[*lv_size];
387 if(!*lv_image) GotoError("", 0);
388 memcpy(*lv_image, image_data.GetImageData(), *lv_size);
389 result = 0;
390Error:
391 if(image_buff) delete[] image_buff;
392 return result;
393}
394
395bool streamLiveview(size_t offset, httplib::DataSink &sink)
396{
397 bool result = false;
398 SCRSDK::CrError err = 0;
399 CrInt8u* image_buff = nullptr;
400 CrInt32u bufSize = 0;
401
402 std::promise<void> lvPromise;
403 std::future<void> lvFuture = lvPromise.get_future();
404 std::future_status status;
405
406 setLvPromise(&lvPromise);
407 status = lvFuture.wait_for(std::chrono::milliseconds(3000));
408 if(status != std::future_status::ready) GotoError("timeout", 0);
409 try{
410 lvFuture.get();
411 } catch(const std::exception&) GotoError("", 0);
412
413 {
414 char buf[256] = {0};
415 int len = 0;
416 if(lvType == 0) { // liveview
417 err = _getLiveView2(m_device_handle, &image_buff, &bufSize);
418 if(err) return false;
419 len = snprintf(buf, sizeof(buf), "--frame\r\n"
420 "Content-Type: image/jpeg\r\n"
421 "Content-Length: %d\r\n\r\n", bufSize);
422 } else { // osd
423 err = _getOsdImage2(m_device_handle, &image_buff, &bufSize);
424 if(err) return false;
425 len = snprintf(buf, sizeof(buf), "--frame\r\n"
426 "Content-Type: image/png\r\n"
427 "Content-Length: %d\r\n\r\n", bufSize);
428 }
429 if(len >= sizeof(buf)) GotoError("", 0);
430 sink.write(buf, len);
431 }
432 sink.write((char*)image_buff, bufSize);
433 sink.write("\r\n", 2);
434
435 //std::this_thread::sleep_for(std::chrono::milliseconds(33));
436 result = true;
437Error:
438 setLvPromise(nullptr);
439 delete[] image_buff;
440 image_buff = nullptr;
441 return result;
442}
443
444void handle_request(const httplib::Request& req, httplib::Response& res)
445{
446 res.set_chunked_content_provider(
447 "multipart/x-mixed-replace; boundary=frame", streamLiveview
448 );
449}
450
451void server_thread(httplib::Server& svr)
452{
453 std::cout << "please access to http://localhost:8080\n";
454 svr.Get("/", handle_request);
455 svr.listen("127.0.0.1", 8080);
456 running = false;
457}
458
459std::vector<std::string> _split(std::string inputLine, char delimiter)
460{
461 std::vector<std::string> strArray;
462 if (inputLine.empty()) return strArray;
463
464 std::string tmp;
465 std::stringstream ss{inputLine};
466 while (getline(ss, tmp, delimiter)) {
467 strArray.push_back(tmp);
468 }
469 return strArray;
470}
471
472int main(void)
473{
474 int result = -1;
475 SCRSDK::CrError err = SCRSDK::CrError_None;
476 SCRSDK::ICrEnumCameraObjectInfo* enumCameraObjectInfo = nullptr;
477 SCRSDK::ICrCameraObjectInfo* objInfo = nullptr;
478 DeviceCallback deviceCallback;
479 httplib::Server svr;
480 std::thread* serverThread = nullptr;
481
482 #if defined(__APPLE__)
483 #define MAC_MAX_PATH 255
484 char pathBuf[MAC_MAX_PATH] = {0};
485 if(NULL == getcwd(pathBuf, sizeof(pathBuf) - 1)) return 1;
486 CrString path = pathBuf;
487 #else
488 CrString path = fs::current_path().native();
489 #endif
490
491 bool boolRet = SCRSDK::Init();
492 if(!boolRet) GotoError("", 0);
493
494 // enumeration
495 {
496 uint32_t count = 0;
497 uint32_t index = 1;
498
499 err = SCRSDK::EnumCameraObjects(&enumCameraObjectInfo, 3/*timeInSec*/);
500 if(err || !enumCameraObjectInfo) GotoError("no camera", err);
501
502 count = enumCameraObjectInfo->GetCount();
503 if(count >= 2) {
504 for (uint32_t i = 0; i < count; ++i) {
505 auto* info = enumCameraObjectInfo->GetCameraObjectInfo(i);
506 CrCout << '[' << i + 1 << "] " << _getModelId(info) << "\n";
507 }
508
509 std::string inputLine;
510 std::cout << "select camera:"; std::getline(std::cin, inputLine);
511 try { index = stoi(inputLine); } catch(const std::exception&) { GotoError("", 0); }
512 if(index < 1 || index > count) GotoError("", 0);
513 }
514 objInfo = (SCRSDK::ICrCameraObjectInfo*)enumCameraObjectInfo->GetCameraObjectInfo(index - 1);
515 m_modelId = _getModelId(objInfo);
516 }
517
518 // connect
519 {
520 std::string fingerprint = "";
521 std::string userId = "";
522 std::string userPassword = "";
523 std::promise<void> eventPromise;
524 std::future<void> eventFuture = eventPromise.get_future();
525
526 if (objInfo->GetSSHsupport() == SCRSDK::CrSSHsupport_ON) {
527 err = _getIdPassword(objInfo, fingerprint, userId, userPassword); if(err) goto Error;
528 }
529
530 setEventPromise(&eventPromise);
531 err = SCRSDK::Connect(objInfo, &deviceCallback, &m_device_handle,
532 SCRSDK::CrSdkControlMode_Remote,
533 SCRSDK::CrReconnecting_ON,
534 userId.c_str(), userPassword.c_str(), fingerprint.c_str(), (uint32_t)fingerprint.size());
535 if(err) GotoError("", err);
536
537 // std::future_status status = eventFuture.wait_for(std::chrono::milliseconds(3000));
538 // if(status != std::future_status::ready) GotoError("timeout",0);
539 try{
540 eventFuture.get();
541 } catch(const std::exception&) GotoError("", 0);
542 }
543
544 // set work directory
545 {
546 CrCout << "path=" << path.data() << "\n";
547 err = SCRSDK::SetSaveInfo(m_device_handle, const_cast<CrChar*>(path.data()), const_cast<CrChar*>(CRSTR("DSC")), -1/*startNo*/);
548 if(err) GotoError("", err);
549 }
550
551 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
552
553 std::cout << "usage:\n";
554 std::cout << " p <1(Main),2(httpLV)> - set live view protocol\n";
555 std::cout << " l - get live view\n";
556 std::cout << " t - turn On OSD image\n";
557 std::cout << " o - get OSD image\n";
558 std::cout << " s <0(liveview),1(osd)> - streaming liveview/osd\n";
559 std::cout << " k <1(U),2(D),3(L),4(R),5(Ent),6(Menu) - send key\n";
560 std::cout << "To exit, please enter 'q'.\n";
561
562 while(1) {
563 std::string inputLine;
564 std::getline(std::cin, inputLine);
565 std::vector<std::string> args = _split(inputLine, ' ');
566
567 if(args.size() == 0) {
568
569 } else if(args[0] == "p" && args.size() >=2) {
570 uint32_t val;
571 try { val = stoi(args[1]); } catch(const std::exception&) { GotoError("", 0); }
572 err = _setDeviceProperty(m_device_handle, SCRSDK::CrDeviceProperty_LiveViewProtocol, val);
573 if(err) goto Error;
574
575 } else if(args[0] == "l" || args[0] == "L") {
576 err = _getLiveView(m_device_handle, path);
577 if(err) goto Error;
578
579 } else if(args[0] == "s" || args[0] == "S") {
580 if(args.size() >= 2) {
581 try { lvType = stoi(args[1]); } catch(const std::exception&) { GotoError("", 0); }
582 }
583 if(!serverThread) {
584 serverThread = new std::thread(server_thread, std::ref(svr));
585 }
586
587 } else if(args[0] == "k" && args.size() >=2) {
588 uint32_t val;
589 try { val = stoi(args[1]); } catch(const std::exception&) { GotoError("", 0); }
590 val = val << 16;
591 err = _setDeviceProperty(m_device_handle, SCRSDK::CrDeviceProperty_CameraButtonFunction, (val|SCRSDK::CrCameraButtonFunctionValue_Down), false);
592 err = _setDeviceProperty(m_device_handle, SCRSDK::CrDeviceProperty_CameraButtonFunction, (val|SCRSDK::CrCameraButtonFunctionValue_Up), false);
593 if(err) goto Error;
594
595 } else if(args[0] == "t" || args[0] == "T") {
596 err = _setDeviceProperty(m_device_handle, SCRSDK::CrDeviceProperty_OSDImageMode, SCRSDK::CrOSDImageMode_On);
597 if(err) goto Error;
598
599 } else if(args[0] == "o" || args[0] == "O") {
600 err = _getOsdImage(m_device_handle, path);
601 if(err) goto Error;
602
603 } else if(args[0] == "q" || args[0] == "Q") {
604 break;
605 } else {
606 std::cout << "unknown command\n";
607 }
608 }
609
610 result = 0;
611Error:
612 if(serverThread) {
613 svr.stop();
614 while(running);
615 serverThread->join();
616 }
617 if(enumCameraObjectInfo) enumCameraObjectInfo->Release();
618
619 if(m_connected) {
620 std::promise<void> eventPromise;
621 std::future<void> eventFuture = eventPromise.get_future();
622 setEventPromise(&eventPromise);
623 SCRSDK::Disconnect(m_device_handle);
624 eventFuture.wait_for(std::chrono::milliseconds(3000));
625 }
626 if(m_device_handle) SCRSDK::ReleaseDevice(m_device_handle);
627 SCRSDK::Release();
628
629 return result;
630}