@bits-innovate/react-native-vstarcam 1.0.52 → 1.0.54
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,14 +11,13 @@ 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.bridge.LifecycleEventListener;
|
|
14
15
|
import com.facebook.react.module.annotations.ReactModule;
|
|
15
16
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
16
17
|
|
|
17
18
|
import java.io.BufferedReader;
|
|
18
19
|
import java.io.InputStreamReader;
|
|
19
|
-
import java.lang.reflect.InvocationHandler;
|
|
20
20
|
import java.lang.reflect.Method;
|
|
21
|
-
import java.lang.reflect.Proxy;
|
|
22
21
|
import java.net.HttpURLConnection;
|
|
23
22
|
import java.net.URL;
|
|
24
23
|
import java.util.HashMap;
|
|
@@ -46,7 +45,7 @@ import org.json.JSONObject;
|
|
|
46
45
|
* - init(ClientStateListener, ClientCommandListener, ClientReleaseListener)
|
|
47
46
|
*/
|
|
48
47
|
@ReactModule(name = VStarCamModule.MODULE_NAME)
|
|
49
|
-
public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
48
|
+
public class VStarCamModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
|
|
50
49
|
private static final String TAG = "VStarCamModule";
|
|
51
50
|
public final static String MODULE_NAME = "VStarCam";
|
|
52
51
|
|
|
@@ -204,6 +203,9 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
204
203
|
this.reactContext = reactContext;
|
|
205
204
|
this.executor = Executors.newCachedThreadPool();
|
|
206
205
|
|
|
206
|
+
// Register for lifecycle events to tear down JNI on fast-refresh
|
|
207
|
+
reactContext.addLifecycleEventListener(this);
|
|
208
|
+
|
|
207
209
|
// Update current context for static proxies
|
|
208
210
|
currentContext = new java.lang.ref.WeakReference<>(reactContext);
|
|
209
211
|
|
|
@@ -234,6 +236,39 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
234
236
|
}
|
|
235
237
|
}
|
|
236
238
|
|
|
239
|
+
@Override
|
|
240
|
+
public void onHostResume() {
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
@Override
|
|
244
|
+
public void onHostPause() {
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
@Override
|
|
248
|
+
public void onHostDestroy() {
|
|
249
|
+
Log.d(TAG, "onHostDestroy: Tearing down all P2P connections before JNI environment goes out of scope.");
|
|
250
|
+
executor.execute(() -> {
|
|
251
|
+
try {
|
|
252
|
+
if (jniApiClass != null) {
|
|
253
|
+
Method disconnectMethod = jniApiClass.getMethod("disconnect", long.class);
|
|
254
|
+
Method destroyMethod = jniApiClass.getMethod("destroy", long.class);
|
|
255
|
+
|
|
256
|
+
for (Map.Entry<Integer, ClientInfo> entry : clients.entrySet()) {
|
|
257
|
+
long sdkPtr = entry.getValue().sdkClientPtr;
|
|
258
|
+
if (sdkPtr != 0) {
|
|
259
|
+
Log.d(TAG, "Teardown SDK client: " + sdkPtr);
|
|
260
|
+
try { disconnectMethod.invoke(null, sdkPtr); } catch (Exception e) {}
|
|
261
|
+
try { destroyMethod.invoke(null, sdkPtr); } catch (Exception e) {}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
clients.clear();
|
|
265
|
+
}
|
|
266
|
+
} catch (Exception e) {
|
|
267
|
+
Log.e(TAG, "Failed to teardown P2P in onHostDestroy", e);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
237
272
|
private void initializeP2P() {
|
|
238
273
|
if (!VStarCamModule.isNativeLibraryLoaded || VStarCamModule.jniApiClass == null) {
|
|
239
274
|
Log.e(TAG, "Cannot initialize P2P: native library or JNIApi not available");
|
|
@@ -246,126 +281,62 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
246
281
|
}
|
|
247
282
|
|
|
248
283
|
try {
|
|
249
|
-
// Create
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
284
|
+
// Create CONCRETE listener implementations (NOT dynamic proxies).
|
|
285
|
+
// Dynamic Proxies ($Proxy0 classes) crash under CheckJNI when invoked
|
|
286
|
+
// from the C++ SDK's native pthreads via CallVoidMethod. Concrete
|
|
287
|
+
// anonymous classes have real vtables that work correctly.
|
|
288
|
+
|
|
289
|
+
com.vstarcam.app_p2p_api.ClientStateListener stateListener =
|
|
290
|
+
new com.vstarcam.app_p2p_api.ClientStateListener() {
|
|
254
291
|
@Override
|
|
255
|
-
public
|
|
292
|
+
public void stateListener(long clientPtr, int state) {
|
|
256
293
|
try {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
// Handle standard Object methods
|
|
260
|
-
if (method.getDeclaringClass() == Object.class) {
|
|
261
|
-
if (methodName.equals("equals")) return proxy == args[0];
|
|
262
|
-
if (methodName.equals("hashCode")) return System.identityHashCode(proxy);
|
|
263
|
-
if (methodName.equals("toString")) return proxy.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(proxy));
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
Log.d(TAG, "ClientStateListener." + methodName + " called");
|
|
267
|
-
if (methodName.equals("stateListener")) {
|
|
268
|
-
// args: long clientPtr, int state
|
|
269
|
-
long clientPtr = 0;
|
|
270
|
-
int state = 0;
|
|
271
|
-
|
|
272
|
-
if (args != null && args.length >= 2) {
|
|
273
|
-
if (args[0] instanceof Number) clientPtr = ((Number) args[0]).longValue();
|
|
274
|
-
if (args[1] instanceof Number) state = ((Number) args[1]).intValue();
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
Log.d(TAG, "State callback: clientPtr=" + clientPtr + ", state=" + state);
|
|
278
|
-
|
|
279
|
-
// Post to main thread for React Native compatibility
|
|
280
|
-
VStarCamModule.handleStateChange(clientPtr, state);
|
|
281
|
-
}
|
|
294
|
+
Log.d(TAG, "State callback: clientPtr=" + clientPtr + ", state=" + state);
|
|
295
|
+
VStarCamModule.handleStateChange(clientPtr, state);
|
|
282
296
|
} catch (Exception e) {
|
|
283
297
|
Log.e(TAG, "Error in stateListener callback", e);
|
|
284
298
|
}
|
|
285
|
-
return null;
|
|
286
299
|
}
|
|
287
|
-
}
|
|
288
|
-
);
|
|
289
|
-
jniProxyRoots.add(stateListenerProxy);
|
|
300
|
+
};
|
|
290
301
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
commandListenerClass.getClassLoader(),
|
|
294
|
-
new Class<?>[] { commandListenerClass },
|
|
295
|
-
new InvocationHandler() {
|
|
302
|
+
com.vstarcam.app_p2p_api.ClientCommandListener commandListener =
|
|
303
|
+
new com.vstarcam.app_p2p_api.ClientCommandListener() {
|
|
296
304
|
@Override
|
|
297
|
-
public
|
|
305
|
+
public void commandListener(long clientPtr, byte[] data, int length) {
|
|
298
306
|
try {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
// Handle standard Object methods
|
|
302
|
-
if (method.getDeclaringClass() == Object.class) {
|
|
303
|
-
if (methodName.equals("equals")) return proxy == args[0];
|
|
304
|
-
if (methodName.equals("hashCode")) return System.identityHashCode(proxy);
|
|
305
|
-
if (methodName.equals("toString")) return proxy.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(proxy));
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
Log.d(TAG, "ClientCommandListener." + methodName + " called");
|
|
309
|
-
if (methodName.equals("commandListener")) {
|
|
310
|
-
// args: long clientPtr, byte[] data, int length (from interface)
|
|
311
|
-
long clientPtr = 0;
|
|
312
|
-
byte[] data = null;
|
|
313
|
-
int length = 0;
|
|
314
|
-
|
|
315
|
-
if (args != null && args.length >= 3) {
|
|
316
|
-
if (args[0] instanceof Number) clientPtr = ((Number) args[0]).longValue();
|
|
317
|
-
if (args[1] instanceof byte[]) data = (byte[]) args[1];
|
|
318
|
-
if (args[2] instanceof Number) length = ((Number) args[2]).intValue();
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
Log.d(TAG, "Command callback: clientPtr=" + clientPtr + ", dataLen=" + (data != null ? data.length : 0));
|
|
322
|
-
|
|
323
|
-
// Post to main thread for React Native compatibility
|
|
324
|
-
VStarCamModule.handleCommandReceive(clientPtr, 0, data);
|
|
325
|
-
}
|
|
307
|
+
Log.d(TAG, "Command callback: clientPtr=" + clientPtr + ", dataLen=" + (data != null ? data.length : 0));
|
|
308
|
+
VStarCamModule.handleCommandReceive(clientPtr, 0, data);
|
|
326
309
|
} catch (Exception e) {
|
|
327
310
|
Log.e(TAG, "Error in commandListener callback", e);
|
|
328
311
|
}
|
|
329
|
-
return null;
|
|
330
312
|
}
|
|
331
|
-
}
|
|
332
|
-
);
|
|
333
|
-
jniProxyRoots.add(commandListenerProxy);
|
|
313
|
+
};
|
|
334
314
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
releaseListenerClass.getClassLoader(),
|
|
338
|
-
new Class<?>[] { releaseListenerClass },
|
|
339
|
-
new InvocationHandler() {
|
|
315
|
+
com.vstarcam.app_p2p_api.ClientReleaseListener releaseListener =
|
|
316
|
+
new com.vstarcam.app_p2p_api.ClientReleaseListener() {
|
|
340
317
|
@Override
|
|
341
|
-
public
|
|
318
|
+
public void releaseListener(long clientPtr) {
|
|
342
319
|
try {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
// Handle standard Object methods
|
|
346
|
-
if (method.getDeclaringClass() == Object.class) {
|
|
347
|
-
if (methodName.equals("equals")) return proxy == args[0];
|
|
348
|
-
if (methodName.equals("hashCode")) return System.identityHashCode(proxy);
|
|
349
|
-
if (methodName.equals("toString")) return proxy.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(proxy));
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
Log.d(TAG, "ClientReleaseListener." + methodName + " called");
|
|
320
|
+
Log.d(TAG, "Release callback: clientPtr=" + clientPtr);
|
|
353
321
|
} catch (Exception e) {
|
|
354
322
|
Log.e(TAG, "Error in releaseListener callback", e);
|
|
355
323
|
}
|
|
356
|
-
return null;
|
|
357
324
|
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
// Keep strong references to prevent GC
|
|
328
|
+
stateListenerProxy = stateListener;
|
|
329
|
+
commandListenerProxy = commandListener;
|
|
330
|
+
releaseListenerProxy = releaseListener;
|
|
331
|
+
jniProxyRoots.add(stateListener);
|
|
332
|
+
jniProxyRoots.add(commandListener);
|
|
333
|
+
jniProxyRoots.add(releaseListener);
|
|
361
334
|
|
|
362
335
|
// Call JNIApi.init(stateListener, commandListener, releaseListener)
|
|
363
|
-
|
|
364
|
-
VStarCamModule.stateListenerClass, VStarCamModule.commandListenerClass, VStarCamModule.releaseListenerClass);
|
|
365
|
-
initMethod.invoke(null, stateListenerProxy, commandListenerProxy, releaseListenerProxy);
|
|
336
|
+
com.vstarcam.JNIApi.init(stateListener, commandListener, releaseListener);
|
|
366
337
|
|
|
367
338
|
VStarCamModule.isP2PInitialized = true;
|
|
368
|
-
Log.d(TAG, "P2P system initialized successfully!");
|
|
339
|
+
Log.d(TAG, "P2P system initialized successfully with concrete listeners!");
|
|
369
340
|
} catch (Exception e) {
|
|
370
341
|
Log.e(TAG, "Failed to initialize P2P: " + e.getMessage(), e);
|
|
371
342
|
}
|