@wazo/sdk 0.42.0 → 0.43.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.
Files changed (91) hide show
  1. package/README.md +32 -21
  2. package/dist/wazo-sdk.js +2 -2
  3. package/esm/__tests__/api-client.test.js +19 -0
  4. package/esm/__tests__/web-rtc-client.test.js +1 -1
  5. package/esm/api/auth.js +6 -0
  6. package/esm/domain/Incall.js +28 -0
  7. package/esm/domain/Phone/CTIPhone.js +1 -1
  8. package/esm/domain/Phone/WebRTCPhone.js +4 -4
  9. package/esm/domain/Profile.js +5 -1
  10. package/esm/domain/__tests__/Profile.test.js +32 -0
  11. package/esm/index.js +1 -0
  12. package/esm/simple/Auth.js +4 -0
  13. package/esm/simple/Phone.js +1 -1
  14. package/esm/simple/room/Room.js +2 -2
  15. package/esm/types/api/auth.d.ts +1 -0
  16. package/esm/types/api/auth.d.ts.map +1 -1
  17. package/esm/types/domain/Incall.d.ts +21 -0
  18. package/esm/types/domain/Incall.d.ts.map +1 -0
  19. package/esm/types/domain/Line.d.ts +5 -16
  20. package/esm/types/domain/Line.d.ts.map +1 -1
  21. package/esm/types/domain/Phone/CTIPhone.d.ts +1 -1
  22. package/esm/types/domain/Phone/Phone.d.ts +1 -1
  23. package/esm/types/domain/Phone/Phone.d.ts.map +1 -1
  24. package/esm/types/domain/Phone/WebRTCPhone.d.ts +2 -2
  25. package/esm/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
  26. package/esm/types/domain/Profile.d.ts +5 -1
  27. package/esm/types/domain/Profile.d.ts.map +1 -1
  28. package/esm/types/domain/types.d.ts +17 -19
  29. package/esm/types/domain/types.d.ts.map +1 -1
  30. package/esm/types/index.d.ts +1 -0
  31. package/esm/types/index.d.ts.map +1 -1
  32. package/esm/types/simple/Auth.d.ts +1 -0
  33. package/esm/types/simple/Auth.d.ts.map +1 -1
  34. package/esm/types/simple/Phone.d.ts +3 -3
  35. package/esm/types/simple/Phone.d.ts.map +1 -1
  36. package/esm/types/web-rtc-client.d.ts +8 -10
  37. package/esm/types/web-rtc-client.d.ts.map +1 -1
  38. package/esm/web-rtc-client.js +18 -24
  39. package/lib/__tests__/api-client.test.js +19 -0
  40. package/lib/__tests__/web-rtc-client.test.js +1 -1
  41. package/lib/api/auth.js +15 -0
  42. package/lib/domain/Incall.js +32 -0
  43. package/lib/domain/Phone/CTIPhone.js +1 -1
  44. package/lib/domain/Phone/WebRTCPhone.js +9 -7
  45. package/lib/domain/Profile.js +4 -1
  46. package/lib/domain/__tests__/Profile.test.js +32 -0
  47. package/lib/index.js +4 -2
  48. package/lib/simple/Auth.js +6 -0
  49. package/lib/simple/Phone.js +1 -1
  50. package/lib/simple/room/Room.js +5 -5
  51. package/lib/types/api/auth.d.ts +1 -0
  52. package/lib/types/api/auth.d.ts.map +1 -1
  53. package/lib/types/domain/Incall.d.ts +21 -0
  54. package/lib/types/domain/Incall.d.ts.map +1 -0
  55. package/lib/types/domain/Line.d.ts +5 -16
  56. package/lib/types/domain/Line.d.ts.map +1 -1
  57. package/lib/types/domain/Phone/CTIPhone.d.ts +1 -1
  58. package/lib/types/domain/Phone/Phone.d.ts +1 -1
  59. package/lib/types/domain/Phone/Phone.d.ts.map +1 -1
  60. package/lib/types/domain/Phone/WebRTCPhone.d.ts +2 -2
  61. package/lib/types/domain/Phone/WebRTCPhone.d.ts.map +1 -1
  62. package/lib/types/domain/Profile.d.ts +5 -1
  63. package/lib/types/domain/Profile.d.ts.map +1 -1
  64. package/lib/types/domain/types.d.ts +17 -19
  65. package/lib/types/domain/types.d.ts.map +1 -1
  66. package/lib/types/index.d.ts +1 -0
  67. package/lib/types/index.d.ts.map +1 -1
  68. package/lib/types/simple/Auth.d.ts +1 -0
  69. package/lib/types/simple/Auth.d.ts.map +1 -1
  70. package/lib/types/simple/Phone.d.ts +3 -3
  71. package/lib/types/simple/Phone.d.ts.map +1 -1
  72. package/lib/types/web-rtc-client.d.ts +8 -10
  73. package/lib/types/web-rtc-client.d.ts.map +1 -1
  74. package/lib/web-rtc-client.js +147 -141
  75. package/package.json +3 -2
  76. package/src/__tests__/api-client.test.ts +21 -0
  77. package/src/__tests__/web-rtc-client.test.ts +1 -1
  78. package/src/api/auth.ts +8 -0
  79. package/src/domain/Incall.ts +50 -0
  80. package/src/domain/Line.ts +5 -17
  81. package/src/domain/Phone/CTIPhone.ts +1 -1
  82. package/src/domain/Phone/Phone.ts +1 -1
  83. package/src/domain/Phone/WebRTCPhone.ts +4 -4
  84. package/src/domain/Profile.ts +8 -0
  85. package/src/domain/__tests__/Profile.test.ts +32 -0
  86. package/src/domain/types.ts +52 -44
  87. package/src/index.ts +1 -0
  88. package/src/simple/Auth.ts +5 -0
  89. package/src/simple/Phone.ts +4 -4
  90. package/src/simple/room/Room.ts +2 -2
  91. package/src/web-rtc-client.ts +20 -26
