@bits-innovate/react-native-vstarcam 1.0.8 → 1.0.9
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,33 @@ 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
|
+
if (sdkClientPtr <= 0) {
|
|
251
|
+
promise.reject("CREATE_ERROR", "Failed to create client, result: " + sdkClientPtr);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Generate our own client ID (hash of deviceId) and store mapping
|
|
256
|
+
int ourClientPtr = Math.abs(deviceId.hashCode());
|
|
153
257
|
|
|
154
258
|
ClientInfo clientInfo = new ClientInfo();
|
|
155
259
|
clientInfo.deviceId = deviceId;
|
|
156
|
-
|
|
260
|
+
clientInfo.sdkClientPtr = sdkClientPtr;
|
|
261
|
+
clients.put(ourClientPtr, clientInfo);
|
|
157
262
|
|
|
158
|
-
Log.d(TAG, "Created client
|
|
159
|
-
promise.resolve(
|
|
263
|
+
Log.d(TAG, "Created client: ourPtr=" + ourClientPtr + ", sdkPtr=" + sdkClientPtr);
|
|
264
|
+
promise.resolve(ourClientPtr);
|
|
160
265
|
} catch (Exception e) {
|
|
161
266
|
Log.e(TAG, "clientCreate failed", e);
|
|
162
267
|
promise.reject("CREATE_ERROR", e.getMessage());
|
|
@@ -166,7 +271,7 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
166
271
|
|
|
167
272
|
/**
|
|
168
273
|
* Connect to camera via P2P
|
|
169
|
-
*
|
|
274
|
+
* JNIApi.connect(long clientPtr, int timeout, String serverParam, int connectType)
|
|
170
275
|
*/
|
|
171
276
|
@ReactMethod
|
|
172
277
|
public void clientConnect(int clientPtr, boolean lanScan, String serverParam, int connectType, Promise promise) {
|
|
@@ -180,8 +285,10 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
180
285
|
return;
|
|
181
286
|
}
|
|
182
287
|
|
|
183
|
-
|
|
184
|
-
|
|
288
|
+
if (jniApiClass == null) {
|
|
289
|
+
promise.reject("CONNECT_ERROR", "JNIApi not available");
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
185
292
|
|
|
186
293
|
// Emit connecting state
|
|
187
294
|
WritableMap params = Arguments.createMap();
|
|
@@ -189,88 +296,26 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
189
296
|
params.putInt("state", 1); // CONNECTING
|
|
190
297
|
sendEvent("onConnectionStateChanged", params);
|
|
191
298
|
|
|
192
|
-
// Use provided server param or default
|
|
193
299
|
String param = (serverParam != null && !serverParam.isEmpty())
|
|
194
300
|
? serverParam
|
|
195
301
|
: P2P_SERVER_PARAM;
|
|
196
302
|
|
|
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
|
-
}
|
|
303
|
+
// Call JNIApi.connect(sdkClientPtr, timeout, serverParam, connectType)
|
|
304
|
+
// Signature: connect([long, int, class java.lang.String, int])
|
|
305
|
+
Method connectMethod = jniApiClass.getMethod("connect",
|
|
306
|
+
long.class, int.class, String.class, int.class);
|
|
259
307
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if (errorMessage != null) {
|
|
265
|
-
params.putString("error", errorMessage);
|
|
266
|
-
}
|
|
267
|
-
sendEvent("onConnectionStateChanged", params);
|
|
308
|
+
Log.d(TAG, "Calling JNIApi.connect(" + clientInfo.sdkClientPtr + ", 15, " + param + ", " + connectType + ")");
|
|
309
|
+
connectMethod.invoke(null, clientInfo.sdkClientPtr, 15, param, connectType);
|
|
310
|
+
|
|
311
|
+
Log.d(TAG, "JNIApi.connect called - waiting for state callback");
|
|
268
312
|
|
|
269
|
-
|
|
313
|
+
// The actual state will come via the ClientStateListener callback
|
|
314
|
+
// For now, return immediately - the JS side will get updates via events
|
|
315
|
+
promise.resolve(1); // CONNECTING
|
|
270
316
|
} catch (Exception e) {
|
|
271
317
|
Log.e(TAG, "clientConnect failed", e);
|
|
272
318
|
|
|
273
|
-
// Emit connection failed state
|
|
274
319
|
WritableMap params = Arguments.createMap();
|
|
275
320
|
params.putInt("clientId", clientPtr);
|
|
276
321
|
params.putInt("state", 4); // CONNECT_FAILED
|
|
@@ -284,6 +329,7 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
284
329
|
|
|
285
330
|
/**
|
|
286
331
|
* Login to camera
|
|
332
|
+
* JNIApi.login(long clientPtr, String username, String password)
|
|
287
333
|
*/
|
|
288
334
|
@ReactMethod
|
|
289
335
|
public void clientLogin(int clientPtr, String username, String password, Promise promise) {
|
|
@@ -297,22 +343,20 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
297
343
|
return;
|
|
298
344
|
}
|
|
299
345
|
|
|
300
|
-
if (
|
|
301
|
-
promise.reject("LOGIN_ERROR", "
|
|
346
|
+
if (jniApiClass == null) {
|
|
347
|
+
promise.reject("LOGIN_ERROR", "JNIApi not available");
|
|
302
348
|
return;
|
|
303
349
|
}
|
|
304
350
|
|
|
305
|
-
//
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
username, password
|
|
309
|
-
);
|
|
351
|
+
// Call JNIApi.login(sdkClientPtr, username, password)
|
|
352
|
+
Method loginMethod = jniApiClass.getMethod("login",
|
|
353
|
+
long.class, String.class, String.class);
|
|
310
354
|
|
|
311
|
-
Log.d(TAG, "
|
|
355
|
+
Log.d(TAG, "Calling JNIApi.login(" + clientInfo.sdkClientPtr + ", " + username + ", ***)");
|
|
356
|
+
loginMethod.invoke(null, clientInfo.sdkClientPtr, username, password);
|
|
312
357
|
|
|
313
|
-
// For now, simulate login success
|
|
314
|
-
// Real implementation would send CGI via P2P channel
|
|
315
358
|
clientInfo.isLoggedIn = true;
|
|
359
|
+
Log.d(TAG, "JNIApi.login called successfully");
|
|
316
360
|
|
|
317
361
|
promise.resolve(true);
|
|
318
362
|
} catch (Exception e) {
|
|
@@ -324,6 +368,7 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
324
368
|
|
|
325
369
|
/**
|
|
326
370
|
* Send CGI command to camera
|
|
371
|
+
* JNIApi.writeCgi(long clientPtr, String cgi, int timeout)
|
|
327
372
|
*/
|
|
328
373
|
@ReactMethod
|
|
329
374
|
public void clientWriteCgi(int clientPtr, String cgi, int timeout, Promise promise) {
|
|
@@ -337,23 +382,19 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
337
382
|
return;
|
|
338
383
|
}
|
|
339
384
|
|
|
340
|
-
if (
|
|
341
|
-
promise.reject("CGI_ERROR", "
|
|
385
|
+
if (jniApiClass == null) {
|
|
386
|
+
promise.reject("CGI_ERROR", "JNIApi not available");
|
|
342
387
|
return;
|
|
343
388
|
}
|
|
344
389
|
|
|
345
|
-
//
|
|
346
|
-
|
|
390
|
+
// Call JNIApi.writeCgi(sdkClientPtr, cgi, timeout)
|
|
391
|
+
Method writeCgiMethod = jniApiClass.getMethod("writeCgi",
|
|
392
|
+
long.class, String.class, int.class);
|
|
347
393
|
|
|
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);
|
|
394
|
+
Log.d(TAG, "Calling JNIApi.writeCgi(" + clientInfo.sdkClientPtr + ", " + cgi + ", " + timeout + ")");
|
|
395
|
+
writeCgiMethod.invoke(null, clientInfo.sdkClientPtr, cgi, timeout);
|
|
356
396
|
|
|
397
|
+
Log.d(TAG, "JNIApi.writeCgi called successfully");
|
|
357
398
|
promise.resolve(true);
|
|
358
399
|
} catch (Exception e) {
|
|
359
400
|
Log.e(TAG, "clientWriteCgi failed", e);
|
|
@@ -367,24 +408,8 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
367
408
|
*/
|
|
368
409
|
@ReactMethod
|
|
369
410
|
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
|
-
});
|
|
411
|
+
// Use writeCgi to send wifi_scan command
|
|
412
|
+
clientWriteCgi(clientPtr, "wifi_scan.cgi?user=admin&pwd=888888", 10, promise);
|
|
388
413
|
}
|
|
389
414
|
|
|
390
415
|
/**
|
|
@@ -392,58 +417,36 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
392
417
|
*/
|
|
393
418
|
@ReactMethod
|
|
394
419
|
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
|
-
});
|
|
420
|
+
String wifiCgi = String.format(
|
|
421
|
+
"set_wifi.cgi?ssid=%s&key=%s&authtype=%d&enc=0&mode=0&wifienable=1",
|
|
422
|
+
ssid, password, authType
|
|
423
|
+
);
|
|
424
|
+
clientWriteCgi(clientPtr, wifiCgi, 10, promise);
|
|
414
425
|
}
|
|
415
426
|
|
|
416
427
|
/**
|
|
417
428
|
* Disconnect from camera
|
|
429
|
+
* JNIApi.disconnect(long clientPtr)
|
|
418
430
|
*/
|
|
419
431
|
@ReactMethod
|
|
420
432
|
public void clientDisconnect(int clientPtr, Promise promise) {
|
|
421
433
|
executor.execute(() -> {
|
|
422
434
|
try {
|
|
423
|
-
Log.d(TAG, "clientDisconnect called");
|
|
435
|
+
Log.d(TAG, "clientDisconnect called for: " + clientPtr);
|
|
424
436
|
|
|
425
437
|
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
|
-
}
|
|
438
|
+
if (clientInfo != null && jniApiClass != null) {
|
|
439
|
+
Method disconnectMethod = jniApiClass.getMethod("disconnect", long.class);
|
|
440
|
+
disconnectMethod.invoke(null, clientInfo.sdkClientPtr);
|
|
437
441
|
|
|
438
442
|
clientInfo.isConnected = false;
|
|
439
443
|
clientInfo.isLoggedIn = false;
|
|
440
|
-
|
|
444
|
+
Log.d(TAG, "JNIApi.disconnect called successfully");
|
|
441
445
|
}
|
|
442
446
|
|
|
443
|
-
// Emit disconnect state
|
|
444
447
|
WritableMap params = Arguments.createMap();
|
|
445
448
|
params.putInt("clientId", clientPtr);
|
|
446
|
-
params.putInt("state", 5); //
|
|
449
|
+
params.putInt("state", 5); // DISCONNECTED
|
|
447
450
|
sendEvent("onConnectionStateChanged", params);
|
|
448
451
|
|
|
449
452
|
promise.resolve(true);
|
|
@@ -456,12 +459,21 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
456
459
|
|
|
457
460
|
/**
|
|
458
461
|
* Destroy client and cleanup resources
|
|
462
|
+
* JNIApi.destroy(long clientPtr)
|
|
459
463
|
*/
|
|
460
464
|
@ReactMethod
|
|
461
465
|
public void clientDestroy(int clientPtr, Promise promise) {
|
|
462
466
|
executor.execute(() -> {
|
|
463
467
|
try {
|
|
464
|
-
Log.d(TAG, "clientDestroy called");
|
|
468
|
+
Log.d(TAG, "clientDestroy called for: " + clientPtr);
|
|
469
|
+
|
|
470
|
+
ClientInfo clientInfo = clients.get(clientPtr);
|
|
471
|
+
if (clientInfo != null && jniApiClass != null) {
|
|
472
|
+
Method destroyMethod = jniApiClass.getMethod("destroy", long.class);
|
|
473
|
+
destroyMethod.invoke(null, clientInfo.sdkClientPtr);
|
|
474
|
+
Log.d(TAG, "JNIApi.destroy called successfully");
|
|
475
|
+
}
|
|
476
|
+
|
|
465
477
|
clients.remove(clientPtr);
|
|
466
478
|
promise.resolve(true);
|
|
467
479
|
} catch (Exception e) {
|
|
@@ -476,15 +488,9 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
476
488
|
*/
|
|
477
489
|
@ReactMethod
|
|
478
490
|
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
|
-
});
|
|
491
|
+
// TODO: Implement video streaming
|
|
492
|
+
Log.d(TAG, "startVideoStream called - not yet implemented");
|
|
493
|
+
promise.resolve(true);
|
|
488
494
|
}
|
|
489
495
|
|
|
490
496
|
/**
|
|
@@ -492,27 +498,35 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
492
498
|
*/
|
|
493
499
|
@ReactMethod
|
|
494
500
|
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
|
-
}
|
|
501
|
+
Log.d(TAG, "stopVideoStream called");
|
|
502
|
+
promise.resolve(true);
|
|
502
503
|
}
|
|
503
504
|
|
|
504
505
|
/**
|
|
505
506
|
* Check connection mode
|
|
507
|
+
* JNIApi.checkMode(long clientPtr)
|
|
506
508
|
*/
|
|
507
509
|
@ReactMethod
|
|
508
510
|
public void clientCheckMode(int clientPtr, Promise promise) {
|
|
509
511
|
try {
|
|
510
512
|
ClientInfo clientInfo = clients.get(clientPtr);
|
|
511
513
|
|
|
514
|
+
int mode = 0;
|
|
515
|
+
if (clientInfo != null && jniApiClass != null && clientInfo.sdkClientPtr > 0) {
|
|
516
|
+
try {
|
|
517
|
+
Method checkModeMethod = jniApiClass.getMethod("checkMode", long.class);
|
|
518
|
+
Object result = checkModeMethod.invoke(null, clientInfo.sdkClientPtr);
|
|
519
|
+
mode = (Integer) result;
|
|
520
|
+
Log.d(TAG, "JNIApi.checkMode result: " + mode);
|
|
521
|
+
} catch (Exception e) {
|
|
522
|
+
Log.e(TAG, "checkMode failed", e);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
512
526
|
WritableMap result = Arguments.createMap();
|
|
513
527
|
result.putBoolean("success", clientInfo != null && clientInfo.isConnected);
|
|
514
|
-
result.putInt("mode",
|
|
515
|
-
result.
|
|
528
|
+
result.putInt("mode", mode);
|
|
529
|
+
result.putDouble("sessionHandle", clientInfo != null ? clientInfo.sdkClientPtr : -1);
|
|
516
530
|
promise.resolve(result);
|
|
517
531
|
} catch (Exception e) {
|
|
518
532
|
Log.e(TAG, "clientCheckMode failed", e);
|
|
@@ -534,7 +548,7 @@ public class VStarCamModule extends ReactContextBaseJavaModule {
|
|
|
534
548
|
@ReactMethod
|
|
535
549
|
public void getSdkVersion(Promise promise) {
|
|
536
550
|
WritableMap result = Arguments.createMap();
|
|
537
|
-
result.putString("version", "1.0.
|
|
551
|
+
result.putString("version", "1.0.9");
|
|
538
552
|
result.putBoolean("nativeLoaded", isNativeLibraryLoaded);
|
|
539
553
|
result.putString("nativeLib", "OKSMARTPPCS");
|
|
540
554
|
result.putBoolean("p2pInitialized", isP2PInitialized);
|