@wazo/sdk 0.49.3 → 0.49.5

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/dist/index.js CHANGED
@@ -4602,12 +4602,6 @@ class WebSocketClient extends Emitter {
4602
4602
  token: obfuscateToken(this.token)
4603
4603
  });
4604
4604
  if (!this.socket) return;
4605
- if (3 === this.socket.readyState) {
4606
- websocket_client_logger.warn('Trying to close an already closed websocket, bailing.', {
4607
- url: this._getUrl()
4608
- });
4609
- return;
4610
- }
4611
4605
  if (force) {
4612
4606
  this.socket.onmessage = null;
4613
4607
  this.socket.onopen = null;
@@ -4931,6 +4925,13 @@ const addIcesInAllBundles = (sdp)=>{
4931
4925
  return external_sdp_transform_default().write(parsedSdp);
4932
4926
  };
4933
4927
  const wazoLogger = IssueReporter ? IssueReporter.loggerFor('webrtc-sdh') : console;
4928
+ const TRANSIENT_SIGNALING_STATES = new Set([
4929
+ 'have-local-offer',
4930
+ 'have-local-pranswer',
4931
+ 'have-remote-pranswer'
4932
+ ]);
4933
+ const SIGNALING_STATE_SETTLE_TIMEOUT = 3000;
4934
+ const ON_CLOSED = 'sdh-closed';
4934
4935
  const wazoMediaStreamFactory = (constraints)=>{
4935
4936
  if (!constraints.audio && !constraints.video) return Promise.resolve(new MediaStream());
4936
4937
  if (void 0 === navigator.mediaDevices) return Promise.reject(new Error('Media devices not available in insecure contexts.'));
@@ -5043,6 +5044,7 @@ class WazoSessionDescriptionHandler extends session_description_handler_namespac
5043
5044
  }
5044
5045
  close() {
5045
5046
  wazoLogger.info('closing sdh');
5047
+ this.eventEmitter.emit(ON_CLOSED);
5046
5048
  if (this.isWeb) return super.close();
5047
5049
  this.logger.debug("SessionDescriptionHandler.close");
5048
5050
  if (void 0 === this._peerConnection) return;
@@ -5058,9 +5060,83 @@ class WazoSessionDescriptionHandler extends session_description_handler_namespac
5058
5060
  this._peerConnection.close();
5059
5061
  this._peerConnection = void 0;
5060
5062
  }
5061
- updateDirection(options, isConference = false, audioOnly = false) {
5063
+ rollbackDescription() {
5064
+ const peerConnection = this._peerConnection;
5065
+ const signalingState = peerConnection?.signalingState;
5066
+ const rollbackWith = (apply)=>{
5067
+ wazoLogger.info('rolling back the rejected offer', {
5068
+ signalingState
5069
+ });
5070
+ return Promise.resolve().then(apply).then(()=>{
5071
+ wazoLogger.info('offer rolled back', {
5072
+ signalingState: peerConnection.signalingState
5073
+ });
5074
+ }).catch((error)=>{
5075
+ wazoLogger.warn('rolling back the offer failed', {
5076
+ message: error?.message,
5077
+ signalingState: peerConnection.signalingState
5078
+ });
5079
+ });
5080
+ };
5081
+ if ('have-local-offer' === signalingState && peerConnection.setLocalDescription) return rollbackWith(()=>peerConnection.setLocalDescription({
5082
+ type: 'rollback'
5083
+ }));
5084
+ if ('have-remote-offer' === signalingState && peerConnection.setRemoteDescription) return rollbackWith(()=>peerConnection.setRemoteDescription({
5085
+ type: 'rollback'
5086
+ }));
5087
+ return Promise.resolve();
5088
+ }
5089
+ waitForSettledSignalingState(timeout = SIGNALING_STATE_SETTLE_TIMEOUT) {
5090
+ const peerConnection = this._peerConnection;
5091
+ if (!peerConnection?.addEventListener) return Promise.reject(new Error(`Invalid signaling state ${peerConnection?.signalingState}`));
5092
+ if (!TRANSIENT_SIGNALING_STATES.has(peerConnection.signalingState)) return 'closed' === peerConnection.signalingState ? Promise.reject(new Error('Invalid signaling state closed')) : Promise.resolve();
5093
+ return new Promise((resolve, reject)=>{
5094
+ let timeoutId;
5095
+ let onSignalingStateChange;
5096
+ let onClosed;
5097
+ const stopListening = ()=>{
5098
+ clearTimeout(timeoutId);
5099
+ this.eventEmitter.removeListener(ON_CLOSED, onClosed);
5100
+ peerConnection.removeEventListener?.('signalingstatechange', onSignalingStateChange);
5101
+ };
5102
+ onSignalingStateChange = ()=>{
5103
+ const { signalingState } = peerConnection;
5104
+ if ('closed' === signalingState) {
5105
+ reject(new Error(`Invalid signaling state ${signalingState}`));
5106
+ stopListening();
5107
+ return;
5108
+ }
5109
+ if (!TRANSIENT_SIGNALING_STATES.has(signalingState)) {
5110
+ resolve();
5111
+ stopListening();
5112
+ }
5113
+ };
5114
+ onClosed = ()=>{
5115
+ reject(new Error('Peer connection closed.'));
5116
+ stopListening();
5117
+ };
5118
+ timeoutId = setTimeout(()=>{
5119
+ const { signalingState } = peerConnection;
5120
+ reject(new Error(`Invalid signaling state ${signalingState}`));
5121
+ wazoLogger.warn('signaling state did not settle, dropping the direction update', {
5122
+ signalingState,
5123
+ timeout
5124
+ });
5125
+ stopListening();
5126
+ }, timeout);
5127
+ this.eventEmitter.once(ON_CLOSED, onClosed);
5128
+ peerConnection.addEventListener('signalingstatechange', onSignalingStateChange);
5129
+ });
5130
+ }
5131
+ updateDirection(options, isConference = false, audioOnly = false, hasWaitedForSettledState = false) {
5062
5132
  if (void 0 === this._peerConnection) return Promise.reject(new Error('Peer connection closed.'));
5063
5133
  if (!this._peerConnection.getTransceivers) return Promise.resolve();
5134
+ if (!hasWaitedForSettledState && TRANSIENT_SIGNALING_STATES.has(this._peerConnection.signalingState)) {
5135
+ wazoLogger.info('direction update issued mid-negotiation, waiting for the signaling state to settle', {
5136
+ signalingState: this._peerConnection.signalingState
5137
+ });
5138
+ return this.waitForSettledSignalingState().then(()=>this.updateDirection(options, isConference, audioOnly, true));
5139
+ }
5064
5140
  switch(this._peerConnection.signalingState){
5065
5141
  case 'stable':
5066
5142
  {
package/dist/index.mjs CHANGED
@@ -4533,12 +4533,6 @@ class WebSocketClient extends Emitter {
4533
4533
  token: obfuscateToken(this.token)
4534
4534
  });
4535
4535
  if (!this.socket) return;
4536
- if (3 === this.socket.readyState) {
4537
- websocket_client_logger.warn('Trying to close an already closed websocket, bailing.', {
4538
- url: this._getUrl()
4539
- });
4540
- return;
4541
- }
4542
4536
  if (force) {
4543
4537
  this.socket.onmessage = null;
4544
4538
  this.socket.onopen = null;
@@ -4844,6 +4838,13 @@ const addIcesInAllBundles = (sdp)=>{
4844
4838
  return __WEBPACK_EXTERNAL_MODULE_sdp_transform_45b84e5d__["default"].write(parsedSdp);
4845
4839
  };
4846
4840
  const wazoLogger = IssueReporter ? IssueReporter.loggerFor('webrtc-sdh') : console;
4841
+ const TRANSIENT_SIGNALING_STATES = new Set([
4842
+ 'have-local-offer',
4843
+ 'have-local-pranswer',
4844
+ 'have-remote-pranswer'
4845
+ ]);
4846
+ const SIGNALING_STATE_SETTLE_TIMEOUT = 3000;
4847
+ const ON_CLOSED = 'sdh-closed';
4847
4848
  const wazoMediaStreamFactory = (constraints)=>{
4848
4849
  if (!constraints.audio && !constraints.video) return Promise.resolve(new MediaStream());
4849
4850
  if (void 0 === navigator.mediaDevices) return Promise.reject(new Error('Media devices not available in insecure contexts.'));
@@ -4956,6 +4957,7 @@ class WazoSessionDescriptionHandler extends __WEBPACK_EXTERNAL_MODULE_sip_js_lib
4956
4957
  }
4957
4958
  close() {
4958
4959
  wazoLogger.info('closing sdh');
4960
+ this.eventEmitter.emit(ON_CLOSED);
4959
4961
  if (this.isWeb) return super.close();
4960
4962
  this.logger.debug("SessionDescriptionHandler.close");
4961
4963
  if (void 0 === this._peerConnection) return;
@@ -4971,9 +4973,83 @@ class WazoSessionDescriptionHandler extends __WEBPACK_EXTERNAL_MODULE_sip_js_lib
4971
4973
  this._peerConnection.close();
4972
4974
  this._peerConnection = void 0;
4973
4975
  }
4974
- updateDirection(options, isConference = false, audioOnly = false) {
4976
+ rollbackDescription() {
4977
+ const peerConnection = this._peerConnection;
4978
+ const signalingState = peerConnection?.signalingState;
4979
+ const rollbackWith = (apply)=>{
4980
+ wazoLogger.info('rolling back the rejected offer', {
4981
+ signalingState
4982
+ });
4983
+ return Promise.resolve().then(apply).then(()=>{
4984
+ wazoLogger.info('offer rolled back', {
4985
+ signalingState: peerConnection.signalingState
4986
+ });
4987
+ }).catch((error)=>{
4988
+ wazoLogger.warn('rolling back the offer failed', {
4989
+ message: error?.message,
4990
+ signalingState: peerConnection.signalingState
4991
+ });
4992
+ });
4993
+ };
4994
+ if ('have-local-offer' === signalingState && peerConnection.setLocalDescription) return rollbackWith(()=>peerConnection.setLocalDescription({
4995
+ type: 'rollback'
4996
+ }));
4997
+ if ('have-remote-offer' === signalingState && peerConnection.setRemoteDescription) return rollbackWith(()=>peerConnection.setRemoteDescription({
4998
+ type: 'rollback'
4999
+ }));
5000
+ return Promise.resolve();
5001
+ }
5002
+ waitForSettledSignalingState(timeout = SIGNALING_STATE_SETTLE_TIMEOUT) {
5003
+ const peerConnection = this._peerConnection;
5004
+ if (!peerConnection?.addEventListener) return Promise.reject(new Error(`Invalid signaling state ${peerConnection?.signalingState}`));
5005
+ if (!TRANSIENT_SIGNALING_STATES.has(peerConnection.signalingState)) return 'closed' === peerConnection.signalingState ? Promise.reject(new Error('Invalid signaling state closed')) : Promise.resolve();
5006
+ return new Promise((resolve, reject)=>{
5007
+ let timeoutId;
5008
+ let onSignalingStateChange;
5009
+ let onClosed;
5010
+ const stopListening = ()=>{
5011
+ clearTimeout(timeoutId);
5012
+ this.eventEmitter.removeListener(ON_CLOSED, onClosed);
5013
+ peerConnection.removeEventListener?.('signalingstatechange', onSignalingStateChange);
5014
+ };
5015
+ onSignalingStateChange = ()=>{
5016
+ const { signalingState } = peerConnection;
5017
+ if ('closed' === signalingState) {
5018
+ reject(new Error(`Invalid signaling state ${signalingState}`));
5019
+ stopListening();
5020
+ return;
5021
+ }
5022
+ if (!TRANSIENT_SIGNALING_STATES.has(signalingState)) {
5023
+ resolve();
5024
+ stopListening();
5025
+ }
5026
+ };
5027
+ onClosed = ()=>{
5028
+ reject(new Error('Peer connection closed.'));
5029
+ stopListening();
5030
+ };
5031
+ timeoutId = setTimeout(()=>{
5032
+ const { signalingState } = peerConnection;
5033
+ reject(new Error(`Invalid signaling state ${signalingState}`));
5034
+ wazoLogger.warn('signaling state did not settle, dropping the direction update', {
5035
+ signalingState,
5036
+ timeout
5037
+ });
5038
+ stopListening();
5039
+ }, timeout);
5040
+ this.eventEmitter.once(ON_CLOSED, onClosed);
5041
+ peerConnection.addEventListener('signalingstatechange', onSignalingStateChange);
5042
+ });
5043
+ }
5044
+ updateDirection(options, isConference = false, audioOnly = false, hasWaitedForSettledState = false) {
4975
5045
  if (void 0 === this._peerConnection) return Promise.reject(new Error('Peer connection closed.'));
4976
5046
  if (!this._peerConnection.getTransceivers) return Promise.resolve();
5047
+ if (!hasWaitedForSettledState && TRANSIENT_SIGNALING_STATES.has(this._peerConnection.signalingState)) {
5048
+ wazoLogger.info('direction update issued mid-negotiation, waiting for the signaling state to settle', {
5049
+ signalingState: this._peerConnection.signalingState
5050
+ });
5051
+ return this.waitForSettledSignalingState().then(()=>this.updateDirection(options, isConference, audioOnly, true));
5052
+ }
4977
5053
  switch(this._peerConnection.signalingState){
4978
5054
  case 'stable':
4979
5055
  {
@@ -6,6 +6,7 @@ import { SessionDescriptionHandler } from 'sip.js/lib/platform/web/session-descr
6
6
  import { SessionDescriptionHandlerOptions } from 'sip.js/lib/platform/web/session-description-handler/session-description-handler-options';
7
7
  import { WazoSession } from '../domain/types';
8
8
  import { type Candidate } from '../utils/sdp';
9
+ export declare const SIGNALING_STATE_SETTLE_TIMEOUT = 3000;
9
10
  export declare const wazoMediaStreamFactory: (constraints: Record<string, any>) => Promise<MediaStream>;
10
11
  declare class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
11
12
  gatheredCandidates: Candidate[];
@@ -22,7 +23,9 @@ declare class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
22
23
  interToneGap: number;
23
24
  }): boolean;
24
25
  close(): void;
25
- updateDirection(options?: SessionDescriptionHandlerOptions, isConference?: boolean, audioOnly?: boolean): Promise<void>;
26
+ rollbackDescription(): Promise<void>;
27
+ waitForSettledSignalingState(timeout?: number): Promise<void>;
28
+ updateDirection(options?: SessionDescriptionHandlerOptions, isConference?: boolean, audioOnly?: boolean, hasWaitedForSettledState?: boolean): Promise<void>;
26
29
  setLocalMediaStream(stream: MediaStream): Promise<void>;
27
30
  getLocalMediaStream(options: Record<string, any>): Promise<any>;
28
31
  private _constraintsEqual;
@@ -1 +1 @@
1
- {"version":3,"file":"WazoSessionDescriptionHandler.d.ts","sourceRoot":"","sources":["../../../src/lib/WazoSessionDescriptionHandler.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0EAA0E,CAAC;AACnH,OAAO,KAAK,EAAE,sCAAsC,EAAE,MAAM,+FAA+F,CAAC;AAC5J,OAAO,EAAE,yBAAyB,EAAE,MAAM,iFAAiF,CAAC;AAC5H,OAAO,EAAE,gCAAgC,EAAE,MAAM,yFAAyF,CAAC;AAC3I,OAAO,EAAkB,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9D,OAAO,EAAE,KAAK,SAAS,EAA+C,MAAM,cAAc,CAAC;AAI3F,eAAO,MAAM,sBAAsB,gBAAiB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAG,OAAO,CAAC,WAAW,CAgB5F,CAAC;AAEF,cAAM,6BAA8B,SAAQ,yBAAyB;IACnE,kBAAkB,EAAE,SAAS,EAAE,CAAC;IAEhC,YAAY,EAAE,YAAY,CAAC;IAE3B,KAAK,EAAE,OAAO,CAAC;IAEf,OAAO,EAAE,WAAW,CAAC;gBAGT,MAAM,EAAE,MAAM,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,sCAAsC,EAAE,sCAAsC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW;IAOxL,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG;IAIxD,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG;IAIzD,2BAA2B,CAAC,kBAAkB,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAYzF,cAAc,CAAC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,EAAE,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAuGhH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE;QAC/B,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;KACa,GAAG,OAAO;IAqB9C,KAAK,IAAI,IAAI;IAwCb,eAAe,CAAC,OAAO,CAAC,EAAE,gCAAgC,EAAE,YAAY,UAAQ,EAAE,SAAS,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAoLnH,mBAAmB,CAAC,MAAM,EAAE,WAAW;IA+FvC,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAwC/D,OAAO,CAAC,iBAAiB;CAe1B;AAED,eAAe,6BAA6B,CAAC"}
1
+ {"version":3,"file":"WazoSessionDescriptionHandler.d.ts","sourceRoot":"","sources":["../../../src/lib/WazoSessionDescriptionHandler.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0EAA0E,CAAC;AACnH,OAAO,KAAK,EAAE,sCAAsC,EAAE,MAAM,+FAA+F,CAAC;AAC5J,OAAO,EAAE,yBAAyB,EAAE,MAAM,iFAAiF,CAAC;AAC5H,OAAO,EAAE,gCAAgC,EAAE,MAAM,yFAAyF,CAAC;AAC3I,OAAO,EAAkB,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9D,OAAO,EAAE,KAAK,SAAS,EAA+C,MAAM,cAAc,CAAC;AAW3F,eAAO,MAAM,8BAA8B,OAAO,CAAC;AAKnD,eAAO,MAAM,sBAAsB,gBAAiB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAG,OAAO,CAAC,WAAW,CAgB5F,CAAC;AAEF,cAAM,6BAA8B,SAAQ,yBAAyB;IACnE,kBAAkB,EAAE,SAAS,EAAE,CAAC;IAEhC,YAAY,EAAE,YAAY,CAAC;IAE3B,KAAK,EAAE,OAAO,CAAC;IAEf,OAAO,EAAE,WAAW,CAAC;gBAGT,MAAM,EAAE,MAAM,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,sCAAsC,EAAE,sCAAsC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW;IAOxL,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG;IAIxD,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG;IAIzD,2BAA2B,CAAC,kBAAkB,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAYzF,cAAc,CAAC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,EAAE,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAuGhH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE;QAC/B,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;KACa,GAAG,OAAO;IAqB9C,KAAK,IAAI,IAAI;IAwDb,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAuCpC,4BAA4B,CAAC,OAAO,GAAE,MAAuC,GAAG,OAAO,CAAC,IAAI,CAAC;IAqE7F,eAAe,CAAC,OAAO,CAAC,EAAE,gCAAgC,EAAE,YAAY,UAAQ,EAAE,SAAS,UAAQ,EAAE,wBAAwB,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA6LrJ,mBAAmB,CAAC,MAAM,EAAE,WAAW;IA+FvC,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IAwC/D,OAAO,CAAC,iBAAiB;CAe1B;AAED,eAAe,6BAA6B,CAAC"}
package/dist/wazo-sdk.js CHANGED
@@ -38492,12 +38492,6 @@ and limitations under the License.
38492
38492
  token: obfuscateToken(this.token)
38493
38493
  });
38494
38494
  if (!this.socket) return;
38495
- if (3 === this.socket.readyState) {
38496
- websocket_client_logger.warn('Trying to close an already closed websocket, bailing.', {
38497
- url: this._getUrl()
38498
- });
38499
- return;
38500
- }
38501
38495
  if (force) {
38502
38496
  this.socket.onmessage = null;
38503
38497
  this.socket.onopen = null;
@@ -50083,6 +50077,13 @@ and limitations under the License.
50083
50077
  return lib.write(parsedSdp);
50084
50078
  };
50085
50079
  const wazoLogger = IssueReporter ? IssueReporter.loggerFor('webrtc-sdh') : console;
50080
+ const TRANSIENT_SIGNALING_STATES = new Set([
50081
+ 'have-local-offer',
50082
+ 'have-local-pranswer',
50083
+ 'have-remote-pranswer'
50084
+ ]);
50085
+ const SIGNALING_STATE_SETTLE_TIMEOUT = 3000;
50086
+ const ON_CLOSED = 'sdh-closed';
50086
50087
  const wazoMediaStreamFactory = (constraints)=>{
50087
50088
  if (!constraints.audio && !constraints.video) return Promise.resolve(new MediaStream());
50088
50089
  if (void 0 === navigator.mediaDevices) return Promise.reject(new Error('Media devices not available in insecure contexts.'));
@@ -50195,6 +50196,7 @@ and limitations under the License.
50195
50196
  }
50196
50197
  close() {
50197
50198
  wazoLogger.info('closing sdh');
50199
+ this.eventEmitter.emit(ON_CLOSED);
50198
50200
  if (this.isWeb) return super.close();
50199
50201
  this.logger.debug("SessionDescriptionHandler.close");
50200
50202
  if (void 0 === this._peerConnection) return;
@@ -50210,9 +50212,83 @@ and limitations under the License.
50210
50212
  this._peerConnection.close();
50211
50213
  this._peerConnection = void 0;
50212
50214
  }
50213
- updateDirection(options, isConference = false, audioOnly = false) {
50215
+ rollbackDescription() {
50216
+ const peerConnection = this._peerConnection;
50217
+ const signalingState = peerConnection?.signalingState;
50218
+ const rollbackWith = (apply)=>{
50219
+ wazoLogger.info('rolling back the rejected offer', {
50220
+ signalingState
50221
+ });
50222
+ return Promise.resolve().then(apply).then(()=>{
50223
+ wazoLogger.info('offer rolled back', {
50224
+ signalingState: peerConnection.signalingState
50225
+ });
50226
+ }).catch((error)=>{
50227
+ wazoLogger.warn('rolling back the offer failed', {
50228
+ message: error?.message,
50229
+ signalingState: peerConnection.signalingState
50230
+ });
50231
+ });
50232
+ };
50233
+ if ('have-local-offer' === signalingState && peerConnection.setLocalDescription) return rollbackWith(()=>peerConnection.setLocalDescription({
50234
+ type: 'rollback'
50235
+ }));
50236
+ if ('have-remote-offer' === signalingState && peerConnection.setRemoteDescription) return rollbackWith(()=>peerConnection.setRemoteDescription({
50237
+ type: 'rollback'
50238
+ }));
50239
+ return Promise.resolve();
50240
+ }
50241
+ waitForSettledSignalingState(timeout = SIGNALING_STATE_SETTLE_TIMEOUT) {
50242
+ const peerConnection = this._peerConnection;
50243
+ if (!peerConnection?.addEventListener) return Promise.reject(new Error(`Invalid signaling state ${peerConnection?.signalingState}`));
50244
+ if (!TRANSIENT_SIGNALING_STATES.has(peerConnection.signalingState)) return 'closed' === peerConnection.signalingState ? Promise.reject(new Error('Invalid signaling state closed')) : Promise.resolve();
50245
+ return new Promise((resolve, reject)=>{
50246
+ let timeoutId;
50247
+ let onSignalingStateChange;
50248
+ let onClosed;
50249
+ const stopListening = ()=>{
50250
+ clearTimeout(timeoutId);
50251
+ this.eventEmitter.removeListener(ON_CLOSED, onClosed);
50252
+ peerConnection.removeEventListener?.('signalingstatechange', onSignalingStateChange);
50253
+ };
50254
+ onSignalingStateChange = ()=>{
50255
+ const { signalingState } = peerConnection;
50256
+ if ('closed' === signalingState) {
50257
+ reject(new Error(`Invalid signaling state ${signalingState}`));
50258
+ stopListening();
50259
+ return;
50260
+ }
50261
+ if (!TRANSIENT_SIGNALING_STATES.has(signalingState)) {
50262
+ resolve();
50263
+ stopListening();
50264
+ }
50265
+ };
50266
+ onClosed = ()=>{
50267
+ reject(new Error('Peer connection closed.'));
50268
+ stopListening();
50269
+ };
50270
+ timeoutId = setTimeout(()=>{
50271
+ const { signalingState } = peerConnection;
50272
+ reject(new Error(`Invalid signaling state ${signalingState}`));
50273
+ wazoLogger.warn('signaling state did not settle, dropping the direction update', {
50274
+ signalingState,
50275
+ timeout
50276
+ });
50277
+ stopListening();
50278
+ }, timeout);
50279
+ this.eventEmitter.once(ON_CLOSED, onClosed);
50280
+ peerConnection.addEventListener('signalingstatechange', onSignalingStateChange);
50281
+ });
50282
+ }
50283
+ updateDirection(options, isConference = false, audioOnly = false, hasWaitedForSettledState = false) {
50214
50284
  if (void 0 === this._peerConnection) return Promise.reject(new Error('Peer connection closed.'));
50215
50285
  if (!this._peerConnection.getTransceivers) return Promise.resolve();
50286
+ if (!hasWaitedForSettledState && TRANSIENT_SIGNALING_STATES.has(this._peerConnection.signalingState)) {
50287
+ wazoLogger.info('direction update issued mid-negotiation, waiting for the signaling state to settle', {
50288
+ signalingState: this._peerConnection.signalingState
50289
+ });
50290
+ return this.waitForSettledSignalingState().then(()=>this.updateDirection(options, isConference, audioOnly, true));
50291
+ }
50216
50292
  switch(this._peerConnection.signalingState){
50217
50293
  case 'stable':
50218
50294
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wazo/sdk",
3
- "version": "0.49.3",
3
+ "version": "0.49.5",
4
4
  "description": "Wazo's JavaScript Software Development Kit.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/types/index.d.ts",