@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
|
-
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
254
|
-
|
|
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
|
-
|
|
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
|
-
|
|
287
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
449
|
-
int ourClientPtr =
|
|
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
package/src/index.ts
CHANGED