struct CustomCallView<Factory: ViewFactory>: View {
@Injected(\.colors) var colors
var viewFactory: Factory
@ObservedObject var viewModel: CallViewModel
@StateObject var microphoneChecker = MicrophoneChecker()
@State var mutedIndicatorShown = false
var body: some View {
CallView(viewFactory: viewFactory, viewModel: viewModel)
.onReceive(viewModel.$callSettings) { callSettings in
Task { await updateMicrophoneChecker() }
}
.onReceive(microphoneChecker.$$audioLevels, perform: { values in
guard !viewModel.callSettings.audioOn else { return }
for value in values {
if (value > -50 && value < 0) && !mutedIndicatorShown {
mutedIndicatorShown = true
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0, execute: {
mutedIndicatorShown = false
})
return
}
}
})
.overlay(
mutedIndicatorShown ?
VStack {
Spacer()
Text("You are muted.")
.padding(8)
.background(Color(UIColor.systemBackground))
.foregroundColor(colors.text)
.cornerRadius(16)
.padding()
}
: nil
)
}
private func updateMicrophoneChecker() async {
if !viewModel.callSettings.audioOn {
await microphoneChecker.startListening()
} else {
await microphoneChecker.stopListening()
}
}
}
Speaking While Muted
Some calling apps show an indicator when you are trying to speak while you are muted. This is helpful for users that forgot to turn on the microphone when they try to speak.
You can easily add such functionality with the StreamVideo
iOS SDK. One approach to achieve this is to add an overlay to the CallView
with the indicator. The logic for displaying the popup can be determined by listening to sounds even when the microphone is turned off. When a sound goes over a certain threshold, we will display the indicator.
Here’s an example implementation for this approach, using the MicrophoneChecker
from the SDK:
In the implementation, we are listening to the callSettings
changes from the view model. Based on that, we decide whether we should listen for sounds from the microphone checker.
Additionally, we are listening to the @Published
property called decibels
from the MicrophoneChecker
, which returns an array of the last 3 decibels. If a value passes our threshold, then we set the mutedIndicatorShown
to true, which displays a simple text popup. We reset the value to false after 2 seconds, to hide the popup.
Finally, we need to use the custom call view in the custom ViewFactory
:
func makeCallView(viewModel: CallViewModel) -> some View {
CustomCallView(viewFactory: self, viewModel: viewModel)
}