Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ export interface IClientMediaCall {
held: boolean;
/* busy = state >= 'accepted' && state < 'hangup' */
busy: boolean;
/* if the other side has put the call on hold */
remoteHeld: boolean;

contact: CallContact;
transferredBy: CallContact | null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export interface IWebRTCProcessor extends IServiceProcessor<WebRTCInternalStateM
localAudioLevel: number;

getStats(selector?: MediaStreamTrack | null): Promise<RTCStatsReport | null>;
isRemoteHeld(): boolean;
}

export type WebRTCProcessorConfig = {
Expand Down
23 changes: 23 additions & 0 deletions packages/media-signaling/src/lib/Call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ export class ClientMediaCall implements IClientMediaCall {
return this.webrtcProcessor.held;
}

private _remoteHeld: boolean;

public get remoteHeld(): boolean {
return this._remoteHeld;
}

/** indicates the call is past the "dialing" stage and not yet over */
public get busy(): boolean {
return !this.isPendingAcceptance() && !this.isOver();
Expand Down Expand Up @@ -217,6 +223,7 @@ export class ClientMediaCall implements IClientMediaCall {
this._contact = null;
this._transferredBy = null;
this._service = null;
this._remoteHeld = false;
}

/**
Expand Down Expand Up @@ -1077,6 +1084,20 @@ export class ClientMediaCall implements IClientMediaCall {
this.stateTimeoutHandlers.clear();
}

private updateRemoteHeld(): void {
if (!this.webrtcProcessor) {
return;
}

const isRemoteHeld = this.webrtcProcessor.isRemoteHeld();
if (isRemoteHeld === this._remoteHeld) {
return;
}

this._remoteHeld = isRemoteHeld;
this.emitter.emit('trackStateChange');
}

private onWebRTCInternalStateChange(stateName: keyof WebRTCInternalStateMap): void {
this.config.logger?.debug('ClientMediaCall.onWebRTCInternalStateChange');
if (!this.webrtcProcessor) {
Expand All @@ -1096,6 +1117,8 @@ export class ClientMediaCall implements IClientMediaCall {

this.requestStateReport();
}

this.updateRemoteHeld();
}

private onWebRTCInternalError({
Expand Down
33 changes: 33 additions & 0 deletions packages/media-signaling/src/lib/services/webrtc/Processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,33 @@ export class MediaCallWebRTCProcessor implements IWebRTCProcessor {
return this.peer.getStats(selector);
}

public isRemoteHeld(): boolean {
if (this.stopped) {
return false;
}

if (['closed', 'failed', 'new'].includes(this.peer.connectionState)) {
return false;
}

let anyTransceiverNotSending = false;
const transceivers = this.getAudioTransceivers();

for (const transceiver of transceivers) {
if (!transceiver.currentDirection || transceiver.currentDirection === 'stopped') {
continue;
}

if (transceiver.currentDirection.includes('send')) {
return false;
}

anyTransceiverNotSending = true;
}

return anyTransceiverNotSending;
}
Comment thread
tassoevan marked this conversation as resolved.

private changeInternalState(stateName: keyof WebRTCInternalStateMap): void {
this.config.logger?.debug('MediaCallWebRTCProcessor.changeInternalState', stateName);
this.emitter.emit('internalStateChange', stateName);
Expand Down Expand Up @@ -301,6 +328,12 @@ export class MediaCallWebRTCProcessor implements IWebRTCProcessor {
await new Promise((resolve) => setTimeout(resolve, 30));
}

private getAudioTransceivers(): RTCRtpTransceiver[] {
return this.peer
.getTransceivers()
.filter((transceiver) => transceiver.sender.track?.kind === 'audio' || transceiver.receiver.track?.kind === 'audio');
}

private registerPeerEvents() {
const { peer } = this;

Expand Down
Loading