Skip to content

Commit

Permalink
Merge pull request #767 from wazo-platform/WDA-2377-missing-ringback
Browse files Browse the repository at this point in the history
[WDA-2377] Fix mishandled ringback
  • Loading branch information
bogue authored May 28, 2024
2 parents a84340a + a62482b commit 3fdda41
Show file tree
Hide file tree
Showing 9 changed files with 38 additions and 47 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@wazo/sdk",
"version": "0.42.0",
"version": "0.43.0-rc.0",
"description": "Wazo's JavaScript Software Development Kit.",
"main": "index.js",
"types": "lib/types/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/web-rtc-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jest.mock('sip.js/lib/api/user-agent', () => ({
},
}));

const client = new WebRTCClient({} as any, null, undefined);
const client = new WebRTCClient({} as any, undefined, undefined);

describe('WebRTC client', () => {
it('should compute muted/unmuted state', async () => {
Expand Down
2 changes: 1 addition & 1 deletion src/domain/Phone/CTIPhone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ export default class CTIPhone extends Emitter implements Phone {

changeVideoInputDevice() { return Promise.resolve(null); }

changeAudioDevice() {}
changeAudioDevice() { return Promise.resolve(); }

changeRingDevice() {}

Expand Down
2 changes: 1 addition & 1 deletion src/domain/Phone/Phone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export type AvailablePhoneOptions = {
};
export interface Phone extends IEmitter {
accept(callSession: CallSession, enableVideo?: boolean): Promise<string | null>;
changeAudioDevice(id: string): PhoneVoid;
changeAudioDevice(id: string): Promise<void>;
changeRingDevice(id: string): PhoneVoid;
changeAudioVolume(volume: number): PhoneVoid;
changeRingVolume(volume: number): PhoneVoid;
Expand Down
8 changes: 4 additions & 4 deletions src/domain/Phone/WebRTCPhone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -612,12 +612,12 @@ export default class WebRTCPhone extends Emitter implements Phone {
return callSession;
}

changeAudioDevice(id: string) {
async changeAudioDevice(id: string) {
logger.info('WebRTC phone - change audio device', {
deviceId: id,
});
this.audioOutputDeviceId = id;
this.client.changeAudioOutputDevice(id);
return this.client.changeAudioOutputDevice(id);
}

createAudioElementFor(sessionId: string) {
Expand Down Expand Up @@ -1528,7 +1528,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
this.eventEmitter.emit.apply(this.eventEmitter, [this.client.ON_REINVITE, ...args]);
}, 2000);
});
this.client.on(this.client.ACCEPTED, (sipSession: WazoSession) => {
this.client.on(this.client.ACCEPTED, async (sipSession: WazoSession) => {
const sessionId = this.getSipSessionId(sipSession);
const hasSession = (sessionId in this.callSessions);
logger.info('WebRTC call accepted', {
Expand All @@ -1546,7 +1546,7 @@ export default class WebRTCPhone extends Emitter implements Phone {
this._onCallAccepted(sipSession, this.client.hasVideo(sessionId));

if (this.audioOutputDeviceId) {
this.client.changeAudioOutputDevice(this.audioOutputDeviceId);
await this.client.changeAudioOutputDevice(this.audioOutputDeviceId);
}
});
this.client.on('ended', () => {});
Expand Down
11 changes: 4 additions & 7 deletions src/domain/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,21 +243,18 @@ export type WebRtcConfig = {
media?: MediaConfig;
iceCheckingTimeout?: number;
log?: Record<string, any>;
audioOutputDeviceId?: string;
audioOutputVolume?: number;
userAgentString?: string;
heartbeatDelay?: number;
heartbeatTimeout?: number;
maxHeartbeats?: number;
skipRegister?: boolean;
userUuid?: string;
userUuid?: string,
uaConfigOverrides?: UserAgentConfigOverrides,
audioDeviceOutput?: string,
audioDeviceRing?: string
}; // @see https://github.com/onsip/SIP.js/blob/master/src/Web/Simple.js

export type ConnectionOptions = WebRtcConfig & {
uaConfigOverrides: UserAgentConfigOverrides;
audioDeviceOutput: string;
audioDeviceRing: string;
};
export type IncomingResponse = SipIncomingResponse & { session: any };

export type PeerConnection = RTCPeerConnection & {
Expand Down
8 changes: 4 additions & 4 deletions src/simple/Phone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import IssueReporter from '../service/IssueReporter';
import Emitter from '../utils/Emitter';
import Wazo from './index';
import SFUNotAvailableError from '../domain/SFUNotAvailableError';
import { ConnectionOptions, WazoSession } from '../domain/types';
import { WazoSession, WebRtcConfig } from '../domain/types';

const logger = IssueReporter.loggerFor('simple-phone');
const sipLogger = IssueReporter.loggerFor('sip.js');
Expand Down Expand Up @@ -127,7 +127,7 @@ export class Phone extends Emitter {
this.SessionState = SessionState;
}

async connect(rawOptions: Partial<ConnectionOptions> = {}, sipLine: SipLine | null | undefined = null): Promise<void> {
async connect(rawOptions: Partial<WebRtcConfig> = {}, sipLine: SipLine | null | undefined = null): Promise<void> {
const options = rawOptions;
if (this.phone) {
// Already connected
Expand Down Expand Up @@ -162,7 +162,7 @@ export class Phone extends Emitter {
server: string,
sipLine: SipLine,
displayName: string,
rawOptions: Partial<ConnectionOptions> = {},
rawOptions: Partial<WebRtcConfig> = {},
): void {
if (this.phone) {
// Already connected
Expand Down Expand Up @@ -194,7 +194,7 @@ export class Phone extends Emitter {
password: sipLine.secret,
uri: `${sipLine.username}@${server}`,
...options,
}, null, options.uaConfigOverrides);
}, undefined, options.uaConfigOverrides);
this.phone = new WebRTCPhone(this.client, options.audioDeviceOutput, true, options.audioDeviceRing);

this._transferEvents();
Expand Down
4 changes: 2 additions & 2 deletions src/simple/room/Room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -492,13 +492,13 @@ class Room extends Emitter {
// Listen to REINVITE to ba able to map msid after upgrading to video in a audio only conference
// This allow to map msid with the non parsed (eg without the `stripVideo` modifier) SDP
Wazo.Phone.phone.on(Wazo.Phone.phone.client.ON_REINVITE, this._boundOnReinvite);
this.on(this.ON_AUDIO_STREAM, stream => {
this.on(this.ON_AUDIO_STREAM, async stream => {
logger.info('on room audio stream');
this.audioStream = stream;

if (!this.roomAudioElement) {
const sessionId = Wazo.Phone.phone?.getSipSessionId(Wazo.Phone.phone?.currentSipSession as WazoSession);
this.roomAudioElement = Wazo.Phone.phone?.createAudioElementFor(sessionId as string) as HTMLAudioElement;
this.roomAudioElement = await Wazo.Phone.phone?.createAudioElementFor(sessionId as string) as HTMLAudioElement;
this.roomAudioElement.srcObject = stream;
} else {
this.roomAudioElement.srcObject = stream;
Expand Down
46 changes: 20 additions & 26 deletions src/web-rtc-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export default class WebRTCClient extends Emitter {

audio: MediaTrackConstraintSet | boolean | undefined;

audioElements: Record<string, HTMLAudioElement & { setSinkId?: (id: string) => void }>;
audioElements: Record<string, HTMLAudioElement>;

video: MediaTrackConstraintSet | boolean | undefined;

Expand Down Expand Up @@ -182,7 +182,7 @@ export default class WebRTCClient extends Emitter {
return [];
}

constructor(config: WebRtcConfig, session: WazoSession | null | undefined, uaConfigOverrides?: UserAgentConfigOverrides) {
constructor(config: WebRtcConfig, session?: WazoSession, uaConfigOverrides?: UserAgentConfigOverrides) {
super();

// For debug purpose
Expand All @@ -198,7 +198,7 @@ export default class WebRTCClient extends Emitter {
this.userAgent = this.createUserAgent(uaConfigOverrides);
});

this.audioOutputDeviceId = config.audioOutputDeviceId;
this.audioOutputDeviceId = config.audioDeviceOutput;
this.audioOutputVolume = config.audioOutputVolume || 1;

if (config.media) {
Expand Down Expand Up @@ -1246,20 +1246,14 @@ export default class WebRTCClient extends Emitter {
this.audioOutputVolume = volume;
}

changeAudioOutputDevice(id: string) {
async changeAudioOutputDevice(id: string) {
logger.info('Changing audio output device', {
id,
});
this.audioOutputDeviceId = id;
Object.values(this.audioElements).forEach(audioElement => {
// `setSinkId` method is not included in any flow type definitions for HTMLAudioElements but is a valid method
// audioElement is an array of HTMLAudioElements, and HTMLAudioElement inherits the method from HTMLMediaElement
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId
if (audioElement.setSinkId) {
audioElement.setSinkId(id);
}
});
const promises: Promise<void>[] = [];
Object.values(this.audioElements).forEach(audioElement => promises.push(audioElement.setSinkId(id)));
await Promise.allSettled(promises);
}

async changeAudioInputDevice(id: string, session: WazoSession | null | undefined, force?: boolean): Promise<MediaStream | null> {
Expand Down Expand Up @@ -1735,7 +1729,7 @@ export default class WebRTCClient extends Emitter {
}
}

updateLocalStream(sipSessionId: string, newStream: MediaStream): void {
async updateLocalStream(sipSessionId: string, newStream: MediaStream): Promise<void> {
const sipSession = this.sipSessions[sipSessionId];

if (!sipSession) {
Expand All @@ -1756,7 +1750,7 @@ export default class WebRTCClient extends Emitter {
this.setLocalMediaStream(sipSessionId, newStream);

// Update the local video element
this._setupMedias(sipSession, newStream);
await this._setupMedias(sipSession, newStream);
}

updateRemoteStream(sessionId: string, allTracks = true): void {
Expand Down Expand Up @@ -1832,14 +1826,14 @@ export default class WebRTCClient extends Emitter {
return sessionId in this.conferences;
}

createAudioElementFor(sessionId: string): HTMLAudioElement {
async createAudioElementFor(sessionId: string): Promise<HTMLAudioElement> {
const audio: HTMLAudioElement = document.createElement('audio');
audio.setAttribute('id', `audio-${sessionId}`);

logger.info('creating audio element', { sessionId, audioOutputDeviceId: this.audioOutputDeviceId });

if ((audio as any).setSinkId && this.audioOutputDeviceId) {
(audio as any).setSinkId(this.audioOutputDeviceId);
if (this.audioOutputDeviceId) {
await audio.setSinkId(this.audioOutputDeviceId);
}

if (document.body) {
Expand Down Expand Up @@ -2135,7 +2129,7 @@ export default class WebRTCClient extends Emitter {
oldInviteRequest(request);
};

session.delegate.onInvite = (request: IncomingRequestMessage) => {
session.delegate.onInvite = async (request: IncomingRequestMessage) => {
let updatedCalleeName: string | null = null;
let updatedNumber = null;

Expand Down Expand Up @@ -2165,14 +2159,14 @@ export default class WebRTCClient extends Emitter {

this.updateRemoteStream(sipSessionId, false);

this._setupMedias(session);
await this._setupMedias(session);

return this.eventEmitter.emit(ON_REINVITE, session, request, updatedCalleeName, updatedNumber, hadRemoteVideo);
};
}

_onProgress(session: WazoSession, early = false): void {
this._setupMedias(session);
async _onProgress(session: WazoSession, early = false): Promise<void> {
await this._setupMedias(session);

const sessionId = this.getSipSessionId(session).substr(0, 20);
this.updateRemoteStream(sessionId);
Expand All @@ -2183,15 +2177,15 @@ export default class WebRTCClient extends Emitter {
this.eventEmitter.emit(early ? ON_EARLY_MEDIA : ON_PROGRESS, session);
}

_onAccepted(session: WazoSession, sessionDialog?: SessionDialog, withEvent = true, initAllTracks = true): void {
async _onAccepted(session: WazoSession, sessionDialog?: SessionDialog, withEvent = true, initAllTracks = true): Promise<void> {
logger.info('on call accepted', {
id: session.id,
clientId: this.clientId,
remoteTag: session.remoteTag,
});
this.storeSipSession(session);

this._setupMedias(session);
await this._setupMedias(session);

this.updateRemoteStream(this.getSipSessionId(session), initAllTracks);
const pc = (session.sessionDescriptionHandler as SessionDescriptionHandler)?.peerConnection;
Expand Down Expand Up @@ -2253,7 +2247,7 @@ export default class WebRTCClient extends Emitter {
return Boolean(session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === stripVideo));
}

_setupMedias(session: WazoSession, newStream: MediaStream | null | undefined = null): void {
async _setupMedias(session: WazoSession, newStream: MediaStream | null | undefined = null): Promise<void> {
if (!this._isWeb()) {
logger.info('Setup media on mobile, no need to setup html element, bailing');
return;
Expand All @@ -2271,7 +2265,7 @@ export default class WebRTCClient extends Emitter {
}

if (this._hasAudio() && this._isWeb() && !(sessionId in this.audioElements)) {
this.createAudioElementFor(sessionId);
await this.createAudioElementFor(sessionId);
}

const audioElement = this.audioElements[sessionId];
Expand Down

0 comments on commit 3fdda41

Please sign in to comment.