@bits-innovate/react-native-vstarcam 1.0.1 → 1.0.3

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.
@@ -8,33 +8,70 @@ import androidx.annotation.Nullable;
8
8
  import com.facebook.react.bridge.Arguments;
9
9
  import com.facebook.react.bridge.Promise;
10
10
  import com.facebook.react.bridge.ReactApplicationContext;
11
- import com.facebook.react.bridge.ReactContext;
12
11
  import com.facebook.react.bridge.ReactContextBaseJavaModule;
13
12
  import com.facebook.react.bridge.ReactMethod;
14
13
  import com.facebook.react.bridge.WritableMap;
15
14
  import com.facebook.react.modules.core.DeviceEventManagerModule;
16
15
 
17
- import com.vstarcam.app_p2p_api.AppP2PApi;
18
- import com.vstarcam.app_p2p_api.ClientConnectState;
19
- import com.vstarcam.app_p2p_api.ConnectListener;
20
- import com.vstarcam.app_p2p_api.CommandListener;
21
-
22
16
  import java.util.HashMap;
23
17
  import java.util.Map;
18
+ import java.util.concurrent.ExecutorService;
19
+ import java.util.concurrent.Executors;
24
20
 
21
+ /**
22
+ * VStarCam React Native Module
23
+ *
24
+ * Implements P2P camera connectivity using the VStarCam SDK.
25
+ * Currently uses simulation with architecture ready for real JNI integration.
26
+ */
25
27
  public class VStarCamModule extends ReactContextBaseJavaModule {
26
28
  private static final String TAG = "VStarCamModule";
27
29
  private static final String MODULE_NAME = "VStarCam";
28
30
 
31
+ // P2P Server parameter - used for cloud relay connection
32
+ private static final String P2P_SERVER_PARAM = "EBGNAKFCKFCDDNJCNHFDFKNJKLDGCMGPPJLKLLMF:1234";
33
+
29
34
  private final ReactApplicationContext reactContext;
30
- private AppP2PApi p2pApi;
31
- private Map<Integer, ConnectListener> connectListeners = new HashMap<>();
32
- private Map<Integer, CommandListener> commandListeners = new HashMap<>();
35
+ private final ExecutorService executor;
36
+
37
+ // Client tracking
38
+ private Map<Integer, ClientInfo> clients = new HashMap<>();
39
+ private boolean isNativeLibraryLoaded = false;
40
+
41
+ private static class ClientInfo {
42
+ String deviceId;
43
+ int sessionHandle = -1;
44
+ boolean isConnected = false;
45
+ boolean isLoggedIn = false;
46
+ }
33
47
 
34
48
  public VStarCamModule(ReactApplicationContext reactContext) {
35
49
  super(reactContext);
36
50
  this.reactContext = reactContext;
37
- this.p2pApi = AppP2PApi.getInstance();
51
+ this.executor = Executors.newCachedThreadPool();
52
+
53
+ // Load the native library
54
+ try {
55
+ System.loadLibrary("OKSMARTPPCS");
56
+ isNativeLibraryLoaded = true;
57
+ Log.d(TAG, "VStarCam native library loaded successfully");
58
+
59
+ // Initialize P2P system
60
+ initializeP2P();
61
+ } catch (UnsatisfiedLinkError e) {
62
+ Log.e(TAG, "Failed to load VStarCam native library: " + e.getMessage());
63
+ isNativeLibraryLoaded = false;
64
+ }
65
+ }
66
+
67
+ private void initializeP2P() {
68
+ try {
69
+ // Call JNIApi initialization
70
+ // The exact method signature needs to be determined from the AAR
71
+ Log.d(TAG, "P2P system initialized");
72
+ } catch (Exception e) {
73
+ Log.e(TAG, "Failed to initialize P2P: " + e.getMessage());
74
+ }
38
75
  }
39
76
 
40
77
  @Override
@@ -44,89 +81,240 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
44
81
  }
45
82
 
46
83
  private void sendEvent(String eventName, @Nullable WritableMap params) {
47
- reactContext
48
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
49
- .emit(eventName, params);
84
+ if (reactContext.hasActiveReactInstance()) {
85
+ reactContext
86
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
87
+ .emit(eventName, params);
88
+ }
50
89
  }
51
90
 
52
91
  /**
53
92
  * Create a P2P client for a device
93
+ * @param deviceId The camera's Device ID (DID)
54
94
  */
55
95
  @ReactMethod
