@voipsdk/react-native-voipcloud 0.2.1 → 1.0.0

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.
Files changed (41) hide show
  1. package/README.md +181 -117
  2. package/android/build.gradle +7 -7
  3. package/android/src/main/java/com/voipcloud/sdk/rn/VoipCloudModule.java +148 -204
  4. package/android/src/main/java/com/voipcloud/sdk/rn/internal/BridgeGuard.java +74 -0
  5. package/android/src/main/java/com/voipcloud/sdk/rn/internal/Events.java +7 -2
  6. package/android/src/main/libs/voipcloud-release.aar +0 -0
  7. package/ios/VoipCloud.mm +8 -8
  8. package/lib/commonjs/VoipCloud.js +29 -47
  9. package/lib/commonjs/VoipCloud.js.map +1 -1
  10. package/lib/commonjs/events.js +13 -7
  11. package/lib/commonjs/events.js.map +1 -1
  12. package/lib/commonjs/index.js +2 -3
  13. package/lib/commonjs/index.js.map +1 -1
  14. package/lib/commonjs/nativeModule.js +18 -0
  15. package/lib/commonjs/nativeModule.js.map +1 -0
  16. package/lib/module/VoipCloud.js +30 -47
  17. package/lib/module/VoipCloud.js.map +1 -1
  18. package/lib/module/events.js +9 -8
  19. package/lib/module/events.js.map +1 -1
  20. package/lib/module/index.js +1 -2
  21. package/lib/module/index.js.map +1 -1
  22. package/lib/module/nativeModule.js +13 -0
  23. package/lib/module/nativeModule.js.map +1 -0
  24. package/lib/typescript/VoipCloud.d.ts +5 -30
  25. package/lib/typescript/events.d.ts +6 -2
  26. package/lib/typescript/index.d.ts +2 -3
  27. package/lib/typescript/nativeModule.d.ts +7 -0
  28. package/lib/typescript/types.d.ts +1 -17
  29. package/package.json +5 -4
  30. package/react-native-voipcloud.podspec +7 -5
  31. package/src/VoipCloud.ts +37 -48
  32. package/src/events.ts +9 -8
  33. package/src/index.ts +1 -3
  34. package/src/nativeModule.ts +17 -0
  35. package/src/types.ts +1 -18
  36. package/lib/commonjs/License.js +0 -51
  37. package/lib/commonjs/License.js.map +0 -1
  38. package/lib/module/License.js +0 -45
  39. package/lib/module/License.js.map +0 -1
  40. package/lib/typescript/License.d.ts +0 -31
  41. package/src/License.ts +0 -52
package/README.md CHANGED
@@ -1,25 +1,45 @@
1
- # react-native-voipcloud
1
+ # @voipsdk/react-native-voipcloud
2
2
 
3
- > Platform: Android (RN 0.70+, Android 12+).
3
+ > Public PJSIP VoIP SDK for React Native — Android only (RN 0.70+, Android 12 / API 31+).
4
+ > Package: `@voipsdk/react-native-voipcloud@1.0.0`
5
+
6
+ ---
7
+
8
+ ## Requirements
9
+
10
+ | | |
11
+ |---|---|
12
+ | React Native | ≥ 0.70 |
13
+ | Android | API 31+ (Android 12+) |
14
+ | ABIs | `arm64-v8a`, `armeabi-v7a`, `x86_64` (emulator) |
15
+ | iOS | Stub only — rejects with `VC_NOT_IMPLEMENTED` |
4
16
 
5
17
  ---
6
18
 
7
19
  ## Install
8
20
 
9
21
  ```bash
10
- npm install react-native-voipcloud
22
+ npm install @voipsdk/react-native-voipcloud
11
23
  # or:
12
- yarn add react-native-voipcloud
24
+ yarn add @voipsdk/react-native-voipcloud
13
25
  ```
14
26
 
15
- Android autolinks the `VoipCloudPackage` if you are on React Native 0.60+.
27
+ Rebuild the native app after install:
28
+
29
+ ```bash
30
+ cd android && ./gradlew clean assembleDebug
31
+ ```
32
+
33
+ React Native 0.60+ autolinks `VoipCloudPackage`. For older RN, add manually in `MainApplication.java`:
16
34
 
17
- For older RN versions, add manually to `MainApplication.java`:
18
35
  ```java
19
36
  packages.add(new com.voipcloud.sdk.rn.VoipCloudPackage());
20
37
  ```