@@ -31,7 +31,7 @@ export type AvailablePhoneOptions = {
31
31
  };
32
32
  export interface Phone extends IEmitter {
33
33
  accept(callSession: CallSession, enableVideo?: boolean): Promise<string | null>;
34
- changeAudioDevice(id: string): PhoneVoid;
34
+ changeAudioDevice(id: string): Promise<void>;
35
35
  changeRingDevice(id: string): PhoneVoid;
36
36
  changeAudioVolume(volume: number): PhoneVoid;
37
37
  changeRingVolume(volume: number): PhoneVoid;
@@ -612,12 +612,12 @@ export default class WebRTCPhone extends Emitter implements Phone {
612
612
  return callSession;
613
613
  }
614
614
 
615
- changeAudioDevice(id: string) {
615
+ async changeAudioDevice(id: string) {
616
616
  logger.info('WebRTC phone - change audio device', {
617
617
  deviceId: id,
618
618
  });
619
619
  this.audioOutputDeviceId = id;
620
- this.client.changeAudioOutputDevice(id);
620
+ return this.client.changeAudioOutputDevice(id);
621
621
  }
622
622
 
623
623
  createAudioElementFor(sessionId: string) {
@@ -1528,7 +1528,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
1528
1528
  this.eventEmitter.emit.apply(this.eventEmitter, [this.client.ON_REINVITE, ...args]);
1529
1529
  }, 2000);
1530
1530
  });
