Noise Cancellation UI

Noise Cancellation

Enabling your application to provide noise cancellation for the audio in the call can be very useful for your users. We understand that this can be a difficult feature to implement and support.

This is why the StreamVideo SDK comes with support for AudioFilters. In addition, we offer an easy-to-integrate package that provides a ready-to-use NoiseCancellation AudioFilter using krisp.ai technology. You can read more about integrating the StreamVideoNoiseCancellation SDK here.

Noise cancellation is a performance-intensive feature. It's recommended to only enable it on devices that support Apple's Neural Engine. You can check this using `streamVideo.isHardwareAccelerationAvailable`.

With that in mind, we can build a simple UI element that will allow the user to toggle on/off the Noise Cancellation feature. The element will also take care of showing/hiding depending on the feature's availability.

struct NoiseCancellationButtonView: View {

    @Injected(\.streamVideo) var streamVideo

    @ObservedObject var viewModel: CallViewModel
    @State var isNoiseCancellationAvailable = false
    @State var isActive: Bool = false

    init(viewModel: CallViewModel) {
        self.viewModel = viewModel
        if let mode = viewModel.call?.state.settings?.audio.noiseCancellation?.mode {
            self.isNoiseCancellationAvailable = mode != .disabled
        } else {
            self.isNoiseCancellationAvailable = false
        }
        self.isActive = streamVideo.videoConfig.noiseCancellationFilter?.id == streamVideo.videoConfig.audioProcessingModule.activeAudioFilterId
    }

    var body: some View {
        if
            let call = viewModel.call, // Ensure we have an active call.
            let noiseCancellationAudioFilter = streamVideo.videoConfig.noiseCancellationFilter, // Ensure that we have noiseCancellation audioFilter to activate.
            streamVideo.isHardwareAccelerationAvailable // Ensure that the device supports Apple's neuralEngine.
        {
            Group {
                if isNoiseCancellationAvailable {
                    Button {
                        if isActive {
                            call.setAudioFilter(nil)
                            isActive = false
                        } else {
                            call.setAudioFilter(noiseCancellationAudioFilter)
                            isActive = true
                        }
                    } label: {
                        Label {
                            Text(isActive ? "Disable Noise Cancellation" : "Noise Cancellation")
                        } icon: {
                            Image(
                                systemName: isActive
                                ? "waveform.path.ecg"
                                : "waveform.path"
                            )
                        }
                    }
                }
            }
            .onReceive(call.state.$settings.map(\.?.audio.noiseCancellation)) {
                if let mode = $0?.mode {
                    isNoiseCancellationAvailable = mode != .disabled
                } else {
                    isNoiseCancellationAvailable = false
                }
            }
        }
    }
}

Alternative: Using Call Methods

You can also use the Call object's built-in methods to control noise cancellation:

// Start noise cancellation
try await call.startNoiseCancellation()

// Stop noise cancellation
try await call.stopNoiseCancellation()

This approach is simpler if you don't need to track the active state manually, as it handles the audio filter management internally.

Integrating with Call Controls

To add the noise cancellation button to your call controls, you can include it in your custom CallControlsView:

struct CustomCallControlsView: View {
    @ObservedObject var viewModel: CallViewModel

    var body: some View {
        HStack(spacing: 16) {
            // Other call controls...

            NoiseCancellationButtonView(viewModel: viewModel)

            // More controls...
        }
    }
}