@bits-innovate/react-native-vstarcam 1.0.34 → 1.0.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -103,6 +103,11 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
103
103
  if (did == null || did.length() < 4) {
104
104
  return SERVICE_PARAM_MAP.get("DEFAULT");
105
105
  }
106
+
107
+ // Special case: If it was converted from an ACAE/ACxx virtual UID,
108
+ // it might work better with the vstarcam2018 parameters even if the real prefix is VSTJ/VSTN.
109
+ // However, we'll try prefix-specific first.
110
+
106
111
  String prefix = did.substring(0, 4).toUpperCase();
107
112
  String param = SERVICE_PARAM_MAP.get(prefix);
108
113
  if (param == null) {
@@ -168,7 +173,7 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
168
173
 
169
174
  // Client tracking - maps our clientPtr to actual SDK client handle
170
175
  // Made static so VStarCamVideoView can access SDK pointers
171
- private static Map<Integer, ClientInfo> clients = new HashMap<>();
176
+ private static Map<Integer, ClientInfo> clients = new java.util.concurrent.ConcurrentHashMap<>();
172
177
  private boolean isNativeLibraryLoaded = false;
173
178
  private boolean isP2PInitialized = false;
174
179
 
@@ -336,20 +341,11 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
336
341
 
337
342
  Log.d(TAG, "ClientCommandListener." + methodName + " called");
338
343
  if (methodName.equals("commandListener")) {
339
- // args: long clientPtr, byte[] data, int length
340
- final long clientPtr = (Long) args[0];
344
+ final long sdkPtr = (Long) args[0];
341
345
  final byte[] data = (byte[]) args[1];
342
346
  final int length = (Integer) args[2];
343
- Log.d(TAG, "Command callback: clientPtr=" + clientPtr + ", dataLen=" + (data != null ? data.length : 0));
344
-
345
- if (reactContext != null) {
346
- reactContext.runOnUiQueueThread(new Runnable() {
347
- @Override
348
- public void run() {
349
- handleCommandReceive(clientPtr, 0, data);
350
- }
351
- });
352
- }
347
+ Log.d(TAG, "Command callback: sdkPtr=" + sdkPtr + ", len=" + length);
348
+ handleCommandReceive(sdkPtr, 0, data);
353
349
  }
354
350
  } catch (Exception e) {
355
351
  Log.e(TAG, "Error in commandListener callback", e);
@@ -378,8 +374,13 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
378
374
 
379
375
  Log.d(TAG, "ClientReleaseListener." + methodName + " called");
380
376
  if (methodName.equals("releaseListener")) {
381
- final long clientPtr = (Long) args[0];
382
- Log.d(TAG, "Release callback: clientPtr=" + clientPtr);
377
+ final long sdkPtr = (Long) args[0];
378
+ Log.d(TAG, "Release callback: sdkPtr=" + sdkPtr);
379
+
380
+ // info.sdkClientPtr = 0
381
+ // NOTE: In 1.0.35 we cleared the pointer here, but it caused "Client not connected"
382
+ // because the SDK seems to call this on various events, not just destruction.
383
+ // We will only clear it on explicit disconnect/destroy.
383
384
  }
384
385
  } catch (Exception e) {
385
386
  Log.e(TAG, "Error in releaseListener callback", e);
@@ -564,11 +565,12 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
564
565
  params.putInt("state", 1); // CONNECTING
565
566
  sendEvent("onConnectionStateChanged", params);
566
567
 
567
- // Use realClientId for service param lookup (it has the correct prefix like VSTN)
568
- String realId = clientInfo.realClientId != null ? clientInfo.realClientId : clientInfo.deviceId;
568
+ // CRITICAL: For virtual UIDs (like ACAE...), always use the ORIGINAL device ID
569
+ // to look up service parameters. Even if it's converted to a VSTJ/VSTN real ID,
570
+ // it often must connect via the specific vstarcam2018/2019 servers matched to its prefix.
569
571
  String param = (serverParam != null && !serverParam.isEmpty())
570
572
  ? serverParam
571
- : getServiceParam(realId);
573
+ : getServiceParam(clientInfo.deviceId);
572
574
 
573
575
  // Default connectType to 126 (from V1 app) if not specified
574
576
  // connectType 126 = P2P/Relay combination that works reliably
@@ -584,6 +586,22 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
584
586
  try {
585
587
  Object result = connectMethod.invoke(null, clientInfo.sdkClientPtr, 15, param, actualConnectType);
586
588
  Log.d(TAG, "JNIApi.connect result: " + result);
589
+
590
+ int res = (Integer) result;
591
+ Log.d(TAG, "JNIApi.connect result: " + res);
592
+
593
+ // CRITICAL: In some P2P SDKs, handles can be negative (like pointers).
594
+ // We also saw '7' as a successful handle.
595
+ // We will only reject if it's a specific known error code (usually -1 or -2, but we'll be permissive).
596
+ if (res == -1) {
597
+ Log.w(TAG, "JNIApi.connect failed with code: " + res);
598
+ promise.reject("CONNECT_FAILED", "SDK connect error code: " + res);
599
+ return;
600
+ }
601
+
602
+ // Code >= 0 or other negative values might be a success (Session ID or State)
603
+ Log.d(TAG, "JNIApi.connect successful or handle returned: " + res);
604
+ clientInfo.isConnected = true; // Optimistically set this if we got a handle
587
605
  } catch (java.lang.reflect.InvocationTargetException ite) {
588
606
  Log.e(TAG, "JNIApi.connect threw exception: " + ite.getCause(), ite.getCause());
589
607
  throw ite;
@@ -645,8 +663,13 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
645
663
  // result is likely boolean based on signature log
646
664
  if (result instanceof Boolean) {
647
665
  loginResult = (Boolean) result;
666
+ } else if (result instanceof Integer) {
667
+ int res = (Integer) result;
668
+ Log.d(TAG, "JNIApi.login integer result: " + res);
669
+ // If it's a handle or 0 (success), treat as true
670
+ loginResult = (res >= 0 || res < -2); // Permissive: only reject -1, -2 as common errors
648
671
  } else if (result != null) {
649
- loginResult = true; // Non-null result usually means success for some SDKs
672
+ loginResult = true; // Non-null result usually means success
650
673
  }
651
674
  } catch (java.lang.reflect.InvocationTargetException ite) {
652
675
  Throwable cause = ite.getCause();
@@ -966,6 +989,13 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
966
989
  Log.d(TAG, "Verifying network: " + cgi);
967
990
  Object result = writeCgiMethod.invoke(null, clientInfo.sdkClientPtr, cgi, 5);
968
991
 
992
+ boolean writeSuccess = (result instanceof Boolean) ? (Boolean) result : true;
993
+ if (!writeSuccess) {
994
+ Log.w(TAG, "Network verification failed: writeCgi returned false");
995
+ promise.reject("E_NOT_RESPONSIVE", "Camera not responsive to commands");
996
+ return;
997
+ }
998
+
969
999
  // If we reach here, the CGI command was at least sent.
970
1000
  // We'll return a basic object representing success for now.
971
1001
  WritableMap response = Arguments.createMap();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bits-innovate/react-native-vstarcam",
3
- "version": "1.0.34",
3
+ "version": "1.0.36",
4
4
  "description": "React Native bridge for VStarCam P2P SDK",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
package/src/index.ts CHANGED
@@ -388,11 +388,11 @@ class VStarCamClient {
388
388
 
389
389
  // Wait for confirmation
390
390
  return new Promise((resolve) => {
391
- const timeout = setTimeout(() => resolve(false), 10000);
391
+ const waitTimeout = setTimeout(() => resolve(false), 10000);
392
392
 
393
393
  const handler: CommandEventListener = (_, cmd, data) => {
394
394
  if (cmd === 24593) {
395
- clearTimeout(timeout);
395
+ clearTimeout(waitTimeout);
396
396
  this.removeCommandListener(handler);
397
397
  const params = this.parseResponse(new TextDecoder().decode(data));
398
398
  resolve(params["result"] === "0");
@@ -407,36 +407,14 @@ class VStarCamClient {
407
407
  * Get device information
408
408
  */
409
409
  async getDeviceInfo(): Promise<DeviceInfo | null> {
410
- const success = await this.sendCommand("get_status.cgi?");
411
- if (!success) return null;
412
-
413
- return new Promise((resolve) => {
414
- const timeout = setTimeout(() => resolve(null), 5000);
415
-
416
- const handler: CommandEventListener = (_, cmd, data) => {
417
- clearTimeout(timeout);
418
- this.removeCommandListener(handler);
419
- const params = this.parseResponse(new TextDecoder().decode(data));
420
-
421
- resolve({
422
- serialNumber: params["id"] || "",
423
- model: params["model"] || "",
424
- firmware: params["sys_ver"] || "",
425
- manufacturer: "VStarCam",
426
- features: {
427
- ptz: params["ptz"] === "1",
428
- audio: params["haveAudio"] === "1",
429
- twoWayAudio: params["support_talk"] === "1",
430
- nightVision: params["haveIR"] === "1",
431
- motionDetection: params["support_alarm"] === "1",
432
- wifi: params["haveWifi"] === "1",
433
- },
434
- responsive: true,
435
- });
436
- };
437
-
438
- this.addCommandListener(handler);
439
- });
410
+ try {
411
+ // The native module handles credentials and basic command sending.
412
+ // It returns a promise that resolves with the device info and responsive: true.
413
+ return await VStarCamModule.clientGetDeviceInfo(this.clientPtr);
414
+ } catch (e: any) {
415
+ console.error("[VStarCam] getDeviceInfo failed:", e);
416
+ return null;
417
+ }
440
418
  }
441
419
 
442
420
  /**