21
38
 
22
- Required `AndroidManifest.xml` permissions (declare in **your** app):
39
+ ### Android permissions
40
+
41
+ Declare in **your** app `AndroidManifest.xml`:
42
+
23
43
  ```xml
24
44
  <uses-permission android:name="android.permission.INTERNET" />
25
45
  <uses-permission android:name="android.permission.RECORD_AUDIO" />
@@ -29,144 +49,188 @@ Required `AndroidManifest.xml` permissions (declare in **your** app):
29
49
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" />
30
50
  ```
31
51
 
32
- Runtime permissions to request:
33
- `RECORD_AUDIO`, `POST_NOTIFICATIONS` (Android 13+), `BLUETOOTH_CONNECT`.
52
+ Request at runtime: `RECORD_AUDIO`, `POST_NOTIFICATIONS` (Android 13+), `BLUETOOTH_CONNECT`.
34
53
 
35
54
  ---
36
55
 
37
56
  ## Quick start
38
57
 
39
58
  ```ts
40
- import { VoipCloud } from 'react-native-voipcloud';
41
-
42
- // 1. Apply the license your operator issued.
43
- try {
44
- await VoipCloud.License.set(myToken);
45
- } catch (e) {
46
- // VC_LICENSE — token format / signature / expiry / bundle issues.
47
- }
48
-
49
- // 2. Start the engine.
50
- await VoipCloud.init({ userAgent: 'acme-voip/1.0' });
51
-
52
- // 3. Register a SIP account.
53
- const accId = await VoipCloud.register({
54
- uri: 'sip:alice@example.com',
55
- registrar: 'sip:example.com:5061;transport=tls',
56
- username: 'alice',
57
- password: '••••••',
58
- transport: 'TLS',
59
+ import { VoipCloud } from '@voipsdk/react-native-voipcloud';
60
+
61
+ // 1. Start PJSIP endpoint (required before any SIP call).
62
+ await VoipCloud.init({ userAgent: 'my-app/1.0' });
63
+
64
+ // 2. Register a SIP account → returns numeric accountId.
65
+ const accountId = await VoipCloud.register({
66
+ uri: 'sip:alice@example.com',
67
+ registrar: 'sip:pbx.example.com:5061;transport=tls',
68
+ username: 'alice',
69
+ password: 'secret',
70
+ transport: 'TLS', // 'UDP' | 'TCP' | 'TLS'
59
71
  });
60
72
 
61
- // 4. Make a call.
62
- const callId = await VoipCloud.makeCall(accId, 'sip:bob@example.com');
73
+ // 3. Place or receive calls.
74
+ const callId = await VoipCloud.makeCall(accountId, 'sip:bob@example.com');
75
+ await VoipCloud.answer(callId); // incoming
76
+ await VoipCloud.hangup(callId);
63
77
 
64
- // 5. In-call controls.
65
- await VoipCloud.hold(callId); // put on hold
66
- await VoipCloud.unhold(callId); // resume
67
- await VoipCloud.mute(callId, true); // mute mic
68
- await VoipCloud.sendDtmf(callId, '1234#'); // send DTMF
69
- await VoipCloud.transferCall(callId, 'sip:charlie@example.com'); // blind transfer
70
- await VoipCloud.hangup(callId); // end this call
71
- await VoipCloud.hangupAllCalls(); // end every active call
78
+ // 4. In-call controls.
79
+ await VoipCloud.hold(callId);
80
+ await VoipCloud.unhold(callId);
81
+ await VoipCloud.mute(callId, true);
82
+ await VoipCloud.sendDtmf(callId, '1234#');
83
+ await VoipCloud.transferCall(callId, 'sip:charlie@example.com');
84
+ await VoipCloud.hangupAllCalls();
72
85
 
73
- // 6. Subscribe to events.
86
+ // 5. Events (always remove in useEffect cleanup).
74
87
  const sub = VoipCloud.on('callState', ({ callId, state }) => {
75
- console.log('call', callId, '→', state);
76
- });
77
- const subMedia = VoipCloud.on('callMediaState', ({ callId, hasAudio, isHold, isMuted }) => {
78
- console.log('media', callId, { hasAudio, isHold, isMuted });
88
+ console.log('call', callId, state);
79
89
  });
80
- // sub.remove() / subMedia.remove() when done
81
-
82
- // 7. License refresh is automatic.
83
- // If your token's payload includes a `ref` field, the SDK starts a
84
- // 24 h refresher in the background after `License.set` succeeds.
85
- // No URL configuration needed on the app side.
86
- //
87
- // Optional: stop the refresher when the user logs out.
88
- await VoipCloud.License.stopRefresh();
90
+ sub.remove();
89
91
 
90
- // 8. Tear down the SDK on app exit.
92
+ // 6. Unregister and tear down.
93
+ await VoipCloud.unregister(accountId);
91
94
  await VoipCloud.shutdown();
92
95
  ```
