@wazo/sdk 0.37.2 → 0.37.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.
Files changed (99) hide show
  1. package/dist/wazo-sdk.js +5 -5
  2. package/esm/__tests__/api-client.test.js +84 -22
  3. package/esm/__tests__/web-rtc-client.test.js +156 -55
  4. package/esm/api/call-logd.js +10 -22
  5. package/esm/api/calld.js +3 -0
  6. package/esm/api/confd.js +71 -0
  7. package/esm/api-client.js +84 -22
  8. package/esm/checker/Checker.js +160 -55
  9. package/esm/checker/checks/aor.js +84 -22
  10. package/esm/checker/checks/api.js +84 -22
  11. package/esm/checker/checks/index.js +160 -55
  12. package/esm/checker/checks/wazo-websocket.js +4 -0
  13. package/esm/checker/checks/webrtc-transport.js +156 -55
  14. package/esm/checker/checks/webrtc.js +156 -55
  15. package/esm/domain/AdHocAPIConference.js +84 -22
  16. package/esm/domain/CallLog.js +10 -22
  17. package/esm/domain/Features.js +84 -22
  18. package/esm/domain/Meeting.js +71 -0
  19. package/esm/domain/Phone/CTIPhone.js +84 -22
  20. package/esm/domain/Phone/WebRTCPhone.js +22 -8
  21. package/esm/domain/__tests__/CallLog.test.js +10 -22
  22. package/esm/index.js +726 -371
  23. package/esm/lib/WazoSessionDescriptionHandler.js +17 -9
  24. package/esm/service/CallApi.js +84 -22
  25. package/esm/service/getApiClient.js +84 -22
  26. package/esm/simple/Auth.js +717 -363
  27. package/esm/simple/Configuration.js +717 -363
  28. package/esm/simple/Directory.js +84 -22
  29. package/esm/simple/Phone.js +709 -355
  30. package/esm/simple/Websocket.js +6 -0
  31. package/esm/simple/index.js +719 -365
  32. package/esm/simple/room/LocalParticipant.js +689 -335
  33. package/esm/simple/room/Participant.js +689 -335
  34. package/esm/simple/room/RemoteParticipant.js +689 -335
  35. package/esm/simple/room/Room.js +689 -335
  36. package/esm/simple/room/SipRoom.js +13001 -0
  37. package/esm/simple/room/Stream.js +719 -365
  38. package/esm/simple/room/__tests__/RemoteParticipant.test.js +4130 -3774
  39. package/esm/simple/utils.js +719 -365
  40. package/esm/web-rtc-client.js +156 -55
  41. package/esm/websocket-client.js +5 -1
  42. package/lib/__tests__/api-client.test.js +84 -22
  43. package/lib/__tests__/web-rtc-client.test.js +156 -55
  44. package/lib/api/call-logd.js +10 -22
  45. package/lib/api/calld.js +3 -0
  46. package/lib/api/confd.js +71 -0
  47. package/lib/api-client.js +84 -22
  48. package/lib/checker/Checker.js +160 -55
  49. package/lib/checker/checks/aor.js +84 -22
  50. package/lib/checker/checks/api.js +84 -22
  51. package/lib/checker/checks/index.js +160 -55
  52. package/lib/checker/checks/wazo-websocket.js +4 -0
  53. package/lib/checker/checks/webrtc-transport.js +156 -55
  54. package/lib/checker/checks/webrtc.js +156 -55
  55. package/lib/domain/AdHocAPIConference.js +84 -22
  56. package/lib/domain/CallLog.js +10 -22
  57. package/lib/domain/Features.js +84 -22
  58. package/lib/domain/Meeting.js +73 -0
  59. package/lib/domain/Phone/CTIPhone.js +84 -22
  60. package/lib/domain/Phone/WebRTCPhone.js +22 -8
  61. package/lib/domain/__tests__/CallLog.test.js +10 -22
  62. package/lib/index.js +726 -371
  63. package/lib/lib/WazoSessionDescriptionHandler.js +17 -9
  64. package/lib/service/CallApi.js +84 -22
  65. package/lib/service/getApiClient.js +84 -22
  66. package/lib/simple/Auth.js +717 -363
  67. package/lib/simple/Configuration.js +717 -363
  68. package/lib/simple/Directory.js +84 -22
  69. package/lib/simple/Phone.js +709 -355
  70. package/lib/simple/Websocket.js +6 -0
  71. package/lib/simple/index.js +719 -365
  72. package/lib/simple/room/LocalParticipant.js +689 -335
  73. package/lib/simple/room/Participant.js +689 -335
  74. package/lib/simple/room/RemoteParticipant.js +689 -335
  75. package/lib/simple/room/Room.js +689 -335
  76. package/lib/simple/room/SipRoom.js +13011 -0
  77. package/lib/simple/room/Stream.js +719 -365
  78. package/lib/simple/room/__tests__/RemoteParticipant.test.js +4131 -3775
  79. package/lib/simple/utils.js +719 -365
  80. package/lib/web-rtc-client.js +156 -55
  81. package/lib/websocket-client.js +6 -0
  82. package/package.json +1 -1
  83. package/src/api/calld.js +3 -0
  84. package/src/api/confd.js +13 -0
  85. package/src/domain/CallLog.js +10 -22
  86. package/src/domain/Meeting.js +59 -0
  87. package/src/domain/Phone/WebRTCPhone.js +22 -8
  88. package/src/index.js +2 -0
  89. package/src/lib/WazoSessionDescriptionHandler.js +17 -9
  90. package/src/simple/Phone.js +13 -4
  91. package/src/simple/index.js +4 -0
  92. package/src/simple/room/Participant.js +7 -0
  93. package/src/simple/room/Room.js +158 -79
  94. package/src/simple/room/SipRoom.js +147 -0
  95. package/src/simple/room/Stream.js +1 -3
  96. package/src/simple/room/__tests__/RemoteParticipant.test.js +3 -2
  97. package/src/types/WebSocketMessage.js +21 -0
  98. package/src/web-rtc-client.js +55 -24
  99. package/src/websocket-client.js +4 -0
