@bits-innovate/react-native-vstarcam 1.0.42 → 1.0.44

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.
@@ -35,11 +35,20 @@ import org.json.JSONObject;
35
35
  *
36
36
  * Implements P2P camera connectivity using the VStarCam SDK.
37
37
  * Uses JNI calls to the native OKSMARTPPCS library via JNIApi class.
38
+ *
39
+ * JNI API Methods (discovered via reflection):
40
+ * - create(String did, String serverParam) -> long clientPtr
41
+ * - connect(long clientPtr, int timeout, String serverParam, int connectType)
42
+ * - login(long clientPtr, String username, String password)
43
+ * - disconnect(long clientPtr)
44
+ * - destroy(long clientPtr)
45
+ * - writeCgi(long clientPtr, String cgi, int timeout)
46
+ * - init(ClientStateListener, ClientCommandListener, ClientReleaseListener)
38
47
  */
39
- @ReactModule(name = "VStarCam")
48
+ @ReactModule(name = VStarCamModule.MODULE_NAME)
40
49
  public class VStarCamModule extends ReactContextBaseJavaModule {
41
50
  private static final String TAG = "VStarCamModule";
42
- public static final String MODULE_NAME = "VStarCam";
51
+ public final static String MODULE_NAME = "VStarCam";
43
52
 
44
53
  // Set to true for verbose logging during development
45
54
  private static final boolean DEBUG_LOGGING = true;
@@ -78,8 +87,6 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
78
87
  put("VSKM", "EIHGFNBAKMIIGLJEEAHKFEEJHLNBHCNIGFFDBLCMAKJNLELPDDAGCNOOGILMJFLJAOMKLADEOEMJAPCDJCNPJF:veepai2024");
79
88
  put("VSLL", "EIHGFOBBKKIOGNJKENHHFKEEGMNOHLMNHBFKBBDOAHJBLMKIDLAJCAPIGDLBJGLKAOMILNDJOJMGAHCLJHNMJG:veepai2024");
80
89
  put("ACAE", "EEGDFHBLKGJIGEJLEKGOFMEDHAMHHJNAGGFABMCOBGJOLHLJDFAFCPPHGILKIKLMANNHKEDKOINIBNCPJOMK:vstarcam2018"); // Try VSTH params
81
- put("ACDG", "EEGDFHBLKGJIGEJLEKGOFMEDHAMHHJNAGGFABMCOBGJOLHLJDFAFCPPHGILKIKLMANNHKEDKOINIBNCPJOMK:vstarcam2018"); // Same as ACAE/VSTH
82
- put("ACAQ", "EEGDFHBLKGJIGEJLEKGOFMEDHAMHHJNAGGFABMCOBGJOLHLJDFAFCPPHGILKIKLMANNHKEDKOINIBNCPJOMK:vstarcam2018"); // Same as ACAE/VSTH
83
90
  // Fallback for unknown prefixes
84
91
  put("DEFAULT", "EBGBEMBMKGJMGAJPEIGIFKEGHBMCHMNFGKEGBFCBBMJELILDCJADCIOLHHLLJBKEAMMBLCDGONMDBJCJJPNFJP");
85
92
  }};
@@ -99,7 +106,56 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
99
106
  return param;
100
107
  }
101
108
 