1531
- this.client.on(this.client.ACCEPTED, (sipSession: WazoSession) => {
1531
+ this.client.on(this.client.ACCEPTED, async (sipSession: WazoSession) => {
1532
1532
  const sessionId = this.getSipSessionId(sipSession);
1533
1533
  const hasSession = (sessionId in this.callSessions);
1534
1534
  logger.info('WebRTC call accepted', {
@@ -1546,7 +1546,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
1546
1546
  this._onCallAccepted(sipSession, this.client.hasVideo(sessionId));
1547
1547
 
1548
1548
  if (this.audioOutputDeviceId) {
1549
- this.client.changeAudioOutputDevice(this.audioOutputDeviceId);
1549
+ await this.client.changeAudioOutputDevice(this.audioOutputDeviceId);
1550
1550
  }
1551
1551
  });
1552
1552
  this.client.on('ended', () => {});
@@ -2,6 +2,7 @@ import Line, { LineResponse } from './Line';
2
2
  import ForwardOption, { FORWARD_KEYS } from './ForwardOption';
3
3
  import newFrom from '../utils/new-from';
4
4
  import SipLine from './SipLine';
5
+ import Incall, { GenericIncall } from './Incall';
5
6
 
6
7
  export const STATE = {
7
8
  AVAILABLE: 'available',
@@ -74,6 +75,7 @@ type ProfileResponse = {
74
75
  uuid: string;
75
76
  }>;
76
77
  online_call_record_enabled: boolean | null | undefined;
78
+ incalls: GenericIncall[];
77
79
  };
78
80
 
79
81
  type ProfileArguments = {
@@ -108,6 +110,7 @@ type ProfileArguments = {
108
110
  uuid: string;
109
111
  }>;
110
112
  onlineCallRecordEnabled?: boolean | null | undefined;
113
+ incalls?: GenericIncall[];
111
114
  };
112
115
  export default class Profile {
113
116
  id: string;
@@ -122,6 +125,8 @@ export default class Profile {
122
125
 
123
126
  sipLines: Array<SipLine>;
124
127
 
128
+ incalls: Array<Incall>;
129
+
125
130
  username: string;
126
131
 
127
132
  mobileNumber: string;
@@ -167,6 +172,7 @@ export default class Profile {
167
172
  lastName: plain.lastName || plain.lastname || '',
168
173
  email: plain.email,
169
174
  lines: plain.lines.map(line => Line.parse(line)),
175
+ incalls: plain.incalls,
170
176
  username: plain.username,
171
177
  mobileNumber: plain.mobile_phone_number || '',
172
178
  ringSeconds: plain.ring_seconds,
@@ -206,6 +212,7 @@ export default class Profile {
206
212
  sipLines,
207
213
  callPickupTargetUsers,
208
214
  onlineCallRecordEnabled,
215
+ incalls,
209
216
  }: ProfileArguments) {
210
217
  this.id = id;
211
218
  this.firstName = firstName;
@@ -226,6 +233,7 @@ export default class Profile {
226
233
  this.onlineCallRecordEnabled = onlineCallRecordEnabled;
227
234
  this.ringSeconds = ringSeconds;
228
235
  this.sipLines = sipLines || [];
236
+ this.incalls = incalls?.map(Incall.parse) || [];
229
237
  }
230
238
 
231
239
  static getLinesState(lines: Array<Record<string, any>>) {
@@ -54,6 +54,21 @@ describe('Profile domain', () => {
54
54
  }],
55
55
  endpoint_custom: null,
56
56
  }],
57
+ incalls: [{
58
+ id: 1,
59
+ extensions: [{
60
+ id: 3,
61
+ exten: '8001112222',
62
+ context: 'incall',
63
+ }],
64
+ }, {
65
+ id: 2,
66
+ extensions: [{
67
+ id: 4,
68
+ exten: '8001113333',
69
+ context: 'incall',
70
+ }],
71
+ }],
57
72
  username: 'john.doe',
58
73
  services: {
59
74
  dnd: {
@@ -121,6 +136,21 @@ describe('Profile domain', () => {
121
136
  context: 'internal',
122
137
  }],
123
138
  })],
139
+ incalls: [{
140
+ id: 1,
141
+ extensions: [{
142
+ id: 3,
143
+ exten: '8001112222',
144
+ context: 'incall',
145
+ }],
146
+ }, {
147
+ id: 2,
148
+ extensions: [{
149
+ id: 4,
150
+ exten: '8001113333',
151
+ context: 'incall',
152
+ }],
153
+ }],
124
154
  mobileNumber: '',
125
155
  username: 'john.doe',
126
156
  doNotDisturb: false,
@@ -134,5 +164,7 @@ describe('Profile domain', () => {
134
164
  }],
135
165
  onlineCallRecordEnabled: true,
136
166
  }));
167
+ expect(profile.incalls[0].extension).toBe(plain.incalls[0].extensions[0].exten);
168
+ expect(profile.incalls[1].extension).toBe(plain.incalls[1].extensions[0].exten);
137
169
  });
