@ondewo/sip-client-nodejs 5.4.1 → 5.5.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 +94 -0
- package/api/ondewo/sip/sip_grpc_pb.d.ts +50 -0
- package/api/ondewo/sip/sip_grpc_pb.js +143 -8
- package/api/ondewo/sip/sip_pb.d.ts +439 -0
- package/api/ondewo/sip/sip_pb.js +3556 -482
- package/auth/grpcChannel.d.ts +146 -0
- package/auth/grpcChannel.js +346 -0
- package/auth/grpcChannel.spec.ts +747 -0
- package/auth/grpcChannel.ts +408 -0
- package/auth/offlineTokenProvider.d.ts +9 -5
- package/auth/offlineTokenProvider.js +86 -100
- package/package.json +1 -1
- package/public-api.d.ts +4 -2
- package/public-api.js +16 -6
package/README.md
CHANGED
|
@@ -70,3 +70,97 @@ npm
|
|
|
70
70
|
└── README.md
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
## TLS, mutual TLS and certificates
|
|
74
|
+
|
|
75
|
+
gRPC encrypts with **TLS** ("SSL" in names such as `credentials.createSsl` or `grpc.ssl_target_name_override` is legacy naming). The package ships a channel helper, `auth/grpcChannel` (exported from the package root), that builds the `@grpc/grpc-js` credentials and channel options for every generated client:
|
|
76
|
+
|
|
77
|
+
| Mode | `useSecureChannel` | Config fields |
|
|
78
|
+
|-----------------------------------------|--------------------|-----------------------------------------------------------------|
|
|
79
|
+
| Plaintext (not for production) | `false` | none |
|
|
80
|
+
| TLS, server verified by the trust store | `true` (default) | none |
|
|
81
|
+
| TLS, server verified by your CA | `true` (default) | `grpcCert` = PEM of the CA that signed the server certificate |
|
|
82
|
+
| Mutual TLS | `true` (default) | `grpcCert` (optional) plus `grpcClientCert` and `grpcClientKey` |
|
|
83
|
+
|
|
84
|
+
Rules the code enforces:
|
|
85
|
+
|
|
86
|
+
- The three fields hold **PEM content** (`string` or `Buffer`), **not file paths**. Read the files yourself; a value without a PEM header line is refused.
|
|
87
|
+
- `grpcClientCert` and `grpcClientKey` go together: setting only one throws when the `GrpcClientConfig` is built, and `createChannelCredentials` refuses half a pair again before anything reaches gRPC. Empty strings on both mean plain server-authenticated TLS.
|
|
88
|
+
- `useSecureChannel: false` with a client certificate throws instead of silently dropping the identity. A plaintext channel otherwise logs a warning naming `host:port` (through `console.warn`, or the `logger` you pass).
|
|
89
|
+
- Without `grpcCert` the server is verified against Node's default CA store (Node's bundled Mozilla roots plus `NODE_EXTRA_CA_CERTS`; start Node with `--use-system-ca` to use the operating system's store instead).
|
|
90
|
+
- The host you connect to must match a subject alternative name (SAN) of the server certificate. When you connect by IP and the certificate has no IP SAN, pass the name to check as the channel option `'grpc.ssl_target_name_override'`.
|
|
91
|
+
- A bare IPv6 host is bracketed for you (`::1` becomes `[::1]:50051`).
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
import { readFileSync } from 'fs';
|
|
95
|
+
|
|
96
|
+
import * as grpc from '@grpc/grpc-js';
|
|
97
|
+
import { createChannelCredentials, createGrpcClient, GrpcClientConfig, SipClient } from '@ondewo/sip-client-nodejs';
|
|
98
|
+
|
|
99
|
+
const config = new GrpcClientConfig({
|
|
100
|
+
host: '10.0.0.5',
|
|
101
|
+
port: 50051,
|
|
102
|
+
grpcCert: readFileSync('certs/ca.pem'),
|
|
103
|
+
grpcClientCert: readFileSync('certs/client.pem'), // leave both out for server-authenticated TLS
|
|
104
|
+
grpcClientKey: readFileSync('certs/client.key')
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const client: SipClient = createGrpcClient(SipClient, config, {
|
|
108
|
+
channelOptions: { 'grpc.ssl_target_name_override': 'sip.example.internal' } // only when connecting by IP
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`createGrpcClient` starts from `DEFAULT_GRPC_CHANNEL_OPTIONS` (maximum message size 2³¹-1 bytes in both directions, reconnect backoff capped at 5 s) and applies your `channelOptions` on top. To build credentials only, call `createChannelCredentials(config, { useSecureChannel })` and pass the result to any generated client constructor.
|
|
113
|
+
|
|
114
|
+
**One connection for several services.** Clients built with the **same credentials object** (and the same target and options) share one connection, so the TLS handshake happens once:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
const credentials: grpc.ChannelCredentials = createChannelCredentials(config);
|
|
118
|
+
const first = createGrpcClient(SipClient, config, { credentials });
|
|
119
|
+
const second = createGrpcClient(SipClient, config, { credentials }); // any other generated client works the same way
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Keepalive is off by default.** `@grpc/grpc-js` has no `grpc.http2.max_pings_without_data`, so with `grpc.keepalive_time_ms` set it keeps pinging a stream that carries no data, and a grpc-core server (as every ONDEWO server is) answers with `GOAWAY too_many_pings`: the call fails with `RESOURCE_EXHAUSTED` (measured: after 150 s at a 30 s keepalive). The Python SDKs' 30 s keepalive therefore is not copied; set `grpc.keepalive_time_ms` yourself only against a server whose `grpc.http2.min_ping_interval_without_data_ms` allows it. `grpc.keepalive_timeout_ms` is preset to 20 s for that case.
|
|
123
|
+
|
|
124
|
+
### A test PKI with openssl
|
|
125
|
+
|
|
126
|
+
A CA, a server certificate with SANs and a client certificate with the `clientAuth` extended key usage. For tests only: the keys are unencrypted.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes -days 365 \
|
|
130
|
+
-subj "/CN=Test CA" -keyout ca.key -out ca.pem
|
|
131
|
+
|
|
132
|
+
printf 'subjectAltName=DNS:localhost,IP:127.0.0.1\nextendedKeyUsage=serverAuth\n' > server.ext
|
|
133
|
+
openssl req -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes \
|
|
134
|
+
-subj "/CN=localhost" -keyout server.key -out server.csr
|
|
135
|
+
openssl x509 -req -in server.csr -CA ca.pem -CAkey ca.key -CAcreateserial -days 365 \
|
|
136
|
+
-extfile server.ext -out server.pem
|
|
137
|
+
|
|
138
|
+
printf 'extendedKeyUsage=clientAuth\n' > client.ext
|
|
139
|
+
openssl req -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes \
|
|
140
|
+
-subj "/CN=my-client" -keyout client.key -out client.csr
|
|
141
|
+
openssl x509 -req -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial -days 365 \
|
|
142
|
+
-extfile client.ext -out client.pem
|
|
143
|
+
|
|
144
|
+
chmod 600 *.key
|
|
145
|
+
openssl verify -CAfile ca.pem server.pem client.pem
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
The client then uses `ca.pem` / `client.pem` / `client.key`; a server that requires client certificates uses `server.pem` / `server.key` and trusts `ca.pem` for its clients.
|
|
149
|
+
|
|
150
|
+
### TLS security notes
|
|
151
|
+
|
|
152
|
+
- Keep the client key out of source control and out of serialized configs: load it from a file (mode `0600`) or a secret store at startup.
|
|
153
|
+
- `GrpcClientConfig` renders the key as `***REDACTED***` in `toString()`, `util.inspect()` / `console.log()` and `JSON.stringify()` (an empty key renders empty). There is no serializer that writes the key, so a config cannot be persisted with it. A plain object you pass instead of a `GrpcClientConfig` has none of this protection: do not log it.
|
|
154
|
+
- No error message of the helper contains a PEM, a key or a whole config; they name the field and `host:port`.
|
|
155
|
+
|
|
156
|
+
### TLS troubleshooting
|
|
157
|
+
|
|
158
|
+
A failed handshake surfaces as gRPC status `UNAVAILABLE` (14); the cause is in the error's `details`:
|
|
159
|
+
|
|
160
|
+
- **`unable to verify the first certificate`**: the server certificate is not signed by `grpcCert` (or, without `grpcCert`, not by a CA Node trusts). Pass the CA that signed the server certificate.
|
|
161
|
+
- **`ERR_TLS_CERT_ALTNAME_INVALID: Hostname/IP does not match certificate's altnames`**: the host you dial is not a SAN of the server certificate. Dial a name in the certificate, or set `'grpc.ssl_target_name_override'`. Some Node releases (seen on 22.23 and 24.18) also reject an IPv6 literal against a matching IP SAN; the override to a DNS SAN works around it.
|
|
162
|
+
- **`tlsv13 alert certificate required`**: the server requires mutual TLS and the client sent no certificate. Set `grpcClientCert` and `grpcClientKey`.
|
|
163
|
+
- **`Failed to connect`** right after the handshake with a client certificate: the server does not trust the CA that signed `grpcClientCert`.
|
|
164
|
+
- **`... grpcCert is not PEM content (no PEM header line)`** (thrown when the config is built): a field holds a file path or other text instead of the file's content. Pass `readFileSync(path)`.
|
|
165
|
+
- **`createChannelCredentials for host:port: gRPC rejected the TLS material: ... key values mismatch`** (thrown, not a call error): `grpcClientKey` is not the key of `grpcClientCert`. Other OpenSSL reasons there mean a damaged PEM block.
|
|
166
|
+
|
|
@@ -21,6 +21,9 @@ interface ISipService extends grpc.ServiceDefinition<grpc.UntypedServiceImplemen
|
|
|
21
21
|
sipPlayWavFiles: ISipService_ISipPlayWavFiles;
|
|
22
22
|
sipMute: ISipService_ISipMute;
|
|
23
23
|
sipUnMute: ISipService_ISipUnMute;
|
|
24
|
+
sipReportAnsweringMachineDetected: ISipService_ISipReportAnsweringMachineDetected;
|
|
25
|
+
sipSetCallMediaControl: ISipService_ISipSetCallMediaControl;
|
|
26
|
+
sipStreamCallAudio: ISipService_ISipStreamCallAudio;
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
interface ISipService_ISipStartSession extends grpc.MethodDefinition<ondewo_sip_sip_pb.SipStartSessionRequest, ondewo_sip_sip_pb.SipStatus> {
|
|
@@ -122,6 +125,33 @@ interface ISipService_ISipUnMute extends grpc.MethodDefinition<google_protobuf_e
|
|
|
122
125
|
responseSerialize: grpc.serialize<ondewo_sip_sip_pb.SipStatus>;
|
|
123
126
|
responseDeserialize: grpc.deserialize<ondewo_sip_sip_pb.SipStatus>;
|
|
124
127
|
}
|
|
128
|
+
interface ISipService_ISipReportAnsweringMachineDetected extends grpc.MethodDefinition<ondewo_sip_sip_pb.SipReportAnsweringMachineDetectedRequest, ondewo_sip_sip_pb.SipStatus> {
|
|
129
|
+
path: "/ondewo.sip.Sip/SipReportAnsweringMachineDetected";
|
|
130
|
+
requestStream: false;
|
|
131
|
+
responseStream: false;
|
|
132
|
+
requestSerialize: grpc.serialize<ondewo_sip_sip_pb.SipReportAnsweringMachineDetectedRequest>;
|
|
133
|
+
requestDeserialize: grpc.deserialize<ondewo_sip_sip_pb.SipReportAnsweringMachineDetectedRequest>;
|
|
134
|
+
responseSerialize: grpc.serialize<ondewo_sip_sip_pb.SipStatus>;
|
|
135
|
+
responseDeserialize: grpc.deserialize<ondewo_sip_sip_pb.SipStatus>;
|
|
136
|
+
}
|
|
137
|
+
interface ISipService_ISipSetCallMediaControl extends grpc.MethodDefinition<ondewo_sip_sip_pb.SipSetCallMediaControlRequest, ondewo_sip_sip_pb.SipStatus> {
|
|
138
|
+
path: "/ondewo.sip.Sip/SipSetCallMediaControl";
|
|
139
|
+
requestStream: false;
|
|
140
|
+
responseStream: false;
|
|
141
|
+
requestSerialize: grpc.serialize<ondewo_sip_sip_pb.SipSetCallMediaControlRequest>;
|
|
142
|
+
requestDeserialize: grpc.deserialize<ondewo_sip_sip_pb.SipSetCallMediaControlRequest>;
|
|
143
|
+
responseSerialize: grpc.serialize<ondewo_sip_sip_pb.SipStatus>;
|
|
144
|
+
responseDeserialize: grpc.deserialize<ondewo_sip_sip_pb.SipStatus>;
|
|
145
|
+
}
|
|
146
|
+
interface ISipService_ISipStreamCallAudio extends grpc.MethodDefinition<ondewo_sip_sip_pb.SipCallAudioRequest, ondewo_sip_sip_pb.SipCallAudioResponse> {
|
|
147
|
+
path: "/ondewo.sip.Sip/SipStreamCallAudio";
|
|
148
|
+
requestStream: true;
|
|
149
|
+
responseStream: true;
|
|
150
|
+
requestSerialize: grpc.serialize<ondewo_sip_sip_pb.SipCallAudioRequest>;
|
|
151
|
+
requestDeserialize: grpc.deserialize<ondewo_sip_sip_pb.SipCallAudioRequest>;
|
|
152
|
+
responseSerialize: grpc.serialize<ondewo_sip_sip_pb.SipCallAudioResponse>;
|
|
153
|
+
responseDeserialize: grpc.deserialize<ondewo_sip_sip_pb.SipCallAudioResponse>;
|
|
154
|
+
}
|
|
125
155
|
|
|
126
156
|
export const SipService: ISipService;
|
|
127
157
|
|
|
@@ -137,6 +167,9 @@ export interface ISipServer {
|
|
|
137
167
|
sipPlayWavFiles: grpc.handleUnaryCall<ondewo_sip_sip_pb.SipPlayWavFilesRequest, ondewo_sip_sip_pb.SipStatus>;
|
|
138
168
|
sipMute: grpc.handleUnaryCall<google_protobuf_empty_pb.Empty, ondewo_sip_sip_pb.SipStatus>;
|
|
139
169
|
sipUnMute: grpc.handleUnaryCall<google_protobuf_empty_pb.Empty, ondewo_sip_sip_pb.SipStatus>;
|
|
170
|
+
sipReportAnsweringMachineDetected: grpc.handleUnaryCall<ondewo_sip_sip_pb.SipReportAnsweringMachineDetectedRequest, ondewo_sip_sip_pb.SipStatus>;
|
|
171
|
+
sipSetCallMediaControl: grpc.handleUnaryCall<ondewo_sip_sip_pb.SipSetCallMediaControlRequest, ondewo_sip_sip_pb.SipStatus>;
|
|
172
|
+
sipStreamCallAudio: grpc.handleBidiStreamingCall<ondewo_sip_sip_pb.SipCallAudioRequest, ondewo_sip_sip_pb.SipCallAudioResponse>;
|
|
140
173
|
}
|
|
141
174
|
|
|
142
175
|
export interface ISipClient {
|
|
@@ -173,6 +206,15 @@ export interface ISipClient {
|
|
|
173
206
|
sipUnMute(request: google_protobuf_empty_pb.Empty, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
174
207
|
sipUnMute(request: google_protobuf_empty_pb.Empty, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
175
208
|
sipUnMute(request: google_protobuf_empty_pb.Empty, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
209
|
+
sipReportAnsweringMachineDetected(request: ondewo_sip_sip_pb.SipReportAnsweringMachineDetectedRequest, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
210
|
+
sipReportAnsweringMachineDetected(request: ondewo_sip_sip_pb.SipReportAnsweringMachineDetectedRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
211
|
+
sipReportAnsweringMachineDetected(request: ondewo_sip_sip_pb.SipReportAnsweringMachineDetectedRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
212
|
+
sipSetCallMediaControl(request: ondewo_sip_sip_pb.SipSetCallMediaControlRequest, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
213
|
+
sipSetCallMediaControl(request: ondewo_sip_sip_pb.SipSetCallMediaControlRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
214
|
+
sipSetCallMediaControl(request: ondewo_sip_sip_pb.SipSetCallMediaControlRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
215
|
+
sipStreamCallAudio(): grpc.ClientDuplexStream<ondewo_sip_sip_pb.SipCallAudioRequest, ondewo_sip_sip_pb.SipCallAudioResponse>;
|
|
216
|
+
sipStreamCallAudio(options: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<ondewo_sip_sip_pb.SipCallAudioRequest, ondewo_sip_sip_pb.SipCallAudioResponse>;
|
|
217
|
+
sipStreamCallAudio(metadata: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<ondewo_sip_sip_pb.SipCallAudioRequest, ondewo_sip_sip_pb.SipCallAudioResponse>;
|
|
176
218
|
}
|
|
177
219
|
|
|
178
220
|
export class SipClient extends grpc.Client implements ISipClient {
|
|
@@ -210,4 +252,12 @@ export class SipClient extends grpc.Client implements ISipClient {
|
|
|
210
252
|
public sipUnMute(request: google_protobuf_empty_pb.Empty, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
211
253
|
public sipUnMute(request: google_protobuf_empty_pb.Empty, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
212
254
|
public sipUnMute(request: google_protobuf_empty_pb.Empty, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
255
|
+
public sipReportAnsweringMachineDetected(request: ondewo_sip_sip_pb.SipReportAnsweringMachineDetectedRequest, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
256
|
+
public sipReportAnsweringMachineDetected(request: ondewo_sip_sip_pb.SipReportAnsweringMachineDetectedRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
257
|
+
public sipReportAnsweringMachineDetected(request: ondewo_sip_sip_pb.SipReportAnsweringMachineDetectedRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
258
|
+
public sipSetCallMediaControl(request: ondewo_sip_sip_pb.SipSetCallMediaControlRequest, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
259
|
+
public sipSetCallMediaControl(request: ondewo_sip_sip_pb.SipSetCallMediaControlRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
260
|
+
public sipSetCallMediaControl(request: ondewo_sip_sip_pb.SipSetCallMediaControlRequest, metadata: grpc.Metadata, options: Partial<grpc.CallOptions>, callback: (error: grpc.ServiceError | null, response: ondewo_sip_sip_pb.SipStatus) => void): grpc.ClientUnaryCall;
|
|
261
|
+
public sipStreamCallAudio(options?: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<ondewo_sip_sip_pb.SipCallAudioRequest, ondewo_sip_sip_pb.SipCallAudioResponse>;
|
|
262
|
+
public sipStreamCallAudio(metadata?: grpc.Metadata, options?: Partial<grpc.CallOptions>): grpc.ClientDuplexStream<ondewo_sip_sip_pb.SipCallAudioRequest, ondewo_sip_sip_pb.SipCallAudioResponse>;
|
|
213
263
|
}
|
|
@@ -32,6 +32,28 @@ function deserialize_google_protobuf_Empty(buffer_arg) {
|
|
|
32
32
|
return google_protobuf_empty_pb.Empty.deserializeBinary(new Uint8Array(buffer_arg));
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
function serialize_ondewo_sip_SipCallAudioRequest(arg) {
|
|
36
|
+
if (!(arg instanceof ondewo_sip_sip_pb.SipCallAudioRequest)) {
|
|
37
|
+
throw new Error('Expected argument of type ondewo.sip.SipCallAudioRequest');
|
|
38
|
+
}
|
|
39
|
+
return Buffer.from(arg.serializeBinary());
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function deserialize_ondewo_sip_SipCallAudioRequest(buffer_arg) {
|
|
43
|
+
return ondewo_sip_sip_pb.SipCallAudioRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function serialize_ondewo_sip_SipCallAudioResponse(arg) {
|
|
47
|
+
if (!(arg instanceof ondewo_sip_sip_pb.SipCallAudioResponse)) {
|
|
48
|
+
throw new Error('Expected argument of type ondewo.sip.SipCallAudioResponse');
|
|
49
|
+
}
|
|
50
|
+
return Buffer.from(arg.serializeBinary());
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function deserialize_ondewo_sip_SipCallAudioResponse(buffer_arg) {
|
|
54
|
+
return ondewo_sip_sip_pb.SipCallAudioResponse.deserializeBinary(new Uint8Array(buffer_arg));
|
|
55
|
+
}
|
|
56
|
+
|
|
35
57
|
function serialize_ondewo_sip_SipEndCallRequest(arg) {
|
|
36
58
|
if (!(arg instanceof ondewo_sip_sip_pb.SipEndCallRequest)) {
|
|
37
59
|
throw new Error('Expected argument of type ondewo.sip.SipEndCallRequest');
|
|
@@ -65,6 +87,28 @@ function deserialize_ondewo_sip_SipRegisterAccountRequest(buffer_arg) {
|
|
|
65
87
|
return ondewo_sip_sip_pb.SipRegisterAccountRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
|
66
88
|
}
|
|
67
89
|
|
|
90
|
+
function serialize_ondewo_sip_SipReportAnsweringMachineDetectedRequest(arg) {
|
|
91
|
+
if (!(arg instanceof ondewo_sip_sip_pb.SipReportAnsweringMachineDetectedRequest)) {
|
|
92
|
+
throw new Error('Expected argument of type ondewo.sip.SipReportAnsweringMachineDetectedRequest');
|
|
93
|
+
}
|
|
94
|
+
return Buffer.from(arg.serializeBinary());
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function deserialize_ondewo_sip_SipReportAnsweringMachineDetectedRequest(buffer_arg) {
|
|
98
|
+
return ondewo_sip_sip_pb.SipReportAnsweringMachineDetectedRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function serialize_ondewo_sip_SipSetCallMediaControlRequest(arg) {
|
|
102
|
+
if (!(arg instanceof ondewo_sip_sip_pb.SipSetCallMediaControlRequest)) {
|
|
103
|
+
throw new Error('Expected argument of type ondewo.sip.SipSetCallMediaControlRequest');
|
|
104
|
+
}
|
|
105
|
+
return Buffer.from(arg.serializeBinary());
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function deserialize_ondewo_sip_SipSetCallMediaControlRequest(buffer_arg) {
|
|
109
|
+
return ondewo_sip_sip_pb.SipSetCallMediaControlRequest.deserializeBinary(new Uint8Array(buffer_arg));
|
|
110
|
+
}
|
|
111
|
+
|
|
68
112
|
function serialize_ondewo_sip_SipStartCallRequest(arg) {
|
|
69
113
|
if (!(arg instanceof ondewo_sip_sip_pb.SipStartCallRequest)) {
|
|
70
114
|
throw new Error('Expected argument of type ondewo.sip.SipStartCallRequest');
|
|
@@ -135,7 +179,8 @@ sipStartSession: {
|
|
|
135
179
|
responseSerialize: serialize_ondewo_sip_SipStatus,
|
|
136
180
|
responseDeserialize: deserialize_ondewo_sip_SipStatus,
|
|
137
181
|
},
|
|
138
|
-
//
|
|
182
|
+
// Not idempotent (no idempotency_level): (re)creates the SIP session and registration.
|
|
183
|
+
// <p>Ends a SIP session for an account registered at a SIP server</p>
|
|
139
184
|
sipEndSession: {
|
|
140
185
|
path: '/ondewo.sip.Sip/SipEndSession',
|
|
141
186
|
requestStream: false,
|
|
@@ -147,7 +192,8 @@ sipEndSession: {
|
|
|
147
192
|
responseSerialize: serialize_ondewo_sip_SipStatus,
|
|
148
193
|
responseDeserialize: deserialize_ondewo_sip_SipStatus,
|
|
149
194
|
},
|
|
150
|
-
//
|
|
195
|
+
// Not idempotent (no idempotency_level): tears down the session; a repeat records a new status.
|
|
196
|
+
// <p>Starts a call in an active SIP session for an account registered at a SIP server</p>
|
|
151
197
|
sipStartCall: {
|
|
152
198
|
path: '/ondewo.sip.Sip/SipStartCall',
|
|
153
199
|
requestStream: false,
|
|
@@ -159,7 +205,8 @@ sipStartCall: {
|
|
|
159
205
|
responseSerialize: serialize_ondewo_sip_SipStatus,
|
|
160
206
|
responseDeserialize: deserialize_ondewo_sip_SipStatus,
|
|
161
207
|
},
|
|
162
|
-
//
|
|
208
|
+
// Not idempotent (no idempotency_level): a repeat dials a second call.
|
|
209
|
+
// <p>Ends a call in an active SIP session for an account registered at a SIP server</p>
|
|
163
210
|
sipEndCall: {
|
|
164
211
|
path: '/ondewo.sip.Sip/SipEndCall',
|
|
165
212
|
requestStream: false,
|
|
@@ -171,7 +218,20 @@ sipEndCall: {
|
|
|
171
218
|
responseSerialize: serialize_ondewo_sip_SipStatus,
|
|
172
219
|
responseDeserialize: deserialize_ondewo_sip_SipStatus,
|
|
173
220
|
},
|
|
174
|
-
//
|
|
221
|
+
// Not idempotent (no idempotency_level): a repeat without a call appends its refusal to the history and ends
|
|
222
|
+
// a one-shot caller container; unscoped it can end the next call.
|
|
223
|
+
// <p>Transfers a call in an active SIP session for an account registered at a SIP server to another SIP account or phone number specified by <code>transfer_id</code></p>
|
|
224
|
+
// <p>Call scoping: when the gRPC metadatum <code>x-ondewo-expected-call-id</code> is present it must equal
|
|
225
|
+
// <code>SipStatus.call_id</code> of the ongoing call, otherwise the request is refused with
|
|
226
|
+
// <code>exception_name=CallScopeMismatch</code> and nothing is assigned to the status. When it is absent the request is
|
|
227
|
+
// accepted for backward compatibility (unless the server requires call scoping).</p>
|
|
228
|
+
// <p>With <code>outcome_timeout_ms = 0</code> the call is transferred as before (REFER, then an immediate hangup).
|
|
229
|
+
// With <code>outcome_timeout_ms > 0</code> see <code>SipTransferCallRequest.outcome_timeout_ms</code>.</p>
|
|
230
|
+
// <p>Refused while invited participants are present (see
|
|
231
|
+
// <code>SipSetCallMediaControlRequest.participants_present</code>): a REFER into a conference bridge transfers every
|
|
232
|
+
// party in it, the invited participant included. The refusal is RETURNED as <code>TRANSFER_CALL_FAILED</code> with
|
|
233
|
+
// <code>exception_name=ParticipantsPresent</code> and <code>description = reason=participants-present</code>; nothing
|
|
234
|
+
// is sent and the call is kept.</p>
|
|
175
235
|
sipTransferCall: {
|
|
176
236
|
path: '/ondewo.sip.Sip/SipTransferCall',
|
|
177
237
|
requestStream: false,
|
|
@@ -183,7 +243,8 @@ sipTransferCall: {
|
|
|
183
243
|
responseSerialize: serialize_ondewo_sip_SipStatus,
|
|
184
244
|
responseDeserialize: deserialize_ondewo_sip_SipStatus,
|
|
185
245
|
},
|
|
186
|
-
//
|
|
246
|
+
// Not idempotent (no idempotency_level): a repeat sends another REFER.
|
|
247
|
+
// <p>Registers s SIP account at a SIP server</p>
|
|
187
248
|
sipRegisterAccount: {
|
|
188
249
|
path: '/ondewo.sip.Sip/SipRegisterAccount',
|
|
189
250
|
requestStream: false,
|
|
@@ -195,7 +256,8 @@ sipRegisterAccount: {
|
|
|
195
256
|
responseSerialize: serialize_ondewo_sip_SipStatus,
|
|
196
257
|
responseDeserialize: deserialize_ondewo_sip_SipStatus,
|
|
197
258
|
},
|
|
198
|
-
//
|
|
259
|
+
// Not idempotent (no idempotency_level): re-registers the account at the SIP server.
|
|
260
|
+
// <p>Gets the current SIP status</p>
|
|
199
261
|
sipGetSipStatus: {
|
|
200
262
|
path: '/ondewo.sip.Sip/SipGetSipStatus',
|
|
201
263
|
requestStream: false,
|
|
@@ -220,6 +282,8 @@ sipGetSipStatusHistory: {
|
|
|
220
282
|
responseDeserialize: deserialize_ondewo_sip_SipStatusHistoryResponse,
|
|
221
283
|
},
|
|
222
284
|
// <p>Plays wav files during an ongoing call of an active SIP session</p>
|
|
285
|
+
// <p>Call scoping as for <code>SipTransferCall</code>: a present <code>x-ondewo-expected-call-id</code> metadatum must
|
|
286
|
+
// match <code>SipStatus.call_id</code>.</p>
|
|
223
287
|
sipPlayWavFiles: {
|
|
224
288
|
path: '/ondewo.sip.Sip/SipPlayWavFiles',
|
|
225
289
|
requestStream: false,
|
|
@@ -231,7 +295,11 @@ sipPlayWavFiles: {
|
|
|
231
295
|
responseSerialize: serialize_ondewo_sip_SipStatus,
|
|
232
296
|
responseDeserialize: deserialize_ondewo_sip_SipStatus,
|
|
233
297
|
},
|
|
234
|
-
//
|
|
298
|
+
// Not idempotent (no idempotency_level): a repeat plays the files again.
|
|
299
|
+
// <p>Mutes the microphone in an ongoing call of an active SIP session</p>
|
|
300
|
+
// <p>Call scoping as for <code>SipTransferCall</code>. Sent by the in-container speech-to-speech pipeline it mutes only
|
|
301
|
+
// the bot's own mixer slot; sent by a remote client it sets the operator mute of
|
|
302
|
+
// <code>SipSetCallMediaControl</code>, which the pipeline cannot undo.</p>
|
|
235
303
|
sipMute: {
|
|
236
304
|
path: '/ondewo.sip.Sip/SipMute',
|
|
237
305
|
requestStream: false,
|
|
@@ -243,7 +311,9 @@ sipMute: {
|
|
|
243
311
|
responseSerialize: serialize_ondewo_sip_SipStatus,
|
|
244
312
|
responseDeserialize: deserialize_ondewo_sip_SipStatus,
|
|
245
313
|
},
|
|
246
|
-
//
|
|
314
|
+
// Not idempotent (no idempotency_level): without a call it assigns NO_ONGOING_CALL and appends to the history.
|
|
315
|
+
// <p>Un-mutes the microphone in an ongoing call of an active SIP session</p>
|
|
316
|
+
// <p>Call scoping and the split between the pipeline's own mute and the operator mute as for <code>SipMute</code>.</p>
|
|
247
317
|
sipUnMute: {
|
|
248
318
|
path: '/ondewo.sip.Sip/SipUnMute',
|
|
249
319
|
requestStream: false,
|
|
@@ -255,6 +325,71 @@ sipUnMute: {
|
|
|
255
325
|
responseSerialize: serialize_ondewo_sip_SipStatus,
|
|
256
326
|
responseDeserialize: deserialize_ondewo_sip_SipStatus,
|
|
257
327
|
},
|
|
328
|
+
// Not idempotent (no idempotency_level): without a call it assigns NO_ONGOING_CALL and appends to the history.
|
|
329
|
+
// <p>Reports that answering machine detection reached a verdict on the ongoing outgoing call. Sets the status
|
|
330
|
+
// <code>OUTGOING_CALL_ANSWERING_MACHINE_DETECTED</code> carrying <code>amd_result</code>; the call stays up.</p>
|
|
331
|
+
// <p>Called by the speech-to-speech pipeline (ONDEWO-CSI) inside the same container, i.e. over loopback only.
|
|
332
|
+
// Refused, and the current status left untouched, when no outgoing call is connected: the returned
|
|
333
|
+
// <code>SipStatus</code> then carries the refusal in <code>exception_name</code> and <code>description</code></p>
|
|
334
|
+
sipReportAnsweringMachineDetected: {
|
|
335
|
+
path: '/ondewo.sip.Sip/SipReportAnsweringMachineDetected',
|
|
336
|
+
requestStream: false,
|
|
337
|
+
responseStream: false,
|
|
338
|
+
requestType: ondewo_sip_sip_pb.SipReportAnsweringMachineDetectedRequest,
|
|
339
|
+
responseType: ondewo_sip_sip_pb.SipStatus,
|
|
340
|
+
requestSerialize: serialize_ondewo_sip_SipReportAnsweringMachineDetectedRequest,
|
|
341
|
+
requestDeserialize: deserialize_ondewo_sip_SipReportAnsweringMachineDetectedRequest,
|
|
342
|
+
responseSerialize: serialize_ondewo_sip_SipStatus,
|
|
343
|
+
responseDeserialize: deserialize_ondewo_sip_SipStatus,
|
|
344
|
+
},
|
|
345
|
+
// Not idempotent (no idempotency_level): assigns a status and records answering machine detection telemetry.
|
|
346
|
+
// <p>Call-scoped operator media control of the ongoing call: mute the bot and/or pause its listening.</p>
|
|
347
|
+
// <p>Metadata REQUIRED: <code>x-ondewo-expected-call-id</code> (must equal <code>SipStatus.call_id</code> of the ongoing
|
|
348
|
+
// call) and <code>x-ondewo-sip-call-control-token</code> (the per-container call-control token).</p>
|
|
349
|
+
// <p>Every request sets a desired level per owner and never toggles; a repeat leaves the level unchanged. The bot is
|
|
350
|
+
// muted while ANY owner holds a mute, and its listening is paused while ANY owner holds a pause.</p>
|
|
351
|
+
// <p>Returns the live status with <code>call_id</code>, <code>bot_muted</code>, <code>listening_paused</code> and
|
|
352
|
+
// <code>call_audio_streams</code> filled. Refusals are RETURNED in <code>exception_name</code> /
|
|
353
|
+
// <code>description</code> (<code>CallScopeMismatch</code>, <code>CallControlUnauthenticated</code>,
|
|
354
|
+
// <code>NoOngoingCall</code>, <code>AmdInProgress</code>, <code>CsiMediaControlFailed</code>) and never assigned to
|
|
355
|
+
// the shared status. When the pipeline refuses or fails, a requested pause is rolled back and a requested mute is
|
|
356
|
+
// kept (the safe direction); the returned fields carry the actual level.</p>
|
|
357
|
+
sipSetCallMediaControl: {
|
|
358
|
+
path: '/ondewo.sip.Sip/SipSetCallMediaControl',
|
|
359
|
+
requestStream: false,
|
|
360
|
+
responseStream: false,
|
|
361
|
+
requestType: ondewo_sip_sip_pb.SipSetCallMediaControlRequest,
|
|
362
|
+
responseType: ondewo_sip_sip_pb.SipStatus,
|
|
363
|
+
requestSerialize: serialize_ondewo_sip_SipSetCallMediaControlRequest,
|
|
364
|
+
requestDeserialize: deserialize_ondewo_sip_SipSetCallMediaControlRequest,
|
|
365
|
+
responseSerialize: serialize_ondewo_sip_SipStatus,
|
|
366
|
+
responseDeserialize: deserialize_ondewo_sip_SipStatus,
|
|
367
|
+
},
|
|
368
|
+
// Deliberately unmarked although a repeat leaves the level unchanged: a retried attempt can land after a newer
|
|
369
|
+
// request of the same owner and restore a stale mute or pause.
|
|
370
|
+
// <p>Bidirectional live audio of the ongoing call.</p>
|
|
371
|
+
// <p>The first request MUST be <code>config</code> and must arrive within 2 seconds. Metadata as for
|
|
372
|
+
// <code>SipSetCallMediaControl</code>.</p>
|
|
373
|
+
// <p>LISTEN receives the caller (plus any conference participants) mixed with the bot. TALK sends the agent's audio to
|
|
374
|
+
// the caller; it REQUIRES <code>take_over</code>, i.e. the bot is muted and does not listen while the stream is
|
|
375
|
+
// connected, and in TALK the agent hears the caller only. Audio is LINEAR16 little-endian mono in 20 ms frames.</p>
|
|
376
|
+
// <p>gRPC status codes: <code>UNAUTHENTICATED</code> (token), <code>FAILED_PRECONDITION</code> (call id mismatch, no
|
|
377
|
+
// connected call, answering machine detection in progress, bot still speaking at TALK start),
|
|
378
|
+
// <code>INVALID_ARGUMENT</code> (missing or invalid <code>config</code>, wrong frame size),
|
|
379
|
+
// <code>RESOURCE_EXHAUSTED</code> (stream cap reached, a second TALK). A normal end sends one <code>ended</code>
|
|
380
|
+
// message and then OK.</p>
|
|
381
|
+
sipStreamCallAudio: {
|
|
382
|
+
path: '/ondewo.sip.Sip/SipStreamCallAudio',
|
|
383
|
+
requestStream: true,
|
|
384
|
+
responseStream: true,
|
|
385
|
+
requestType: ondewo_sip_sip_pb.SipCallAudioRequest,
|
|
386
|
+
responseType: ondewo_sip_sip_pb.SipCallAudioResponse,
|
|
387
|
+
requestSerialize: serialize_ondewo_sip_SipCallAudioRequest,
|
|
388
|
+
requestDeserialize: deserialize_ondewo_sip_SipCallAudioRequest,
|
|
389
|
+
responseSerialize: serialize_ondewo_sip_SipCallAudioResponse,
|
|
390
|
+
responseDeserialize: deserialize_ondewo_sip_SipCallAudioResponse,
|
|
391
|
+
},
|
|
392
|
+
// Not idempotent (no idempotency_level): a stream takes a slot and, in TALK, takes over the call.
|
|
258
393
|
};
|
|
259
394
|
|
|
260
395
|
exports.SipClient = grpc.makeGenericClientConstructor(SipService, 'Sip');
|