@voipsdk/react-native-voipcloud 1.0.5 → 1.0.6

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 CHANGED
@@ -5,6 +5,37 @@ 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.6] - 2026-08-10
9
+
10
+ Folds in the push-wake registration-refresh fixes that were living as an app-side
11
+ `patch-package` patch (`@voipsdk+react-native-voipcloud+1.0.5.patch`), so a fresh
12
+ install behaves correctly without any patch. Root-cause mitigation for the
13
+ multi-contact fork that yields **482 Loop Detected** and slow-or-missed calls
14
+ after a NAT-port change on a push-wake.
15
+
16
+ ### Added
17
+
18
+ - `VoipCloud.refreshRegistration(accountId)` — re-send REGISTER on the EXISTING
19
+ account (renew, same socket/binding) instead of `unregister()` + `register()`.
20
+ Reuses the live PJSIP account so the registrar updates the SAME binding — no new
21
+ contact, no fork. Prefer it over `register()` on a push-wake / periodic refresh;
22
+ rejects `VC_REFRESH` if the account was never registered (fall back to
23
+ `register()` on a cold start). Wired on iOS (`refreshRegistrationAccount:error:`)
24
+ and Android.
25
+ - Stable per-install SIP instance id (`+sip.instance`, RFC 5626 form) on the
26
+ Contact of each account, so a one-contact-per-AOR registrar (Kamailio
27
+ `max_contacts=1` / `matching_mode=instance`, Asterisk PJSIP `remove_existing=yes`)
28
+ replaces the device's previous binding instead of appending. Uses
29
+ `identifierForVendor` (iOS) / `ANDROID_ID` (Android); harmless if the server
30
+ ignores it.
31
+
32
+ ### Changed / Fixed
33
+
34
+ - **iOS:** `natConfig.contactUseSrcPort = 1` — keep the learned NAT source **port**
35
+ (not just the IP) in the rewritten Contact, matching Android. Fixes stale-port
36
+ Contacts after an iOS suspend/rebind that routed inbound INVITEs to a dead port
37
+ and prevented re-REGISTER from matching the old binding.
38
+
8
39
  ## [1.0.3] - 2026-07-17
9
40
 
10
41
  Folds in the NAT / media / call-routing fixes that were living as app-side
package/README.md CHANGED
@@ -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;
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
@@ -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;
@@ -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>
@@ -419,10 +420,40 @@ void VCCall::onDtmfDigit(OnDtmfDigitParam &prm) {
419
420
  acfg.natConfig.contactRewriteUse = 1;
420
421
  acfg.natConfig.viaRewriteUse = 1;
421
422
  acfg.natConfig.udpKaIntervalSec = 20;
423
+ // Keep the learned NAT source PORT (not just the source IP) in the
424
+ // rewritten Contact — PARITY WITH ANDROID (setContactUseSrcPort(1)),
425
+ // previously missing on iOS. After iOS suspends the app the OS rebinds the
426
+ // NAT pinhole to a NEW port; the next REGISTER must advertise the EXACT
427
+ // ip:port it now sends from. Without this the Contact can carry a stale
428
+ // port, so (a) inbound INVITEs route to the dead port and (b) an
429
+ // unregister/re-REGISTER from the new port cannot match the old binding at
430
+ // the registrar → the AOR accumulates contacts → the PBX forks the INVITE
431
+ // to all of them → 482 Loop Detected + losing branches CANCELled.
432
+ acfg.natConfig.contactUseSrcPort = 1;
422
433
  acfg.regConfig.timeoutSec = 120;
423
434
  acfg.regConfig.firstRetryIntervalSec = 5;
424
435
  acfg.regConfig.retryIntervalSec = 30;
425
436
 
437
+ // Stable per-install SIP instance id (+sip.instance, RFC 5626 form). The
438
+ // registrar can then REPLACE this device's previous binding on every
439
+ // re-REGISTER instead of appending a new contact. Combined with a
440
+ // one-contact-per-AOR server policy (Kamailio max_contacts=1 /
441
+ // matching_mode=instance, or Asterisk PJSIP remove_existing=yes) this is
442
+ // the root-cause fix for the multi-contact fork that yields 482 Loop
443
+ // Detected after a NAT-port change on a push-wake. It is HARMLESS when the
444
+ // server ignores it (just an extra Contact param). identifierForVendor is
445
+ // stable across launches/suspends for this vendor's apps and only resets on
446
+ // reinstall — exactly the lifetime wanted for a device-binding id. We set
447
+ // it via contactParams (Contact header suffix) rather than enabling full
448
+ // outbound (sipOutboundUse), which would require server Path support.
449
+ NSString *vendorId = [[UIDevice currentDevice] identifierForVendor].UUIDString;
450
+ if (vendorId.length) {
451
+ std::string instance = ";+sip.instance=\"<urn:uuid:";
452
+ instance += std::string(vendorId.UTF8String);
453
+ instance += ">\"";
454
+ acfg.sipConfig.contactParams = instance;
455
+ }
456
+
426
457
  // STUN for MEDIA only: without it the SDP offer carries the LAN IP
427
458
  // (c=192.168.x) and the far end sends RTP to an unroutable address →
428
459
  // no 2-way audio. Falls back to the host addr if STUN is unreachable.
@@ -486,6 +517,35 @@ void VCCall::onDtmfDigit(OnDtmfDigitParam &prm) {
486
517
  return YES;
487
518
  }
488
519
 
520
+ // Re-send REGISTER on the EXISTING account instead of unregister()+register().
521
+ //
522
+ // On an iOS VoIP push-wake the app was only SUSPENDED (not killed): the PJSUA
523
+ // account and its pinned UDP transport/socket are still alive, so a plain refresh
524
+ // re-REGISTERs from the SAME NAT source port and the registrar updates the SAME
525
+ // binding. Delete+recreate (the old path) instead built a brand-new account on a
526
+ // new ephemeral port, so the registrar saw a NEW contact while the stale one
527
+ // lingered — the multi-contact churn behind 482 Loop Detected / slow-or-missed
528
+ // calls. Prefer this whenever the account already exists (see VoipCloudSipManager
529
+ // warm-refresh path); fall back to register() only on a cold start (no account).
530
+ //
531
+ // setRegistration(true) forces PJSIP to send REGISTER now (renew) even before the
532
+ // timer elapses; autoreg stays on so periodic refresh continues normally.
533
+ - (BOOL)refreshRegistrationAccount:(int)accountId error:(NSError **)error {
534
+ auto it = _accounts.find(accountId);
535
+ if (it == _accounts.end()) {
536
+ if (error) *error = VCMakeError(-1, [NSString stringWithFormat:
537
+ @"Unknown accountId %d. Call register() first.", accountId]);
538
+ return NO;
539
+ }
540
+ try {
541
+ it->second->setRegistration(true);
542
+ return YES;
543
+ } catch (Error &err) {
544
+ if (error) *error = VCMakeError(err.status, VCStr(err.info()));
545
+ return NO;
546
+ }
547
+ }
548
+
489
549
  #pragma mark Calls
490
550
 
491
551
  - (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":"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","ignoreList":[]}
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":[]}
@@ -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":"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","ignoreList":[]}
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.5",
4
- "description": "Public React Native VoIP SDK backed by PJSIP (VoipCloud).",
3
+ "version": "1.0.6",
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
  },