@voipsdk/react-native-voipcloud 0.2.1 → 1.0.1
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 +44 -0
- package/README.md +182 -117
- package/android/build.gradle +7 -7
- package/android/src/main/java/com/voipcloud/sdk/rn/VoipCloudModule.java +307 -208
- 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/java/com/voipcloud/sdk/rn/internal/ManagedAccount.java +49 -5
- package/android/src/main/java/com/voipcloud/sdk/rn/internal/ManagedCall.java +58 -2
- package/android/src/main/java/com/voipcloud/sdk/rn/internal/ManagedCallRegistry.java +4 -0
- package/android/src/main/libs/voipcloud-release.aar +0 -0
- package/ios/VoipCloud.mm +8 -8
- package/lib/commonjs/VoipCloud.js +33 -48
- 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 +34 -48
- 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 +7 -31
- 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 +5 -17
- package/package.json +7 -5
- package/react-native-voipcloud.podspec +7 -5
- package/src/VoipCloud.ts +42 -49
- package/src/events.ts +9 -8
- package/src/index.ts +1 -3
- package/src/nativeModule.ts +17 -0
- package/src/types.ts +5 -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
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
package com.voipcloud.sdk.rn.internal;
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Promise;
|
|
4
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Shared guards and input validation for the RN bridge — reject with clear
|
|
8
|
+
* VC_* codes instead of letting native/JNI exceptions crash the app.
|
|
9
|
+
*/
|
|
10
|
+
public final class BridgeGuard {
|
|
11
|
+
|
|
12
|
+
private static volatile boolean nativeLoaded = false;
|
|
13
|
+
private static volatile String nativeLoadError =
|
|
14
|
+
"libvoipcloud.so failed to load (missing ABI, stale build, or AAR not packaged)";
|
|
15
|
+
|
|
16
|
+
/** Loads libvoipcloud.so before any SWIG type (Endpoint, voipcloudJNI). */
|
|
17
|
+
static {
|
|
18
|
+
try {
|
|
19
|
+
System.loadLibrary("voipcloud");
|
|
20
|
+
nativeLoaded = true;
|
|
21
|
+
} catch (UnsatisfiedLinkError e) {
|
|
22
|
+
nativeLoadError = "Failed to load libvoipcloud.so: " + e.getMessage()
|
|
23
|
+
+ ". Ensure voipcloud-release.aar is included and the app was rebuilt.";
|
|
24
|
+
} catch (Throwable t) {
|
|
25
|
+
nativeLoadError = "Failed to load libvoipcloud.so: " + t.getMessage();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private BridgeGuard() {}
|
|
30
|
+
|
|
31
|
+
public static boolean isNativeLoaded() { return nativeLoaded; }
|
|
32
|
+
|
|
33
|
+
public static String nativeLoadError() { return nativeLoadError; }
|
|
34
|
+
|
|
35
|
+
/** Reject the promise if native .so did not load. Returns false when rejected. */
|
|
36
|
+
public static boolean ensureNative(Promise promise) {
|
|
37
|
+
if (nativeLoaded) return true;
|
|
38
|
+
promise.reject("VC_NATIVE_LOAD", nativeLoadError);
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Reject if {@link VoipCloudModule} endpoint is not running. */
|
|
43
|
+
public static boolean ensureInited(boolean inited, Promise promise) {
|
|
44
|
+
if (inited) return true;
|
|
45
|
+
promise.reject("VC_NOT_INITIALIZED",
|
|
46
|
+
"VoipCloud.init() must succeed before calling this method.");
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Read a required non-empty string field from a JS config object.
|
|
52
|
+
* Rejects with VC_INVALID_ARGUMENT and returns null on failure.
|
|
53
|
+
*/
|
|
54
|
+
public static String requireString(ReadableMap map, String key, Promise promise) {
|
|
55
|
+
if (map == null || !map.hasKey(key) || map.isNull(key)) {
|
|
56
|
+
promise.reject("VC_INVALID_ARGUMENT", "Missing required field: " + key);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
String value = map.getString(key);
|
|
60
|
+
if (value == null || value.trim().isEmpty()) {
|
|
61
|
+
promise.reject("VC_INVALID_ARGUMENT", "Field must not be empty: " + key);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return value.trim();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Reject with a stable code; message includes PJSIP detail when available. */
|
|
68
|
+
public static void reject(Promise promise, String code, String context, Throwable t) {
|
|
69
|
+
String detail = (t != null && t.getMessage() != null && !t.getMessage().isEmpty())
|
|
70
|
+
? t.getMessage()
|
|
71
|
+
: (t != null ? t.getClass().getSimpleName() : "unknown error");
|
|
72
|
+
promise.reject(code, context + ": " + detail, t);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -32,7 +32,12 @@ public final class Events {
|
|
|
32
32
|
|
|
33
33
|
public static void emit(ReactContext ctx, String name, WritableMap payload) {
|
|
34
34
|
if (ctx == null || !ctx.hasActiveReactInstance()) return;
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
// PJSIP fires callbacks on its worker thread — hop to the RN UI queue
|
|
36
|
+
// so DeviceEventEmitter does not crash the app on some RN versions.
|
|
37
|
+
ctx.runOnUiQueueThread(() -> {
|
|
38
|
+
if (!ctx.hasActiveReactInstance()) return;
|
|
39
|
+
ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
40
|
+
.emit(name, payload);
|
|
41
|
+
});
|
|
37
42
|
}
|
|
38
43
|
}
|
|
@@ -7,8 +7,10 @@ import com.facebook.react.bridge.WritableMap;
|
|
|
7
7
|
import com.voipcloud.sdk.Account;
|
|
8
8
|
import com.voipcloud.sdk.AccountInfo;
|
|
9
9
|
import com.voipcloud.sdk.CallOpParam;
|
|
10
|
+
import com.voipcloud.sdk.Endpoint;
|
|
10
11
|
import com.voipcloud.sdk.OnIncomingCallParam;
|
|
11
12
|
import com.voipcloud.sdk.OnRegStateParam;
|
|
13
|
+
import com.voipcloud.sdk.pjsip_status_code;
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Account subclass forwarding PJSUA2 callbacks to JS as RN events.
|
|
@@ -17,10 +19,12 @@ import com.voipcloud.sdk.OnRegStateParam;
|
|
|
17
19
|
public final class ManagedAccount extends Account {
|
|
18
20
|
private final ReactContext ctx;
|
|
19
21
|
private final ManagedCallRegistry callRegistry;
|
|
22
|
+
private final Endpoint endpoint;
|
|
20
23
|
|
|
21
|
-
public ManagedAccount(ReactContext ctx, ManagedCallRegistry callRegistry) {
|
|
24
|
+
public ManagedAccount(ReactContext ctx, ManagedCallRegistry callRegistry, Endpoint endpoint) {
|
|
22
25
|
this.ctx = ctx;
|
|
23
26
|
this.callRegistry = callRegistry;
|
|
27
|
+
this.endpoint = endpoint;
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
public int accountId() {
|
|
@@ -41,23 +45,63 @@ public final class ManagedAccount extends Account {
|
|
|
41
45
|
// Allocate a ManagedCall so we can fire callState events for
|
|
42
46
|
// this inbound leg. The consumer must call answer(callId) or
|
|
43
47
|
// hangup(callId) to proceed.
|
|
44
|
-
ManagedCall call = new ManagedCall(ctx, this, prm.getCallId());
|
|
48
|
+
ManagedCall call = new ManagedCall(ctx, this, prm.getCallId(), callRegistry);
|
|
49
|
+
call.bindEndpoint(endpoint);
|
|
45
50
|
callRegistry.put(call);
|
|
46
51
|
|
|
52
|
+
// Send 180 Ringing immediately: without a provisional response the
|
|
53
|
+
// caller hears dead silence and many PBX/trunk setups drop the call
|
|
54
|
+
// before the callee can answer.
|
|
55
|
+
try {
|
|
56
|
+
CallOpParam ringing = new CallOpParam();
|
|
57
|
+
ringing.setStatusCode(pjsip_status_code.PJSIP_SC_RINGING);
|
|
58
|
+
call.answer(ringing);
|
|
59
|
+
} catch (Throwable ignored) {}
|
|
60
|
+
|
|
61
|
+
String from = "";
|
|
62
|
+
String to = "";
|
|
47
63
|
try {
|
|
48
64
|
AccountInfo accInfo = getInfo();
|
|
65
|
+
com.voipcloud.sdk.CallInfo callInfo = call.getInfo();
|
|
66
|
+
from = callInfo.getRemoteUri();
|
|
67
|
+
to = accInfo.getUri();
|
|
49
68
|
WritableMap payload = Arguments.createMap();
|
|
50
69
|
payload.putInt("accountId", accountId());
|
|
51
70
|
payload.putInt("callId", call.callId());
|
|
52
|
-
payload.putString("from",
|
|
53
|
-
payload.putString("to",
|
|
71
|
+
payload.putString("from", from);
|
|
72
|
+
payload.putString("to", to);
|
|
73
|
+
// SIP Call-ID header — stable across systems (PBX CDR, CRM sync),
|
|
74
|
+
// unlike the numeric PJSUA call slot which is recycled.
|
|
75
|
+
payload.putString("sipCallId", callInfo.getCallIdString());
|
|
54
76
|
Events.emit(ctx, Events.INCOMING_CALL, payload);
|
|
55
77
|
} catch (Exception ignored) {
|
|
56
|
-
// If we cannot pull info, still notify with what we have.
|
|
57
78
|
WritableMap payload = Arguments.createMap();
|
|
58
79
|
payload.putInt("accountId", accountId());
|
|
59
80
|
payload.putInt("callId", call.callId());
|
|
60
81
|
Events.emit(ctx, Events.INCOMING_CALL, payload);
|
|
61
82
|
}
|
|
83
|
+
dispatchIncomingToApp(ctx, accountId(), call.callId(), from, to);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Notify VoicePBX native layer before JS (background incoming calls). */
|
|
87
|
+
private static void dispatchIncomingToApp(
|
|
88
|
+
ReactContext ctx, int accountId, int callId, String from, String to) {
|
|
89
|
+
try {
|
|
90
|
+
Class<?> cls = Class.forName("com.voicepbx.voip.VoipIncomingNotifier");
|
|
91
|
+
cls.getMethod(
|
|
92
|
+
"onIncomingCall",
|
|
93
|
+
android.content.Context.class,
|
|
94
|
+
int.class,
|
|
95
|
+
int.class,
|
|
96
|
+
String.class,
|
|
97
|
+
String.class)
|
|
98
|
+
.invoke(
|
|
99
|
+
null,
|
|
100
|
+
ctx.getApplicationContext(),
|
|
101
|
+
accountId,
|
|
102
|
+
callId,
|
|
103
|
+
from != null ? from : "",
|
|
104
|
+
to != null ? to : "");
|
|
105
|
+
} catch (Throwable ignored) {}
|
|
62
106
|
}
|
|
63
107
|
}
|
|
@@ -22,23 +22,31 @@ import com.voipcloud.sdk.pjsua_call_media_status;
|
|
|
22
22
|
/** Call subclass forwarding state callbacks to JS. */
|
|
23
23
|
public final class ManagedCall extends Call {
|
|
24
24
|
private final ReactContext ctx;
|
|
25
|
+
private final ManagedCallRegistry registry;
|
|
25
26
|
/** Local snapshot of the PJSUA call id — Call.getId() can throw post-disconnect. */
|
|
26
27
|
private final int cachedId;
|
|
27
28
|
/** Mute is tracked at the bridge level — PJSIP does not own this state. */
|
|
28
29
|
private volatile boolean isMuted = false;
|
|
30
|
+
private Endpoint endpoint;
|
|
29
31
|
|
|
30
|
-
public ManagedCall(ReactContext ctx, Account acc) {
|
|
32
|
+
public ManagedCall(ReactContext ctx, Account acc, ManagedCallRegistry registry) {
|
|
31
33
|
super(acc);
|
|
32
34
|
this.ctx = ctx;
|
|
35
|
+
this.registry = registry;
|
|
33
36
|
this.cachedId = -1;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
|
-
public ManagedCall(ReactContext ctx, Account acc, int callId) {
|
|
39
|
+
public ManagedCall(ReactContext ctx, Account acc, int callId, ManagedCallRegistry registry) {
|
|
37
40
|
super(acc, callId);
|
|
38
41
|
this.ctx = ctx;
|
|
42
|
+
this.registry = registry;
|
|
39
43
|
this.cachedId = callId;
|
|
40
44
|
}
|
|
41
45
|
|
|
46
|
+
public void bindEndpoint(Endpoint ep) {
|
|
47
|
+
this.endpoint = ep;
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
public int callId() {
|
|
43
51
|
try { return getId(); } catch (Exception e) { return cachedId; }
|
|
44
52
|
}
|
|
@@ -54,6 +62,7 @@ public final class ManagedCall extends Call {
|
|
|
54
62
|
* tracked so unhold-then-emit reflects the user's intent.
|
|
55
63
|
*/
|
|
56
64
|
public void setMuted(Endpoint endpoint, boolean muted) throws Exception {
|
|
65
|
+
this.endpoint = endpoint;
|
|
57
66
|
AudDevManager adm = endpoint.audDevManager();
|
|
58
67
|
AudioMedia mic = adm.getCaptureDevMedia();
|
|
59
68
|
CallInfo info = getInfo();
|
|
@@ -74,6 +83,43 @@ public final class ManagedCall extends Call {
|
|
|
74
83
|
emitMediaState();
|
|
75
84
|
}
|
|
76
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Re-wire capture ↔ call ↔ playback (e.g. after hold/unhold or speaker change).
|
|
88
|
+
*/
|
|
89
|
+
public void reconnectAudioMedia() {
|
|
90
|
+
connectAudioMedia();
|
|
91
|
+
emitMediaState();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Wire capture ↔ call ↔ playback whenever media becomes active.
|
|
96
|
+
* Required for two-way audio — PJSIP does not auto-bridge on Android.
|
|
97
|
+
*/
|
|
98
|
+
private void connectAudioMedia() {
|
|
99
|
+
if (endpoint == null) return;
|
|
100
|
+
try {
|
|
101
|
+
AudDevManager adm = endpoint.audDevManager();
|
|
102
|
+
AudioMedia mic = adm.getCaptureDevMedia();
|
|
103
|
+
AudioMedia speaker = adm.getPlaybackDevMedia();
|
|
104
|
+
CallInfo info = getInfo();
|
|
105
|
+
for (int i = 0; i < info.getMedia().size(); i++) {
|
|
106
|
+
CallMediaInfo mi = info.getMedia().get(i);
|
|
107
|
+
if (mi.getType() != pjmedia_type.PJMEDIA_TYPE_AUDIO) continue;
|
|
108
|
+
AudioMedia leg = getAudioMedia(i);
|
|
109
|
+
int status = mi.getStatus();
|
|
110
|
+
if (status == pjsua_call_media_status.PJSUA_CALL_MEDIA_ACTIVE) {
|
|
111
|
+
if (!isMuted) {
|
|
112
|
+
mic.startTransmit(leg);
|
|
113
|
+
}
|
|
114
|
+
leg.startTransmit(speaker);
|
|
115
|
+
} else {
|
|
116
|
+
try { mic.stopTransmit(leg); } catch (Exception ignored) {}
|
|
117
|
+
try { leg.stopTransmit(speaker); } catch (Exception ignored) {}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} catch (Exception ignored) {}
|
|
121
|
+
}
|
|
122
|
+
|
|
77
123
|
@Override
|
|
78
124
|
public void onCallState(OnCallStateParam prm) {
|
|
79
125
|
CallInfo info;
|
|
@@ -86,6 +132,7 @@ public final class ManagedCall extends Call {
|
|
|
86
132
|
p.putInt("code", 0);
|
|
87
133
|
p.putString("reason", "");
|
|
88
134
|
Events.emit(ctx, Events.CALL_STATE, p);
|
|
135
|
+
if (cachedId >= 0) registry.remove(cachedId);
|
|
89
136
|
return;
|
|
90
137
|
}
|
|
91
138
|
WritableMap p = Arguments.createMap();
|
|
@@ -93,11 +140,20 @@ public final class ManagedCall extends Call {
|
|
|
93
140
|
p.putString("state", invStateName(info.getState()));
|
|
94
141
|
p.putInt("code", info.getLastStatusCode());
|
|
95
142
|
p.putString("reason", info.getLastReason());
|
|
143
|
+
// SIP Call-ID header — lets JS attach the dialog id to outgoing
|
|
144
|
+
// calls too (makeCall only returns the recycled PJSUA slot).
|
|
145
|
+
try { p.putString("sipCallId", info.getCallIdString()); } catch (Exception ignored) {}
|
|
96
146
|
Events.emit(ctx, Events.CALL_STATE, p);
|
|
147
|
+
int state = info.getState();
|
|
148
|
+
if (state == pjsip_inv_state.PJSIP_INV_STATE_DISCONNECTED
|
|
149
|
+
|| state == pjsip_inv_state.PJSIP_INV_STATE_NULL) {
|
|
150
|
+
registry.remove(callId());
|
|
151
|
+
}
|
|
97
152
|
}
|
|
98
153
|
|
|
99
154
|
@Override
|
|
100
155
|
public void onCallMediaState(OnCallMediaStateParam prm) {
|
|
156
|
+
connectAudioMedia();
|
|
101
157
|
emitMediaState();
|
|
102
158
|
}
|
|
103
159
|
|
|
Binary file
|
package/ios/VoipCloud.mm
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
// react-native-voipcloud — iOS placeholder.
|
|
1
|
+
// @voipsdk/react-native-voipcloud — iOS placeholder.
|
|
2
2
|
//
|
|
3
3
|
// The Android build of the SDK is complete (libvoipcloud.so + JNI
|
|
4
4
|
// bridge). iOS bindings need an xcframework build of PJSIP, which
|
|
5
5
|
// requires Xcode on macOS. Until then, every JS call from iOS rejects
|
|
6
6
|
// with NOT_IMPLEMENTED so consumer apps notice early.
|
|
7
|
+
//
|
|
8
|
+
// Native module name must match VoipCloudModule.getName() on Android
|
|
9
|
+
// and NATIVE_MODULE_NAME in src/nativeModule.ts.
|
|
7
10
|
|
|
8
11
|
#import <React/RCTBridgeModule.h>
|
|
9
12
|
|
|
10
|
-
@interface
|
|
13
|
+
@interface VoipsdkReactNativeVoipcloud : NSObject <RCTBridgeModule>
|
|
11
14
|
@end
|
|
12
15
|
|
|
13
|
-
@implementation
|
|
16
|
+
@implementation VoipsdkReactNativeVoipcloud
|
|
14
17
|
|
|
15
|
-
RCT_EXPORT_MODULE(
|
|
18
|
+
RCT_EXPORT_MODULE();
|
|
16
19
|
|
|
17
20
|
#define VC_STUB(name, ...) \
|
|
18
21
|
RCT_EXPORT_METHOD(name:(__VA_ARGS__) \
|
|
19
22
|
resolver:(RCTPromiseResolveBlock)resolve \
|
|
20
23
|
rejecter:(RCTPromiseRejectBlock)reject) \
|
|
21
|
-
{ reject(@"VC_NOT_IMPLEMENTED", @"
|
|
24
|
+
{ reject(@"VC_NOT_IMPLEMENTED", @"@voipsdk/react-native-voipcloud iOS bindings not yet shipped.", nil); }
|
|
22
25
|
|
|
23
|
-
VC_STUB(setLicense, NSString *token)
|
|
24
|
-
VC_STUB(getLicenseStatus)
|
|
25
|
-
VC_STUB(stopLicenseRefresh)
|
|
26
26
|
VC_STUB(init_, NSDictionary *config) // renamed because of init clash
|
|
27
27
|
VC_STUB(shutdown)
|
|
28
28
|
VC_STUB(register, NSDictionary *cfg)
|
|
@@ -4,86 +4,71 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.VoipCloud = void 0;
|
|
7
|
-
var
|
|
8
|
-
var _License = require("./License");
|
|
7
|
+
var _nativeModule = require("./nativeModule");
|
|
9
8
|
var _events = require("./events");
|
|
10
|
-
|
|
9
|
+
/** Thrown as Promise rejection — never crashes at import time. */
|
|
10
|
+
function rejectNotLinked() {
|
|
11
|
+
return Promise.reject(Object.assign(new Error('@voipsdk/react-native-voipcloud native module is not linked. ' + 'Install the package, rebuild the Android app ' + '(./gradlew clean assembleDebug), and ensure voipcloud-release.aar is packaged.'), {
|
|
12
|
+
code: 'VC_NOT_LINKED'
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
function callNative(fn) {
|
|
16
|
+
if (!_nativeModule.NativeVoipCloud) return rejectNotLinked();
|
|
17
|
+
return fn();
|
|
18
|
+
}
|
|
11
19
|
|
|
12
20
|
/**
|
|
13
|
-
* Top-level VoIP SDK. Workflow:
|
|
21
|
+
* Top-level VoIP SDK for {@code @voipsdk/react-native-voipcloud}. Workflow:
|
|
14
22
|
*
|
|
15
|
-
* 1. {@link
|
|
16
|
-
* 2. {@link
|
|
17
|
-
* 3. {@link
|
|
18
|
-
* 4. {@link makeCall} / {@link answer} / {@link hangup}.
|
|
23
|
+
* 1. {@link init} — start the PJSIP endpoint.
|
|
24
|
+
* 2. {@link register} — get an `accountId` back.
|
|
25
|
+
* 3. {@link makeCall} / {@link answer} / {@link hangup}.
|
|
19
26
|
*
|
|
20
|
-
* Every method returns a Promise.
|
|
21
|
-
* Promise rejection with `code = "VC_<NAME>"` matching the
|
|
22
|
-
* `PJ_EVOIPCLOUD_*` enum from `voipcloud_errno.h`.
|
|
27
|
+
* Every method returns a Promise. Failures reject with a `VC_*` code.
|
|
23
28
|
*/
|
|
24
29
|
const VoipCloud = exports.VoipCloud = {
|
|
25
|
-
// ---------------------- License ---------------------------------
|
|
26
|
-
License: _License.License,
|
|
27
|
-
// ---------------------- Lifecycle -------------------------------
|
|
28
30
|
init(cfg = {}) {
|
|
29
|
-
return
|
|
31
|
+
return callNative(() => _nativeModule.NativeVoipCloud.init(cfg ?? {}));
|
|
30
32
|
},
|
|
31
33
|
shutdown() {
|
|
32
|
-
return
|
|
34
|
+
return callNative(() => _nativeModule.NativeVoipCloud.shutdown());
|
|
33
35
|
},
|
|
34
|
-
// ---------------------- Accounts --------------------------------
|
|
35
|
-
/** Register a new SIP account. Resolves with the account id. */
|
|
36
36
|
register(account) {
|
|
37
|
-
return
|
|
37
|
+
return callNative(() => _nativeModule.NativeVoipCloud.register(account));
|
|
38
38
|
},
|
|
39
39
|
unregister(accountId) {
|
|
40
|
-
return
|
|
40
|
+
return callNative(() => _nativeModule.NativeVoipCloud.unregister(accountId));
|
|
41
41
|
},
|
|
42
|
-
// ---------------------- Calls -----------------------------------
|
|
43
|
-
/** Place an outbound call. Resolves with the new callId. */
|
|
44
42
|
makeCall(accountId, destinationUri) {
|
|
45
|
-
return
|
|
43
|
+
return callNative(() => _nativeModule.NativeVoipCloud.makeCall(accountId, destinationUri));
|
|
46
44
|
},
|
|
47
45
|
answer(callId) {
|
|
48
|
-
return
|
|
46
|
+
return callNative(() => _nativeModule.NativeVoipCloud.answer(callId));
|
|
49
47
|
},
|
|
50
|
-
hangup(callId) {
|
|
51
|
-
return
|
|
48
|
+
hangup(callId, mode = 'normal') {
|
|
49
|
+
return callNative(() => _nativeModule.NativeVoipCloud.hangup(callId, mode));
|
|
52
50
|
},
|
|
53
51
|
hold(callId) {
|
|
54
|
-
return
|
|
52
|
+
return callNative(() => _nativeModule.NativeVoipCloud.hold(callId));
|
|
55
53
|
},
|
|
56
54
|
unhold(callId) {
|
|
57
|
-
return
|
|
55
|
+
return callNative(() => _nativeModule.NativeVoipCloud.unhold(callId));
|
|
58
56
|
},
|
|
59
|
-
/**
|
|
60
|
-
* Mute / unmute the local microphone for a call. Implemented by
|
|
61
|
-
* stopping / starting the capture device's transmission to the
|
|
62
|
-
* call's active audio media — independent of `hold`. A
|
|
63
|
-
* `callMediaState` event fires after the toggle so the UI can
|
|
64
|
-
* mirror the new `isMuted` flag without polling.
|
|
65
|
-
*/
|
|
66
57
|
mute(callId, on) {
|
|
67
|
-
return
|
|
58
|
+
return callNative(() => _nativeModule.NativeVoipCloud.mute(callId, on));
|
|
68
59
|
},
|
|
69
60
|
sendDtmf(callId, digits) {
|
|
70
|
-
return
|
|
61
|
+
return callNative(() => _nativeModule.NativeVoipCloud.sendDtmf(callId, digits));
|
|
71
62
|
},
|
|
72
|
-
/**
|
|
73
|
-
* Blind-transfer a call (SIP REFER) to a new destination. The
|
|
74
|
-
* local leg moves to DISCONNECTED once the remote party accepts.
|
|
75
|
-
*/
|
|
76
63
|
transferCall(callId, destinationUri) {
|
|
77
|
-
return
|
|
64
|
+
return callNative(() => _nativeModule.NativeVoipCloud.transferCall(callId, destinationUri));
|
|
78
65
|
},
|
|
79
|
-
/**
|
|
80
|
-
* End every active call. Each call still emits its own
|
|
81
|
-
* `callState` event with state=DISCONNECTED.
|
|
82
|
-
*/
|
|
83
66
|
hangupAllCalls() {
|
|
84
|
-
return
|
|
67
|
+
return callNative(() => _nativeModule.NativeVoipCloud.hangupAllCalls());
|
|
68
|
+
},
|
|
69
|
+
reconnectCallAudio(callId) {
|
|
70
|
+
return callNative(() => _nativeModule.NativeVoipCloud.reconnectCallAudio(callId));
|
|
85
71
|
},
|
|
86
|
-
// ---------------------- Events ----------------------------------
|
|
87
72
|
on: _events.on
|
|
88
73
|
};
|
|
89
74
|
//# sourceMappingURL=VoipCloud.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
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":[]}
|
package/lib/commonjs/events.js
CHANGED
|
@@ -3,17 +3,21 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
Object.defineProperty(exports, "NATIVE_MODULE_NAME", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _nativeModule.NATIVE_MODULE_NAME;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
6
12
|
exports.on = on;
|
|
7
13
|
var _reactNative = require("react-native");
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// Lazy emitter — must point at the module to satisfy the contract
|
|
11
|
-
// NativeEventEmitter expects on RN 0.65+.
|
|
12
|
-
const emitter = Native ? new _reactNative.NativeEventEmitter(Native) : null;
|
|
14
|
+
var _nativeModule = require("./nativeModule");
|
|
15
|
+
const emitter = _nativeModule.NativeVoipCloud ? new _reactNative.NativeEventEmitter(_nativeModule.NativeVoipCloud) : null;
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
|
-
* Subscribe to a typed event
|
|
16
|
-
* be called from a React `useEffect`
|
|
18
|
+
* Subscribe to a typed event from {@code @voipsdk/react-native-voipcloud}.
|
|
19
|
+
* Returns a handle whose `remove()` must be called from a React `useEffect`
|
|
20
|
+
* cleanup to avoid leaks.
|
|
17
21
|
*/
|
|
18
22
|
function on(name, callback) {
|
|
19
23
|
if (!emitter) {
|
|
@@ -26,4 +30,6 @@ function on(name, callback) {
|
|
|
26
30
|
remove: () => sub.remove()
|
|
27
31
|
};
|
|
28
32
|
}
|
|
33
|
+
|
|
34
|
+
/** Native module name registered with React Native (for debugging). */
|
|
29
35
|
//# sourceMappingURL=events.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","
|
|
1
|
+
{"version":3,"names":["_reactNative","require","_nativeModule","emitter","NativeVoipCloud","NativeEventEmitter","on","name","callback","remove","sub","addListener"],"sourceRoot":"../../src","sources":["events.ts"],"mappings":";;;;;;;;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEA,IAAAC,aAAA,GAAAD,OAAA;AAEA,MAAME,OAAO,GAAGC,6BAAe,GAAG,IAAIC,+BAAkB,CAACD,6BAAe,CAAC,GAAG,IAAI;;AAEhF;AACA;AACA;AACA;AACA;AACO,SAASE,EAAEA,CACdC,IAAO,EACPC,QAAsC,EAC1B;EACZ,IAAI,CAACL,OAAO,EAAE;IACV,OAAO;MAAEM,MAAM,EAAEA,CAAA,KAAM,CAAC;IAAE,CAAC;EAC/B;EACA,MAAMC,GAAG,GAAGP,OAAO,CAACQ,WAAW,CAACJ,IAAI,EAAEC,QAAgC,CAAC;EACvE,OAAO;IAAEC,MAAM,EAAEA,CAAA,KAAMC,GAAG,CAACD,MAAM,CAAC;EAAE,CAAC;AACzC;;AAEA","ignoreList":[]}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
Object.defineProperty(exports, "
|
|
6
|
+
Object.defineProperty(exports, "NATIVE_MODULE_NAME", {
|
|
7
7
|
enumerable: true,
|
|
8
8
|
get: function () {
|
|
9
|
-
return
|
|
9
|
+
return _events.NATIVE_MODULE_NAME;
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
12
|
Object.defineProperty(exports, "VoipCloud", {
|
|
@@ -22,6 +22,5 @@ Object.defineProperty(exports, "addEventListener", {
|
|
|
22
22
|
}
|
|
23
23
|
});
|
|
24
24
|
var _VoipCloud = require("./VoipCloud");
|
|
25
|
-
var _License = require("./License");
|
|
26
25
|
var _events = require("./events");
|
|
27
26
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_VoipCloud","require","
|
|
1
|
+
{"version":3,"names":["_VoipCloud","require","_events"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,UAAA,GAAAC,OAAA;AACA,IAAAC,OAAA,GAAAD,OAAA","ignoreList":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.NativeVoipCloud = exports.NATIVE_MODULE_NAME = void 0;
|
|
7
|
+
var _reactNative = require("react-native");
|
|
8
|
+
/**
|
|
9
|
+
* Native module name — must match {@code VoipCloudModule.getName()} on Android
|
|
10
|
+
* and the future iOS RCT export. Derived from npm package
|
|
11
|
+
* {@code @voipsdk/react-native-voipcloud}.
|
|
12
|
+
*/
|
|
13
|
+
const NATIVE_MODULE_NAME = exports.NATIVE_MODULE_NAME = 'VoipsdkReactNativeVoipcloud';
|
|
14
|
+
const NativeVoipCloud = exports.NativeVoipCloud = _reactNative.NativeModules[NATIVE_MODULE_NAME];
|
|
15
|
+
if (!NativeVoipCloud) {
|
|
16
|
+
console.warn('[@voipsdk/react-native-voipcloud] Native module not linked. ' + 'Methods will reject with VC_NOT_LINKED until the app is rebuilt.');
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=nativeModule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNative","require","NATIVE_MODULE_NAME","exports","NativeVoipCloud","NativeModules","console","warn"],"sourceRoot":"../../src","sources":["nativeModule.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEA;AACA;AACA;AACA;AACA;AACO,MAAMC,kBAAkB,GAAAC,OAAA,CAAAD,kBAAA,GAAG,6BAA6B;AAExD,MAAME,eAAe,GAAAD,OAAA,CAAAC,eAAA,GAAGC,0BAAa,CAACH,kBAAkB,CAAC;AAEhE,IAAI,CAACE,eAAe,EAAE;EAClBE,OAAO,CAACC,IAAI,CACR,8DAA8D,GAC9D,kEACJ,CAAC;AACL","ignoreList":[]}
|