93
96
 
97
+ ### React example
98
+
99
+ ```tsx
100
+ import { useEffect } from 'react';
101
+ import { VoipCloud } from '@voipsdk/react-native-voipcloud';
102
+
103
+ export function useVoipEvents() {
104
+ useEffect(() => {
105
+ const subs = [
106
+ VoipCloud.on('registrationState', e =>
107
+ console.log('reg', e.accountId, e.code, e.reason)),
108
+ VoipCloud.on('incomingCall', e =>
109
+ console.log('incoming', e.callId, e.from)),
110
+ VoipCloud.on('callState', e =>
111
+ console.log('call', e.callId, e.state)),
112
+ ];
113
+ return () => subs.forEach(s => s.remove());
114
+ }, []);
115
+ }
116
+ ```
117
+
94
118
  ---
95
119
 
96
- ## Error codes (Promise rejection.code)
97
-
98
- Mọi method trả Promise; khi reject, `code` mang một trong các mã sau.
99
- Cụ thể lỗi license được tách thành các mã granular để app dễ hiển thị
100
- thông báo phù hợp.
101
-
102
- License (từ `License.set` / `License.status`):
103
-
104
- | code | Ý nghĩa |
105
- |-----------------------|------------------------------------------------------|
106
- | `VC_NO_LICENSE` | Chưa cài token, hoặc token đã bị reset |
107
- | `VC_BAD_FORMAT` | Token sai định dạng (không phải base64url JWT) |
108
- | `VC_BAD_SIGNATURE` | Chữ ký Ed25519 không hợp lệ |
109
- | `VC_EXPIRED` | Token hết hạn |
110
- | `VC_NOT_ACTIVE` | Token bị tạm khoá (status ≠ active) |
111
- | `VC_REVOKED` | Token đã bị thu hồi |
112
- | `VC_BUNDLE_MISMATCH` | Bundle id app không khớp `bundle_id` trong token |
113
- | `VC_PAYLOAD_TOO_BIG` | Payload token quá lớn |
114
- | `VC_CLOCK_SKEW` | Đồng hồ thiết bị bị chỉnh lùi so với mốc server |
115
- | `VC_LICENSE` | Lỗi license chung không khớp các mã trên |
116
- | `VC_STATUS` | Đọc trạng thái thất bại |
117
-
118
- Endpoint / call:
119
-
120
- | code | Ý nghĩa |
121
- |-----------------------|------------------------------------------------------|
122
- | `VC_INIT` | Endpoint không khởi động được |
123
- | `VC_SHUTDOWN` | Lỗi khi `shutdown()` dọn endpoint |
124
- | `VC_REGISTER` | `register()` thất bại |
125
- | `VC_UNREGISTER` | `unregister()` thất bại |
126
- | `VC_NO_ACCOUNT` | accountId không tồn tại |
127
- | `VC_MAKE_CALL` | `makeCall()` thất bại (bao gồm `VC_CCU_EXCEEDED`) |
128
- | `VC_CCU_EXCEEDED` | Vượt số cuộc gọi đồng thời license cho phép |
129
- | `VC_NO_CALL` | callId không tồn tại |
130
- | `VC_ANSWER` | `answer()` thất bại |
131
- | `VC_HANGUP` | `hangup()` thất bại |
132
- | `VC_HOLD` / `VC_UNHOLD` | `hold()` / `unhold()` thất bại |
133
- | `VC_MUTE` | `mute()` thất bại (vd: chưa init endpoint) |
134
- | `VC_DTMF` | `sendDtmf()` thất bại |
135
- | `VC_TRANSFER` | `transferCall()` thất bại |
136
- | `VC_HANGUP_ALL` | `hangupAllCalls()` thất bại |
137
-
138
- `message` đính kèm là `pj_strerror` từ PJSIP, hữu ích khi log.
120
+ ## API reference
121
+
122
+ | Method | Description |
123
+ |--------|-------------|
124
+ | `init(config?)` | Create and start PJSIP endpoint |
125
+ | `shutdown()` | Hang up all, destroy endpoint |
126
+ | `register(account)` | Register SIP account → `accountId` |
127
+ | `unregister(accountId)` | Unregister account |
128
+ | `makeCall(accountId, uri)` | Outbound call → `callId` |
129
+ | `answer(callId)` | Answer incoming call |
130
+ | `hangup(callId)` | End one call |
131
+ | `hangupAllCalls()` | End all active calls |
132
+ | `hold(callId)` / `unhold(callId)` | Hold / resume |
133
+ | `mute(callId, on)` | Mute / unmute microphone |
134
+ | `sendDtmf(callId, digits)` | Send DTMF tones |
135
+ | `transferCall(callId, uri)` | Blind transfer |
136
+ | `on(event, callback)` | Subscribe to native events |
137
+
138
+ ### `InitConfig`
139
+
140
+ | Field | Type | Description |
141
+ |-------|------|-------------|
142
+ | `userAgent` | `string` | SIP User-Agent header |
143
+ | `stunServer` | `string` | STUN server URI |
144
+ | `logLevel` | `number` | PJSIP log level (0–6) |
145
+
146
+ ### `AccountConfig`
147
+
148
+ | Field | Type | Required |
149
+ |-------|------|----------|
150
+ | `uri` | `string` | SIP AOR, e.g. `sip:user@domain` |
151
+ | `registrar` | `string` | Registrar URI |
152
+ | `username` | `string` | Auth username |
153
+ | `password` | `string` | Auth password |
154
+ | `transport` | `'UDP' \| 'TCP' \| 'TLS'` | Signaling transport |
139
155
 
