Skip to content

Commit aed0629

Browse files
Merge pull request #281 from Azure-Samples/yassirb/4146407
Added Voice Isolation support
2 parents 80b3f66 + afb7125 commit aed0629

File tree

3 files changed

+139
-6
lines changed

3 files changed

+139
-6
lines changed

Project/src/MakeCall/AudioEffects/AudioEffectsContainer.js

Lines changed: 116 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import React from 'react';
22
import { Features, LocalAudioStream } from '@azure/communication-calling';
33
import {
44
EchoCancellationEffect,
5-
DeepNoiseSuppressionEffect
5+
DeepNoiseSuppressionEffect,
6+
VoiceIsolationEffect
67
} from '@azure/communication-calling-effects';
78
import { Dropdown, PrimaryButton } from '@fluentui/react';
89

@@ -41,10 +42,17 @@ export default class AudioEffectsContainer extends React.Component {
4142
noiseSuppressionList: [],
4243
currentSelected: undefined
4344
},
45+
voiceIsolation: {
46+
startLoading: false,
47+
stopLoading: false,
48+
voiceIsolationList: [],
49+
currentSelected: undefined
50+
},
4451
activeEffects: {
4552
autoGainControl: [],
4653
echoCancellation: [],
47-
noiseSuppression: []
54+
noiseSuppression: [],
55+
voiceIsolation: []
4856
}
4957
};
5058

@@ -123,6 +131,7 @@ export default class AudioEffectsContainer extends React.Component {
123131
const autoGainControlList = [];
124132
const echoCancellationList = [];
125133
const noiseSuppressionList = [];
134+
const voiceIsolationList = [];
126135

127136
if (this.localAudioStreamFeatureApi) {
128137
if (await this.localAudioStreamFeatureApi.isSupported('BrowserAutoGainControl')) {
@@ -167,6 +176,15 @@ export default class AudioEffectsContainer extends React.Component {
167176
});
168177
}
169178

179+
const voiceIsolation = new VoiceIsolationEffect();
180+
if (await this.localAudioStreamFeatureApi.isSupported(voiceIsolation)) {
181+
supported.push(voiceIsolation);
182+
voiceIsolationList.push({
183+
key: voiceIsolation.name,
184+
text: 'Voice Isolation'
185+
});
186+
}
187+
170188
this.setState({
171189
supportedAudioEffects: [ ...supported ],
172190
supportedAudioEffectsPopulated: true,
@@ -182,10 +200,15 @@ export default class AudioEffectsContainer extends React.Component {
182200
...this.state.noiseSuppression,
183201
noiseSuppressionList
184202
},
203+
voiceIsolation: {
204+
...this.state.voiceIsolation,
205+
voiceIsolationList
206+
},
185207
activeEffects: {
186208
autoGainControl: this.localAudioStreamFeatureApi?.activeEffects?.autoGainControl,
187209
echoCancellation: this.localAudioStreamFeatureApi?.activeEffects?.echoCancellation,
188-
noiseSuppression: this.localAudioStreamFeatureApi?.activeEffects?.noiseSuppression
210+
noiseSuppression: this.localAudioStreamFeatureApi?.activeEffects?.noiseSuppression,
211+
voiceIsolation: this.localAudioStreamFeatureApi?.activeEffects?.voiceIsolation
189212
}
190213
});
191214
}
@@ -377,6 +400,64 @@ export default class AudioEffectsContainer extends React.Component {
377400
}
378401
/* ------------ NS control functions - end ---------------- */
379402

