Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
119 changes: 116 additions & 3 deletions Project/src/MakeCall/AudioEffects/AudioEffectsContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import React from 'react';
import { Features, LocalAudioStream } from '@azure/communication-calling';
import {
EchoCancellationEffect,
DeepNoiseSuppressionEffect
DeepNoiseSuppressionEffect,
VoiceIsolationEffect
} from '@azure/communication-calling-effects';
import { Dropdown, PrimaryButton } from '@fluentui/react';

Expand Down Expand Up @@ -41,10 +42,17 @@ export default class AudioEffectsContainer extends React.Component {
noiseSuppressionList: [],
currentSelected: undefined
},
voiceIsolation: {
startLoading: false,
stopLoading: false,
voiceIsolationList: [],
currentSelected: undefined
},
activeEffects: {
autoGainControl: [],
echoCancellation: [],
noiseSuppression: []
noiseSuppression: [],
voiceIsolation: []
}
};

Expand Down Expand Up @@ -123,6 +131,7 @@ export default class AudioEffectsContainer extends React.Component {
const autoGainControlList = [];
const echoCancellationList = [];
const noiseSuppressionList = [];
const voiceIsolationList = [];

if (this.localAudioStreamFeatureApi) {
if (await this.localAudioStreamFeatureApi.isSupported('BrowserAutoGainControl')) {
Expand Down Expand Up @@ -167,6 +176,15 @@ export default class AudioEffectsContainer extends React.Component {
});
}

const voiceIsolation = new VoiceIsolationEffect();
if (await this.localAudioStreamFeatureApi.isSupported(voiceIsolation)) {
supported.push(voiceIsolation);
voiceIsolationList.push({
key: voiceIsolation.name,
text: 'Voice Isolation'
});
}

this.setState({
supportedAudioEffects: [ ...supported ],
supportedAudioEffectsPopulated: true,
Expand All @@ -182,10 +200,15 @@ export default class AudioEffectsContainer extends React.Component {
...this.state.noiseSuppression,
noiseSuppressionList
},
voiceIsolation: {
...this.state.voiceIsolation,
voiceIsolationList
},
activeEffects: {
autoGainControl: this.localAudioStreamFeatureApi?.activeEffects?.autoGainControl,
echoCancellation: this.localAudioStreamFeatureApi?.activeEffects?.echoCancellation,
noiseSuppression: this.localAudioStreamFeatureApi?.activeEffects?.noiseSuppression
noiseSuppression: this.localAudioStreamFeatureApi?.activeEffects?.noiseSuppression,
voiceIsolation: this.localAudioStreamFeatureApi?.activeEffects?.voiceIsolation
}
});
}
Expand Down Expand Up @@ -377,6 +400,64 @@ export default class AudioEffectsContainer extends React.Component {
}
/* ------------ NS control functions - end ---------------- */

/* ------------ VI control functions - start ---------------- */
viSelectionChanged(e, item) {
const effect = this.findEffectFromSupportedList(item.key);
if (effect) {
this.setState({
voiceIsolation: {
...this.state.voiceIsolation,
currentSelected: effect
}
});
}
}

async startVi() {
this.setState({
voiceIsolation: {
...this.state.voiceIsolation,
startLoading: true
}
});

if (this.localAudioStreamFeatureApi) {
await this.localAudioStreamFeatureApi.startEffects({
voiceIsolation: this.state.voiceIsolation.currentSelected
});
}

this.setState({
voiceIsolation: {
...this.state.voiceIsolation,
startLoading: false
}
});
}

async stopVi() {
this.setState({
voiceIsolation: {
...this.state.voiceIsolation,
stopLoading: true
}
});

if (this.localAudioStreamFeatureApi) {
await this.localAudioStreamFeatureApi.stopEffects({
voiceIsolation: true
});
}

this.setState({
voiceIsolation: {
...this.state.voiceIsolation,
stopLoading: false
}
});
}
/* ------------ VI control functions - end ---------------- */

