This is beta documentation for Stream Chat IOS SDK v5. For the latest stable version, see the latest version (v4) .

Voice Recording

Stream Chat's SwiftUI SDK allows you to record and share async voice messages in your channels. The voice recordings have a built-in attachment type (as defined here).

Voice recording is disabled by default. In order to enable it, you should setup the isVoiceRecordingEnabled property to true, when setting up the StreamChat client:

let utils = Utils(
    composerConfig: ComposerConfig(isVoiceRecordingEnabled: true)
)
let streamChat = StreamChat(chatClient: chatClient, utils: utils)

Before shipping, add a microphone usage description to your Info.plist (for example NSMicrophoneUsageDescription). iOS will not allow recording without it.

Recording UI Flows

The voice recording feature supports several different recording states: active recording, locked recording, preview (stopped but not yet sent), and a short-press tip.

All of these states are handled by a single unified ViewFactory method — makeComposerVoiceRecordingInputView. Use the recordingState property of the options to branch your UI for each state:

public func makeComposerVoiceRecordingInputView(
    options: ComposerVoiceRecordingInputViewOptions
) -> some View {
    CustomVoiceRecordingInputView(
        recordingState: options.recordingState,
        audioRecordingInfo: options.audioRecordingInfo,
        pendingAudioRecordingURL: options.pendingAudioRecordingURL,
        gestureLocation: options.gestureLocation,
        stopRecording: options.stopRecording,
        confirmRecording: options.confirmRecording,
        discardRecording: options.discardRecording,
        previewRecording: options.previewRecording
    )
}

The ComposerVoiceRecordingInputViewOptions provides:

  • recordingState – the current VoiceRecordingState (.recording, .locked, .stopped, .showTip, or .idle).
  • audioRecordingInfo – live metadata about the ongoing recording (waveform, duration, etc.).
  • pendingAudioRecordingURL – the file URL of a finished recording that has not yet been confirmed.
  • gestureLocation – the current touch location, used to animate the slide-to-cancel and lock indicators.
  • stopRecording – callback to stop the active recording.
  • confirmRecording – callback to add the recording to the composer input.
  • discardRecording – callback to discard the recording entirely.
  • previewRecording – callback to enter preview (play) state without sending.

Voice Recording Attachment

When a message with a voice recording attachment is sent, it appears in the message list with a voice recording specific user interface.

If you want to change the default UI, you should implement the makeVoiceRecordingView in the ViewFactory.

public func makeVoiceRecordingView(options: VoiceRecordingViewOptions) -> some View {
    CustomVoiceRecordingView(
        message: options.message,
        width: options.availableWidth,
        isFirst: options.isFirst,
        scrolledId: options.scrolledId
    )
}

Utils Configuration

Audio player

The AudioPlayer that will be used for the voice recording playback.

let utils = Utils()
utils.audioPlayerBuilder = { StreamAudioPlayer() }

By default, the AudioPlayer is set to StreamAudioPlayer, but you can subclass it and provide your own implementation, as well as providing a complete custom implementation by conforming to the AudioPlaying protocol.

If you want to provide a custom audio session configuration, you can by providing it in initializer of the audio player. This can be useful if you want to change the logic of the audio session, for example, force the audio to play from the speaker even if a Bluetooth device is connected.

Here is an example of how to provide a custom audio session configuration:

let utils = Utils()
utils.audioPlayerBuilder = {
    StreamAudioPlayer(
        assetPropertyLoader: StreamAssetPropertyLoader(),
        audioSessionConfigurator: CustomAudioSessionConfigurator()
    )
}

Audio recorder

The AudioRecorder that will be used to record new voice recordings.

let utils = Utils()
utils.audioRecorderBuilder = { StreamAudioRecorder() }

By default, the AudioRecorder is set to StreamAudioRecorder, but you can subclass it and provide your own implementation, as well as providing a complete custom implementation by conforming to the AudioRecording protocol.

When recording audio, it will also use the Bluetooth device's mic if there is one connected. If you need to customize this behaviour, you can provide a custom audio session configuration in the AudioRecorder initializer.

let utils = Utils()
utils.audioRecorderBuilder = {
    StreamAudioRecorder(
        configuration: .default,
        audioSessionConfigurator: CustomAudioSessionConfigurator()
    )
}

Feedback generator

A feedbackGenerator that will be used to provide haptic feedback during the recording flow. It can be customized in cases where you want to provide different or no haptic feedback for actions during the recording flow.

let utils = Utils()
utils.audioSessionFeedbackGenerator = StreamAudioSessionFeedbackGenerator()