403+
/* ------------ VI control functions - start ---------------- */
404+
viSelectionChanged(e, item) {
405+
const effect = this.findEffectFromSupportedList(item.key);
406+
if (effect) {
407+
this.setState({
408+
voiceIsolation: {
409+
...this.state.voiceIsolation,
410+
currentSelected: effect
411+
}
412+
});
413+
}
414+
}
415+
416+
async startVi() {
417+
this.setState({
418+
voiceIsolation: {
419+
...this.state.voiceIsolation,
420+
startLoading: true
421+
}
422+
});
423+
424+
if (this.localAudioStreamFeatureApi) {
425+
await this.localAudioStreamFeatureApi.startEffects({
426+
voiceIsolation: this.state.voiceIsolation.currentSelected
427+
});
428+
}
429+
430+
this.setState({
431+
voiceIsolation: {
432+
...this.state.voiceIsolation,
433+
startLoading: false
434+
}
435+
});
436+
}
437+
438+
async stopVi() {
439+
this.setState({
440+
voiceIsolation: {
441+
...this.state.voiceIsolation,
442+
stopLoading: true
443+
}
444+
});
445+
446+
if (this.localAudioStreamFeatureApi) {
447+
await this.localAudioStreamFeatureApi.stopEffects({
448+
voiceIsolation: true
449+
});
450+
}
451+
452+
this.setState({
453+
voiceIsolation: {
454+
...this.state.voiceIsolation,
455+
stopLoading: false
456+
}
457+
});
458+
}
459+
/* ------------ VI control functions - end ---------------- */
460+
380461
render() {
381462
return (
382463
<>
@@ -403,6 +484,11 @@ export default class AudioEffectsContainer extends React.Component {
403484
{this.state.activeEffects.noiseSuppression[0]}
404485
</div>
405486
}
487+
{this.state.activeEffects.voiceIsolation?.length > 0 &&
488+
<div className='ms-Grid-col ms-sm4 ms-md4 ms-lg4'>
489+
{this.state.activeEffects.voiceIsolation[0]}
490+
</div>
491+
}
406492
</div>
407493
<div className='ms-Grid-row'>
408494
<div className='ms-Grid-col ms-sm12 ms-md12 ms-lg12'>
@@ -484,6 +570,33 @@ export default class AudioEffectsContainer extends React.Component {
484570
</PrimaryButton>
485571
</div>
486572
</div>
573+
574+
<div className='ms-Grid-row'>
575+
<div className='ms-Grid-col ms-sm12 ms-md12 ms-lg12'>
576+
<Dropdown
577+
label='Voice Isolation'
578+
onChange={(e, item) => this.viSelectionChanged(e, item)}
579+
options={this.state.voiceIsolation.voiceIsolationList}
580+
placeholder={'Select an option'}
581+
styles={{ dropdown: { width: 300, color: 'black' }, label: { color: 'white' } }}
582+
/>
583+
</div>
584+
<div className='ms-Grid-col ms-sm12 ms-md12 ms-lg12'>
585+
<PrimaryButton
586+
className='secondary-button mt-2'
587+
onClick={() => this.startNs()}
588+
>
589+
{this.state.noiseSuppression.startLoading ? <LoadingSpinner /> : 'Start NS'}
590+
</PrimaryButton>
591+
592+
<PrimaryButton
593+
className='secondary-button mt-2'
594+
onClick={() => this.stopNs()}
595+
>
596+
{this.state.noiseSuppression.stopLoading ? <LoadingSpinner /> : 'Stop NS'}
597+
</PrimaryButton>
598+
</div>
599+
</div>
487600
</div>
488601
:
489602
<div>

Project/src/MakeCall/Login.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ export default class Login extends React.Component {
4949
},
5050
isTeamsUser: false,
5151
isEntraUser: false,
52-
isJoinOnlyToken: false
52+
isJoinOnlyToken: false,
53+
headsetEnhancement: false,
5354
}
5455
}
5556

@@ -121,7 +122,8 @@ export default class Login extends React.Component {
121122
proxy: this.state.proxy,
122123
customTurn: this.state.customTurn,
123124
isTeamsUser: this.state.isTeamsUser,
124-
isEntraUser: this.state.isEntraUser
125+
isEntraUser: this.state.isEntraUser,
126+
headsetEnhancement: this.state.headsetEnhancement
125127
});
126128
}
127129
console.log('Login response: ', this.userDetailsResponse);
@@ -211,7 +213,8 @@ export default class Login extends React.Component {
211213
displayName: this.displayName,
212214
clientTag:this.clientTag,
213215
proxy: this.state.proxy,
214-
customTurn: this.state.customTurn
216+
customTurn: this.state.customTurn,
217+
headsetEnhancement: this.state.headsetEnhancement
215218
});
216219
this._callAgentInitPromise = new Promise((resolve) => { this._callAgentInitPromiseResolve = resolve });
217220
await this._callAgentInitPromise;
@@ -705,6 +708,15 @@ const isSupportedEnvironment = this.environmentInfo.isSupportedEnvironment;
705708
onChange={(e, isChecked) => this.setState({isJoinOnlyToken: isChecked})} />
706709
</div>
707710
</div>
711+
<div className="ms-Grid-row">
712+
<div className="ms-Grid-col">
713+
<Checkbox
714+
className='mt-3'
715+
label='Headset Enhancement'
716+
checked={this.state.headsetEnhancement}
717+
onChange={(e, isChecked) => this.setState({headsetEnhancement: isChecked})} />
718+
</div>
719+
</div>
708720
<div className="ms-Grid-row">
709721
<div className="ms-Grid-col">
710722
<PrimaryButton className="primary-button mt-3"

Project/src/MakeCall/MakeCall.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export default class MakeCall extends React.Component {
8383
},
8484
preCallDiagnosticsResults: {},
8585
isTeamsUser: false,
86+
headsetEnhancement: false,
8687
identityMri: undefined,
8788
activeCallDetails: undefined
8889
};
@@ -130,6 +131,10 @@ export default class MakeCall extends React.Component {
130131
this.tokenCredential = tokenCredential;
131132
setLogLevel('verbose');
132133

134+
this.setState({ headsetEnhancement: userDetails.headsetEnhancement });
135+
136+
console.log("MakeCall::handleLogIn, headsetEnhancement: ", userDetails.headsetEnhancement);
137+
133138
const proxyConfiguration = userDetails.proxy.useProxy ? { url: userDetails.proxy.url } : undefined;
134139
const turnConfiguration = userDetails.customTurn.useCustomTurn ? userDetails.customTurn.turn : undefined;
135140
this.callClient = new CallClient({
@@ -142,6 +147,9 @@ export default class MakeCall extends React.Component {
142147
networkConfiguration: {
143148
proxy: proxyConfiguration,
144149
turn: turnConfiguration
150+
},
151+
audioOptions: {
152+
headsetEnhancement: userDetails.headsetEnhancement
145153
}
146154
});
147155

0 commit comments

Comments
 (0)