@@ -0,0 +1,147 @@
1
+ // @flow
2
+
3
+ import type { Message } from 'sip.js/lib/api/message';
4
+ import IssueReporter from '../../service/IssueReporter';
5
+ import Wazo from '../index';
6
+ import Room from './Room';
7
+
8
+ const logger = IssueReporter.loggerFor('sdk-sip-room');
9
+
10
+ class SipRoom extends Room {
11
+
12
+ static async connect({ extension, constraints, audioOnly = false, extra, room }: Object) {
13
+ logger.info('connecting to sip room', { extension, audioOnly, room: !!room });
14
+
15
+ if (!room) {
16
+ await Wazo.Phone.connect();
17
+
18
+ const withCamera = constraints && !!constraints.video;
19
+
20
+ const callSession = await Wazo.Phone.call(extension, withCamera, null, audioOnly, true);
21
+ // eslint-disable-next-line no-param-reassign
22
+ room = new SipRoom(callSession, extension, null, null, extra);
23
+ }
24
+
25
+ if (room && room.callSession && room.callSession.call) {
26
+ room.setCallId(room.callSession.call.id);
27
+ }
28
+
29
+ logger.info('connected to room', {
30
+ extension: room.extension,
31
+ });
32
+
33
+ return room;
34
+ }
35
+
36
+ mute() {
37
+ logger.info('mute sip room');
38
+
39
+ Wazo.Phone.mute(this.callSession, false);
40
+
41
+ this.sendMuteStatus();
42
+ }
43
+
44
+ unmute() {
45
+ logger.info('unmute sip room');
46
+
47
+ Wazo.Phone.unmute(this.callSession, false);
48
+
49
+ this.sendUnMuteStatus();
50
+ }
51
+
52
+ getLocalGuestName() {
53
+ return Wazo.Phone.phone.client.userAgent.options.displayName;
54
+ }
55
+
56
+ // Overridden to not listen to websocket messages
57
+ _transferEvents() {
58
+ // Phone events
59
+ Wazo.Phone.on(this.ON_MESSAGE, this._boundOnMessage);
60
+ Wazo.Phone.on(this.ON_CHAT, this._boundOnChat);
61
+ Wazo.Phone.on(this.ON_SIGNAL, this._boundOnSignal);
62
+ Wazo.Phone.on(this.ON_VIDEO_INPUT_CHANGE, this._boundSaveLocalVideoStream);
63
+
64
+ [this.ON_AUDIO_STREAM, this.ON_VIDEO_STREAM, this.ON_REMOVE_STREAM].forEach(event =>
65
+ Wazo.Phone.on(event, (...args) => this.eventEmitter.emit.apply(this.eventEmitter, [event, ...args])));
66
+ }
67
+
68
+ _onMessage(message: Message) {
69
+ // eslint-disable-next-line no-underscore-dangle
70
+ const body = super._onMessage(message);
71
+ if (!body) {
72
+ return;
73
+ }
74
+
75
+ const getChannel = () => body.channels[0];
76
+
77
+ switch (body.type) {
78
+ case 'ConfbridgeWelcome':
79
+ body.channels.forEach(channel => {
80
+ this._onParticipantJoined(channel);
81
+ });
82
+
83
+ break;
84
+ case 'ConfbridgeJoin': {
85
+ const channel = getChannel();
86
+ this._onParticipantJoined(channel);
87
+ break;
88
+ }
89
+ case 'ConfbridgeLeave': {
90
+ const channel = getChannel();
91
+ this._onParticipantLeft({
92
+ data: {
93
+ call_id: channel.id,
94
+ },
95
+ });
96
+ break;
97
+ }
98
+ default:
99
+ break;
100
+ }
101
+ }
102
+
103
+ async _onParticipantJoined(channel: Object) {
104
+ const isLocal = channel.channelvars.WAZO_SIP_CALL_ID === this._getCurrentSipCallIs();
105
+ const callId = channel.id;
106
+ const ParticipantClass = isLocal ? Wazo.LocalParticipant : Wazo.RemoteParticipant;
107
+ const name = channel.caller ? channel.caller.name : null;
108
+ const extra = isLocal ? { guestName: this.getLocalGuestName() } : {};
109
+ const participant = new ParticipantClass(this, {
110
+ caller_id_name: name,
111
+ call_id: callId,
112
+ }, extra);
113
+
114
+ const participantIdx = this.participants.findIndex(other => other.callId === participant.callId);
115
+ if (participantIdx !== -1 && name) {
116
+ this.participants[participantIdx].name = name;
117
+ return;
118
+ }
119
+
120
+ if (isLocal) {
121
+ // Should be updated by the Wazo WS but we don't have it for now
122
+ if (this.callSession) {
123
+ this.callSession.ringing = false;
124
+ }
125
+
126
+ this._onLocalParticipantJoined(participant);
127
+
128
+ // Give some time for the stream to be updated
129
+ setTimeout(() => {
130
+ this.eventEmitter.emit(this.ON_JOINED, participant, this.participants);
131
+ }, 1000);
132
+ }
133
+
134
+ this.participants.push(participant);
135
+
136
+ this._isParticipantJoining(participant);
137
+
138
+ return participant;
139
+ }
140
+
141
+ _getCurrentSipCallIs() {
142
+ return Wazo.Phone.getSipSessionId(Wazo.Phone.phone.currentSipSession);
143
+ }
144
+
145
+ }
146
+
147
+ export default SipRoom;
@@ -52,9 +52,7 @@ class Stream {
52
52
  return false;
53
53
  }
