Skip to content

Commit 69eead5

Browse files
feat: wait until call signaling is confirmed before playing the "calling" sound effect - #41224
1 parent c8db311 commit 69eead5

7 files changed

Lines changed: 46 additions & 1 deletion

File tree

packages/media-signaling/src/definition/call/CallEvents.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ export type CallEvents = {
2525
active: void;
2626
/* Triggered when this client puts the call on the ignore list, either because the call was accepted on a different client or because you called `call.ignore()` */
2727
hidden: void;
28+
/* Triggered when the call has reached the other user and started ringing */
29+
ringing: void;
2830

2931
/* Triggered when the call's state on the server changes to 'hangup' */
3032
ended: void;

packages/media-signaling/src/definition/call/callStates/IDirectMediaCallData.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export interface IDirectMediaCallData {
1111
readonly features: readonly CallFeature[];
1212
readonly state: CallState;
1313
readonly hidden: boolean;
14+
readonly ringing: boolean;
1415

1516
readonly transferredBy: CallContact | null;
1617

packages/media-signaling/src/lib/Call.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,23 @@ export class ClientMediaCall implements IClientMediaCall {
158158
return !this.isPendingAcceptance() && !this.isOver();
159159
}
160160

161+
public get ringing(): boolean {
162+
if (this.hidden) {
163+
return false;
164+
}
165+
166+
if (this._state !== 'ringing' || !this.hasRemoteData) {
167+
return false;
168+
}
169+
170+
if (this.role === 'caller' && this._contact?.type === 'sip') {
171+
// On SIP Calls, the caller should start ringing only after the offer is sent to the server
172+
return this.sentLocalSdp;
173+
}
174+
175+
return true;
176+
}
177+
161178
public get confirmed(): boolean {
162179
return this.hasRemoteData;
163180
}
@@ -202,6 +219,8 @@ export class ClientMediaCall implements IClientMediaCall {
202219

203220
private oldClientState: ClientState;
204221

222+
private hasFiredRingingEvent: boolean;
223+
205224
private serviceStates: Map<string, string>;
206225

207226
private stateReporterTimeoutHandler: ReturnType<typeof setTimeout> | null;
@@ -279,6 +298,7 @@ export class ClientMediaCall implements IClientMediaCall {
279298
activeTimestamp: this.activeTimestamp,
280299
tempCallId: this.tempCallId,
281300
hidden: this.hidden,
301+
ringing: this.ringing,
282302

283303
localParticipant: this.localParticipant,
284304
remoteParticipant: this.remoteParticipant,
@@ -319,6 +339,7 @@ export class ClientMediaCall implements IClientMediaCall {
319339
this._role = 'callee';
320340
this._state = 'none';
321341
this.oldClientState = 'none';
342+
this.hasFiredRingingEvent = false;
322343
this._ignored = false;
323344
this._contact = null;
324345
this._transferredBy = null;
@@ -465,6 +486,7 @@ export class ClientMediaCall implements IClientMediaCall {
465486
}
466487
this.emitter.emit('contactUpdate');
467488
this.emitter.emit('confirmed');
489+
this.updateRingingEvent();
468490
}
469491

470492
await this.processEarlySignals();
@@ -947,6 +969,7 @@ export class ClientMediaCall implements IClientMediaCall {
947969
this._state = newState;
948970
this.maybeStopWebRTC();
949971
this.updateClientState();
972+
this.updateRingingEvent();
950973

951974
this.emitter.emit('stateChange', oldState);
952975
this.requestStateReport();
@@ -991,6 +1014,15 @@ export class ClientMediaCall implements IClientMediaCall {
9911014
this.emitter.emit('clientStateChange', oldClientState);
9921015
}
9931016

1017+
private updateRingingEvent(): void {
1018+
if (this.hasFiredRingingEvent || !this.ringing) {
1019+
return;
1020+
}
1021+
1022+
this.hasFiredRingingEvent = true;
1023+
this.emitter.emit('ringing');
1024+
}
1025+
9941026
private maybeStopWebRTC(): void {
9951027
if (!this.webrtcProcessor) {
9961028
return;
@@ -1101,6 +1133,7 @@ export class ClientMediaCall implements IClientMediaCall {
11011133
}
11021134

11031135
this.updateClientState();
1136+
this.updateRingingEvent();
11041137
}
11051138

11061139
protected getLocalStreamIds(): MediaStreamIdentification[] {

packages/media-signaling/src/lib/Session.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,7 @@ export class MediaSignalingSession extends Emitter<MediaSignalingEvents> {
679679
call.emitter.on('accepting', () => this.onAcceptingCall(call));
680680
call.emitter.on('hidden', () => this.onHiddenCall(call));
681681
call.emitter.on('active', () => this.onActiveCall(call));
682+
call.emitter.on('ringing', () => this.onRingingCall());
682683
call.emitter.on('ended', () => this.onEndedCall(call));
683684
call.emitter.on('screenShareRequestChange', (requested: boolean) => this.onScreenShareRequestChange(call, requested));
684685
call.emitter.on('streamChange', () => this.onSessionStateChange());
@@ -742,6 +743,11 @@ export class MediaSignalingSession extends Emitter<MediaSignalingEvents> {
742743
this.onSessionStateChange();
743744
}
744745

746+
private onRingingCall(): void {
747+
this.config.logger?.debug('MediaSignalingSession.onRingingCall');
748+
this.emit('sessionStateChange');
749+
}
750+
745751
private async onScreenShareRequestChange(call: ClientMediaCall, requested: boolean): Promise<void> {
746752
this.config.logger?.debug('MediaSignalingSession.onScreenShareRequestChange');
747753

packages/ui-voip/src/context/definitions.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ interface IBaseSession {
3333
remoteHeld: boolean;
3434
startedAt?: Date;
3535
hidden: boolean;
36+
ringing?: boolean;
3637
supportedFeatures: readonly CallFeature[];
3738
}
3839

packages/ui-voip/src/providers/MediaCallViewProvider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ const MediaCallViewProvider = ({ children }: MediaCallViewProviderProps) => {
6060
}, [audioInput?.id, controls, sessionState.hidden]);
6161

6262
useCallSounds(
63-
sessionState.hidden ? 'none' : sessionState.state,
63+
sessionState.hidden || !sessionState.ringing ? 'none' : sessionState.state,
6464
useCallback(
6565
(callback) => {
6666
if (!instance) {

packages/ui-voip/src/providers/useMediaSession.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ export const useMediaSession = (instance?: MediaSignalingSession): SessionState
124124
features: supportedFeatures,
125125
transferredBy: callTransferredBy,
126126
remoteParticipant: { muted: remoteMuted, held: remoteHeld, contact },
127+
ringing,
127128
} = instanceState;
128129

129130
const transferredBy = callTransferredBy?.displayName || callTransferredBy?.username || undefined;
@@ -160,6 +161,7 @@ export const useMediaSession = (instance?: MediaSignalingSession): SessionState
160161
callId,
161162
startedAt,
162163
supportedFeatures,
164+
ringing,
163165
},
164166
});
165167
};

0 commit comments

Comments
 (0)