140
156
  ---
141
157
 
142
158
  ## Events
143
159
 
144
- Account / call lifecycle (do PJSIP phát):
160
+ | Event | Payload highlights |
161
+ |-------|-------------------|
162
+ | `registrationState` | `{ accountId, code, reason }` |
163
+ | `incomingCall` | `{ accountId, callId, from, to }` |
164
+ | `callState` | `{ callId, state, code, reason }` |
165
+ | `callMediaState` | `{ callId, hasAudio, isHold, isMuted }` |
166
+ | `callHold` / `callUnhold` | `{ callId }` |
167
+ | `callMute` | `{ callId, isMuted }` |
168
+ | `callDtmfSent` | `{ callId, digits }` |
169
+ | `callTransfer` | `{ callId, destinationUri }` |
170
+ | `callTransferStatus` | `{ callId, statusCode, reason, finalNotify }` |
171
+ | `incomingDtmf` | `{ callId, digit, duration }` |
145
172
 
146
- ```ts
147
- VoipCloud.on('registrationState', e => /* { accountId, code, reason } */);
148
- VoipCloud.on('incomingCall', e => /* { accountId, callId, from, to } */);
149
- VoipCloud.on('callState', e => /* { callId, state, code, reason } */);
150
- VoipCloud.on('callMediaState', e => /* { callId, hasAudio, isHold, isMuted } */);
151
- ```
173
+ ---
174
+
175
+ ## Error handling
152
176
 
153
- Per-action xác nhận (bridge phát sau khi action thành công — tiện cho
154
- UI bind 1-1 với từng nút bấm):
177
+ Every method returns a `Promise`. Failures reject with `error.code` (string). The bridge **never crashes** the host app for API misuse or recoverable PJSIP errors.
155
178
 
156
179
  ```ts
157
- VoipCloud.on('callHold', e => /* { callId } */);
158
- VoipCloud.on('callUnhold', e => /* { callId } */);
159
- VoipCloud.on('callMute', e => /* { callId, isMuted } */);
160
- VoipCloud.on('callDtmfSent', e => /* { callId, digits } */);
161
- VoipCloud.on('callTransfer', e => /* { callId, destinationUri } */);
180
+ try {
181
+ await VoipCloud.init();
182
+ } catch (e: any) {
183
+ console.warn(e.code, e.message);
184
+ }
162
185
  ```
163
186
 