102
-
109
+ // Pattern to detect virtual UIDs (like ACAE0001151GWYQ)
110
+ // Virtual UIDs: start with letters, have 7+ digits, end with letters
111
+ private static final Pattern VIRTUAL_UID_PATTERN = Pattern.compile("^[a-zA-Z]{1,}\\d{7,}.*[a-zA-Z]$");
112
+
113
+ // Check if a device ID is a virtual UID that needs conversion
114
+ private static boolean isVirtualId(String deviceId) {
115
+ if (deviceId == null || deviceId.length() < 10) return false;
116
+ return VIRTUAL_UID_PATTERN.matcher(deviceId).matches();
117
+ }
118
+
119
+ // Convert virtual UID to real client ID using VStarCam API
120
+ // Returns: {uid, supplier, cluster} or null on failure
121
+ private String[] convertVirtualUid(String virtualUid) {
122
+ try {
123
+ URL url = new URL("https://vuid.eye4.cn?vuid=" + virtualUid);
124
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
125
+ conn.setRequestMethod("GET");
126
+ conn.setConnectTimeout(10000);
127
+ conn.setReadTimeout(10000);
128
+ conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
129
+
130
+ int responseCode = conn.getResponseCode();
131
+ if (responseCode == 200) {
132
+ BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
133
+ StringBuilder response = new StringBuilder();
134
+ String line;
135
+ while ((line = reader.readLine()) != null) {
136
+ response.append(line);
137
+ }
138
+ reader.close();
139
+
140
+ JSONObject json = new JSONObject(response.toString());
141
+ String uid = json.optString("uid", null);
142
+ String supplier = json.optString("supplier", "");
143
+ String cluster = json.optString("cluster", "");
144
+
145
+ if (uid != null && !uid.isEmpty()) {
146
+ Log.d(TAG, "Converted virtual UID " + virtualUid + " -> real UID: " + uid + " (supplier: " + supplier + ", cluster: " + cluster + ")");
147
+ return new String[]{uid, supplier, cluster};
148
+ }
149
+ } else {
150
+ Log.e(TAG, "Virtual UID conversion failed, HTTP " + responseCode);
151
+ }
152
+ conn.disconnect();
153
+ } catch (Exception e) {
154
+ Log.e(TAG, "Failed to convert virtual UID: " + e.getMessage(), e);
155
+ }
156
+ return null;
157
+ }
158
+
103
159
  private final ReactApplicationContext reactContext;
104
160
  private final ExecutorService executor;
105
161
 
@@ -116,7 +172,8 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
116
172
  private Class<?> releaseListenerClass = null;
117
173
 