54
54
 
55
- // With canvas track (used to fake upgrade in conference), we don't have a width
56
- return this.htmlStream.getTracks().find(track => track.kind === 'video'
57
- && track.readyState !== 'ended' && 'width' in track.getSettings());
55
+ return this.htmlStream.getTracks().some(track => track.kind === 'video' && track.readyState !== 'ended');
58
56
  }
59
57
 
60
58
  get id() {
@@ -1,9 +1,10 @@
1
- import RemoteParticipant from '../RemoteParticipant';
1
+ // Using directly Wazo to avoid issues with require cycle
2
+ import Wazo from '../../index';
2
3
 
3
4
  describe('RemoteParticipant', () => {
4
5
  it('should fall back on number when name is <unknown>', () => {
5
6
  const number = '1234';
6
- const participant = new RemoteParticipant(null, { caller_id_name: '<unknown>', caller_id_number: number });
7
+ const participant = new Wazo.RemoteParticipant(null, { caller_id_name: '<unknown>', caller_id_number: number });
7
8
  expect(participant.name).toEqual(number);
8
9
  });
9
10
  });
@@ -91,6 +91,17 @@ export type RoomParticipantUpdate = {
91
91
  muted: boolean,
92
92
  user_uuid: string,
93
93
  };
94
+ export type MeetingParticipantUpdate = {
95
+ admin: boolean,
96
+ call_id: string,
97
+ caller_id_name: string,
98
+ caller_id_number: string,
99
+ room_uuid: string,
100
+ id: string,
101
+ language: string,
102
+ muted: boolean,
103
+ user_uuid: string,
104
+ };
94
105
 
95
106
  export type FaxOutboundFailedEvent = {
96
107
  call_id: string,
@@ -145,6 +156,14 @@ type ParticipantLeftRoom = WebSocketBaseMessage & {
145
156
  data: RoomParticipantUpdate,
146
157
  name: 'conference_user_participant_left',
147
158
  };
159
+ type ParticipantJoinedMeeting = WebSocketBaseMessage & {
160
+ data: MeetingParticipantUpdate,
161
+ name: 'meeting_user_participant_joined',
162
+ };
163
+ type ParticipantLeftMeeting = WebSocketBaseMessage & {
164
+ data: MeetingParticipantUpdate,
165
+ name: 'meeting_user_participant_left',
166
+ };
148
167
  type SwitchboardQueuedCallsUpdated = WebSocketBaseMessage & {
149
168
  data: SwitchboardCallItems,
150
169
  name: 'switchboard_queued_calls_updated',
@@ -194,6 +213,8 @@ export type WebSocketMessage =
194
213
  | SwitchboardHeldCallAnswered
195
214
  | ParticipantJoinedRoom
196
215
  | ParticipantLeftRoom
216
+ | ParticipantJoinedMeeting
217
+ | ParticipantLeftMeeting
197
218
  | FaxOutboundFailed
198
219
  | FaxOutboundSucceeded
199
220
  | AgentStatusUpdate
@@ -96,6 +96,7 @@ type WebRtcConfig = {
96
96
  heartbeatDelay: number,
97
97
  heartbeatTimeout: number,
98
98
  maxHeartbeats: number,
99
+ skipRegister: boolean,
99
100
  };
100
101
 
101
102
  // @see https://github.com/onsip/SIP.js/blob/master/src/Web/Simple.js
@@ -121,6 +122,7 @@ export default class WebRTCClient extends Emitter {
121
122
  statsIntervals: Object;
122
123
  sipSessions: { [string]: Session };
123
124
  conferences: { [string]: boolean };
125
+ skipRegister: boolean;
124
126
 
125
127
  // sugar
126
128
  ON_USER_AGENT: string;
@@ -159,6 +161,8 @@ export default class WebRTCClient extends Emitter {
159
161
  super();
160
162
  this.uaConfigOverrides = uaConfigOverrides;
161
163
  this.config = config;
164
+ this.skipRegister = config.skipRegister;
165
+
162
166
  this._buildConfig(config, session).then((newConfig: WebRtcConfig) => {
163
167
  this.config = newConfig;
164
168
  this.userAgent = this.createUserAgent(uaConfigOverrides);
@@ -286,14 +290,22 @@ export default class WebRTCClient extends Emitter {
286
290
  }
287
291
 
288
292
  register(tries: number = 0): Promise<any> {
289
- logger.info('sdk webrtc registering...', {
293
+ const logInfo = {
290
294
  userAgent: !!this.userAgent,
291
295
  registered: this.isRegistered(),
292
296
  connectionPromise: !!this.connectionPromise,
293
297
  registerer: !!this.registerer,
294
298
  waiting: this.registerer && this.registerer.waiting,
295
299
  tries,
296
- });
300
+ skipRegister: this.skipRegister,
301
+ };
302
+
303
+ if (this.skipRegister) {
304
+ logger.info('sdk webrtc skip register...', logInfo);
305
+ return Promise.resolve();
306
+ }
307
+
308
+ logger.info('sdk webrtc registering...', logInfo);
297
309
 
298
310
  if (!this.userAgent) {
299
311
  logger.info('sdk webrtc recreating User Agent');
@@ -624,12 +636,18 @@ export default class WebRTCClient extends Emitter {
624
636
  }
625
637
 
626
638
  if (pc.getSenders) {
639
+ if (!pc.getSenders().length) {
640
+ return false;
641
+ }
627
642
  pc.getSenders().forEach(sender => {
628
643
  if (sender && sender.track && sender.track.kind === 'audio') {
629
644
  muted = muted && !sender.track.enabled;
630
645
  }
631
646
  });
632
647
  } else {
648
+ if (!pc.getLocalStreams().length) {
649
+ return false;
650
+ }
633
651
  pc.getLocalStreams().forEach(stream => {
634
652
  stream.getAudioTracks().forEach(track => {
635
653
  muted = muted && !track.enabled;
@@ -688,6 +706,8 @@ export default class WebRTCClient extends Emitter {
688
706
  }
689
707
  options.sessionDescriptionHandlerOptions = {
690
708
  constraints: options.constraints,
709
+ hold: true,
710
+ conference: isConference,
691
711
  };
692
712
 
693
713
  // Send re-INVITE
@@ -730,6 +750,8 @@ export default class WebRTCClient extends Emitter {
730
750
  }
731
751
  options.sessionDescriptionHandlerOptions = {
732
752
  constraints: options.constraints,
753
+ hold: false,
754
+ conference: isConference,
733
755
  };
734
756
 
735
757
  // Send re-INVITE
@@ -913,7 +935,8 @@ export default class WebRTCClient extends Emitter {
913
935
  }
914
936
  const sdh = session.sessionDescriptionHandler;
915
937
  const pc = sdh.peerConnection;
916
- const localStream = this.getLocalStream(this.getSipSessionId(session));
938
+ const sessionId = this.getSipSessionId(session);
939
+ const localStream = this.getLocalStream(sessionId);
917
940
 
918
941
  // Release old video stream
919
942
  if (localStream) {
@@ -939,11 +962,8 @@ export default class WebRTCClient extends Emitter {
939
962
 
940
963
  // let's update the local stream
941
964
  this.eventEmitter.emit('onVideoInputChange', stream);
942
- try {
943
- await sdh.setLocalMediaStream(stream);
944
- } catch (_) {
945
- // Nothing to do
946
- }
965
+ this.setLocalMediaStream(sessionId, stream);
966
+
947
967
  return stream;
948
968
  });
949
969
  }
@@ -1245,9 +1265,11 @@ export default class WebRTCClient extends Emitter {
1245
1265
  remoteStream.removeTrack(track);
1246
1266
  });
1247
1267
 
1248
- pc.getReceivers().forEach(receiver => {
1249
- remoteStream.addTrack(receiver.track);
1250
- });
1268
+ if (pc.getReceivers) {
1269
+ pc.getReceivers().forEach(receiver => {
1270
+ remoteStream.addTrack(receiver.track);
1271
+ });
1272
+ }
1251
1273
  }
1252
1274
 
1253
1275
  getMediaConfiguration(enableVideo: boolean, conference: boolean = false, constraints: ?Object = null): Object {
@@ -1282,6 +1304,25 @@ export default class WebRTCClient extends Emitter {
1282
1304
  return sessionId in this.conferences;
1283
1305
  }
1284
1306
 
1307
+ createAudioElementFor(sessionId: string) {
1308
+ const audio: any = document.createElement('audio');
1309
+ audio.setAttribute('id', `audio-${sessionId}`);
1310
+
1311
+ if (audio.setSinkId && this.audioOutputDeviceId) {
1312
+ audio.setSinkId(this.audioOutputDeviceId);
1313
+ }
1314
+
1315
+ if (document.body) {
1316
+ document.body.appendChild(audio);
1317
+ }
1318
+ this.audioElements[sessionId] = audio;
1319
+
1320
+ audio.volume = this.audioOutputVolume;
1321
+ audio.autoplay = true;
1322
+
1323
+ return audio;
1324
+ }
1325
+
1285
1326
  _onTransportError() {
1286
1327
  this.eventEmitter.emit(TRANSPORT_ERROR);
1287
1328
  this.attemptReconnection();
@@ -1511,7 +1552,7 @@ export default class WebRTCClient extends Emitter {
1511
1552
  let hadRemoteVideo = false;
1512
1553
 
1513
1554
  // Monkey patch `onInviteRequest` to be able to know if there was a remote video stream before `onInvite` is called
1514
- // Becase when `onInvite` is called we already got the video track
1555
+ // Because when `onInvite` is called we already got the video track
1515
1556
  session.onInviteRequest = (request) => {
1516
1557
  hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
1517
1558
 
@@ -1586,20 +1627,10 @@ export default class WebRTCClient extends Emitter {
1586
1627
  const isConference = this.isConference(sessionId);
1587
1628
 
1588
1629
  if (this._hasAudio() && this._isWeb() && !(sessionId in this.audioElements)) {
1589
- const audio: any = document.createElement('audio');
1590
- audio.setAttribute('id', `audio-${sessionId}`);
1591
-
1592
- if (audio.setSinkId && this.audioOutputDeviceId) {
1593
- audio.setSinkId(this.audioOutputDeviceId);
1594
- }
1595
-
1596
- if (document.body) {
1597
- document.body.appendChild(audio);
1598
- }
1599
- this.audioElements[sessionId] = audio;
1630
+ this.createAudioElementFor(sessionId);
1600
1631
  }
1601
1632
 
1602
- const audioElement = this.audioElements[this.getSipSessionId(session)];
1633
+ const audioElement = this.audioElements[sessionId];
1603
1634
  const stream = newStream || this.getRemoteStream(sessionId);
1604
1635
 
1605
1636
  if (!this._isWeb() || !stream) {
@@ -59,6 +59,8 @@ export const CONFERENCE_USER_PARTICIPANT_JOINED = 'conference_user_participant_j
59
59
  export const CONFERENCE_USER_PARTICIPANT_LEFT = 'conference_user_participant_left';
60
60
  export const CONFERENCE_USER_PARTICIPANT_TALK_STARTED = 'conference_user_participant_talk_started';
61
61
  export const CONFERENCE_USER_PARTICIPANT_TALK_STOPPED = 'conference_user_participant_talk_stopped';
62
+ export const MEETING_USER_PARTICIPANT_JOINED = 'meeting_user_participant_joined';
63
+ export const MEETING_USER_PARTICIPANT_LEFT = 'meeting_user_participant_left';
62
64
  export const SWITCHBOARD_QUEUED_CALLS_UPDATED = 'switchboard_queued_calls_updated';
63
65
  export const SWITCHBOARD_QUEUED_CALL_ANSWERED = 'switchboard_queued_call_answered';
64
66
  export const SWITCHBOARD_HELD_CALLS_UPDATED = 'switchboard_held_calls_updated';
@@ -408,6 +410,8 @@ WebSocketClient.eventLists = [
408
410
  CHATD_USER_ROOM_CREATED,
409
411
  CONFERENCE_USER_PARTICIPANT_JOINED,
410
412
  CONFERENCE_USER_PARTICIPANT_LEFT,
413
+ MEETING_USER_PARTICIPANT_JOINED,
414
+ MEETING_USER_PARTICIPANT_LEFT,
411
415
  CONFERENCE_USER_PARTICIPANT_TALK_STARTED,
412
416
  CONFERENCE_USER_PARTICIPANT_TALK_STOPPED,
413
417
  SWITCHBOARD_QUEUED_CALLS_UPDATED,