164
- Remote-driven (PJSIP forward từ callback gốc):
187
+ | code | Meaning |
188
+ |------|---------|
189
+ | `VC_NOT_LINKED` | Native module not linked — reinstall package and rebuild Android |
190
+ | `VC_NATIVE_LOAD` | `libvoipcloud.so` failed to load (missing ABI or AAR) |
191
+ | `VC_NOT_INITIALIZED` | SIP API called before successful `init()` |
192
+ | `VC_INVALID_ARGUMENT` | Missing or empty required field |
193
+ | `VC_INIT` | Endpoint failed to start |
194
+ | `VC_SHUTDOWN` | Shutdown error |
195
+ | `VC_REGISTER` / `VC_UNREGISTER` | Account registration error |
196
+ | `VC_NO_ACCOUNT` | Unknown `accountId` |
197
+ | `VC_MAKE_CALL` / `VC_ANSWER` / `VC_HANGUP` | Call operation error |
198
+ | `VC_NO_CALL` | Unknown `callId` |
199
+ | `VC_HOLD` / `VC_UNHOLD` / `VC_MUTE` / `VC_DTMF` / `VC_TRANSFER` | In-call control error |
165
200
 
166
- ```ts
167
- // REFER multi-stage: nhận một event mỗi NOTIFY; finalNotify=true là kết quả cuối.
168
- VoipCloud.on('callTransferStatus', e => /* { callId, statusCode, reason, finalNotify } */);
201
+ ---
169
202
 
170
- // DTMF do đầu remote gửi qua RTP (RFC 2833).
171
- VoipCloud.on('incomingDtmf', e => /* { callId, digit, duration } */);
172
- ```
203
+ ## Native artifacts (Android)
204
+
205
+ Shipped inside `android/src/main/libs/voipcloud-release.aar`:
206
+
207
+ | Artifact | Name |
208
+ |----------|------|
209
+ | Shared library | `libvoipcloud.so` — `System.loadLibrary("voipcloud")` |
210
+ | SWIG JNI class | `com.voipcloud.sdk.voipcloudJNI` |
211
+ | RN bridge module | `VoipsdkReactNativeVoipcloud` (JS: `VoipCloud`) |
212
+ | Java SDK | `com.voipcloud.sdk.*` |
213
+
214
+ This package does **not** use upstream `libpjsua2.so` / `pjsua2JNI`.
215
+
216
+ ---
217
+
218
+ ## Troubleshooting
219
+
220
+ **`VC_NOT_LINKED` after install**
221
+ Run `cd android && ./gradlew clean assembleDebug`. Confirm `@voipsdk/react-native-voipcloud` appears in `settings.gradle` / autolinking.
222
+
223
+ **`VC_NATIVE_LOAD`**
224
+ Ensure your device ABI is supported (`arm64-v8a` on most phones). For release builds, R8 applies ProGuard rules from the AAR automatically.
225
+
226
+ **Registration fails (`VC_REGISTER`)**
227
+ Check `registrar`, credentials, and network. TLS requires a valid server certificate or appropriate PJSIP TLS settings on the PBX side.
228
+
229
+ **No audio**
230
+ Grant `RECORD_AUDIO` at runtime before placing a call.
231
+
232
+ ---
233
+
234
+ ## License
235
+
236
+ UNLICENSED — see package metadata. Contact the author for commercial terms.
@@ -1,11 +1,11 @@
1
- // react-native-voipcloud — Android library module.
1
+ // @voipsdk/react-native-voipcloud — Android library module.
2
2
  //
3
- // Consumer apps that include this package via Gradle pull in:
4
- // * com.voipcloud.sdk.* from voipcloud-release.aar
5
- // * com.voipcloud.sdk.rn.* React Native bridge classes (this module)
3
+ // npm: @voipsdk/react-native-voipcloud
4
+ // native module: VoipsdkReactNativeVoipcloud (VoipCloudModule.getName())
6
5
  //
7
- // The AAR ships its own ProGuard rules (proguard.txt) which R8 auto-
8
- // applies to the consumer release build; no extra setup needed.
6
+ // Consumer apps pull in:
7
+ // * com.voipcloud.sdk.* from voipcloud-release.aar
8
+ // * com.voipcloud.sdk.rn.* React Native bridge (this module)
9
9
 
10
10
  buildscript {
11
11
  repositories {
@@ -52,7 +52,7 @@ repositories {
52
52
  }
53
53
 
54
54
  dependencies {
55
- // Prebuilt PJSIP + license layer (com.voipcloud.sdk.*).
55
+ // Prebuilt PJSIP SDK (com.voipcloud.sdk.*).
56
56
  implementation(name: 'voipcloud-release', ext: 'aar')
57
57
 
58
58
  // Pin to a permissive range — the consumer app controls the actual