@bits-innovate/react-native-vstarcam 1.0.8 → 1.0.10
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.
|
@@ -13,7 +13,9 @@ import com.facebook.react.bridge.ReactMethod;
|
|
|
13
13
|
import com.facebook.react.bridge.WritableMap;
|
|
14
14
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
15
15
|
|
|
16
|
+
import java.lang.reflect.InvocationHandler;
|
|
16
17
|
import java.lang.reflect.Method;
|
|
18
|
+
import java.lang.reflect.Proxy;
|
|
17
19
|
import java.util.HashMap;
|
|
18
20
|
import java.util.Map;
|
|
19
21
|
import java.util.concurrent.ExecutorService;
|
|
@@ -23,30 +25,41 @@ import java.util.concurrent.Executors;
|
|
|
23
25
|
* VStarCam React Native Module
|
|
24
26
|
*
|
|
25
27
|
* Implements P2P camera connectivity using the VStarCam SDK.
|
|
26
|
-
* Uses JNI calls to the native OKSMARTPPCS library.
|
|
28
|
+
* Uses JNI calls to the native OKSMARTPPCS library via JNIApi class.
|
|
29
|
+
*
|
|
30
|
+
* JNI API Methods (discovered via reflection):
|
|
31
|
+
* - create(String did, String serverParam) -> long clientPtr
|
|
32
|
+
* - connect(long clientPtr, int timeout, String serverParam, int connectType)
|
|
33
|
+
* - login(long clientPtr, String username, String password)
|
|
34
|
+
* - disconnect(long clientPtr)
|
|
35
|
+
* - destroy(long clientPtr)
|
|
36
|
+
* - writeCgi(long clientPtr, String cgi, int timeout)
|
|
37
|
+
* - init(ClientStateListener, ClientCommandListener, ClientReleaseListener)
|
|
27
38
|
*/
|
|
28
39
|
public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
29
40
|
private static final String TAG = "VStarCamModule";
|
|
30
41
|
private static final String MODULE_NAME = "VStarCam";
|
|
31
42
|
|
|
32
43
|
// P2P Server parameter - used for cloud relay connection
|
|
33
|
-
// Format: InitString:Port
|
|
34
44
|
private static final String P2P_SERVER_PARAM = "EBGNAKFCKFCDDNJCNHFDFKNJKLDGCMGPPJLKLLMF:1234";
|
|
35
45
|
|
|
36
46
|
private final ReactApplicationContext reactContext;
|
|
37
47
|
private final ExecutorService executor;
|
|
38
48
|
|
|
39
|
-
// Client tracking
|
|
49
|
+
// Client tracking - maps our clientPtr to actual SDK client handle
|
|
40
50
|
private Map<Integer, ClientInfo> clients = new HashMap<>();
|
|
41
51
|
private boolean isNativeLibraryLoaded = false;
|
|
42
52
|
private boolean isP2PInitialized = false;
|
|
43
53
|
|
|
44
|
-
// JNI API class
|
|
54
|
+
// JNI API class and listener interfaces
|
|
45
55
|
private Class<?> jniApiClass = null;
|
|
56
|
+
private Class<?> stateListenerClass = null;
|
|
57
|
+
private Class<?> commandListenerClass = null;
|
|
58
|
+
private Class<?> releaseListenerClass = null;
|
|
46
59
|
|
|
47
60
|
private static class ClientInfo {
|
|
48
61
|
String deviceId;
|
|
49
|
-
|
|
62
|
+
long sdkClientPtr = 0; // Actual SDK client pointer (long)
|
|
50
63
|
boolean isConnected = false;
|
|
51
64
|
boolean isLoggedIn = false;
|
|
52
65
|
}
|
|
@@ -67,29 +80,22 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
67
80
|
isNativeLibraryLoaded = true;
|
|
68
81
|
Log.d(TAG, "OKSMARTPPCS library loaded successfully");
|
|
69
82
|
|
|
70
|
-
//
|
|
83
|
+
// Load JNI API class
|
|
71
84
|
try {
|
|
72
85
|
jniApiClass = Class.forName("com.vstarcam.JNIApi");
|
|
73
86
|
Log.d(TAG, "JNIApi class found: " + jniApiClass.getName());
|
|
74
87
|
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
Log.w(TAG, "JNIApi class not found, will try AppP2PApiPlugin");
|
|
88
|
+
// Load listener interfaces
|
|
89
|
+
stateListenerClass = Class.forName("com.vstarcam.app_p2p_api.ClientStateListener");
|
|
90
|
+
commandListenerClass = Class.forName("com.vstarcam.app_p2p_api.ClientCommandListener");
|
|
91
|
+
releaseListenerClass = Class.forName("com.vstarcam.app_p2p_api.ClientReleaseListener");
|
|
92
|
+
Log.d(TAG, "Listener interfaces loaded");
|
|
81
93
|
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
} catch (ClassNotFoundException e2) {
|
|
87
|
-
Log.e(TAG, "No P2P API class found in AAR");
|
|
88
|
-
}
|
|
94
|
+
// Initialize P2P system with listeners
|
|
95
|
+
initializeP2P();
|
|
96
|
+
} catch (ClassNotFoundException e) {
|
|
97
|
+
Log.e(TAG, "JNIApi class not found: " + e.getMessage());
|
|
89
98
|
}
|
|
90
|
-
|
|
91
|
-
// Initialize P2P system
|
|
92
|
-
initializeP2P();
|
|
93
99
|
} catch (UnsatisfiedLinkError e) {
|
|
94
100
|
Log.e(TAG, "Failed to load native library: " + e.getMessage());
|
|
95
101
|
isNativeLibraryLoaded = false;
|
|
@@ -97,30 +103,111 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
97
103
|
}
|
|
98
104
|
|
|
99
105
|
private void initializeP2P() {
|
|
100
|
-
if (!isNativeLibraryLoaded) {
|
|
101
|
-
Log.e(TAG, "Cannot initialize P2P: native library not
|
|
106
|
+
if (!isNativeLibraryLoaded || jniApiClass == null) {
|
|
107
|
+
Log.e(TAG, "Cannot initialize P2P: native library or JNIApi not available");
|
|
102
108
|
return;
|
|
103
109
|
}
|
|
104
110
|
|
|
105
111
|
try {
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
Object
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
112
|
+
// Create dynamic proxy for ClientStateListener
|
|
113
|
+
Object stateListener = Proxy.newProxyInstance(
|
|
114
|
+
stateListenerClass.getClassLoader(),
|
|
115
|
+
new Class<?>[] { stateListenerClass },
|
|
116
|
+
new InvocationHandler() {
|
|
117
|
+
@Override
|
|
118
|
+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
|
119
|
+
Log.d(TAG, "ClientStateListener." + method.getName() + " called");
|
|
120
|
+
if (method.getName().equals("stateChange")) {
|
|
121
|
+
// args: long clientPtr, int state
|
|
122
|
+
long clientPtr = (Long) args[0];
|
|
123
|
+
int state = (Integer) args[1];
|
|
124
|
+
handleStateChange(clientPtr, state);
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
119
128
|
}
|
|
120
|
-
|
|
121
|
-
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
// Create dynamic proxy for ClientCommandListener
|
|
132
|
+
Object commandListener = Proxy.newProxyInstance(
|
|
133
|
+
commandListenerClass.getClassLoader(),
|
|
134
|
+
new Class<?>[] { commandListenerClass },
|
|
135
|
+
new InvocationHandler() {
|
|
136
|
+
@Override
|
|
137
|
+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
|
138
|
+
Log.d(TAG, "ClientCommandListener." + method.getName() + " called");
|
|
139
|
+
if (method.getName().equals("commandReceive")) {
|
|
140
|
+
// args: long clientPtr, int command, byte[] data, int length
|
|
141
|
+
long clientPtr = (Long) args[0];
|
|
142
|
+
int command = (Integer) args[1];
|
|
143
|
+
byte[] data = (byte[]) args[2];
|
|
144
|
+
handleCommandReceive(clientPtr, command, data);
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
// Create dynamic proxy for ClientReleaseListener
|
|
152
|
+
Object releaseListener = Proxy.newProxyInstance(
|
|
153
|
+
releaseListenerClass.getClassLoader(),
|
|
154
|
+
new Class<?>[] { releaseListenerClass },
|
|
155
|
+
new InvocationHandler() {
|
|
156
|
+
@Override
|
|
157
|
+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
|
158
|
+
Log.d(TAG, "ClientReleaseListener." + method.getName() + " called");
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// Call JNIApi.init(stateListener, commandListener, releaseListener)
|
|
165
|
+
Method initMethod = jniApiClass.getMethod("init",
|
|
166
|
+
stateListenerClass, commandListenerClass, releaseListenerClass);
|
|
167
|
+
initMethod.invoke(null, stateListener, commandListener, releaseListener);
|
|
168
|
+
|
|
169
|
+
isP2PInitialized = true;
|
|
170
|
+
Log.d(TAG, "P2P system initialized successfully!");
|
|
122
171
|
} catch (Exception e) {
|
|
123
|
-
Log.e(TAG, "Failed to initialize P2P: " + e.getMessage());
|
|
172
|
+
Log.e(TAG, "Failed to initialize P2P: " + e.getMessage(), e);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private void handleStateChange(long clientPtr, int state) {
|
|
177
|
+
Log.d(TAG, "State change: clientPtr=" + clientPtr + ", state=" + state);
|
|
178
|
+
|
|
179
|
+
// Find our client by SDK pointer
|
|
180
|
+
for (Map.Entry<Integer, ClientInfo> entry : clients.entrySet()) {
|
|
181
|
+
if (entry.getValue().sdkClientPtr == clientPtr) {
|
|
182
|
+
int ourClientPtr = entry.getKey();
|
|
183
|
+
|
|
184
|
+
WritableMap params = Arguments.createMap();
|
|
185
|
+
params.putInt("clientId", ourClientPtr);
|
|
186
|
+
params.putInt("state", state);
|
|
187
|
+
sendEvent("onConnectionStateChanged", params);
|
|
188
|
+
|
|
189
|
+
// Update connected state
|
|
190
|
+
entry.getValue().isConnected = (state == 3); // ONLINE
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private void handleCommandReceive(long clientPtr, int command, byte[] data) {
|
|
197
|
+
Log.d(TAG, "Command receive: clientPtr=" + clientPtr + ", command=" + command);
|
|
198
|
+
|
|
199
|
+
// Find our client by SDK pointer
|
|
200
|
+
for (Map.Entry<Integer, ClientInfo> entry : clients.entrySet()) {
|
|
201
|
+
if (entry.getValue().sdkClientPtr == clientPtr) {
|
|
202
|
+
int ourClientPtr = entry.getKey();
|
|
203
|
+
|
|
204
|
+
WritableMap params = Arguments.createMap();
|
|
205
|
+
params.putInt("clientId", ourClientPtr);
|
|
206
|
+
params.putInt("command", command);
|
|
207
|
+
params.putString("data", data != null ? new String(data) : "");
|
|
208
|
+
sendEvent("onCommandReceived", params);
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
124
211
|
}
|
|
125
212
|
}
|
|
126
213
|
|
|
@@ -140,7 +227,7 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
140
227
|
|
|
141
228
|
/**
|
|
142
229
|
* Create a P2P client for a device
|
|
143
|
-
*
|
|
230
|
+
* JNIApi.create(String did, String serverParam) -> long
|
|
144
231
|
*/
|
|
145
232
|
@ReactMethod
|
|
146
233
|
public void clientCreate(String deviceId, Promise promise) {
|
|
@@ -148,15 +235,34 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
148
235
|
try {
|
|
149
236
|
Log.d(TAG, "clientCreate called with deviceId: " + deviceId);
|
|
150
237
|
|
|
151
|
-
|
|
152
|
-
|
|
238
|
+
if (jniApiClass == null) {
|
|
239
|
+
promise.reject("CREATE_ERROR", "JNIApi not available");
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Call JNIApi.create(did, serverParam)
|
|
244
|
+
Method createMethod = jniApiClass.getMethod("create", String.class, String.class);
|
|
245
|
+
Object result = createMethod.invoke(null, deviceId, P2P_SERVER_PARAM);
|
|
246
|
+
long sdkClientPtr = (Long) result;
|
|
247
|
+
|
|
248
|
+
Log.d(TAG, "JNIApi.create result: " + sdkClientPtr);
|
|
249
|
+
|
|
250
|
+
// Note: pointer can be negative (unsigned long cast to signed) - only 0 is invalid
|
|
251
|
+
if (sdkClientPtr == 0) {
|
|
252
|
+
promise.reject("CREATE_ERROR", "Failed to create client, result: " + sdkClientPtr);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Generate our own client ID (hash of deviceId) and store mapping
|
|
257
|
+
int ourClientPtr = Math.abs(deviceId.hashCode());
|
|
153
258
|
|
|
154
259
|
ClientInfo clientInfo = new ClientInfo();
|
|
155
260
|
clientInfo.deviceId = deviceId;
|
|
156
|
-
|
|
261
|
+
clientInfo.sdkClientPtr = sdkClientPtr;
|
|
262
|
+
clients.put(ourClientPtr, clientInfo);
|
|
157
263
|
|
|
158
|
-
Log.d(TAG, "Created client
|
|
159
|
-
promise.resolve(
|
|
264
|
+
Log.d(TAG, "Created client: ourPtr=" + ourClientPtr + ", sdkPtr=" + sdkClientPtr);
|
|
265
|
+
promise.resolve(ourClientPtr);
|
|
160
266
|
} catch (Exception e) {
|
|
161
267
|
Log.e(TAG, "clientCreate failed", e);
|
|
162
268
|
promise.reject("CREATE_ERROR", e.getMessage());
|
|
@@ -166,7 +272,7 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
166
272
|
|
|
167
273
|
/**
|
|
168
274
|
* Connect to camera via P2P
|
|
169
|
-
*
|
|
275
|
+
* JNIApi.connect(long clientPtr, int timeout, String serverParam, int connectType)
|
|
170
276
|
*/
|
|
171
277
|
@ReactMethod
|
|
172
278
|
public void clientConnect(int clientPtr, boolean lanScan, String serverParam, int connectType, Promise promise) {
|
|
@@ -180,8 +286,10 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
180
286
|
return;
|
|
181
287
|
}
|
|
182
288
|
|
|
183
|
-
|
|
184
|
-
|
|
289
|
+
if (jniApiClass == null) {
|
|
290
|
+
promise.reject("CONNECT_ERROR", "JNIApi not available");
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
185
293
|
|
|
186
294
|
// Emit connecting state
|
|
187
295
|
WritableMap params = Arguments.createMap();
|
|
@@ -189,88 +297,26 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
189
297
|
params.putInt("state", 1); // CONNECTING
|
|
190
298
|
sendEvent("onConnectionStateChanged", params);
|
|
191
299
|
|
|
192
|
-
// Use provided server param or default
|
|
193
300
|
String param = (serverParam != null && !serverParam.isEmpty())
|
|
194
301
|
? serverParam
|
|
195
302
|
: P2P_SERVER_PARAM;
|
|
196
303
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
if (jniApiClass != null && isNativeLibraryLoaded) {
|
|
202
|
-
try {
|
|
203
|
-
// Try PPCS_Connect method
|
|
204
|
-
Method connectMethod = jniApiClass.getMethod("PPCS_Connect",
|
|
205
|
-
String.class, int.class, int.class);
|
|
206
|
-
|
|
207
|
-
// Parameters: DID, timeout, mode
|
|
208
|
-
Object result = connectMethod.invoke(null, did, 15, connectType);
|
|
209
|
-
int sessionHandle = (Integer) result;
|
|
210
|
-
|
|
211
|
-
Log.d(TAG, "PPCS_Connect result: " + sessionHandle);
|
|
212
|
-
|
|
213
|
-
if (sessionHandle >= 0) {
|
|
214
|
-
clientInfo.sessionHandle = sessionHandle;
|
|
215
|
-
clientInfo.isConnected = true;
|
|
216
|
-
resultState = 3; // ONLINE
|
|
217
|
-
Log.d(TAG, "P2P connection successful! Handle: " + sessionHandle);
|
|
218
|
-
} else {
|
|
219
|
-
errorMessage = "Connection failed with code: " + sessionHandle;
|
|
220
|
-
Log.e(TAG, errorMessage);
|
|
221
|
-
}
|
|
222
|
-
} catch (NoSuchMethodException e) {
|
|
223
|
-
Log.w(TAG, "PPCS_Connect method not found, trying PPCS_ConnectByServer");
|
|
224
|
-
|
|
225
|
-
try {
|
|
226
|
-
// Try alternative method
|
|
227
|
-
Method connectMethod = jniApiClass.getMethod("PPCS_ConnectByServer",
|
|
228
|
-
String.class, byte[].class, int.class, int.class);
|
|
229
|
-
|
|
230
|
-
byte[] serverBytes = param.getBytes();
|
|
231
|
-
Object result = connectMethod.invoke(null, did, serverBytes, 15, connectType);
|
|
232
|
-
int sessionHandle = (Integer) result;
|
|
233
|
-
|
|
234
|
-
Log.d(TAG, "PPCS_ConnectByServer result: " + sessionHandle);
|
|
235
|
-
|
|
236
|
-
if (sessionHandle >= 0) {
|
|
237
|
-
clientInfo.sessionHandle = sessionHandle;
|
|
238
|
-
clientInfo.isConnected = true;
|
|
239
|
-
resultState = 3; // ONLINE
|
|
240
|
-
} else {
|
|
241
|
-
errorMessage = "Connection failed with code: " + sessionHandle;
|
|
242
|
-
}
|
|
243
|
-
} catch (Exception e2) {
|
|
244
|
-
errorMessage = "JNI method call failed: " + e2.getMessage();
|
|
245
|
-
Log.e(TAG, "Full exception: ", e2);
|
|
246
|
-
// List available methods for debugging
|
|
247
|
-
Log.d(TAG, "Available methods in " + jniApiClass.getName() + ":");
|
|
248
|
-
for (java.lang.reflect.Method m : jniApiClass.getDeclaredMethods()) {
|
|
249
|
-
Log.d(TAG, " -> " + m.getName() + "(" + java.util.Arrays.toString(m.getParameterTypes()) + ")");
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
} else {
|
|
254
|
-
// No JNI class available - return error, don't simulate
|
|
255
|
-
errorMessage = "JNI class not found. Native library loaded: " + isNativeLibraryLoaded;
|
|
256
|
-
Log.e(TAG, errorMessage);
|
|
257
|
-
resultState = 4; // CONNECT_FAILED
|
|
258
|
-
}
|
|
304
|
+
// Call JNIApi.connect(sdkClientPtr, timeout, serverParam, connectType)
|
|
305
|
+
// Signature: connect([long, int, class java.lang.String, int])
|
|
306
|
+
Method connectMethod = jniApiClass.getMethod("connect",
|
|
307
|
+
long.class, int.class, String.class, int.class);
|
|
259
308
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if (errorMessage != null) {
|
|
265
|
-
params.putString("error", errorMessage);
|
|
266
|
-
}
|
|
267
|
-
sendEvent("onConnectionStateChanged", params);
|
|
309
|
+
Log.d(TAG, "Calling JNIApi.connect(" + clientInfo.sdkClientPtr + ", 15, " + param + ", " + connectType + ")");
|
|
310
|
+
connectMethod.invoke(null, clientInfo.sdkClientPtr, 15, param, connectType);
|
|
311
|
+
|
|
312
|
+
Log.d(TAG, "JNIApi.connect called - waiting for state callback");
|
|
268
313
|
|
|
269
|
-
|
|
314
|
+
// The actual state will come via the ClientStateListener callback
|
|
315
|
+
// For now, return immediately - the JS side will get updates via events
|
|
316
|
+
promise.resolve(1); // CONNECTING
|
|
270
317
|
} catch (Exception e) {
|
|
271
318
|
Log.e(TAG, "clientConnect failed", e);
|
|
272
319
|
|
|
273
|
-
// Emit connection failed state
|
|
274
320
|
WritableMap params = Arguments.createMap();
|
|
275
321
|
params.putInt("clientId", clientPtr);
|
|
276
322
|
params.putInt("state", 4); // CONNECT_FAILED
|
|
@@ -284,6 +330,7 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
284
330
|
|
|
285
331
|
/**
|
|
286
332
|
* Login to camera
|
|
333
|
+
* JNIApi.login(long clientPtr, String username, String password)
|
|
287
334
|
*/
|
|
288
335
|
@ReactMethod
|
|
289
336
|
public void clientLogin(int clientPtr, String username, String password, Promise promise) {
|
|
@@ -297,22 +344,20 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
297
344
|
return;
|
|
298
345
|
}
|
|
299
346
|
|
|
300
|
-
if (
|
|
301
|
-
promise.reject("LOGIN_ERROR", "
|
|
347
|
+
if (jniApiClass == null) {
|
|
348
|
+
promise.reject("LOGIN_ERROR", "JNIApi not available");
|
|
302
349
|
return;
|
|
303
350
|
}
|
|
304
351
|
|
|
305
|
-
//
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
username, password
|
|
309
|
-
);
|
|
352
|
+
// Call JNIApi.login(sdkClientPtr, username, password)
|
|
353
|
+
Method loginMethod = jniApiClass.getMethod("login",
|
|
354
|
+
long.class, String.class, String.class);
|
|
310
355
|
|
|
311
|
-
Log.d(TAG, "
|
|
356
|
+
Log.d(TAG, "Calling JNIApi.login(" + clientInfo.sdkClientPtr + ", " + username + ", ***)");
|
|
357
|
+
loginMethod.invoke(null, clientInfo.sdkClientPtr, username, password);
|
|
312
358
|
|
|
313
|
-
// For now, simulate login success
|
|
314
|
-
// Real implementation would send CGI via P2P channel
|
|
315
359
|
clientInfo.isLoggedIn = true;
|
|
360
|
+
Log.d(TAG, "JNIApi.login called successfully");
|
|
316
361
|
|
|
317
362
|
promise.resolve(true);
|
|
318
363
|
} catch (Exception e) {
|
|
@@ -324,6 +369,7 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
324
369
|
|
|
325
370
|
/**
|
|
326
371
|
* Send CGI command to camera
|
|
372
|
+
* JNIApi.writeCgi(long clientPtr, String cgi, int timeout)
|
|
327
373
|
*/
|
|
328
374
|
@ReactMethod
|
|
329
375
|
public void clientWriteCgi(int clientPtr, String cgi, int timeout, Promise promise) {
|
|
@@ -337,23 +383,19 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
337
383
|
return;
|
|
338
384
|
}
|
|
339
385
|
|
|
340
|
-
if (
|
|
341
|
-
promise.reject("CGI_ERROR", "
|
|
386
|
+
if (jniApiClass == null) {
|
|
387
|
+
promise.reject("CGI_ERROR", "JNIApi not available");
|
|
342
388
|
return;
|
|
343
389
|
}
|
|
344
390
|
|
|
345
|
-
//
|
|
346
|
-
|
|
391
|
+
// Call JNIApi.writeCgi(sdkClientPtr, cgi, timeout)
|
|
392
|
+
Method writeCgiMethod = jniApiClass.getMethod("writeCgi",
|
|
393
|
+
long.class, String.class, int.class);
|
|
347
394
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
// Emit command result
|
|
351
|
-
WritableMap params = Arguments.createMap();
|
|
352
|
-
params.putInt("clientId", clientPtr);
|
|
353
|
-
params.putInt("command", cgi.hashCode());
|
|
354
|
-
params.putString("data", "OK");
|
|
355
|
-
sendEvent("onCommandReceived", params);
|
|
395
|
+
Log.d(TAG, "Calling JNIApi.writeCgi(" + clientInfo.sdkClientPtr + ", " + cgi + ", " + timeout + ")");
|
|
396
|
+
writeCgiMethod.invoke(null, clientInfo.sdkClientPtr, cgi, timeout);
|
|
356
397
|
|
|
398
|
+
Log.d(TAG, "JNIApi.writeCgi called successfully");
|
|
357
399
|
promise.resolve(true);
|
|
358
400
|
} catch (Exception e) {
|
|
359
401
|
Log.e(TAG, "clientWriteCgi failed", e);
|
|
@@ -367,24 +409,8 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
367
409
|
*/
|
|
368
410
|
@ReactMethod
|
|
369
411
|
public void scanWifi(int clientPtr, Promise promise) {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
Log.d(TAG, "scanWifi called");
|
|
373
|
-
|
|
374
|
-
String scanCgi = "wifi_scan.cgi?user=admin&pwd=888888";
|
|
375
|
-
|
|
376
|
-
Thread.sleep(1000);
|
|
377
|
-
|
|
378
|
-
WritableMap result = Arguments.createMap();
|
|
379
|
-
result.putBoolean("success", true);
|
|
380
|
-
result.putString("networks", "[]");
|
|
381
|
-
|
|
382
|
-
promise.resolve(result);
|
|
383
|
-
} catch (Exception e) {
|
|
384
|
-
Log.e(TAG, "scanWifi failed", e);
|
|
385
|
-
promise.reject("WIFI_ERROR", e.getMessage());
|
|
386
|
-
}
|
|
387
|
-
});
|
|
412
|
+
// Use writeCgi to send wifi_scan command
|
|
413
|
+
clientWriteCgi(clientPtr, "wifi_scan.cgi?user=admin&pwd=888888", 10, promise);
|
|
388
414
|
}
|
|
389
415
|
|
|
390
416
|
/**
|
|
@@ -392,58 +418,36 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
392
418
|
*/
|
|
393
419
|
@ReactMethod
|
|
394
420
|
public void configureWifi(int clientPtr, String ssid, String password, int authType, Promise promise) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
"set_wifi.cgi?ssid=%s&key=%s&authtype=%d&enc=0&mode=0&wifienable=1",
|
|
401
|
-
ssid, password, authType
|
|
402
|
-
);
|
|
403
|
-
|
|
404
|
-
Log.d(TAG, "Would send WiFi config: " + wifiCgi);
|
|
405
|
-
|
|
406
|
-
Thread.sleep(500);
|
|
407
|
-
|
|
408
|
-
promise.resolve(true);
|
|
409
|
-
} catch (Exception e) {
|
|
410
|
-
Log.e(TAG, "configureWifi failed", e);
|
|
411
|
-
promise.reject("WIFI_ERROR", e.getMessage());
|
|
412
|
-
}
|
|
413
|
-
});
|
|
421
|
+
String wifiCgi = String.format(
|
|
422
|
+
"set_wifi.cgi?ssid=%s&key=%s&authtype=%d&enc=0&mode=0&wifienable=1",
|
|
423
|
+
ssid, password, authType
|
|
424
|
+
);
|
|
425
|
+
clientWriteCgi(clientPtr, wifiCgi, 10, promise);
|
|
414
426
|
}
|
|
415
427
|
|
|
416
428
|
/**
|
|
417
429
|
* Disconnect from camera
|
|
430
|
+
* JNIApi.disconnect(long clientPtr)
|
|
418
431
|
*/
|
|
419
432
|
@ReactMethod
|
|
420
433
|
public void clientDisconnect(int clientPtr, Promise promise) {
|
|
421
434
|
executor.execute(() -> {
|
|
422
435
|
try {
|
|
423
|
-
Log.d(TAG, "clientDisconnect called");
|
|
436
|
+
Log.d(TAG, "clientDisconnect called for: " + clientPtr);
|
|
424
437
|
|
|
425
438
|
ClientInfo clientInfo = clients.get(clientPtr);
|
|
426
|
-
if (clientInfo != null) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
try {
|
|
430
|
-
Method closeMethod = jniApiClass.getMethod("PPCS_Close", int.class);
|
|
431
|
-
closeMethod.invoke(null, clientInfo.sessionHandle);
|
|
432
|
-
Log.d(TAG, "PPCS_Close called for session: " + clientInfo.sessionHandle);
|
|
433
|
-
} catch (Exception e) {
|
|
434
|
-
Log.w(TAG, "PPCS_Close failed: " + e.getMessage());
|
|
435
|
-
}
|
|
436
|
-
}
|
|
439
|
+
if (clientInfo != null && jniApiClass != null) {
|
|
440
|
+
Method disconnectMethod = jniApiClass.getMethod("disconnect", long.class);
|
|
441
|
+
disconnectMethod.invoke(null, clientInfo.sdkClientPtr);
|
|
437
442
|
|
|
438
443
|
clientInfo.isConnected = false;
|
|
439
444
|
clientInfo.isLoggedIn = false;
|
|
440
|
-
|
|
445
|
+
Log.d(TAG, "JNIApi.disconnect called successfully");
|
|
441
446
|
}
|
|
442
447
|
|
|
443
|
-
// Emit disconnect state
|
|
444
448
|
WritableMap params = Arguments.createMap();
|
|
445
449
|
params.putInt("clientId", clientPtr);
|
|
446
|
-
params.putInt("state", 5); //
|
|
450
|
+
params.putInt("state", 5); // DISCONNECTED
|
|
447
451
|
sendEvent("onConnectionStateChanged", params);
|
|
448
452
|
|
|
449
453
|
promise.resolve(true);
|
|
@@ -456,12 +460,21 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
456
460
|
|
|
457
461
|
/**
|
|
458
462
|
* Destroy client and cleanup resources
|
|
463
|
+
* JNIApi.destroy(long clientPtr)
|
|
459
464
|
*/
|
|
460
465
|
@ReactMethod
|
|
461
466
|
public void clientDestroy(int clientPtr, Promise promise) {
|
|
462
467
|
executor.execute(() -> {
|
|
463
468
|
try {
|
|
464
|
-
Log.d(TAG, "clientDestroy called");
|
|
469
|
+
Log.d(TAG, "clientDestroy called for: " + clientPtr);
|
|
470
|
+
|
|
471
|
+
ClientInfo clientInfo = clients.get(clientPtr);
|
|
472
|
+
if (clientInfo != null && jniApiClass != null) {
|
|
473
|
+
Method destroyMethod = jniApiClass.getMethod("destroy", long.class);
|
|
474
|
+
destroyMethod.invoke(null, clientInfo.sdkClientPtr);
|
|
475
|
+
Log.d(TAG, "JNIApi.destroy called successfully");
|
|
476
|
+
}
|
|
477
|
+
|
|
465
478
|
clients.remove(clientPtr);
|
|
466
479
|
promise.resolve(true);
|
|
467
480
|
} catch (Exception e) {
|
|
@@ -476,15 +489,9 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
476
489
|
*/
|
|
477
490
|
@ReactMethod
|
|
478
491
|
public void startVideoStream(int clientPtr, int streamType, Promise promise) {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
promise.resolve(true);
|
|
483
|
-
} catch (Exception e) {
|
|
484
|
-
Log.e(TAG, "startVideoStream failed", e);
|
|
485
|
-
promise.reject("VIDEO_ERROR", e.getMessage());
|
|
486
|
-
}
|
|
487
|
-
});
|
|
492
|
+
// TODO: Implement video streaming
|
|
493
|
+
Log.d(TAG, "startVideoStream called - not yet implemented");
|
|
494
|
+
promise.resolve(true);
|
|
488
495
|
}
|
|
489
496
|
|
|
490
497
|
/**
|
|
@@ -492,27 +499,35 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
492
499
|
*/
|
|
493
500
|
@ReactMethod
|
|
494
501
|
public void stopVideoStream(int clientPtr, Promise promise) {
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
promise.resolve(true);
|
|
498
|
-
} catch (Exception e) {
|
|
499
|
-
Log.e(TAG, "stopVideoStream failed", e);
|
|
500
|
-
promise.reject("VIDEO_ERROR", e.getMessage());
|
|
501
|
-
}
|
|
502
|
+
Log.d(TAG, "stopVideoStream called");
|
|
503
|
+
promise.resolve(true);
|
|
502
504
|
}
|
|
503
505
|
|
|
504
506
|
/**
|
|
505
507
|
* Check connection mode
|
|
508
|
+
* JNIApi.checkMode(long clientPtr)
|
|
506
509
|
*/
|
|
507
510
|
@ReactMethod
|
|
508
511
|
public void clientCheckMode(int clientPtr, Promise promise) {
|
|
509
512
|
try {
|
|
510
513
|
ClientInfo clientInfo = clients.get(clientPtr);
|
|
511
514
|
|
|
515
|
+
int mode = 0;
|
|
516
|
+
if (clientInfo != null && jniApiClass != null && clientInfo.sdkClientPtr > 0) {
|
|
517
|
+
try {
|
|
518
|
+
Method checkModeMethod = jniApiClass.getMethod("checkMode", long.class);
|
|
519
|
+
Object result = checkModeMethod.invoke(null, clientInfo.sdkClientPtr);
|
|
520
|
+
mode = (Integer) result;
|
|
521
|
+
Log.d(TAG, "JNIApi.checkMode result: " + mode);
|
|
522
|
+
} catch (Exception e) {
|
|
523
|
+
Log.e(TAG, "checkMode failed", e);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
512
527
|
WritableMap result = Arguments.createMap();
|
|
513
528
|
result.putBoolean("success", clientInfo != null && clientInfo.isConnected);
|
|
514
|
-
result.putInt("mode",
|
|
515
|
-
result.
|
|
529
|
+
result.putInt("mode", mode);
|
|
530
|
+
result.putDouble("sessionHandle", clientInfo != null ? clientInfo.sdkClientPtr : -1);
|
|
516
531
|
promise.resolve(result);
|
|
517
532
|
} catch (Exception e) {
|
|
518
533
|
Log.e(TAG, "clientCheckMode failed", e);
|
|
@@ -534,7 +549,7 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
534
549
|
@ReactMethod
|
|
535
550
|
public void getSdkVersion(Promise promise) {
|
|
536
551
|
WritableMap result = Arguments.createMap();
|
|
537
|
-
result.putString("version", "1.0.
|
|
552
|
+
result.putString("version", "1.0.10");
|
|
538
553
|
result.putBoolean("nativeLoaded", isNativeLibraryLoaded);
|
|
539
554
|
result.putString("nativeLib", "OKSMARTPPCS");
|
|
540
555
|
result.putBoolean("p2pInitialized", isP2PInitialized);
|