@voipsdk/react-native-voipcloud 1.0.5 → 1.0.7
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/CHANGELOG.md +54 -0
- package/README.md +2 -1
- package/android/src/main/java/com/voipcloud/sdk/rn/VoipCloudModule.java +42 -0
- package/android/src/main/java/com/voipcloud/sdk/rn/internal/ManagedCall.java +68 -0
- package/ios/VoipCloud.mm +11 -0
- package/ios/VoipCloudEngine.h +4 -0
- package/ios/VoipCloudEngine.mm +74 -0
- package/lib/commonjs/VoipCloud.js +11 -0
- package/lib/commonjs/VoipCloud.js.map +1 -1
- package/lib/module/VoipCloud.js +11 -0
- package/lib/module/VoipCloud.js.map +1 -1
- package/lib/typescript/VoipCloud.d.ts +9 -0
- package/package.json +2 -2
- package/src/VoipCloud.ts +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,60 @@ All notable changes to `@voipsdk/react-native-voipcloud` are documented here.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.0.7] - 2026-08-13
|
|
9
|
+
|
|
10
|
+
Folds in the SDP bandwidth-modifier fixes that were living as app-side
|
|
11
|
+
`patch-package` patches (`@voipsdk+react-native-voipcloud+1.0.6.patch`), so a
|
|
12
|
+
fresh install behaves correctly without any patch. Root-cause mitigation for a
|
|
13
|
+
malformed `b=` line (e.g. `=:40` / `=:4000` / `:=4000`) that some PBX/proxy SDP
|
|
14
|
+
rewriters produce and that breaks SDP parsing / call negotiation.
|
|
15
|
+
|
|
16
|
+
### Changed / Fixed
|
|
17
|
+
|
|
18
|
+
- **iOS:** disable pjmedia's `b=TIAS:<bps>` SDP bandwidth modifier by setting
|
|
19
|
+
`pjmedia_add_bandwidth_tias_in_sdp = PJ_FALSE` right after `libInit`. pjmedia
|
|
20
|
+
stamps that line onto every SDP we author (offer + answer), and some
|
|
21
|
+
PBX/proxy SDP rewriters mangle it (leaving `=:40` / `=:4000`) → corrupt SDP /
|
|
22
|
+
broken call info. We never rely on TIAS, so it is disabled at the source; only
|
|
23
|
+
SDP we author is affected, remote SDP is untouched.
|
|
24
|
+
- **Android:** `ManagedCall.onCallSdpCreated` now sanitizes both the local and
|
|
25
|
+
the remote SDP just before/after negotiation (`sanitizeSdp`). It keeps only
|
|
26
|
+
strictly RFC 4566 well-formed `<type>=<value>` lines (single `a-z` key,
|
|
27
|
+
non-empty value) and drops every bandwidth (`b=`) line, so a single corrupt
|
|
28
|
+
line can never invalidate the whole SDP. Line endings are normalized to CRLF
|
|
29
|
+
and the session is only rewritten when something actually changed.
|
|
30
|
+
|
|
31
|
+
## [1.0.6] - 2026-08-10
|
|
32
|
+
|
|
33
|
+
Folds in the push-wake registration-refresh fixes that were living as an app-side
|
|
34
|
+
`patch-package` patch (`@voipsdk+react-native-voipcloud+1.0.5.patch`), so a fresh
|
|
35
|
+
install behaves correctly without any patch. Root-cause mitigation for the
|
|
36
|
+
multi-contact fork that yields **482 Loop Detected** and slow-or-missed calls
|
|
37
|
+
after a NAT-port change on a push-wake.
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- `VoipCloud.refreshRegistration(accountId)` — re-send REGISTER on the EXISTING
|
|
42
|
+
account (renew, same socket/binding) instead of `unregister()` + `register()`.
|
|
43
|
+
Reuses the live PJSIP account so the registrar updates the SAME binding — no new
|
|
44
|
+
contact, no fork. Prefer it over `register()` on a push-wake / periodic refresh;
|
|
45
|
+
rejects `VC_REFRESH` if the account was never registered (fall back to
|
|
46
|
+
`register()` on a cold start). Wired on iOS (`refreshRegistrationAccount:error:`)
|
|
47
|
+
and Android.
|
|
48
|
+
- Stable per-install SIP instance id (`+sip.instance`, RFC 5626 form) on the
|
|
49
|
+
Contact of each account, so a one-contact-per-AOR registrar (Kamailio
|
|
50
|
+
`max_contacts=1` / `matching_mode=instance`, Asterisk PJSIP `remove_existing=yes`)
|
|
51
|
+
replaces the device's previous binding instead of appending. Uses
|
|
52
|
+
`identifierForVendor` (iOS) / `ANDROID_ID` (Android); harmless if the server
|
|
53
|
+
ignores it.
|
|
54
|
+
|
|
55
|
+
### Changed / Fixed
|
|
56
|
+
|
|
57
|
+
- **iOS:** `natConfig.contactUseSrcPort = 1` — keep the learned NAT source **port**
|
|
58
|
+
(not just the IP) in the rewritten Contact, matching Android. Fixes stale-port
|
|
59
|
+
Contacts after an iOS suspend/rebind that routed inbound INVITEs to a dead port
|
|
60
|
+
and prevented re-REGISTER from matching the old binding.
|
|
61
|
+
|
|
8
62
|
## [1.0.3] - 2026-07-17
|
|
9
63
|
|
|
10
64
|
Folds in the NAT / media / call-routing fixes that were living as app-side
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @voipsdk/react-native-voipcloud
|
|
2
2
|
|
|
3
3
|
> Public VoIP SDK for React Native — Android **and** iOS (RN 0.70+).
|
|
4
|
-
> Package: `@voipsdk/react-native-voipcloud@1.0.
|
|
4
|
+
> Package: `@voipsdk/react-native-voipcloud@1.0.7`
|
|
5
5
|
|
|
6
6
|
Android and iOS expose the **same** JS API, events and `VC_*` error codes.
|
|
7
7
|
|
|
@@ -146,6 +146,7 @@ export function useVoipEvents() {
|
|
|
146
146
|
| `shutdown()` | Hang up all, destroy endpoint |
|
|
147
147
|
| `register(account)` | Register SIP account → `accountId` |
|
|
148
148
|
| `unregister(accountId)` | Unregister account |
|
|
149
|
+
| `refreshRegistration(accountId)` | Re-REGISTER an existing account (renew, same binding) — push-wake refresh that avoids contact churn / 482 |
|
|
149
150
|
| `makeCall(accountId, uri)` | Outbound call → `callId` |
|
|
150
151
|
| `answer(callId)` | Answer incoming call |
|
|
151
152
|
| `hangup(callId, mode?)` | End one call (`mode`: `'normal'` \| `'busy'` \| `'cancel'`) |
|
|
@@ -276,6 +276,25 @@ public class VoipCloudModule extends ReactContextBaseJavaModule {
|
|
|
276
276
|
AuthCredInfo cred = new AuthCredInfo("digest", "*", username, 0, password);
|
|
277
277
|
acfg.getSipConfig().getAuthCreds().add(cred);
|
|
278
278
|
|
|
279
|
+
// Stable per-install SIP instance id (+sip.instance) so the registrar
|
|
280
|
+
// can REPLACE this device's previous binding on re-REGISTER instead of
|
|
281
|
+
// appending a new contact — root-cause mitigation for the multi-contact
|
|
282
|
+
// fork that yields 482 Loop Detected (needs a one-contact-per-AOR server
|
|
283
|
+
// policy; harmless if the server ignores it). ANDROID_ID is stable per
|
|
284
|
+
// app-signing-key per device and resets on reinstall — the lifetime we
|
|
285
|
+
// want for a device-binding id. Mirrors the iOS engine
|
|
286
|
+
// (identifierForVendor). Wrapped so a lookup failure never breaks
|
|
287
|
+
// registration. The value is matched opaquely by the registrar.
|
|
288
|
+
try {
|
|
289
|
+
String androidId = android.provider.Settings.Secure.getString(
|
|
290
|
+
ctx.getContentResolver(),
|
|
291
|
+
android.provider.Settings.Secure.ANDROID_ID);
|
|
292
|
+
if (androidId != null && !androidId.isEmpty()) {
|
|
293
|
+
acfg.getSipConfig().setContactParams(
|
|
294
|
+
";+sip.instance=\"<urn:uuid:" + androidId + ">\"");
|
|
295
|
+
}
|
|
296
|
+
} catch (Throwable ignored) {}
|
|
297
|
+
|
|
279
298
|
ManagedAccount acc = new ManagedAccount(ctx, calls, endpoint);
|
|
280
299
|
acc.create(acfg);
|
|
281
300
|
int id = acc.accountId();
|
|
@@ -306,6 +325,29 @@ public class VoipCloudModule extends ReactContextBaseJavaModule {
|
|
|
306
325
|
}
|
|
307
326
|
}
|
|
308
327
|
|
|
328
|
+
// Re-REGISTER on the EXISTING account (renew) instead of unregister()+register().
|
|
329
|
+
// On a push-wake the account/transport are still alive, so this re-REGISTERs
|
|
330
|
+
// from the SAME socket and the registrar updates the SAME binding — no new
|
|
331
|
+
// contact, no fork (the churn behind 482 Loop Detected / slow-or-missed calls).
|
|
332
|
+
// Prefer this over unregister+register whenever the account already exists
|
|
333
|
+
// (see VoipCloudSipManager warm-refresh path).
|
|
334
|
+
@ReactMethod
|
|
335
|
+
public void refreshRegistration(int accountId, Promise promise) {
|
|
336
|
+
if (!BridgeGuard.ensureNative(promise)) return;
|
|
337
|
+
try {
|
|
338
|
+
ManagedAccount acc = accounts.get(accountId);
|
|
339
|
+
if (acc == null) {
|
|
340
|
+
promise.reject("VC_REFRESH",
|
|
341
|
+
"Unknown accountId " + accountId + ". Call register() first.");
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
acc.setRegistration(true);
|
|
345
|
+
promise.resolve(null);
|
|
346
|
+
} catch (Throwable t) {
|
|
347
|
+
BridgeGuard.reject(promise, "VC_REFRESH", "Failed to refresh registration", t);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
309
351
|
@ReactMethod
|
|
310
352
|
public void makeCall(int accountId, String uri, Promise promise) {
|
|
311
353
|
if (!BridgeGuard.ensureNative(promise)) return;
|
|
@@ -12,9 +12,11 @@ import com.voipcloud.sdk.CallInfo;
|
|
|
12
12
|
import com.voipcloud.sdk.CallMediaInfo;
|
|
13
13
|
import com.voipcloud.sdk.Endpoint;
|
|
14
14
|
import com.voipcloud.sdk.OnCallMediaStateParam;
|
|
15
|
+
import com.voipcloud.sdk.OnCallSdpCreatedParam;
|
|
15
16
|
import com.voipcloud.sdk.OnCallStateParam;
|
|
16
17
|
import com.voipcloud.sdk.OnCallTransferStatusParam;
|
|
17
18
|
import com.voipcloud.sdk.OnDtmfDigitParam;
|
|
19
|
+
import com.voipcloud.sdk.SdpSession;
|
|
18
20
|
import com.voipcloud.sdk.pjmedia_type;
|
|
19
21
|
import com.voipcloud.sdk.pjsip_inv_state;
|
|
20
22
|
import com.voipcloud.sdk.pjsua_call_media_status;
|
|
@@ -189,6 +191,72 @@ public final class ManagedCall extends Call {
|
|
|
189
191
|
emitMediaState();
|
|
190
192
|
}
|
|
191
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Fired after PJSIP builds the local SDP (our offer for outgoing calls, our
|
|
196
|
+
* answer for incoming ones, and re-offer/answer on hold/unhold) but BEFORE
|
|
197
|
+
* it is sent. We sanitize both the SDP we send and PJSIP's copy of the
|
|
198
|
+
* remote SDP so a malformed line or a bandwidth modifier can never break
|
|
199
|
+
* negotiation — see {@link #sanitizeSdp}.
|
|
200
|
+
*/
|
|
201
|
+
@Override
|
|
202
|
+
public void onCallSdpCreated(OnCallSdpCreatedParam prm) {
|
|
203
|
+
try {
|
|
204
|
+
sanitizeSdp(prm.getSdp());
|
|
205
|
+
sanitizeSdp(prm.getRemSdp());
|
|
206
|
+
} catch (Throwable ignored) {}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Rewrite an SdpSession in place, keeping ONLY strictly well-formed lines
|
|
211
|
+
* and dropping every bandwidth ("b=") line.
|
|
212
|
+
*
|
|
213
|
+
* Per RFC 4566 every SDP line is {@code <type>=<value>} where {@code <type>}
|
|
214
|
+
* is exactly one letter and {@code <value>} is non-empty. We enforce that
|
|
215
|
+
* grammar and treat anything else as corruption to be removed — not just the
|
|
216
|
+
* one observed artifact ({@code :=4000}) but ANY bad key or value:
|
|
217
|
+
* <ul>
|
|
218
|
+
* <li>key is not a single {@code a-z} letter — {@code :=4}, {@code S=4},
|
|
219
|
+
* {@code =64000}, {@code 3=x}, {@code " b=…"} (leading space)…</li>
|
|
220
|
+
* <li>second char is not {@code '='} — {@code ba=…}, {@code b:AS…}…</li>
|
|
221
|
+
* <li>empty value — {@code a=} with nothing after {@code '='}</li>
|
|
222
|
+
* </ul>
|
|
223
|
+
* Dropping a bad line (rather than trusting it) means a single corrupt line
|
|
224
|
+
* can never invalidate the whole SDP, and the value it carried is irrelevant.
|
|
225
|
+
* Line endings are normalized to CRLF. No-op when the SDP is absent; the
|
|
226
|
+
* session is only rewritten if something actually changed.
|
|
227
|
+
*/
|
|
228
|
+
private static void sanitizeSdp(SdpSession session) {
|
|
229
|
+
if (session == null) return;
|
|
230
|
+
String sdp;
|
|
231
|
+
try { sdp = session.getWholeSdp(); } catch (Throwable e) { return; }
|
|
232
|
+
if (sdp == null || sdp.isEmpty()) return;
|
|
233
|
+
|
|
234
|
+
// Split on any newline style (CRLF / CR / LF) so a stray ending cannot
|
|
235
|
+
// smuggle a corrupt token through as part of another line.
|
|
236
|
+
String[] lines = sdp.split("\r\n|\r|\n");
|
|
237
|
+
StringBuilder out = new StringBuilder(sdp.length());
|
|
238
|
+
boolean changed = false;
|
|
239
|
+
for (String line : lines) {
|
|
240
|
+
int len = line.length();
|
|
241
|
+
if (len == 0) { continue; }
|
|
242
|
+
char key = line.charAt(0);
|
|
243
|
+
boolean wellFormed =
|
|
244
|
+
len >= 3 // key + '=' + at least one value char
|
|
245
|
+
&& line.charAt(1) == '=' // "<key>=" separator
|
|
246
|
+
&& key >= 'a' && key <= 'z'; // key is a single a-z letter only
|
|
247
|
+
if (!wellFormed || key == 'b') { // corrupt/invalid line, or bandwidth
|
|
248
|
+
changed = true;
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
out.append(line).append("\r\n");
|
|
252
|
+
}
|
|
253
|
+
// Only push back a non-empty result; a real SDP always keeps v=/o=/… so
|
|
254
|
+
// out is never empty in practice, but guard against wiping the session.
|
|
255
|
+
if (changed && out.length() > 0) {
|
|
256
|
+
try { session.setWholeSdp(out.toString()); } catch (Throwable ignored) {}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
192
260
|
/**
|
|
193
261
|
* Multi-stage progress notifications for a REFER (call transfer)
|
|
194
262
|
* we initiated. Fires for each NOTIFY received from the remote
|
package/ios/VoipCloud.mm
CHANGED
|
@@ -98,6 +98,17 @@ RCT_EXPORT_METHOD(unregister:(NSInteger)accountId
|
|
|
98
98
|
else reject(@"VC_UNREGISTER", err.localizedDescription ?: @"Failed to unregister account", err);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
// Re-REGISTER on the existing account (renew, same socket) — the push-wake refresh
|
|
102
|
+
// that avoids the unregister+recreate contact churn behind 482 / slow calls.
|
|
103
|
+
RCT_EXPORT_METHOD(refreshRegistration:(NSInteger)accountId
|
|
104
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
105
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
106
|
+
{
|
|
107
|
+
NSError *err = nil;
|
|
108
|
+
if ([VoipCloudEngine.shared refreshRegistrationAccount:(int)accountId error:&err]) resolve(nil);
|
|
109
|
+
else reject(@"VC_REFRESH", err.localizedDescription ?: @"Failed to refresh registration", err);
|
|
110
|
+
}
|
|
111
|
+
|
|
101
112
|
#pragma mark - Calls
|
|
102
113
|
|
|
103
114
|
RCT_EXPORT_METHOD(makeCall:(NSInteger)accountId
|
package/ios/VoipCloudEngine.h
CHANGED
|
@@ -42,6 +42,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
42
42
|
/// Returns the accountId, or -1 on failure (with *error set).
|
|
43
43
|
- (int)registerAccountWithConfig:(NSDictionary *)cfg error:(NSError **)error;
|
|
44
44
|
- (BOOL)unregisterAccount:(int)accountId error:(NSError **)error;
|
|
45
|
+
/// Re-send REGISTER on the EXISTING account (renew, same socket/Contact) instead
|
|
46
|
+
/// of unregister+recreate — the push-wake refresh that avoids contact churn/482.
|
|
47
|
+
/// NO (with *error) if the account was never registered.
|
|
48
|
+
- (BOOL)refreshRegistrationAccount:(int)accountId error:(NSError **)error;
|
|
45
49
|
|
|
46
50
|
/// Place a call from `accountId` to `uri` (full SIP URI). Returns callId, or -1.
|
|
47
51
|
- (int)makeCallFromAccount:(int)accountId toUri:(NSString *)uri error:(NSError **)error;
|
package/ios/VoipCloudEngine.mm
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
//
|
|
5
5
|
#import "VoipCloudEngine.h"
|
|
6
6
|
#import <AVFoundation/AVFoundation.h>
|
|
7
|
+
#import <UIKit/UIKit.h> // UIDevice.identifierForVendor — stable per-install SIP instance id
|
|
7
8
|
#include <pjsua2.hpp>
|
|
8
9
|
#include <pjsua-lib/pjsua.h>
|
|
9
10
|
#include <string>
|
|
@@ -13,6 +14,15 @@
|
|
|
13
14
|
|
|
14
15
|
using namespace pj;
|
|
15
16
|
|
|
17
|
+
// pjmedia run-time flag (defined in pjmedia endpoint.c, C linkage). Default 1 →
|
|
18
|
+
// pjmedia stamps a "b=TIAS:<bps>" bandwidth modifier onto every SDP it generates
|
|
19
|
+
// (our outgoing offer + our answer). Some PBX/proxy SDP rewriters mangle that line
|
|
20
|
+
// (e.g. leaving "=:40"/"=:4000") → corrupt SDP / broken call info. We never rely on
|
|
21
|
+
// TIAS, so disable at the source. Only touches SDP *we* author; remote SDP is
|
|
22
|
+
// untouched (strip those at the PBX). Declared here because config.h only mentions
|
|
23
|
+
// it in a doc comment, not as a real extern.
|
|
24
|
+
extern "C" pj_bool_t pjmedia_add_bandwidth_tias_in_sdp;
|
|
25
|
+
|
|
16
26
|
static NSString *const kVCErrorDomain = @"VoipCloudEngine";
|
|
17
27
|
|
|
18
28
|
static NSError *VCMakeError(NSInteger code, NSString *msg) {
|
|
@@ -322,6 +332,11 @@ void VCCall::onDtmfDigit(OnDtmfDigitParam &prm) {
|
|
|
322
332
|
|
|
323
333
|
_ep->libInit(epCfg);
|
|
324
334
|
|
|
335
|
+
// Never emit the SDP "b=TIAS:" bandwidth modifier — it triggers broken
|
|
336
|
+
// SDP rewrites downstream (=:40 / =:4000) and we don't use it. Safe to set
|
|
337
|
+
// once the pjmedia endpoint exists (after libInit); read at SDP-gen time.
|
|
338
|
+
pjmedia_add_bandwidth_tias_in_sdp = PJ_FALSE;
|
|
339
|
+
|
|
325
340
|
// Ephemeral ports (0) avoid "Address already in use" for SIP clients.
|
|
326
341
|
// Keep each transport id so registerAccountWithConfig can pin the
|
|
327
342
|
// account to the matching one (0 is a valid id → init to -1).
|
|
@@ -419,10 +434,40 @@ void VCCall::onDtmfDigit(OnDtmfDigitParam &prm) {
|
|
|
419
434
|
acfg.natConfig.contactRewriteUse = 1;
|
|
420
435
|
acfg.natConfig.viaRewriteUse = 1;
|
|
421
436
|
acfg.natConfig.udpKaIntervalSec = 20;
|
|
437
|
+
// Keep the learned NAT source PORT (not just the source IP) in the
|
|
438
|
+
// rewritten Contact — PARITY WITH ANDROID (setContactUseSrcPort(1)),
|
|
439
|
+
// previously missing on iOS. After iOS suspends the app the OS rebinds the
|
|
440
|
+
// NAT pinhole to a NEW port; the next REGISTER must advertise the EXACT
|
|
441
|
+
// ip:port it now sends from. Without this the Contact can carry a stale
|
|
442
|
+
// port, so (a) inbound INVITEs route to the dead port and (b) an
|
|
443
|
+
// unregister/re-REGISTER from the new port cannot match the old binding at
|
|
444
|
+
// the registrar → the AOR accumulates contacts → the PBX forks the INVITE
|
|
445
|
+
// to all of them → 482 Loop Detected + losing branches CANCELled.
|
|
446
|
+
acfg.natConfig.contactUseSrcPort = 1;
|
|
422
447
|
acfg.regConfig.timeoutSec = 120;
|
|
423
448
|
acfg.regConfig.firstRetryIntervalSec = 5;
|
|
424
449
|
acfg.regConfig.retryIntervalSec = 30;
|
|
425
450
|
|
|
451
|
+
// Stable per-install SIP instance id (+sip.instance, RFC 5626 form). The
|
|
452
|
+
// registrar can then REPLACE this device's previous binding on every
|
|
453
|
+
// re-REGISTER instead of appending a new contact. Combined with a
|
|
454
|
+
// one-contact-per-AOR server policy (Kamailio max_contacts=1 /
|
|
455
|
+
// matching_mode=instance, or Asterisk PJSIP remove_existing=yes) this is
|
|
456
|
+
// the root-cause fix for the multi-contact fork that yields 482 Loop
|
|
457
|
+
// Detected after a NAT-port change on a push-wake. It is HARMLESS when the
|
|
458
|
+
// server ignores it (just an extra Contact param). identifierForVendor is
|
|
459
|
+
// stable across launches/suspends for this vendor's apps and only resets on
|
|
460
|
+
// reinstall — exactly the lifetime wanted for a device-binding id. We set
|
|
461
|
+
// it via contactParams (Contact header suffix) rather than enabling full
|
|
462
|
+
// outbound (sipOutboundUse), which would require server Path support.
|
|
463
|
+
NSString *vendorId = [[UIDevice currentDevice] identifierForVendor].UUIDString;
|
|
464
|
+
if (vendorId.length) {
|
|
465
|
+
std::string instance = ";+sip.instance=\"<urn:uuid:";
|
|
466
|
+
instance += std::string(vendorId.UTF8String);
|
|
467
|
+
instance += ">\"";
|
|
468
|
+
acfg.sipConfig.contactParams = instance;
|
|
469
|
+
}
|
|
470
|
+
|
|
426
471
|
// STUN for MEDIA only: without it the SDP offer carries the LAN IP
|
|
427
472
|
// (c=192.168.x) and the far end sends RTP to an unroutable address →
|
|
428
473
|
// no 2-way audio. Falls back to the host addr if STUN is unreachable.
|
|
@@ -486,6 +531,35 @@ void VCCall::onDtmfDigit(OnDtmfDigitParam &prm) {
|
|
|
486
531
|
return YES;
|
|
487
532
|
}
|
|
488
533
|
|
|
534
|
+
// Re-send REGISTER on the EXISTING account instead of unregister()+register().
|
|
535
|
+
//
|
|
536
|
+
// On an iOS VoIP push-wake the app was only SUSPENDED (not killed): the PJSUA
|
|
537
|
+
// account and its pinned UDP transport/socket are still alive, so a plain refresh
|
|
538
|
+
// re-REGISTERs from the SAME NAT source port and the registrar updates the SAME
|
|
539
|
+
// binding. Delete+recreate (the old path) instead built a brand-new account on a
|
|
540
|
+
// new ephemeral port, so the registrar saw a NEW contact while the stale one
|
|
541
|
+
// lingered — the multi-contact churn behind 482 Loop Detected / slow-or-missed
|
|
542
|
+
// calls. Prefer this whenever the account already exists (see VoipCloudSipManager
|
|
543
|
+
// warm-refresh path); fall back to register() only on a cold start (no account).
|
|
544
|
+
//
|
|
545
|
+
// setRegistration(true) forces PJSIP to send REGISTER now (renew) even before the
|
|
546
|
+
// timer elapses; autoreg stays on so periodic refresh continues normally.
|
|
547
|
+
- (BOOL)refreshRegistrationAccount:(int)accountId error:(NSError **)error {
|
|
548
|
+
auto it = _accounts.find(accountId);
|
|
549
|
+
if (it == _accounts.end()) {
|
|
550
|
+
if (error) *error = VCMakeError(-1, [NSString stringWithFormat:
|
|
551
|
+
@"Unknown accountId %d. Call register() first.", accountId]);
|
|
552
|
+
return NO;
|
|
553
|
+
}
|
|
554
|
+
try {
|
|
555
|
+
it->second->setRegistration(true);
|
|
556
|
+
return YES;
|
|
557
|
+
} catch (Error &err) {
|
|
558
|
+
if (error) *error = VCMakeError(err.status, VCStr(err.info()));
|
|
559
|
+
return NO;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
489
563
|
#pragma mark Calls
|
|
490
564
|
|
|
491
565
|
- (int)makeCallFromAccount:(int)accountId toUri:(NSString *)uri error:(NSError **)error {
|
|
@@ -39,6 +39,17 @@ const VoipCloud = exports.VoipCloud = {
|
|
|
39
39
|
unregister(accountId) {
|
|
40
40
|
return callNative(() => _nativeModule.NativeVoipCloud.unregister(accountId));
|
|
41
41
|
},
|
|
42
|
+
/**
|
|
43
|
+
* Re-send REGISTER on an EXISTING account (renew) without unregister+recreate.
|
|
44
|
+
* Reuses the same PJSIP account/socket, so the registrar updates the SAME
|
|
45
|
+
* binding — no new contact. Prefer this over `register()` on a push-wake or
|
|
46
|
+
* periodic refresh (avoids the multi-contact churn behind 482 Loop Detected /
|
|
47
|
+
* slow-or-missed calls). Rejects with `VC_REFRESH` if `accountId` was never
|
|
48
|
+
* registered — the caller should fall back to `register()` on a cold start.
|
|
49
|
+
*/
|
|
50
|
+
refreshRegistration(accountId) {
|
|
51
|
+
return callNative(() => _nativeModule.NativeVoipCloud.refreshRegistration(accountId));
|
|
52
|
+
},
|
|
42
53
|
makeCall(accountId, destinationUri) {
|
|
43
54
|
return callNative(() => _nativeModule.NativeVoipCloud.makeCall(accountId, destinationUri));
|
|
44
55
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_nativeModule","require","_events","rejectNotLinked","Promise","reject","Object","assign","Error","code","callNative","fn","NativeVoipCloud","VoipCloud","exports","init","cfg","shutdown","register","account","unregister","accountId","makeCall","destinationUri","answer","callId","hangup","mode","hold","unhold","mute","on","sendDtmf","digits","transferCall","hangupAllCalls","reconnectCallAudio"],"sourceRoot":"../../src","sources":["VoipCloud.ts"],"mappings":";;;;;;AACA,IAAAA,aAAA,GAAAC,OAAA;AACA,IAAAC,OAAA,GAAAD,OAAA;AAEA;AACA,SAASE,eAAeA,CAAA,EAAmB;EACvC,OAAOC,OAAO,CAACC,MAAM,CACjBC,MAAM,CAACC,MAAM,CACT,IAAIC,KAAK,CACL,+DAA+D,GAC/D,+CAA+C,GAC/C,gFACJ,CAAC,EACD;IAAEC,IAAI,EAAE;EAAgB,CAC5B,CACJ,CAAC;AACL;AAEA,SAASC,UAAUA,CAAIC,EAAoB,EAAc;EACrD,IAAI,CAACC,6BAAe,EAAE,OAAOT,eAAe,CAAC,CAAC;EAC9C,OAAOQ,EAAE,CAAC,CAAC;AACf;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAME,SAAS,GAAAC,OAAA,CAAAD,SAAA,GAAG;EACrBE,IAAIA,CAACC,GAAe,GAAG,CAAC,CAAC,EAAiB;IACtC,OAAON,UAAU,CAAC,MAAME,6BAAe,CAACG,IAAI,CAACC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;EAC5D,CAAC;EAEDC,QAAQA,CAAA,EAAkB;IACtB,OAAOP,UAAU,CAAC,MAAME,6BAAe,CAACK,QAAQ,CAAC,CAAC,CAAC;EACvD,CAAC;EAEDC,QAAQA,CAACC,OAAsB,EAAmB;IAC9C,OAAOT,UAAU,CAAC,MAAME,6BAAe,CAACM,QAAQ,CAACC,OAAO,CAAC,CAAC;EAC9D,CAAC;EAEDC,UAAUA,CAACC,SAAiB,EAAiB;IACzC,OAAOX,UAAU,CAAC,MAAME,6BAAe,CAACQ,UAAU,CAACC,SAAS,CAAC,CAAC;EAClE,CAAC;
|
|
1
|
+
{"version":3,"names":["_nativeModule","require","_events","rejectNotLinked","Promise","reject","Object","assign","Error","code","callNative","fn","NativeVoipCloud","VoipCloud","exports","init","cfg","shutdown","register","account","unregister","accountId","refreshRegistration","makeCall","destinationUri","answer","callId","hangup","mode","hold","unhold","mute","on","sendDtmf","digits","transferCall","hangupAllCalls","reconnectCallAudio"],"sourceRoot":"../../src","sources":["VoipCloud.ts"],"mappings":"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","ignoreList":[]}
|
package/lib/module/VoipCloud.js
CHANGED
|
@@ -34,6 +34,17 @@ export const VoipCloud = {
|
|
|
34
34
|
unregister(accountId) {
|
|
35
35
|
return callNative(() => NativeVoipCloud.unregister(accountId));
|
|
36
36
|
},
|
|
37
|
+
/**
|
|
38
|
+
* Re-send REGISTER on an EXISTING account (renew) without unregister+recreate.
|
|
39
|
+
* Reuses the same PJSIP account/socket, so the registrar updates the SAME
|
|
40
|
+
* binding — no new contact. Prefer this over `register()` on a push-wake or
|
|
41
|
+
* periodic refresh (avoids the multi-contact churn behind 482 Loop Detected /
|
|
42
|
+
* slow-or-missed calls). Rejects with `VC_REFRESH` if `accountId` was never
|
|
43
|
+
* registered — the caller should fall back to `register()` on a cold start.
|
|
44
|
+
*/
|
|
45
|
+
refreshRegistration(accountId) {
|
|
46
|
+
return callNative(() => NativeVoipCloud.refreshRegistration(accountId));
|
|
47
|
+
},
|
|
37
48
|
makeCall(accountId, destinationUri) {
|
|
38
49
|
return callNative(() => NativeVoipCloud.makeCall(accountId, destinationUri));
|
|
39
50
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeVoipCloud","on","rejectNotLinked","Promise","reject","Object","assign","Error","code","callNative","fn","VoipCloud","init","cfg","shutdown","register","account","unregister","accountId","makeCall","destinationUri","answer","callId","hangup","mode","hold","unhold","mute","sendDtmf","digits","transferCall","hangupAllCalls","reconnectCallAudio"],"sourceRoot":"../../src","sources":["VoipCloud.ts"],"mappings":"AACA,SAASA,eAAe,QAAQ,gBAAgB;AAChD,SAASC,EAAE,QAAQ,UAAU;;AAE7B;AACA,SAASC,eAAeA,CAAA,EAAmB;EACvC,OAAOC,OAAO,CAACC,MAAM,CACjBC,MAAM,CAACC,MAAM,CACT,IAAIC,KAAK,CACL,+DAA+D,GAC/D,+CAA+C,GAC/C,gFACJ,CAAC,EACD;IAAEC,IAAI,EAAE;EAAgB,CAC5B,CACJ,CAAC;AACL;AAEA,SAASC,UAAUA,CAAIC,EAAoB,EAAc;EACrD,IAAI,CAACV,eAAe,EAAE,OAAOE,eAAe,CAAC,CAAC;EAC9C,OAAOQ,EAAE,CAAC,CAAC;AACf;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,SAAS,GAAG;EACrBC,IAAIA,CAACC,GAAe,GAAG,CAAC,CAAC,EAAiB;IACtC,OAAOJ,UAAU,CAAC,MAAMT,eAAe,CAACY,IAAI,CAACC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;EAC5D,CAAC;EAEDC,QAAQA,CAAA,EAAkB;IACtB,OAAOL,UAAU,CAAC,MAAMT,eAAe,CAACc,QAAQ,CAAC,CAAC,CAAC;EACvD,CAAC;EAEDC,QAAQA,CAACC,OAAsB,EAAmB;IAC9C,OAAOP,UAAU,CAAC,MAAMT,eAAe,CAACe,QAAQ,CAACC,OAAO,CAAC,CAAC;EAC9D,CAAC;EAEDC,UAAUA,CAACC,SAAiB,EAAiB;IACzC,OAAOT,UAAU,CAAC,MAAMT,eAAe,CAACiB,UAAU,CAACC,SAAS,CAAC,CAAC;EAClE,CAAC;
|
|
1
|
+
{"version":3,"names":["NativeVoipCloud","on","rejectNotLinked","Promise","reject","Object","assign","Error","code","callNative","fn","VoipCloud","init","cfg","shutdown","register","account","unregister","accountId","refreshRegistration","makeCall","destinationUri","answer","callId","hangup","mode","hold","unhold","mute","sendDtmf","digits","transferCall","hangupAllCalls","reconnectCallAudio"],"sourceRoot":"../../src","sources":["VoipCloud.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -14,6 +14,15 @@ export declare const VoipCloud: {
|
|
|
14
14
|
shutdown(): Promise<void>;
|
|
15
15
|
register(account: AccountConfig): Promise<number>;
|
|
16
16
|
unregister(accountId: number): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Re-send REGISTER on an EXISTING account (renew) without unregister+recreate.
|
|
19
|
+
* Reuses the same PJSIP account/socket, so the registrar updates the SAME
|
|
20
|
+
* binding — no new contact. Prefer this over `register()` on a push-wake or
|
|
21
|
+
* periodic refresh (avoids the multi-contact churn behind 482 Loop Detected /
|
|
22
|
+
* slow-or-missed calls). Rejects with `VC_REFRESH` if `accountId` was never
|
|
23
|
+
* registered — the caller should fall back to `register()` on a cold start.
|
|
24
|
+
*/
|
|
25
|
+
refreshRegistration(accountId: number): Promise<void>;
|
|
17
26
|
makeCall(accountId: number, destinationUri: string): Promise<number>;
|
|
18
27
|
answer(callId: number): Promise<void>;
|
|
19
28
|
hangup(callId: number, mode?: "busy" | "cancel" | "normal"): Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voipsdk/react-native-voipcloud",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Public React Native VoIP SDK
|
|
3
|
+
"version": "1.0.7",
|
|
4
|
+
"description": "Public React Native VoIP SDK (VoipCloud).",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
7
7
|
"react-native": "src/index.ts",
|
package/src/VoipCloud.ts
CHANGED
|
@@ -47,6 +47,18 @@ export const VoipCloud = {
|
|
|
47
47
|
return callNative(() => NativeVoipCloud.unregister(accountId));
|
|
48
48
|
},
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Re-send REGISTER on an EXISTING account (renew) without unregister+recreate.
|
|
52
|
+
* Reuses the same PJSIP account/socket, so the registrar updates the SAME
|
|
53
|
+
* binding — no new contact. Prefer this over `register()` on a push-wake or
|
|
54
|
+
* periodic refresh (avoids the multi-contact churn behind 482 Loop Detected /
|
|
55
|
+
* slow-or-missed calls). Rejects with `VC_REFRESH` if `accountId` was never
|
|
56
|
+
* registered — the caller should fall back to `register()` on a cold start.
|
|
57
|
+
*/
|
|
58
|
+
refreshRegistration(accountId: number): Promise<void> {
|
|
59
|
+
return callNative(() => NativeVoipCloud.refreshRegistration(accountId));
|
|
60
|
+
},
|
|
61
|
+
|
|
50
62
|
makeCall(accountId: number, destinationUri: string): Promise<number> {
|
|
51
63
|
return callNative(() => NativeVoipCloud.makeCall(accountId, destinationUri));
|
|
52
64
|
},
|