Skip to content

Commit

Permalink
Signal local audio track feature updates (#1087)
Browse files Browse the repository at this point in the history
* Signal local audio track feature updates

* Create gold-tomatoes-protect.md
  • Loading branch information
lukasIO authored Apr 10, 2024
1 parent b1e41d5 commit 9a59311
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/gold-tomatoes-protect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"livekit-client": patch
---

Signal local audio track feature updates
6 changes: 3 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions src/api/SignalClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
AddTrackRequest,
AudioTrackFeature,
ClientInfo,
ConnectionQualityUpdate,
DisconnectReason,
Expand Down Expand Up @@ -27,6 +28,7 @@ import {
TrackPublishedResponse,
TrackUnpublishedResponse,
TrickleRequest,
UpdateLocalAudioTrack,
UpdateParticipantMetadata,
UpdateSubscription,
UpdateTrackSettings,
Expand Down Expand Up @@ -583,6 +585,13 @@ export class SignalClient {
]);
}

sendUpdateLocalAudioTrack(trackSid: string, features: AudioTrackFeature[]) {
return this.sendRequest({
case: 'updateAudioTrack',
value: new UpdateLocalAudioTrack({ trackSid, features }),
});
}

sendLeave() {
return this.sendRequest({
case: 'leave',
Expand Down
5 changes: 5 additions & 0 deletions src/room/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -557,4 +557,9 @@ export enum TrackEvent {
* @internal
*/
TrackProcessorUpdate = 'trackProcessorUpdate',

/**
* @internal
*/
AudioTrackFeatureUpdate = 'audioTrackFeatureUpdate',
}
14 changes: 14 additions & 0 deletions src/room/participant/LocalParticipant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,7 @@ export default class LocalParticipant extends Participant {
track.on(TrackEvent.Ended, this.handleTrackEnded);
track.on(TrackEvent.UpstreamPaused, this.onTrackUpstreamPaused);
track.on(TrackEvent.UpstreamResumed, this.onTrackUpstreamResumed);
track.on(TrackEvent.AudioTrackFeatureUpdate, this.onTrackFeatureUpdate);

// create track publication from track
const req = new AddTrackRequest({
Expand Down Expand Up @@ -1037,6 +1038,7 @@ export default class LocalParticipant extends Participant {
track.off(TrackEvent.Ended, this.handleTrackEnded);
track.off(TrackEvent.UpstreamPaused, this.onTrackUpstreamPaused);
track.off(TrackEvent.UpstreamResumed, this.onTrackUpstreamResumed);
track.off(TrackEvent.AudioTrackFeatureUpdate, this.onTrackFeatureUpdate);

if (stopOnUnpublish === undefined) {
stopOnUnpublish = this.roomOptions?.stopLocalTrackOnUnpublish ?? true;
Expand Down Expand Up @@ -1293,6 +1295,18 @@ export default class LocalParticipant extends Participant {
this.onTrackMuted(track, track.isMuted);
};

private onTrackFeatureUpdate = (track: LocalAudioTrack) => {
const pub = this.audioTrackPublications.get(track.sid!);
if (!pub) {
this.log.warn(
`Could not update local audio track settings, missing publication for track ${track.sid}`,
this.logContext,
);
return;
}
this.engine.client.sendUpdateLocalAudioTrack(pub.trackSid, pub.getTrackFeatures());
};

private handleSubscribedQualityUpdate = async (update: SubscribedQualityUpdate) => {
if (!this.roomOptions?.dynacast) {
return;
Expand Down
40 changes: 40 additions & 0 deletions src/room/track/LocalAudioTrack.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AudioTrackFeature } from '@livekit/protocol';
import { TrackEvent } from '../events';
import { computeBitrate, monitorFrequency } from '../stats';
import type { AudioSenderStats } from '../stats';
Expand All @@ -15,8 +16,17 @@ export default class LocalAudioTrack extends LocalTrack<Track.Kind.Audio> {

private prevStats?: AudioSenderStats;

private isKrispNoiseFilterEnabled = false;

protected processor?: TrackProcessor<Track.Kind.Audio, AudioProcessorOptions> | undefined;

/**
* boolean indicating whether enhanced noise cancellation is currently being used on this track
*/
get enhancedNoiseCancellation() {
return this.isKrispNoiseFilterEnabled;
}

/**
*
* @param mediaTrack
Expand Down Expand Up @@ -152,6 +162,28 @@ export default class LocalAudioTrack extends LocalTrack<Track.Kind.Audio> {
this.prevStats = stats;
};

private handleKrispNoiseFilterEnable = () => {
this.isKrispNoiseFilterEnabled = true;
this.log.debug(`Krisp noise filter enabled`, this.logContext);
this.emit(
TrackEvent.AudioTrackFeatureUpdate,
this,
AudioTrackFeature.TF_ENHANCED_NOISE_CANCELLATION,
true,
);
};

private handleKrispNoiseFilterDisable = () => {
this.isKrispNoiseFilterEnabled = false;
this.log.debug(`Krisp noise filter disabled`, this.logContext);
this.emit(
TrackEvent.AudioTrackFeatureUpdate,
this,
AudioTrackFeature.TF_ENHANCED_NOISE_CANCELLATION,
false,
);
};

async setProcessor(processor: TrackProcessor<Track.Kind.Audio, AudioProcessorOptions>) {
const unlock = await this.processorLock.lock();
try {
Expand All @@ -175,6 +207,14 @@ export default class LocalAudioTrack extends LocalTrack<Track.Kind.Audio> {
this.processor = processor;
if (this.processor.processedTrack) {
await this.sender?.replaceTrack(this.processor.processedTrack);
this.processor.processedTrack.addEventListener(
'enable-lk-krisp-noise-filter',
this.handleKrispNoiseFilterEnable,
);
this.processor.processedTrack.addEventListener(
'disable-lk-krisp-noise-filter',
this.handleKrispNoiseFilterDisable,
);
}
this.emit(TrackEvent.TrackProcessorUpdate, this.processor);
} finally {
Expand Down
30 changes: 28 additions & 2 deletions src/room/track/LocalTrackPublication.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { TrackInfo } from '@livekit/protocol';
import { AudioTrackFeature, TrackInfo } from '@livekit/protocol';
import { TrackEvent } from '../events';
import type { LoggerOptions } from '../types';
import type LocalAudioTrack from './LocalAudioTrack';
import LocalAudioTrack from './LocalAudioTrack';
import type LocalTrack from './LocalTrack';
import type LocalVideoTrack from './LocalVideoTrack';
import type { Track } from './Track';
Expand Down Expand Up @@ -82,6 +82,32 @@ export default class LocalTrackPublication extends TrackPublication {
await this.track?.resumeUpstream();
}

getTrackFeatures() {
if (this.track instanceof LocalAudioTrack) {
const settings = this.track!.mediaStreamTrack.getSettings();
const features: Set<AudioTrackFeature> = new Set();
if (settings.autoGainControl) {
features.add(AudioTrackFeature.TF_AUTO_GAIN_CONTROL);
}
if (settings.echoCancellation) {
features.add(AudioTrackFeature.TF_ECHO_CANCELLATION);
}
if (settings.noiseSuppression) {
features.add(AudioTrackFeature.TF_NOISE_SUPPRESSION);
}
if (settings.channelCount && settings.channelCount > 1) {
features.add(AudioTrackFeature.TF_STEREO);
}
if (!this.options?.dtx) {
features.add(AudioTrackFeature.TF_STEREO);
}
if (this.track.enhancedNoiseCancellation) {
features.add(AudioTrackFeature.TF_ENHANCED_NOISE_CANCELLATION);
}
return Array.from(features.values());
} else return [];
}

handleTrackEnded = () => {
this.emit(TrackEvent.Ended);
};
Expand Down
2 changes: 2 additions & 0 deletions src/room/track/Track.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
AudioTrackFeature,
VideoQuality as ProtoQuality,
StreamState as ProtoStreamState,
TrackSource,
Expand Down Expand Up @@ -504,4 +505,5 @@ export type TrackEventCallbacks = {
upstreamPaused: (track: any) => void;
upstreamResumed: (track: any) => void;
trackProcessorUpdate: (processor?: TrackProcessor<Track.Kind, any>) => void;
audioTrackFeatureUpdate: (track: any, feature: AudioTrackFeature, enabled: boolean) => void;
};

0 comments on commit 9a59311

Please sign in to comment.