@bits-innovate/react-native-vstarcam 1.0.43 → 1.0.45

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.
@@ -11,6 +11,7 @@ import com.facebook.react.bridge.ReactApplicationContext;
11
11
  import com.facebook.react.bridge.ReactContextBaseJavaModule;
12
12
  import com.facebook.react.bridge.ReactMethod;
13
13
  import com.facebook.react.bridge.WritableMap;
14
+ import com.facebook.react.module.annotations.ReactModule;
14
15
  import com.facebook.react.modules.core.DeviceEventManagerModule;
15
16
 
16
17
  import java.io.BufferedReader;
@@ -44,12 +45,21 @@ import org.json.JSONObject;
44
45
  * - writeCgi(long clientPtr, String cgi, int timeout)
45
46
  * - init(ClientStateListener, ClientCommandListener, ClientReleaseListener)
46
47
  */
48
+ @ReactModule(name = VStarCamModule.MODULE_NAME)
47
49
  public class VStarCamModule extends ReactContextBaseJavaModule {
48
50
  private static final String TAG = "VStarCamModule";
49
- private static final String MODULE_NAME = "VStarCam";
51
+ public final static String MODULE_NAME = "VStarCam";
50
52
 
51
53
  // Set to true for verbose logging during development
52
- private static final boolean DEBUG_LOGGING = false;
54
+ private static final boolean DEBUG_LOGGING = true;
55
+
56
+ // Counter for unique internal client IDs
57
+ private static final java.util.concurrent.atomic.AtomicInteger nextClientPtr = new java.util.concurrent.atomic.AtomicInteger(1000);
58
+
59
+ // Static proxy references to prevent GC.
60
+ private static Object stateListenerProxy;
61
+ private static Object commandListenerProxy;
62
+ private static Object releaseListenerProxy;
53
63
 
54
64
  // Helper for conditional debug logging
55
65
  private static void logDebug(String message) {
@@ -151,7 +161,7 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
151
161
 
152
162
  // Client tracking - maps our clientPtr to actual SDK client handle
153
163
  // Made static so VStarCamVideoView can access SDK pointers
154
- private static Map<Integer, ClientInfo> clients = new HashMap<>();
164
+ private static Map<Integer, ClientInfo> clients = new java.util.concurrent.ConcurrentHashMap<>();
155
165
  private boolean isNativeLibraryLoaded = false;
156
166
  private boolean isP2PInitialized = false;
157
167
 
@@ -243,15 +253,24 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
243
253
 
244
254
  try {
245
255
  // Create dynamic proxy for ClientStateListener
246
- Object stateListener = Proxy.newProxyInstance(
256
+ stateListenerProxy = Proxy.newProxyInstance(
247
257
  stateListenerClass.getClassLoader(),
248
258
  new Class<?>[] { stateListenerClass },
249
259
  new InvocationHandler() {
250
260
  @Override
251
261
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
252
262
  try {
253
- Log.d(TAG, "ClientStateListener." + method.getName() + " called with " + (args != null ? args.length : 0) + " args");
254
- if (method.getName().equals("stateListener")) {
263
+ String methodName = method.getName();
264
+
265
+ // Handle standard Object methods
266
+ if (method.getDeclaringClass() == Object.class) {
267
+ if (methodName.equals("equals")) return proxy == args[0];
268
+ if (methodName.equals("hashCode")) return System.identityHashCode(proxy);
269
+ if (methodName.equals("toString")) return proxy.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(proxy));
270
+ }
271
+
272
+ Log.d(TAG, "ClientStateListener." + methodName + " called");
273
+ if (methodName.equals("stateListener")) {
255
274
  // args: long clientPtr, int state
256
275
  final long clientPtr = (Long) args[0];
257
276
  final int state = (Integer) args[1];
@@ -276,15 +295,24 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
276
295
  );
277
296
 
278
297
  // Create dynamic proxy for ClientCommandListener
279
- Object commandListener = Proxy.newProxyInstance(
298
+ commandListenerProxy = Proxy.newProxyInstance(
280
299
  commandListenerClass.getClassLoader(),
281
300
  new Class<?>[] { commandListenerClass },
282
301
  new InvocationHandler() {
283
302
  @Override
284
303
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
285
304
  try {
286
- Log.d(TAG, "ClientCommandListener." + method.getName() + " called with " + (args != null ? args.length : 0) + " args");
287
- if (method.getName().equals("commandListener")) {
305
+ String methodName = method.getName();
306
+
307
+ // Handle standard Object methods
308
+ if (method.getDeclaringClass() == Object.class) {
309
+ if (methodName.equals("equals")) return proxy == args[0];
310
+ if (methodName.equals("hashCode")) return System.identityHashCode(proxy);
311
+ if (methodName.equals("toString")) return proxy.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(proxy));
312
+ }
313
+
314
+ Log.d(TAG, "ClientCommandListener." + methodName + " called");
315
+ if (methodName.equals("commandListener")) {
288
316
  // args: long clientPtr, byte[] data, int length (from interface)
289
317
  final long clientPtr = (Long) args[0];
290
318
  final byte[] data = (byte[]) args[1];
@@ -309,14 +337,23 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
309
337
  );
310
338
 
311
339
  // Create dynamic proxy for ClientReleaseListener
312
- Object releaseListener = Proxy.newProxyInstance(
340
+ releaseListenerProxy = Proxy.newProxyInstance(
313
341
  releaseListenerClass.getClassLoader(),
314
342
  new Class<?>[] { releaseListenerClass },
315
343
  new InvocationHandler() {
316
344
  @Override
317
345
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
318
346
  try {
319
- Log.d(TAG, "ClientReleaseListener." + method.getName() + " called");
347
+ String methodName = method.getName();
348
+
349
+ // Handle standard Object methods
350
+ if (method.getDeclaringClass() == Object.class) {
351
+ if (methodName.equals("equals")) return proxy == args[0];
352
+ if (methodName.equals("hashCode")) return System.identityHashCode(proxy);
353
+ if (methodName.equals("toString")) return proxy.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(proxy));
354
+ }
355
+
356
+ Log.d(TAG, "ClientReleaseListener." + methodName + " called");
320
357
  } catch (Exception e) {
321
358
  Log.e(TAG, "Error in releaseListener callback", e);
322
359
  }
@@ -328,7 +365,7 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
328
365
  // Call JNIApi.init(stateListener, commandListener, releaseListener)
329
366
  Method initMethod = jniApiClass.getMethod("init",
330
367
  stateListenerClass, commandListenerClass, releaseListenerClass);
331
- initMethod.invoke(null, stateListener, commandListener, releaseListener);
368
+ initMethod.invoke(null, stateListenerProxy, commandListenerProxy, releaseListenerProxy);
332
369
 
333
370
  isP2PInitialized = true;
334
371
  Log.d(TAG, "P2P system initialized successfully!");
@@ -396,13 +433,26 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
396
433
  }
397
434
 
398
435
  private void sendEvent(String eventName, @Nullable WritableMap params) {
399
- if (reactContext.hasActiveReactInstance()) {
436
+ if (reactContext != null && reactContext.hasActiveReactInstance()) {
400
437
  reactContext
401
438
  .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
402
439
  .emit(eventName, params);
403
440
  }
404
441
  }
405
442
 
443
+ /**
444
+ * Test the bridge connection
445
+ */
446
+ @ReactMethod
447
+ public void testBridge(Promise promise) {
448
+ Log.d(TAG, "testBridge called");
449
+ WritableMap result = Arguments.createMap();
450
+ result.putBoolean("success", true);
451
+ result.putString("message", "Bridge is working");
452
+ result.putDouble("timestamp", (double) System.currentTimeMillis());
453
+ promise.resolve(result);
454
+ }
455
+
406
456
  /**
407
457
  * Create a P2P client for a device
408
458
  * JNIApi.create(String did, String serverParam) -> long
@@ -445,8 +495,8 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
445
495
  return;
446
496
  }
447
497
 
448
- // Generate our own client ID (hash of deviceId) and store mapping
449
- int ourClientPtr = Math.abs(deviceId.hashCode());
498
+ // Generate our own client ID and store mapping
499
+ int ourClientPtr = nextClientPtr.getAndIncrement();
450
500
 
451
501
  ClientInfo clientInfo = new ClientInfo();
452
502
  clientInfo.deviceId = deviceId;
@@ -537,6 +587,24 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
537
587
  });
538
588
  }
539
589
 
590
+ /**
591
+ * Get the current connection state of a client
592
+ */
593
+ @ReactMethod
594
+ public void clientGetState(int clientPtr, Promise promise) {
595
+ ClientInfo clientInfo = clients.get(clientPtr);
596
+ if (clientInfo == null) {
597
+ promise.resolve(5); // DISCONNECTED
598
+ return;
599
+ }
600
+
601
+ WritableMap result = Arguments.createMap();
602
+ result.putInt("state", clientInfo.isConnected ? 3 : 1); // 3=ONLINE, 1=CONNECTING (approx)
603
+ result.putBoolean("isConnected", clientInfo.isConnected);
604
+ result.putBoolean("isLoggedIn", clientInfo.isLoggedIn);
605
+ promise.resolve(result);
606
+ }
607
+
540
608
  /**
541
609
  * Login to camera
542
610
  * JNIApi.login(long clientPtr, String username, String password)
@@ -714,6 +782,48 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
714
782
  });
715
783
  }
716
784
 
785
+ /**
786
+ * Get device information
787
+ */
788
+ @ReactMethod
789
+ public void clientGetDeviceInfo(int clientPtr, Promise promise) {
790
+ Log.d(TAG, "clientGetDeviceInfo called for ptr: " + clientPtr);
791
+ executor.execute(() -> {
792
+ try {
793
+ ClientInfo clientInfo = clients.get(clientPtr);
794
+ if (clientInfo == null) {
795
+ Log.w(TAG, "clientGetDeviceInfo: client not found for ptr " + clientPtr);
796
+ promise.reject("E_CLIENT_NOT_FOUND", "Client not found");
797
+ return;
798
+ }
799
+
800
+ Log.d(TAG, "Fetching device info for device: " + clientInfo.deviceId);
801
+
802
+ WritableMap result = Arguments.createMap();
803
+ result.putString("serialNumber", clientInfo.deviceId != null ? clientInfo.deviceId : "Unknown");
804
+ result.putString("model", "VStarCam");
805
+ result.putString("firmware", "Unknown");
806
+ result.putString("manufacturer", "VStarCam");
807
+ result.putBoolean("responsive", clientInfo.isConnected);
808
+
809
+ WritableMap features = Arguments.createMap();
810
+ features.putBoolean("ptz", true);
811
+ features.putBoolean("audio", true);
812
+ features.putBoolean("twoWayAudio", true);
813
+ features.putBoolean("nightVision", true);
814
+ features.putBoolean("motionDetection", true);
815
+ features.putBoolean("wifi", true);
816
+ result.putMap("features", features);
817
+
818
+ Log.d(TAG, "Resolving device info for " + clientInfo.deviceId);
819
+ promise.resolve(result);
820
+ } catch (Throwable t) {
821
+ Log.e(TAG, "clientGetDeviceInfo crashed: " + t.getMessage(), t);
822
+ promise.reject("E_GET_INFO_FAILED", t.getMessage());
823
+ }
824
+ });
825
+ }
826
+
717
827
  /**
718
828
  * Start video stream by sending livestream.cgi command
719
829
  * Resolution: 1=high, 2=general, 4=low, 100=superHD
@@ -90,6 +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", // Added as alternative
93
94
  "com.veepai.app_player.AppPlayerPlugin", // Flutter plugin wrapper
94
95
  "com.vstarcam.player.AppPlayer",
95
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.43",
3
+ "version": "1.0.45",
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
@@ -237,6 +237,10 @@ class VStarCamClient {
237
237
  });
238
238
  }
239
239
 
240
+ async testBridge(): Promise<any> {
241
+ return VStarCamModule.testBridge();
242
+ }
243
+
240
244
  /**
241
245
  * Create a P2P client for a device
242
246
  * @param deviceId The device ID (DID) from VStarCam