render() {
return (
<>
Expand All @@ -403,6 +484,11 @@ export default class AudioEffectsContainer extends React.Component {
{this.state.activeEffects.noiseSuppression[0]}
</div>
}
{this.state.activeEffects.voiceIsolation?.length > 0 &&
<div className='ms-Grid-col ms-sm4 ms-md4 ms-lg4'>
{this.state.activeEffects.voiceIsolation[0]}
</div>
}
</div>
<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm12 ms-md12 ms-lg12'>
Expand Down Expand Up @@ -484,6 +570,33 @@ export default class AudioEffectsContainer extends React.Component {
</PrimaryButton>
</div>
</div>

<div className='ms-Grid-row'>
<div className='ms-Grid-col ms-sm12 ms-md12 ms-lg12'>
<Dropdown
label='Voice Isolation'
onChange={(e, item) => this.viSelectionChanged(e, item)}
options={this.state.voiceIsolation.voiceIsolationList}
placeholder={'Select an option'}
styles={{ dropdown: { width: 300, color: 'black' }, label: { color: 'white' } }}
/>
</div>
<div className='ms-Grid-col ms-sm12 ms-md12 ms-lg12'>
<PrimaryButton
className='secondary-button mt-2'
onClick={() => this.startNs()}
>
{this.state.noiseSuppression.startLoading ? <LoadingSpinner /> : 'Start NS'}
</PrimaryButton>

<PrimaryButton
className='secondary-button mt-2'
onClick={() => this.stopNs()}
>
{this.state.noiseSuppression.stopLoading ? <LoadingSpinner /> : 'Stop NS'}
</PrimaryButton>
</div>
</div>
</div>
:
<div>
Expand Down
18 changes: 15 additions & 3 deletions Project/src/MakeCall/Login.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ export default class Login extends React.Component {
},
isTeamsUser: false,
isEntraUser: false,
isJoinOnlyToken: false
isJoinOnlyToken: false,
headsetEnhancement: false,
}
}

Expand Down Expand Up @@ -121,7 +122,8 @@ export default class Login extends React.Component {
proxy: this.state.proxy,
customTurn: this.state.customTurn,
isTeamsUser: this.state.isTeamsUser,
isEntraUser: this.state.isEntraUser
isEntraUser: this.state.isEntraUser,
headsetEnhancement: this.state.headsetEnhancement
});
}
console.log('Login response: ', this.userDetailsResponse);
Expand Down Expand Up @@ -211,7 +213,8 @@ export default class Login extends React.Component {
displayName: this.displayName,
clientTag:this.clientTag,
proxy: this.state.proxy,
customTurn: this.state.customTurn
customTurn: this.state.customTurn,
headsetEnhancement: this.state.headsetEnhancement
});
this._callAgentInitPromise = new Promise((resolve) => { this._callAgentInitPromiseResolve = resolve });
await this._callAgentInitPromise;
Expand Down Expand Up @@ -705,6 +708,15 @@ const isSupportedEnvironment = this.environmentInfo.isSupportedEnvironment;
onChange={(e, isChecked) => this.setState({isJoinOnlyToken: isChecked})} />
</div>
</div>
<div className="ms-Grid-row">
<div className="ms-Grid-col">
<Checkbox
className='mt-3'
label='Headset Enhancement'
checked={this.state.headsetEnhancement}
onChange={(e, isChecked) => this.setState({headsetEnhancement: isChecked})} />
</div>
</div>
<div className="ms-Grid-row">
<div className="ms-Grid-col">
<PrimaryButton className="primary-button mt-3"
Expand Down
8 changes: 8 additions & 0 deletions Project/src/MakeCall/MakeCall.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export default class MakeCall extends React.Component {
},
preCallDiagnosticsResults: {},
isTeamsUser: false,
headsetEnhancement: false,
identityMri: undefined
};

Expand Down Expand Up @@ -129,6 +130,10 @@ export default class MakeCall extends React.Component {
this.tokenCredential = tokenCredential;
setLogLevel('verbose');

this.setState({ headsetEnhancement: userDetails.headsetEnhancement });

console.log("MakeCall::handleLogIn, headsetEnhancement: ", userDetails.headsetEnhancement);

const proxyConfiguration = userDetails.proxy.useProxy ? { url: userDetails.proxy.url } : undefined;
const turnConfiguration = userDetails.customTurn.useCustomTurn ? userDetails.customTurn.turn : undefined;
this.callClient = new CallClient({
Expand All @@ -141,6 +146,9 @@ export default class MakeCall extends React.Component {
networkConfiguration: {
proxy: proxyConfiguration,
turn: turnConfiguration
},
audioOptions: {
headsetEnhancement: userDetails.headsetEnhancement
}
});

Expand Down
Loading