118
174
  private static class ClientInfo {
119
- String deviceId; // Original device ID
175
+ String deviceId; // Original device ID (can be virtual UID)
176
+ String realClientId; // Converted client ID (for JNI calls)
120
177
  long sdkClientPtr = 0; // Actual SDK client pointer (long)
121
178
  boolean isConnected = false;
122
179
  boolean isLoggedIn = false;
@@ -158,11 +215,25 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
158
215
  Log.d(TAG, "JNIApi class found: " + jniApiClass.getName());
159
216
 
160
217
  // Load listener interfaces
161
- stateListenerClass = Class.forName("com.vstarcam.app_p2p_api.ClientStateListener", true, jniApiClass.getClassLoader());
162
- commandListenerClass = Class.forName("com.vstarcam.app_p2p_api.ClientCommandListener", true, jniApiClass.getClassLoader());
163
- releaseListenerClass = Class.forName("com.vstarcam.app_p2p_api.ClientReleaseListener", true, jniApiClass.getClassLoader());
218
+ stateListenerClass = Class.forName("com.vstarcam.app_p2p_api.ClientStateListener");
219
+ commandListenerClass = Class.forName("com.vstarcam.app_p2p_api.ClientCommandListener");
220
+ releaseListenerClass = Class.forName("com.vstarcam.app_p2p_api.ClientReleaseListener");
164
221
  Log.d(TAG, "Listener interfaces loaded");
165
222
 
223
+ // Log all methods on each listener for debugging
224
+ Log.d(TAG, "ClientStateListener methods:");
225
+ for (Method m : stateListenerClass.getDeclaredMethods()) {
226
+ Log.d(TAG, " -> " + m.getName() + "(" + java.util.Arrays.toString(m.getParameterTypes()) + ")");
227
+ }
228
+ Log.d(TAG, "ClientCommandListener methods:");
229
+ for (Method m : commandListenerClass.getDeclaredMethods()) {
230
+ Log.d(TAG, " -> " + m.getName() + "(" + java.util.Arrays.toString(m.getParameterTypes()) + ")");
231
+ }
232
+ Log.d(TAG, "ClientReleaseListener methods:");
233
+ for (Method m : releaseListenerClass.getDeclaredMethods()) {
234
+ Log.d(TAG, " -> " + m.getName() + "(" + java.util.Arrays.toString(m.getParameterTypes()) + ")");
235
+ }
236
+
166
237
  // Initialize P2P system with listeners
167
238
  initializeP2P();
168
239
  } catch (ClassNotFoundException e) {
@@ -242,16 +313,17 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
242
313
 
243
314
  Log.d(TAG, "ClientCommandListener." + methodName + " called");
244
315
  if (methodName.equals("commandListener")) {
245
- final long sdkPtr = (Long) args[0];
316
+ // args: long clientPtr, byte[] data, int length (from interface)
317
+ final long clientPtr = (Long) args[0];
246
318
  final byte[] data = (byte[]) args[1];
247
319
  final int length = (Integer) args[2];
248
- Log.d(TAG, "Command callback: sdkPtr=" + sdkPtr + ", len=" + length);
320
+ Log.d(TAG, "Command callback: clientPtr=" + clientPtr + ", dataLen=" + (data != null ? data.length : 0));
249
321
 
250
322
  if (reactContext != null) {
251
323
  reactContext.runOnUiQueueThread(new Runnable() {
252
324
  @Override
253
325
  public void run() {
254
- handleCommandReceive(sdkPtr, 0, data);
326
+ handleCommandReceive(clientPtr, 0, data);
255
327
  }
256
328
  });
257
329
  }
@@ -383,10 +455,23 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
383
455
  return;
384
456
  }
385
457
 
386
- // Call JNIApi.create(did, serverParam)
387
- String serviceParam = getServiceParam(deviceId);
458
+ // Check if this is a virtual UID that needs conversion
459
+ String realClientId = deviceId;
460
+ if (isVirtualId(deviceId)) {
461
+ Log.d(TAG, "Device ID " + deviceId + " looks like a virtual UID, converting...");
462
+ String[] conversionResult = convertVirtualUid(deviceId);
463
+ if (conversionResult != null && conversionResult[0] != null) {
464
+ realClientId = conversionResult[0];
465
+ Log.d(TAG, "Using converted client ID: " + realClientId);
466
+ } else {
467
+ Log.w(TAG, "Virtual UID conversion failed, trying with original ID");
468
+ }
469
+ }
470
+
471
+ // Call JNIApi.create(did, serverParam) with real client ID
472
+ String serviceParam = getServiceParam(realClientId); // Use real client ID prefix
388
473
  Method createMethod = jniApiClass.getMethod("create", String.class, String.class);
389
- Object result = createMethod.invoke(null, deviceId, serviceParam);
474
+ Object result = createMethod.invoke(null, realClientId, serviceParam);
390
475
  long sdkClientPtr = (Long) result;
391
476
 
392
477
  Log.d(TAG, "JNIApi.create result: " + sdkClientPtr);
@@ -402,10 +487,11 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
402
487
 
403
488
  ClientInfo clientInfo = new ClientInfo();
404
489
  clientInfo.deviceId = deviceId;
490
+ clientInfo.realClientId = realClientId; // Store the converted ID
405
491
  clientInfo.sdkClientPtr = sdkClientPtr;
406
492
  clients.put(ourClientPtr, clientInfo);
407
493
 
408
- Log.d(TAG, "Created client: ourPtr=" + ourClientPtr + ", sdkPtr=" + sdkClientPtr);
494
+ Log.d(TAG, "Created client: ourPtr=" + ourClientPtr + ", sdkPtr=" + sdkClientPtr + ", realId=" + realClientId);
409
495
  promise.resolve(ourClientPtr);
410
496
  } catch (Exception e) {
411
497
  Log.e(TAG, "clientCreate failed", e);
@@ -441,10 +527,11 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
441
527
  params.putInt("state", 1); // CONNECTING
442
528
  sendEvent("onConnectionStateChanged", params);
443
529
 
444
- // Construct the service param string
530
+ // Use realClientId for service param lookup (it has the correct prefix like VSTN)
531
+ String realId = clientInfo.realClientId != null ? clientInfo.realClientId : clientInfo.deviceId;
445
532
  String param = (serverParam != null && !serverParam.isEmpty())
446
533
  ? serverParam
447
- : getServiceParam(clientInfo.deviceId);
534
+ : getServiceParam(realId);
448
535
 
449
536
  // Default connectType to 126 (from V1 app) if not specified
450
537
  // connectType 126 = P2P/Relay combination that works reliably
@@ -458,8 +545,8 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
458
545
  Log.d(TAG, "Calling JNIApi.connect(" + clientInfo.sdkClientPtr + ", 15, " + param + ", " + actualConnectType + ")");
459
546
 
460
547
  try {
461
- Object result = connectMethod.invoke(null, clientInfo.sdkClientPtr, 15, param, actualConnectType);
462
- Log.d(TAG, "JNIApi.connect result: " + result);
548
+ connectMethod.invoke(null, clientInfo.sdkClientPtr, 15, param, actualConnectType);
549
+ Log.d(TAG, "JNIApi.connect returned normally");
463
550
  } catch (java.lang.reflect.InvocationTargetException ite) {
464
551
  Log.e(TAG, "JNIApi.connect threw exception: " + ite.getCause(), ite.getCause());
465
552
  throw ite;
@@ -530,21 +617,34 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
530
617
  Method loginMethod = jniApiClass.getMethod("login",
531
618
  long.class, String.class, String.class);
532
619
 
533
- Log.d(TAG, "Calling JNIApi.login(" + clientInfo.sdkClientPtr + ", " + username + ")");
620
+ Log.d(TAG, "Calling JNIApi.login(" + clientInfo.sdkClientPtr + ", " + username + ", ***)");
534
621
 
622
+ boolean loginSuccess = false;
535
623
  try {
536
624
  loginMethod.invoke(null, clientInfo.sdkClientPtr, username, password);
537
- } catch (Exception e) {
538
- Log.e(TAG, "Login failed: " + e.getMessage());
625
+ Log.d(TAG, "JNIApi.login returned normally");
626
+ loginSuccess = true;
627
+ } catch (java.lang.reflect.InvocationTargetException ite) {
628
+ Throwable cause = ite.getCause();
629
+ Log.e(TAG, "JNIApi.login threw exception: " + cause, cause);
630
+ // Don't rethrow - return false instead to prevent crash
631
+ promise.resolve(false);
632
+ return;
633
+ } catch (Throwable t) {
634
+ Log.e(TAG, "JNIApi.login crashed: " + t.getMessage(), t);
635
+ // Don't rethrow - return false instead to prevent crash
539
636
  promise.resolve(false);
540
637
  return;
541
638
  }
542
639
 
543
- clientInfo.isLoggedIn = true;
544
- clientInfo.username = username;
545
- clientInfo.password = password;
640
+ if (loginSuccess) {
641
+ clientInfo.isLoggedIn = true;
642
+ clientInfo.username = username;
643
+ clientInfo.password = password;
644
+ }
546
645
 
547
- promise.resolve(true);
646
+ Log.d(TAG, "JNIApi.login completed with result: " + loginSuccess);
647
+ promise.resolve(loginSuccess);
548
648
  } catch (Exception e) {
549
649
  Log.e(TAG, "clientLogin failed", e);
550
650
  promise.reject("LOGIN_ERROR", e.getMessage());
@@ -90,7 +90,7 @@ public class VStarCamVideoView extends FrameLayout
90
90
  // Based on decompiling app_player-5.0.0.aar classes.jar
91
91
  String[] classNames = {
92
92
  "com.veepai.AppPlayerApi", // Main API class from AAR
93
- "com.veepai.AppPlayer", // Possible alternative
93
+ "com.veepai.AppPlayer", // Added as alternative
94
94
  "com.veepai.app_player.AppPlayerPlugin", // Flutter plugin wrapper
95
95
  "com.vstarcam.player.AppPlayer",
96
96
  "com.vstarcam.AppPlayer",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bits-innovate/react-native-vstarcam",
3
- "version": "1.0.42",
3
+ "version": "1.0.44",
4
4
  "description": "React Native bridge for VStarCam P2P SDK",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",