@bits-innovate/react-native-vstarcam 1.0.53 → 1.0.55
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.
|
@@ -17,9 +17,7 @@ import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
|
17
17
|
|
|
18
18
|
import java.io.BufferedReader;
|
|
19
19
|
import java.io.InputStreamReader;
|
|
20
|
-
import java.lang.reflect.InvocationHandler;
|
|
21
20
|
import java.lang.reflect.Method;
|
|
22
|
-
import java.lang.reflect.Proxy;
|
|
23
21
|
import java.net.HttpURLConnection;
|
|
24
22
|
import java.net.URL;
|
|
25
23
|
import java.util.HashMap;
|
|
@@ -283,126 +281,62 @@ public class VStarCamModule extends ReactContextBaseJavaModule implements Lifecy
|
|
|
283
281
|
}
|
|
284
282
|
|
|
285
283
|
try {
|
|
286
|
-
// Create
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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() {
|
|
291
291
|
@Override
|
|
292
|
-
public
|
|
292
|
+
public void stateListener(long clientPtr, int state) {
|
|
293
293
|
try {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
// Handle standard Object methods
|
|
297
|
-
if (method.getDeclaringClass() == Object.class) {
|
|
298
|
-
if (methodName.equals("equals")) return proxy == args[0];
|
|
299
|
-
if (methodName.equals("hashCode")) return System.identityHashCode(proxy);
|
|
300
|
-
if (methodName.equals("toString")) return proxy.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(proxy));
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
Log.d(TAG, "ClientStateListener." + methodName + " called");
|
|
304
|
-
if (methodName.equals("stateListener")) {
|
|
305
|
-
// args: long clientPtr, int state
|
|
306
|
-
long clientPtr = 0;
|
|
307
|
-
int state = 0;
|
|
308
|
-
|
|
309
|
-
if (args != null && args.length >= 2) {
|
|
310
|
-
if (args[0] instanceof Number) clientPtr = ((Number) args[0]).longValue();
|
|
311
|
-
if (args[1] instanceof Number) state = ((Number) args[1]).intValue();
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
Log.d(TAG, "State callback: clientPtr=" + clientPtr + ", state=" + state);
|
|
315
|
-
|
|
316
|
-
// Post to main thread for React Native compatibility
|
|
317
|
-
VStarCamModule.handleStateChange(clientPtr, state);
|
|
318
|
-
}
|
|
294
|
+
Log.d(TAG, "State callback: clientPtr=" + clientPtr + ", state=" + state);
|
|
295
|
+
VStarCamModule.handleStateChange(clientPtr, state);
|
|
319
296
|
} catch (Exception e) {
|
|
320
297
|
Log.e(TAG, "Error in stateListener callback", e);
|
|
321
298
|
}
|
|
322
|
-
return null;
|
|
323
299
|
}
|
|
324
|
-
}
|
|
325
|
-
);
|
|
326
|
-
jniProxyRoots.add(stateListenerProxy);
|
|
300
|
+
};
|
|
327
301
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
commandListenerClass.getClassLoader(),
|
|
331
|
-
new Class<?>[] { commandListenerClass },
|
|
332
|
-
new InvocationHandler() {
|
|
302
|
+
com.vstarcam.app_p2p_api.ClientCommandListener commandListener =
|
|
303
|
+
new com.vstarcam.app_p2p_api.ClientCommandListener() {
|
|
333
304
|
@Override
|
|
334
|
-
public
|
|
305
|
+
public void commandListener(long clientPtr, byte[] data, int length) {
|
|
335
306
|
try {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
// Handle standard Object methods
|
|
339
|
-
if (method.getDeclaringClass() == Object.class) {
|
|
340
|
-
if (methodName.equals("equals")) return proxy == args[0];
|
|
341
|
-
if (methodName.equals("hashCode")) return System.identityHashCode(proxy);
|
|
342
|
-
if (methodName.equals("toString")) return proxy.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(proxy));
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
Log.d(TAG, "ClientCommandListener." + methodName + " called");
|
|
346
|
-
if (methodName.equals("commandListener")) {
|
|
347
|
-
// args: long clientPtr, byte[] data, int length (from interface)
|
|
348
|
-
long clientPtr = 0;
|
|
349
|
-
byte[] data = null;
|
|
350
|
-
int length = 0;
|
|
351
|
-
|
|
352
|
-
if (args != null && args.length >= 3) {
|
|
353
|
-
if (args[0] instanceof Number) clientPtr = ((Number) args[0]).longValue();
|
|
354
|
-
if (args[1] instanceof byte[]) data = (byte[]) args[1];
|
|
355
|
-
if (args[2] instanceof Number) length = ((Number) args[2]).intValue();
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
Log.d(TAG, "Command callback: clientPtr=" + clientPtr + ", dataLen=" + (data != null ? data.length : 0));
|
|
359
|
-
|
|
360
|
-
// Post to main thread for React Native compatibility
|
|
361
|
-
VStarCamModule.handleCommandReceive(clientPtr, 0, data);
|
|
362
|
-
}
|
|
307
|
+
Log.d(TAG, "Command callback: clientPtr=" + clientPtr + ", dataLen=" + (data != null ? data.length : 0));
|
|
308
|
+
VStarCamModule.handleCommandReceive(clientPtr, 0, data);
|
|
363
309
|
} catch (Exception e) {
|
|
364
310
|
Log.e(TAG, "Error in commandListener callback", e);
|
|
365
311
|
}
|
|
366
|
-
return null;
|
|
367
312
|
}
|
|
368
|
-
}
|
|
369
|
-
);
|
|
370
|
-
jniProxyRoots.add(commandListenerProxy);
|
|
313
|
+
};
|
|
371
314
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
releaseListenerClass.getClassLoader(),
|
|
375
|
-
new Class<?>[] { releaseListenerClass },
|
|
376
|
-
new InvocationHandler() {
|
|
315
|
+
com.vstarcam.app_p2p_api.ClientReleaseListener releaseListener =
|
|
316
|
+
new com.vstarcam.app_p2p_api.ClientReleaseListener() {
|
|
377
317
|
@Override
|
|
378
|
-
public
|
|
318
|
+
public void releaseListener(long clientPtr) {
|
|
379
319
|
try {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
// Handle standard Object methods
|
|
383
|
-
if (method.getDeclaringClass() == Object.class) {
|
|
384
|
-
if (methodName.equals("equals")) return proxy == args[0];
|
|
385
|
-
if (methodName.equals("hashCode")) return System.identityHashCode(proxy);
|
|
386
|
-
if (methodName.equals("toString")) return proxy.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(proxy));
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
Log.d(TAG, "ClientReleaseListener." + methodName + " called");
|
|
320
|
+
Log.d(TAG, "Release callback: clientPtr=" + clientPtr);
|
|
390
321
|
} catch (Exception e) {
|
|
391
322
|
Log.e(TAG, "Error in releaseListener callback", e);
|
|
392
323
|
}
|
|
393
|
-
return null;
|
|
394
324
|
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
|
|
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);
|
|
398
334
|
|
|
399
335
|
// Call JNIApi.init(stateListener, commandListener, releaseListener)
|
|
400
|
-
|
|
401
|
-
VStarCamModule.stateListenerClass, VStarCamModule.commandListenerClass, VStarCamModule.releaseListenerClass);
|
|
402
|
-
initMethod.invoke(null, stateListenerProxy, commandListenerProxy, releaseListenerProxy);
|
|
336
|
+
com.vstarcam.JNIApi.init(stateListener, commandListener, releaseListener);
|
|
403
337
|
|
|
404
338
|
VStarCamModule.isP2PInitialized = true;
|
|
405
|
-
Log.d(TAG, "P2P system initialized successfully!");
|
|
339
|
+
Log.d(TAG, "P2P system initialized successfully with concrete listeners!");
|
|
406
340
|
} catch (Exception e) {
|
|
407
341
|
Log.e(TAG, "Failed to initialize P2P: " + e.getMessage(), e);
|
|
408
342
|
}
|
|
@@ -46,6 +46,7 @@ public class VStarCamVideoView extends FrameLayout
|
|
|
46
46
|
private long playerPtr = 0;
|
|
47
47
|
private boolean isStreaming = false;
|
|
48
48
|
private boolean playerInitialized = false;
|
|
49
|
+
private boolean pendingStartStream = false;
|
|
49
50
|
|
|
50
51
|
// Player class (from AAR)
|
|
51
52
|
private Class<?> appPlayerClass;
|
|
@@ -184,8 +185,9 @@ public class VStarCamVideoView extends FrameLayout
|
|
|
184
185
|
}
|
|
185
186
|
|
|
186
187
|
if (surface == null) {
|
|
187
|
-
Log.
|
|
188
|
-
statusView.setText("
|
|
188
|
+
Log.d(TAG, "Surface not yet available — deferring stream start");
|
|
189
|
+
statusView.setText("Preparing...");
|
|
190
|
+
pendingStartStream = true;
|
|
189
191
|
return;
|
|
190
192
|
}
|
|
191
193
|
|
|
@@ -344,7 +346,15 @@ public class VStarCamVideoView extends FrameLayout
|
|
|
344
346
|
Log.d(TAG, "Surface available: " + width + "x" + height);
|
|
345
347
|
this.surface = new Surface(surfaceTexture);
|
|
346
348
|
|
|
347
|
-
// If
|
|
349
|
+
// If startStream() was called before surface was ready, start now
|
|
350
|
+
if (pendingStartStream) {
|
|
351
|
+
Log.d(TAG, "Deferred stream start — surface now available");
|
|
352
|
+
pendingStartStream = false;
|
|
353
|
+
startStream();
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// If already streaming, update the surface on the existing player
|
|
348
358
|
if (isStreaming && playerPtr != 0 && appPlayerClass != null) {
|
|
349
359
|
try {
|
|
350
360
|
Method setSurfaceMethod = appPlayerClass.getMethod(
|