138
170
  });
@@ -1,4 +1,9 @@
1
- import type { Invitation, Inviter, Session as SipSession, UserAgentOptions as sipJsUserAgentOptions } from 'sip.js';
1
+ import type {
2
+ Invitation,
3
+ Inviter,
4
+ Session as SipSession,
5
+ UserAgentOptions as sipJsUserAgentOptions,
6
+ } from 'sip.js';
2
7
  import { SessionDescriptionHandlerFactoryOptions } from 'sip.js/lib/platform/web';
3
8
  import type { IncomingResponse as SipIncomingResponse } from 'sip.js/lib/core/messages/incoming-response';
4
9
  import { Transport } from 'sip.js/lib/api';
@@ -6,10 +11,7 @@ import WazoSessionDescriptionHandler from '../lib/WazoSessionDescriptionHandler'
6
11
  import { Websocket } from '../simple/Websocket';
7
12
  import * as WebSocketClient from '../websocket-client';
8
13
 
9
- const {
10
- SOCKET_EVENTS,
11
- ...OTHER_EVENTS
12
- } = WebSocketClient;
14
+ const { SOCKET_EVENTS, ...OTHER_EVENTS } = WebSocketClient;
13
15
 
14
16
  type GenericObject = Record<string, any>;
15
17
 
@@ -79,6 +81,12 @@ export type Link = {
79
81
  href: string;
80
82
  rel: string;
81
83
  };