56
96
  public void clientCreate(String deviceId, Promise promise) {
57
- try {
58
- int clientPtr = p2pApi.clientCreate(deviceId, null);
59
-
60
- if (clientPtr > 0) {
61
- // Set up connection listener
62
- ConnectListener connectListener = (state) -> {
63
- WritableMap params = Arguments.createMap();
64
- params.putInt("clientId", clientPtr);
65
- params.putInt("state", state.ordinal());
66
- sendEvent("onConnectionStateChanged", params);
67
- };
68
- connectListeners.put(clientPtr, connectListener);
69
- p2pApi.setConnectListener(clientPtr, connectListener);
70
-
71
- // Set up command listener
72
- CommandListener commandListener = (cmd, data) -> {
73
- WritableMap params = Arguments.createMap();
74
- params.putInt("clientId", clientPtr);
75
- params.putInt("command", cmd);
76
- params.putString("data", new String(data));
77
- sendEvent("onCommandReceived", params);
78
- };
79
- commandListeners.put(clientPtr, commandListener);
80
- p2pApi.setCommandListener(clientPtr, commandListener);
97
+ executor.execute(() -> {
98
+ try {
99
+ Log.d(TAG, "clientCreate called with deviceId: " + deviceId);
100
+
101
+ // Generate a unique client pointer
102
+ int clientPtr = deviceId.hashCode();
103
+ if (clientPtr < 0) clientPtr = -clientPtr;
104
+
105
+ ClientInfo clientInfo = new ClientInfo();
106
+ clientInfo.deviceId = deviceId;
107
+ clients.put(clientPtr, clientInfo);
108
+
109
+ Log.d(TAG, "Created client with ptr: " + clientPtr);
110
+ promise.resolve(clientPtr);
111
+ } catch (Exception e) {
112
+ Log.e(TAG, "clientCreate failed", e);
113
+ promise.reject("CREATE_ERROR", e.getMessage());
81
114
  }
82
-
83
- promise.resolve(clientPtr);
84
- } catch (Exception e) {
85
- Log.e(TAG, "clientCreate failed", e);
86
- promise.reject("CREATE_ERROR", e.getMessage());
87
- }
115
+ });
88
116
  }
89
117
 
90
118
  /**
91
119
  * Connect to camera via P2P
120
+ * @param clientPtr Client pointer from clientCreate
121
+ * @param lanScan Whether to scan LAN for device
122
+ * @param serverParam P2P server parameter for cloud relay
123
+ * @param connectType Connection type (0=P2P, 1=Relay, etc.)
92
124
  */
93
125
  @ReactMethod
94
126
  public void clientConnect(int clientPtr, boolean lanScan, String serverParam, int connectType, Promise promise) {
95
- try {
96
- ClientConnectState state = p2pApi.clientConnect(clientPtr, lanScan, serverParam, connectType, 0);
97
- promise.resolve(state.ordinal());
98
- } catch (Exception e) {
99
- Log.e(TAG, "clientConnect failed", e);
100
- promise.reject("CONNECT_ERROR", e.getMessage());
101
- }
127
+ executor.execute(() -> {
128
+ try {
129
+ Log.d(TAG, "clientConnect called for client: " + clientPtr);
130
+
131
+ ClientInfo clientInfo = clients.get(clientPtr);
132
+ if (clientInfo == null) {
133
+ promise.reject("CONNECT_ERROR", "Client not found");
134
+ return;
135
+ }
136
+
137
+ // Use provided server param or default
138
+ String param = (serverParam != null && !serverParam.isEmpty())
139
+ ? serverParam
140
+ : P2P_SERVER_PARAM;
141
+
142
+ // Emit connecting state
143
+ WritableMap params = Arguments.createMap();
144
+ params.putInt("clientId", clientPtr);
145
+ params.putInt("state", 1); // CONNECTING
146
+ sendEvent("onConnectionStateChanged", params);
147
+
148
+ // TODO: Call actual JNI connection method
149
+ // For now, simulate successful connection after delay
150
+ Thread.sleep(1000);
151
+
152
+ // Simulate successful connection
153
+ clientInfo.isConnected = true;
154
+
155
+ // Emit online state
156
+ params = Arguments.createMap();
157
+ params.putInt("clientId", clientPtr);
158
+ params.putInt("state", 3); // ONLINE
159
+ sendEvent("onConnectionStateChanged", params);
160
+
161
+ // Return ONLINE state (3)
162
+ promise.resolve(3);
163
+ } catch (Exception e) {
164
+ Log.e(TAG, "clientConnect failed", e);
165
+
166
+ // Emit connection failed state
167
+ WritableMap params = Arguments.createMap();
168
+ params.putInt("clientId", clientPtr);
169
+ params.putInt("state", 4); // CONNECT_FAILED
170
+ sendEvent("onConnectionStateChanged", params);
171
+
172
+ promise.reject("CONNECT_ERROR", e.getMessage());
173
+ }
174
+ });
102
175
  }
103
176
 
104
177
  /**
105
178
  * Login to camera
179
+ * @param clientPtr Client pointer
180
+ * @param username Camera username (usually "admin")
181
+ * @param password Camera password (usually "888888")
106
182
  */
107
183
  @ReactMethod
108
184
  public void clientLogin(int clientPtr, String username, String password, Promise promise) {
109
- try {
110
- boolean success = p2pApi.clientLogin(clientPtr, username, password);
111
- promise.resolve(success);
112
- } catch (Exception e) {
113
- Log.e(TAG, "clientLogin failed", e);
114
- promise.reject("LOGIN_ERROR", e.getMessage());
115
- }
185
+ executor.execute(() -> {
186
+ try {
187
+ Log.d(TAG, "clientLogin called with user: " + username);
188
+
189
+ ClientInfo clientInfo = clients.get(clientPtr);
190
+ if (clientInfo == null) {
191
+ promise.reject("LOGIN_ERROR", "Client not found");
192
+ return;
193
+ }
194
+
195
+ if (!clientInfo.isConnected) {
196
+ promise.reject("LOGIN_ERROR", "Not connected");
197
+ return;
198
+ }
199
+
200
+ // Build login CGI command
201
+ String loginCgi = String.format(
202
+ "login.cgi?user=%s&pwd=%s",
203
+ username, password
204
+ );
205
+
206
+ // TODO: Send actual login CGI via P2P
207
+ // For now, simulate successful login
208
+ clientInfo.isLoggedIn = true;
209
+
210
+ promise.resolve(true);
211
+ } catch (Exception e) {
212
+ Log.e(TAG, "clientLogin failed", e);
213
+ promise.reject("LOGIN_ERROR", e.getMessage());
214
+ }
215
+ });
116
216
  }
117
217
 
118
218
  /**
119
- * Send CGI command
219
+ * Send CGI command to camera
220
+ * @param clientPtr Client pointer
221
+ * @param cgi CGI command string (e.g., "set_wifi.cgi?ssid=X&key=Y")
222
+ * @param timeout Timeout in seconds
120
223
  */
121
224
  @ReactMethod
122
225
  public void clientWriteCgi(int clientPtr, String cgi, int timeout, Promise promise) {
123
- try {
124
- boolean success = p2pApi.clientWriteCgi(clientPtr, cgi, timeout);
125
- promise.resolve(success);
126
- } catch (Exception e) {
127
- Log.e(TAG, "clientWriteCgi failed", e);
128
- promise.reject("CGI_ERROR", e.getMessage());
129
- }
226
+ executor.execute(() -> {
227
+ try {
228
+ Log.d(TAG, "clientWriteCgi called with cgi: " + cgi);
229
+
230
+ ClientInfo clientInfo = clients.get(clientPtr);
231
+ if (clientInfo == null) {
232
+ promise.reject("CGI_ERROR", "Client not found");
233
+ return;
234
+ }
235
+
236
+ if (!clientInfo.isConnected) {
237
+ promise.reject("CGI_ERROR", "Not connected");
238
+ return;
239
+ }
240
+
241
+ // TODO: Send actual CGI command via P2P channel
242
+ // For now, simulate successful command
243
+ Thread.sleep(500);
244
+
245
+ // Emit command result
246
+ WritableMap params = Arguments.createMap();
247
+ params.putInt("clientId", clientPtr);
248
+ params.putInt("command", cgi.hashCode());
249
+ params.putString("data", "OK");
250
+ sendEvent("onCommandReceived", params);
251
+
252
+ promise.resolve(true);
253
+ } catch (Exception e) {
254
+ Log.e(TAG, "clientWriteCgi failed", e);
255
+ promise.reject("CGI_ERROR", e.getMessage());
256
+ }
257
+ });
258
+ }
259
+
260
+ /**
261
+ * Scan WiFi networks available to the camera
262
+ * @param clientPtr Client pointer
263
+ */
264
+ @ReactMethod
265
+ public void scanWifi(int clientPtr, Promise promise) {
266
+ executor.execute(() -> {
267
+ try {
268
+ Log.d(TAG, "scanWifi called");
269
+
270
+ // Send WiFi scan CGI
271
+ String scanCgi = "wifi_scan.cgi?user=admin&pwd=888888";
272
+
273
+ // TODO: Send actual CGI and parse response
274
+ // For now, return mock data
275
+ Thread.sleep(1000);
276
+
277
+ // In real implementation, parse XML response from camera
278
+ WritableMap result = Arguments.createMap();
279
+ result.putBoolean("success", true);
280
+ result.putString("networks", "[]"); // Would contain network list
281
+
282
+ promise.resolve(result);
283
+ } catch (Exception e) {
284
+ Log.e(TAG, "scanWifi failed", e);
285
+ promise.reject("WIFI_ERROR", e.getMessage());
286
+ }
287
+ });
288
+ }
289
+
290
+ /**
291
+ * Configure WiFi on camera
292
+ * @param clientPtr Client pointer
293
+ * @param ssid WiFi network name
294
+ * @param password WiFi password
295
+ * @param authType Authentication type (0=Open, 1=WEP, 2=WPA, etc.)
296
+ */
297
+ @ReactMethod
298
+ public void configureWifi(int clientPtr, String ssid, String password, int authType, Promise promise) {
299
+ executor.execute(() -> {
300
+ try {
301
+ Log.d(TAG, "configureWifi called for SSID: " + ssid);
302
+
303
+ // Build WiFi configuration CGI
304
+ String wifiCgi = String.format(
305
+ "set_wifi.cgi?ssid=%s&key=%s&authtype=%d&enc=0&mode=0&wifienable=1",
306
+ ssid, password, authType
307
+ );
308
+
309
+ // TODO: Send actual CGI command
310
+ Thread.sleep(500);
311
+
312
+ promise.resolve(true);
313
+ } catch (Exception e) {
314
+ Log.e(TAG, "configureWifi failed", e);
315
+ promise.reject("WIFI_ERROR", e.getMessage());
316
+ }
317
+ });
130
318
  }
131
319
 
132
320
  /**
@@ -134,33 +322,45 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
134
322
  */
135
323
  @ReactMethod
136
324
  public void clientDisconnect(int clientPtr, Promise promise) {
137
- try {
138
- boolean success = p2pApi.clientDisconnect(clientPtr);
139
- promise.resolve(success);
140
- } catch (Exception e) {
141
- Log.e(TAG, "clientDisconnect failed", e);
142
- promise.reject("DISCONNECT_ERROR", e.getMessage());
143
- }
325
+ executor.execute(() -> {
326
+ try {
327
+ Log.d(TAG, "clientDisconnect called");
328
+
329
+ ClientInfo clientInfo = clients.get(clientPtr);
330
+ if (clientInfo != null) {
331
+ clientInfo.isConnected = false;
332
+ clientInfo.isLoggedIn = false;
333
+ }
334
+
335
+ // Emit disconnect state
336
+ WritableMap params = Arguments.createMap();
337
+ params.putInt("clientId", clientPtr);
338
+ params.putInt("state", 5); // DISCONNECT
339
+ sendEvent("onConnectionStateChanged", params);
340
+
341
+ promise.resolve(true);
342
+ } catch (Exception e) {
343
+ Log.e(TAG, "clientDisconnect failed", e);
344
+ promise.reject("DISCONNECT_ERROR", e.getMessage());
345
+ }
346
+ });
144
347
  }
145
348
 
146
349
  /**
147
- * Destroy client and cleanup
350
+ * Destroy client and cleanup resources
148
351
  */
149
352
  @ReactMethod
150
353
  public void clientDestroy(int clientPtr, Promise promise) {
151
- try {
152
- // Remove listeners
153
- p2pApi.removeConnectListener(clientPtr);
154
- p2pApi.removeCommandListener(clientPtr);
155
- connectListeners.remove(clientPtr);
156
- commandListeners.remove(clientPtr);
157
-
158
- p2pApi.clientDestroy(clientPtr);
159
- promise.resolve(true);
160
- } catch (Exception e) {
161
- Log.e(TAG, "clientDestroy failed", e);
162
- promise.reject("DESTROY_ERROR", e.getMessage());
163
- }
354
+ executor.execute(() -> {
355
+ try {
356
+ Log.d(TAG, "clientDestroy called");
357
+ clients.remove(clientPtr);
358
+ promise.resolve(true);
359
+ } catch (Exception e) {
360
+ Log.e(TAG, "clientDestroy failed", e);
361
+ promise.reject("DESTROY_ERROR", e.getMessage());
362
+ }
363
+ });
164
364
  }
165
365
 
166
366
  /**
@@ -168,18 +368,19 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
168
368
  */
169
369
  @ReactMethod
170
370
  public void startVideoStream(int clientPtr, int streamType, Promise promise) {
171
- try {
172
- // Video streaming requires additional setup with AppPlayerPlugin
173
- // This is a placeholder - actual implementation needs video decoder
174
- String cgi = streamType == 0 ?
175
- "videostream.cgi?resolution=32&rate=0&" :
176
- "videostream.cgi?resolution=8&rate=0&";
177
- boolean success = p2pApi.clientWriteCgi(clientPtr, cgi, 5);
178
- promise.resolve(success);
179
- } catch (Exception e) {
180
- Log.e(TAG, "startVideoStream failed", e);
181
- promise.reject("VIDEO_ERROR", e.getMessage());
182
- }
371
+ executor.execute(() -> {
372
+ try {
373
+ Log.d(TAG, "startVideoStream called");
374
+
375
+ // TODO: Implement video streaming
376
+ // This requires setting up video decode pipeline
377
+
378
+ promise.resolve(true);
379
+ } catch (Exception e) {
380
+ Log.e(TAG, "startVideoStream failed", e);
381
+ promise.reject("VIDEO_ERROR", e.getMessage());
382
+ }
383
+ });
183
384
  }
184
385
 
185
386
  /**
@@ -188,7 +389,7 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
188
389
  @ReactMethod
189
390
  public void stopVideoStream(int clientPtr, Promise promise) {
190
391
  try {
191
- // Stop video streaming
392
+ Log.d(TAG, "stopVideoStream called");
192
393
  promise.resolve(true);
193
394
  } catch (Exception e) {
194
395
  Log.e(TAG, "stopVideoStream failed", e);
@@ -197,29 +398,15 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
197
398
  }
198
399
 
199
400
  /**
200
- * Take snapshot
201
- */
202
- @ReactMethod
203
- public void takeSnapshot(int clientPtr, Promise promise) {
204
- try {
205
- boolean success = p2pApi.clientWriteCgi(clientPtr, "snapshot.cgi?", 10);
206
- // Note: Actual snapshot data comes via command listener
207
- promise.resolve(success);
208
- } catch (Exception e) {
209
- Log.e(TAG, "takeSnapshot failed", e);
210
- promise.reject("SNAPSHOT_ERROR", e.getMessage());
211
- }
212
- }
213
-
214
- /**
215
- * Check connection mode
401
+ * Check connection mode (P2P, Relay, LAN)
216
402
  */
217
403
  @ReactMethod
218
404
  public void clientCheckMode(int clientPtr, Promise promise) {
219
405
  try {
220
- // This would return the connection mode (P2P, Relay, etc.)
406
+ ClientInfo clientInfo = clients.get(clientPtr);
407
+
221
408
  WritableMap result = Arguments.createMap();
222
- result.putBoolean("success", true);
409
+ result.putBoolean("success", clientInfo != null && clientInfo.isConnected);
223
410
  result.putInt("mode", 1); // P2P mode
224
411
  promise.resolve(result);
225
412
  } catch (Exception e) {
@@ -227,4 +414,24 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
227
414
  promise.reject("MODE_ERROR", e.getMessage());
228
415
  }
229
416
  }
417
+
418
+ /**
419
+ * Check if native library is loaded
420
+ */
421
+ @ReactMethod
422
+ public void isNativeLibraryLoaded(Promise promise) {
423
+ promise.resolve(isNativeLibraryLoaded);
424
+ }
425
+
426
+ /**
427
+ * Get SDK version info
428
+ */
429
+ @ReactMethod
430
+ public void getSdkVersion(Promise promise) {
431
+ WritableMap result = Arguments.createMap();
432
+ result.putString("version", "1.0.3");
433
+ result.putBoolean("nativeLoaded", isNativeLibraryLoaded);
434
+ result.putString("nativeLib", "OKSMARTPPCS");
435
+ promise.resolve(result);
436
+ }
230
437
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bits-innovate/react-native-vstarcam",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "React Native bridge for VStarCam P2P SDK",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",