@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.
- package/README.md +181 -117
- package/android/build.gradle +7 -7
- package/android/src/main/java/com/voipcloud/sdk/rn/VoipCloudModule.java +148 -204
- package/android/src/main/java/com/voipcloud/sdk/rn/internal/BridgeGuard.java +74 -0
- package/android/src/main/java/com/voipcloud/sdk/rn/internal/Events.java +7 -2
- package/android/src/main/libs/voipcloud-release.aar +0 -0
- package/ios/VoipCloud.mm +8 -8
- package/lib/commonjs/VoipCloud.js +29 -47
- package/lib/commonjs/VoipCloud.js.map +1 -1
- package/lib/commonjs/events.js +13 -7
- package/lib/commonjs/events.js.map +1 -1
- package/lib/commonjs/index.js +2 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/nativeModule.js +18 -0
- package/lib/commonjs/nativeModule.js.map +1 -0
- package/lib/module/VoipCloud.js +30 -47
- package/lib/module/VoipCloud.js.map +1 -1
- package/lib/module/events.js +9 -8
- package/lib/module/events.js.map +1 -1
- package/lib/module/index.js +1 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/nativeModule.js +13 -0
- package/lib/module/nativeModule.js.map +1 -0
- package/lib/typescript/VoipCloud.d.ts +5 -30
- package/lib/typescript/events.d.ts +6 -2
- package/lib/typescript/index.d.ts +2 -3
- package/lib/typescript/nativeModule.d.ts +7 -0
- package/lib/typescript/types.d.ts +1 -17
- package/package.json +5 -4
- package/react-native-voipcloud.podspec +7 -5
- package/src/VoipCloud.ts +37 -48
- package/src/events.ts +9 -8
- package/src/index.ts +1 -3
- package/src/nativeModule.ts +17 -0
- package/src/types.ts +1 -18
- package/lib/commonjs/License.js +0 -51
- package/lib/commonjs/License.js.map +0 -1
- package/lib/module/License.js +0 -45
- package/lib/module/License.js.map +0 -1
- package/lib/typescript/License.d.ts +0 -31
- 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
|
-
>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
//
|
|
62
|
-
const callId = await VoipCloud.makeCall(
|
|
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
|
-
//
|
|
65
|
-
await VoipCloud.hold(callId);
|
|
66
|
-
await VoipCloud.unhold(callId);
|
|
67
|
-
await VoipCloud.mute(callId, true);
|
|
68
|
-
await VoipCloud.sendDtmf(callId, '1234#');
|
|
69
|
-
await VoipCloud.transferCall(callId, 'sip:charlie@example.com');
|
|
70
|
-
await VoipCloud.
|
|
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
|
-
//
|
|
86
|
+
// 5. Events (always remove in useEffect cleanup).
|
|
74
87
|
const sub = VoipCloud.on('callState', ({ callId, state }) => {
|
|
75
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
##
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
|
105
|
-
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
| `
|
|
111
|
-
| `
|
|
112
|
-
| `
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
|
125
|
-
|
|
126
|
-
| `
|
|
127
|
-
| `
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
130
|
-
| `
|
|
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
|
-
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
|
|
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
|
-
|
|
158
|
-
VoipCloud.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
180
|
+
try {
|
|
181
|
+
await VoipCloud.init();
|
|
182
|
+
} catch (e: any) {
|
|
183
|
+
console.warn(e.code, e.message);
|
|
184
|
+
}
|
|
162
185
|
```
|
|
163
186
|
|
|
164
|
-
|
|
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
|
-
|
|
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
|
-
|
|
171
|
-
|
|
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.
|
package/android/build.gradle
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// react-native-voipcloud — Android library module.
|
|
1
|
+
// @voipsdk/react-native-voipcloud — Android library module.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
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
|
-
//
|
|
8
|
-
//
|
|
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
|
|
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
|