84
+ export type ExtensionRelation = {
85
+ id: number;
86
+ exten: string;
87
+ context: string;
88
+ links?: Link[];
89
+ };
82
90
  type LocalLine = {
83
91
  id: number;
84
92
  endpoint_sip: {
@@ -88,12 +96,7 @@ type LocalLine = {
88
96
  };
89
97
  endpoint_sccp: string | null | undefined;
90
98
  endpoint_custom: string | null | undefined;
91
- extensions: Array<{
92
- id: number;
93
- exten: string;
94
- context: string;
95
- links: Array<Link>;
96
- }>;
99
+ extensions: ExtensionRelation[];
97
100
  };
98
101
  export type ConfdUser = {
99
102
  id: number;
@@ -169,7 +172,6 @@ export type ConfdUser = {
169
172
  // @TODO
170
173
  voicemail: string | null | undefined;
171
174
  queues: Array<Record<string, any>>; // @TODO
172
-
173
175
  };
174
176
  export type ListConfdUsersResponse = {
175
177
  total: number;
@@ -193,7 +195,6 @@ export type ListApplicationsResponse = {
193
195
  export type Node = {
194
196
  uuid: UUID;
195
197
  calls: Array<Record<string, any>>; // @TODO
196
-
197
198
  };
198
199
  export type CallNode = GenericObject;
199
200
  export type ListNodesResponse = {
@@ -206,21 +207,26 @@ export type ListCallNodesResponse = {
206
207
  export type GetTenantResponse = GenericObject;
207
208
  export type GetUserResponse = GenericObject;
208
209
  export type CTITransfer = {
209
- 'flow': string;
210
- 'id': string;
211
- 'initiator_call': string;
212
- 'initiator_uuid': string;
213
- 'recipient_call': string;
214
- 'status': string;
215
- 'transferred_call': string;
210
+ flow: string;
211
+ id: string;
212
+ initiator_call: string;
213
+ initiator_uuid: string;
214
+ recipient_call: string;
215
+ status: string;
216
+ transferred_call: string;
216
217
  };
217
218
  export type UserAgentOptions = sipJsUserAgentOptions & {
218
- peerConnectionOptions?: Record<string, any>,
219
- sessionDescriptionHandlerFactory: (session: SipSession, options: SessionDescriptionHandlerFactoryOptions) => WazoSessionDescriptionHandler,
219
+ peerConnectionOptions?: Record<string, any>;
220
+ sessionDescriptionHandlerFactory: (
221
+ session: SipSession,
222
+ options: SessionDescriptionHandlerFactoryOptions
223
+ ) => WazoSessionDescriptionHandler;
220
224
  };
221
- export type UserAgentConfigOverrides = Partial<UserAgentOptions & {
222
- traceSip: any,
223
- }>;
225
+ export type UserAgentConfigOverrides = Partial<
226
+ UserAgentOptions & {
227
+ traceSip: any;
228
+ }
229
+ >;
224
230
  export type MediaConfig = {
225
231
  audio: Record<string, any> | boolean;
226
232
  video?: Record<string, any> | boolean;
@@ -237,7 +243,6 @@ export type WebRtcConfig = {
237
243
  media?: MediaConfig;
238
244
  iceCheckingTimeout?: number;
239
245
  log?: Record<string, any>;
240
- audioOutputDeviceId?: string;
241
246
  audioOutputVolume?: number;
242
247
  userAgentString?: string;
243
248
  heartbeatDelay?: number;
@@ -245,31 +250,32 @@ export type WebRtcConfig = {
245
250
  maxHeartbeats?: number;
246
251
  skipRegister?: boolean;
247
252
  userUuid?: string,
253
+ uaConfigOverrides?: UserAgentConfigOverrides,
254
+ audioDeviceOutput?: string,
255
+ audioDeviceRing?: string
248
256
  }; // @see https://github.com/onsip/SIP.js/blob/master/src/Web/Simple.js
249
257
 
250
- export type ConnectionOptions = WebRtcConfig & {
251
- uaConfigOverrides: UserAgentConfigOverrides,
252
- audioDeviceOutput: string,
253
- audioDeviceRing: string
254
- };
255
258
  export type IncomingResponse = SipIncomingResponse & { session: any };
256
259
 
257
260
  export type PeerConnection = RTCPeerConnection & {
258
- getRemoteStreams: () => MediaStream[],
259
- getLocalStreams: () => MediaStream[],
260
- onremovestream: (func: any) => void,
261
- addStream: (stream: MediaStream) => void,
262
- sfu: any
261
+ getRemoteStreams: () => MediaStream[];
262
+ getLocalStreams: () => MediaStream[];
263
+ onremovestream: (func: any) => void;
264
+ addStream: (stream: MediaStream) => void;
265
+ sfu: any;
263
266
  };
264
267
 
265
- export type WazoSession = (Invitation | Inviter) & { remoteTag?: any, callId?: string };
268
+ export type WazoSession = (Invitation | Inviter) & {
269
+ remoteTag?: any;
270
+ callId?: string;
271
+ };
266
272
 
267
273
  export type WazoTransport = Transport & {
268
- configuration: Record<string, any>,
269
- connectPromise: Promise<any>,
270
- disconnectPromise: Promise<any>,
271
- disconnectResolve: any,
272
- transitionState: any,
274
+ configuration: Record<string, any>;
275
+ connectPromise: Promise<any>;
276
+ disconnectPromise: Promise<any>;
277
+ disconnectResolve: any;
278
+ transitionState: any;
273
279
  transitioningState: any;
274
280
  _ws: any;
275
281
  };
@@ -302,7 +308,7 @@ export type PresenceResponse = {
302
308
  state: string;
303
309
  status: string;
304
310
  user_uuid: string;
305
- last_activity?: string,
311
+ last_activity?: string;
306
312
  };
307
313
 
308
314
  export type QueryParams = {
@@ -320,4 +326,6 @@ export type UuidSearchableQueryParams = SearchableQueryParams & {
320
326
  uuid?: string;
321
327
  };
322
328
 
323
- export type WebsocketType = Websocket & typeof SOCKET_EVENTS & typeof OTHER_EVENTS;
329
+ export type WebsocketType = Websocket &
330
+ typeof SOCKET_EVENTS &
331
+ typeof OTHER_EVENTS;
package/src/index.ts CHANGED
@@ -14,6 +14,7 @@ export { default as Contact } from './domain/Contact';
14
14
  export { default as COUNTRIES } from './domain/Country';
15
15
  export { default as Features } from './domain/Features';
16
16
  export { default as ForwardOption, FORWARD_KEYS } from './domain/ForwardOption';
17
+ export { default as Incall } from './domain/Incall';
17
18
  export { default as Line } from './domain/Line';
18
19
  export { default as NotificationOptions } from './domain/NotificationOptions';
19
20
  export { default as Profile, STATE as PROFILE_STATE, LINE_STATE } from './domain/Profile';
@@ -160,6 +160,11 @@ export class Auth {
160
160
  return this._onAuthenticated(rawSession as Session);
161
161
  }
162
162
 
163
+ async samlLogIn(samlSessionId: string): Promise<Session | null> {
164
+ const rawSession = await getApiClient().auth.samlLogIn(samlSessionId);
165
+ return this._onAuthenticated(rawSession as Session);
166
+ }
167
+
163
168
  async logInViaRefreshToken(refreshToken: string): Promise<Session | null> {
164
169
  const rawSession = await getApiClient().auth.refreshToken(refreshToken, '', this.expiration, this.mobile);
165
170
  return this._onAuthenticated(rawSession as Session);
@@ -11,7 +11,7 @@ import IssueReporter from '../service/IssueReporter';
11
11
  import Emitter from '../utils/Emitter';
12
12
  import Wazo from './index';
13
13
  import SFUNotAvailableError from '../domain/SFUNotAvailableError';
14
- import { ConnectionOptions, WazoSession } from '../domain/types';
14
+ import { WazoSession, WebRtcConfig } from '../domain/types';
15
15
 
16
16
  const logger = IssueReporter.loggerFor('simple-phone');
17
17
  const sipLogger = IssueReporter.loggerFor('sip.js');
@@ -127,7 +127,7 @@ export class Phone extends Emitter {
127
127
  this.SessionState = SessionState;
128
128
  }
129
129
 
130
- async connect(rawOptions: Partial<ConnectionOptions> = {}, sipLine: SipLine | null | undefined = null): Promise<void> {
130
+ async connect(rawOptions: Partial<WebRtcConfig> = {}, sipLine: SipLine | null | undefined = null): Promise<void> {
131
131
  const options = rawOptions;
132
132
  if (this.phone) {
133
133
  // Already connected
@@ -162,7 +162,7 @@ export class Phone extends Emitter {
162
162
  server: string,
163
163
  sipLine: SipLine,
164
164
  displayName: string,
165
- rawOptions: Partial<ConnectionOptions> = {},
165
+ rawOptions: Partial<WebRtcConfig> = {},
166
166
  ): void {
167
167
  if (this.phone) {
168
168
  // Already connected
@@ -194,7 +194,7 @@ export class Phone extends Emitter {
194
194
  password: sipLine.secret,
195
195
  uri: `${sipLine.username}@${server}`,
196
196
  ...options,
197
- }, null, options.uaConfigOverrides);
197
+ }, undefined, options.uaConfigOverrides);
198
198
  this.phone = new WebRTCPhone(this.client, options.audioDeviceOutput, true, options.audioDeviceRing);
199
199
 
200
200
  this._transferEvents();
@@ -492,13 +492,13 @@ class Room extends Emitter {
492
492
  // Listen to REINVITE to ba able to map msid after upgrading to video in a audio only conference
493
493
  // This allow to map msid with the non parsed (eg without the `stripVideo` modifier) SDP
494
494
  Wazo.Phone.phone.on(Wazo.Phone.phone.client.ON_REINVITE, this._boundOnReinvite);
495
- this.on(this.ON_AUDIO_STREAM, stream => {
495
+ this.on(this.ON_AUDIO_STREAM, async stream => {
496
496
  logger.info('on room audio stream');
497
497
  this.audioStream = stream;
498
498
 
499
499
  if (!this.roomAudioElement) {
500
500
  const sessionId = Wazo.Phone.phone?.getSipSessionId(Wazo.Phone.phone?.currentSipSession as WazoSession);
501
- this.roomAudioElement = Wazo.Phone.phone?.createAudioElementFor(sessionId as string) as HTMLAudioElement;
501
+ this.roomAudioElement = await Wazo.Phone.phone?.createAudioElementFor(sessionId as string) as HTMLAudioElement;
502
502
  this.roomAudioElement.srcObject = stream;
503
503
  } else {
504
504
  this.roomAudioElement.srcObject = stream;
@@ -90,7 +90,7 @@ export default class WebRTCClient extends Emitter {
90
90
 
91
91
  audio: MediaTrackConstraintSet | boolean | undefined;
92
92
 
93
- audioElements: Record<string, HTMLAudioElement & { setSinkId?: (id: string) => void }>;
93
+ audioElements: Record<string, HTMLAudioElement>;
94
94
 
95
95
  video: MediaTrackConstraintSet | boolean | undefined;
96
96
 
@@ -182,7 +182,7 @@ export default class WebRTCClient extends Emitter {
182
182
  return [];
183
183
  }
184
184
 
185
- constructor(config: WebRtcConfig, session: WazoSession | null | undefined, uaConfigOverrides?: UserAgentConfigOverrides) {
185
+ constructor(config: WebRtcConfig, session?: WazoSession, uaConfigOverrides?: UserAgentConfigOverrides) {
186
186
  super();
187
187
 
188
188
  // For debug purpose
@@ -198,7 +198,7 @@ export default class WebRTCClient extends Emitter {
198
198
  this.userAgent = this.createUserAgent(uaConfigOverrides);
199
199
  });
200
200
 
201
- this.audioOutputDeviceId = config.audioOutputDeviceId;
201
+ this.audioOutputDeviceId = config.audioDeviceOutput;
202
202
  this.audioOutputVolume = config.audioOutputVolume || 1;
203
203
 
204
204
  if (config.media) {
@@ -1246,20 +1246,14 @@ export default class WebRTCClient extends Emitter {
1246
1246
  this.audioOutputVolume = volume;
1247
1247
  }
1248
1248
 
1249
- changeAudioOutputDevice(id: string) {
1249
+ async changeAudioOutputDevice(id: string) {
1250
1250
  logger.info('Changing audio output device', {
1251
1251
  id,
1252
1252
  });
1253
1253
  this.audioOutputDeviceId = id;
1254
- Object.values(this.audioElements).forEach(audioElement => {
1255
- // `setSinkId` method is not included in any flow type definitions for HTMLAudioElements but is a valid method
1256
- // audioElement is an array of HTMLAudioElements, and HTMLAudioElement inherits the method from HTMLMediaElement
1257
- // https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement
1258
- // https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId
1259
- if (audioElement.setSinkId) {
1260
- audioElement.setSinkId(id);
1261
- }
1262
- });
1254
+ const promises: Promise<void>[] = [];
1255
+ Object.values(this.audioElements).forEach(audioElement => promises.push(audioElement.setSinkId(id)));
1256
+ await Promise.allSettled(promises);
1263
1257
  }
1264
1258
 
1265
1259
  async changeAudioInputDevice(id: string, session: WazoSession | null | undefined, force?: boolean): Promise<MediaStream | null> {
@@ -1735,7 +1729,7 @@ export default class WebRTCClient extends Emitter {
1735
1729
  }
1736
1730
  }
1737
1731
 
1738
- updateLocalStream(sipSessionId: string, newStream: MediaStream): void {
1732
+ async updateLocalStream(sipSessionId: string, newStream: MediaStream): Promise<void> {
1739
1733
  const sipSession = this.sipSessions[sipSessionId];
1740
1734
 
1741
1735
  if (!sipSession) {
@@ -1756,7 +1750,7 @@ export default class WebRTCClient extends Emitter {
1756
1750
  this.setLocalMediaStream(sipSessionId, newStream);
1757
1751
 
1758
1752
  // Update the local video element
1759
- this._setupMedias(sipSession, newStream);
1753
+ await this._setupMedias(sipSession, newStream);
1760
1754
  }
1761
1755
 
1762
1756
  updateRemoteStream(sessionId: string, allTracks = true): void {
@@ -1832,14 +1826,14 @@ export default class WebRTCClient extends Emitter {
1832
1826
  return sessionId in this.conferences;
1833
1827
  }
1834
1828
 
1835
- createAudioElementFor(sessionId: string): HTMLAudioElement {
1829
+ async createAudioElementFor(sessionId: string): Promise<HTMLAudioElement> {
1836
1830
  const audio: HTMLAudioElement = document.createElement('audio');
1837
1831
  audio.setAttribute('id', `audio-${sessionId}`);
1838
1832
 
1839
1833
  logger.info('creating audio element', { sessionId, audioOutputDeviceId: this.audioOutputDeviceId });
1840
1834
 
1841
- if ((audio as any).setSinkId && this.audioOutputDeviceId) {
1842
- (audio as any).setSinkId(this.audioOutputDeviceId);
1835
+ if (this.audioOutputDeviceId) {
1836
+ await audio.setSinkId(this.audioOutputDeviceId);
1843
1837
  }
1844
1838
 
1845
1839
  if (document.body) {
@@ -2135,7 +2129,7 @@ export default class WebRTCClient extends Emitter {
2135
2129
  oldInviteRequest(request);
2136
2130
  };
2137
2131
 
2138
- session.delegate.onInvite = (request: IncomingRequestMessage) => {
2132
+ session.delegate.onInvite = async (request: IncomingRequestMessage) => {
2139
2133
  let updatedCalleeName: string | null = null;
2140
2134
  let updatedNumber = null;
2141
2135
 
@@ -2165,14 +2159,14 @@ export default class WebRTCClient extends Emitter {
2165
2159
 
2166
2160
  this.updateRemoteStream(sipSessionId, false);
2167
2161
 
2168
- this._setupMedias(session);
2162
+ await this._setupMedias(session);
2169
2163
 
2170
2164
  return this.eventEmitter.emit(ON_REINVITE, session, request, updatedCalleeName, updatedNumber, hadRemoteVideo);
2171
2165
  };
2172
2166
  }
2173
2167
 
2174
- _onProgress(session: WazoSession, early = false): void {
2175
- this._setupMedias(session);
2168
+ async _onProgress(session: WazoSession, early = false): Promise<void> {
2169
+ await this._setupMedias(session);
2176
2170
 
2177
2171
  const sessionId = this.getSipSessionId(session).substr(0, 20);
2178
2172
  this.updateRemoteStream(sessionId);
@@ -2183,7 +2177,7 @@ export default class WebRTCClient extends Emitter {
2183
2177
  this.eventEmitter.emit(early ? ON_EARLY_MEDIA : ON_PROGRESS, session);
2184
2178
  }
2185
2179
 
2186
- _onAccepted(session: WazoSession, sessionDialog?: SessionDialog, withEvent = true, initAllTracks = true): void {
2180
+ async _onAccepted(session: WazoSession, sessionDialog?: SessionDialog, withEvent = true, initAllTracks = true): Promise<void> {
2187
2181
  logger.info('on call accepted', {
2188
2182
  id: session.id,
2189
2183
  clientId: this.clientId,
@@ -2191,7 +2185,7 @@ export default class WebRTCClient extends Emitter {
2191
2185
  });
2192
2186
  this.storeSipSession(session);
2193
2187
 
2194
- this._setupMedias(session);
2188
+ await this._setupMedias(session);
2195
2189
 
2196
2190
  this.updateRemoteStream(this.getSipSessionId(session), initAllTracks);
2197
2191
  const pc = (session.sessionDescriptionHandler as SessionDescriptionHandler)?.peerConnection;
@@ -2253,7 +2247,7 @@ export default class WebRTCClient extends Emitter {
2253
2247
  return Boolean(session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === stripVideo));
2254
2248
  }
2255
2249
 
2256
- _setupMedias(session: WazoSession, newStream: MediaStream | null | undefined = null): void {
2250
+ async _setupMedias(session: WazoSession, newStream: MediaStream | null | undefined = null): Promise<void> {
2257
2251
  if (!this._isWeb()) {
2258
2252
  logger.info('Setup media on mobile, no need to setup html element, bailing');
2259
2253
  return;
@@ -2271,7 +2265,7 @@ export default class WebRTCClient extends Emitter {
2271
2265
  }
2272
2266
 
2273
2267
  if (this._hasAudio() && this._isWeb() && !(sessionId in this.audioElements)) {
2274
- this.createAudioElementFor(sessionId);
2268
+ await this.createAudioElementFor(sessionId);
2275
2269
  }
2276
2270
 
2277
2271
  const audioElement = this.audioElements[sessionId];