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

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.
@@ -433,13 +433,26 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
433
433
  }
434
434
 
435
435
  private void sendEvent(String eventName, @Nullable WritableMap params) {
436
- if (reactContext.hasActiveReactInstance()) {
436
+ if (reactContext != null && reactContext.hasActiveReactInstance()) {
437
437
  reactContext
438
438
  .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
439
439
  .emit(eventName, params);
440
440
  }
441
441
  }
442
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
+
443
456
  /**
444
457
  * Create a P2P client for a device
445
458
  * JNIApi.create(String did, String serverParam) -> long
@@ -482,8 +495,8 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
482
495
  return;
483
496
  }
484
497
 
485
- // Generate our own client ID (hash of deviceId) and store mapping
486
- int ourClientPtr = Math.abs(deviceId.hashCode());
498
+ // Generate our own client ID and store mapping
499
+ int ourClientPtr = nextClientPtr.getAndIncrement();
487
500
 
488
501
  ClientInfo clientInfo = new ClientInfo();
489
502
  clientInfo.deviceId = deviceId;
@@ -774,16 +787,20 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
774
787
  */
775
788
  @ReactMethod
776
789
  public void clientGetDeviceInfo(int clientPtr, Promise promise) {
790
+ Log.d(TAG, "clientGetDeviceInfo called for ptr: " + clientPtr);
777
791
  executor.execute(() -> {
778
792
  try {
779
793
  ClientInfo clientInfo = clients.get(clientPtr);
780
794
  if (clientInfo == null) {
795
+ Log.w(TAG, "clientGetDeviceInfo: client not found for ptr " + clientPtr);
781
796
  promise.reject("E_CLIENT_NOT_FOUND", "Client not found");
782
797
  return;
783
798
  }
784
799
 
800
+ Log.d(TAG, "Fetching device info for device: " + clientInfo.deviceId);
801
+
785
802
  WritableMap result = Arguments.createMap();
786
- result.putString("serialNumber", clientInfo.deviceId);
803
+ result.putString("serialNumber", clientInfo.deviceId != null ? clientInfo.deviceId : "Unknown");
787
804
  result.putString("model", "VStarCam");
788
805
  result.putString("firmware", "Unknown");
789
806
  result.putString("manufacturer", "VStarCam");
@@ -798,9 +815,11 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
798
815
  features.putBoolean("wifi", true);
799
816
  result.putMap("features", features);
800
817
 
818
+ Log.d(TAG, "Resolving device info for " + clientInfo.deviceId);
801
819
  promise.resolve(result);
802
- } catch (Exception e) {
803
- promise.reject("E_GET_INFO_FAILED", e.getMessage());
820
+ } catch (Throwable t) {
821
+ Log.e(TAG, "clientGetDeviceInfo crashed: " + t.getMessage(), t);
822
+ promise.reject("E_GET_INFO_FAILED", t.getMessage());
804
823
  }
805
824
  });
806
825
  }
@@ -811,39 +830,53 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
811
830
  */
812
831
  @ReactMethod
813
832
  public void startVideoStream(int clientPtr, int streamType, Promise promise) {
814
- Log.d(TAG, "startVideoStream called with type: " + streamType);
833
+ boolean success = sendCgiInternal(clientPtr,
834
+ String.format("livestream.cgi?streamid=10&substream=%d", streamType), 5);
835
+
836
+ if (success) {
837
+ WritableMap response = Arguments.createMap();
838
+ response.putBoolean("success", true);
839
+ response.putString("message", "Video stream started");
840
+ response.putInt("resolution", streamType);
841
+ promise.resolve(response);
842
+ } else {
843
+ promise.reject("E_VIDEO_START_FAILED", "Failed to send livestream.cgi");
844
+ }
845
+ }
846
+
847
+ /**
848
+ * Helper for internal components to send CGI commands without a Promise
849
+ */
850
+ public static boolean sendCgiInternal(int clientPtr, String cgi, int timeout) {
815
851
  try {
816
852
  ClientInfo clientInfo = clients.get(clientPtr);
817
853
  if (clientInfo == null || clientInfo.sdkClientPtr == 0) {
818
- promise.reject("E_NOT_CONNECTED", "Client not connected");
819
- return;
854
+ Log.e(TAG, "sendCgiInternal: Client not connected for ptr " + clientPtr);
855
+ return false;
820
856
  }
821
857
 
822
- // Send livestream.cgi command to start streaming
823
- // streamid=10 starts the stream, substream is the resolution
824
- String cgi = String.format(
825
- "livestream.cgi?streamid=10&substream=%d&loginuse=%s&loginpas=%s",
826
- streamType,
827
- clientInfo.username != null ? clientInfo.username : "admin",
828
- clientInfo.password != null ? clientInfo.password : ""
829
- );
830
-
831
- Log.d(TAG, "Sending livestream start command: " + cgi);
832
-
833
- Method writeCgiMethod = jniApiClass.getMethod("writeCgi", long.class, String.class, int.class);
834
- Object result = writeCgiMethod.invoke(null, clientInfo.sdkClientPtr, cgi, 5);
835
-
836
- Log.d(TAG, "livestream start command sent, result: " + result);
858
+ // Append login info if missing
859
+ String finalCgi = cgi;
860
+ if (!cgi.contains("loginuse=")) {
861
+ String sep = cgi.contains("?") ? "&" : "?";
862
+ finalCgi = cgi + sep + "loginuse=" + (clientInfo.username != null ? clientInfo.username : "admin") +
863
+ "&loginpas=" + (clientInfo.password != null ? clientInfo.password : "");
864
+ }
865
+
866
+ Log.d(TAG, "sendCgiInternal: " + finalCgi);
837
867
 
838
- WritableMap response = Arguments.createMap();
839
- response.putBoolean("success", true);
840
- response.putString("message", "Video stream started");
841
- response.putInt("resolution", streamType);
842
- promise.resolve(response);
868
+ // Invoke JNIApi.writeCgi
869
+ // Since we need to access jniApiClass which is not static, we use reflection on the instance if available
870
+ // but for simplicity, we can just grab the class by name again or make the class ref static.
871
+ Class<?> jniClass = Class.forName("com.vstarcam.JNIApi");
872
+ Method writeCgiMethod = jniClass.getMethod("writeCgi", long.class, String.class, int.class);
873
+ Object result = writeCgiMethod.invoke(null, clientInfo.sdkClientPtr, finalCgi, timeout);
843
874
 
875
+ int res = (Integer) result;
876
+ return res == 0; // 0 usually means success in VStarCam JNI
844
877
  } catch (Exception e) {
845
- Log.e(TAG, "startVideoStream error", e);
846
- promise.reject("E_VIDEO_START_FAILED", e.getMessage(), e);
878
+ Log.e(TAG, "sendCgiInternal failed", e);
879
+ return false;
847
880
  }
848
881
  }
849
882
 
@@ -945,7 +978,7 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
945
978
  @ReactMethod
946
979
  public void getSdkVersion(Promise promise) {
947
980
  WritableMap result = Arguments.createMap();
948
- result.putString("version", "1.0.22");
981
+ result.putString("version", "1.0.46");
949
982
  result.putBoolean("nativeLoaded", isNativeLibraryLoaded);
950
983
  result.putString("nativeLib", "OKSMARTPPCS");
951
984
  result.putBoolean("p2pInitialized", isP2PInitialized);
@@ -194,6 +194,11 @@ public class VStarCamVideoView extends FrameLayout
194
194
 
195
195
  statusView.setText("Starting stream...");
196
196
 
197
+ // Start video stream on camera side via CGI
198
+ Log.d(TAG, "Requesting livestream start from camera...");
199
+ VStarCamModule.sendCgiInternal((int) clientPtr,
200
+ String.format("livestream.cgi?streamid=10&substream=%d", resolution), 5);
201
+
197
202
  try {
198
203
  // 1. Create player instance if needed
199
204
  // API: createPlayer(long identifier, Surface surface, int width, int height, int flags)
@@ -245,6 +250,10 @@ public class VStarCamVideoView extends FrameLayout
245
250
 
246
251
  Log.d(TAG, "Stopping stream...");
247
252
 
253
+ // Stop video stream on camera side via CGI
254
+ Log.d(TAG, "Requesting livestream stop from camera...");
255
+ VStarCamModule.sendCgiInternal((int) clientPtr, "livestream.cgi?streamid=11", 5);
256
+
248
257
  try {
249
258
  try {
250
259
  Method stopMethod = appPlayerClass.getMethod("stop", long.class);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bits-innovate/react-native-vstarcam",
3
- "version": "1.0.44",
3
+ "version": "1.0.46",
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