SonixRecorder

Unified audio recorder for capturing microphone input.

What is SonixRecorder?

SonixRecorder captures audio from the device microphone and saves it to a file. It provides:

  • Multiple formats: M4A (AAC), MP3, WAV

  • Quality presets: Voice (16kHz), Standard (44.1kHz), High (48kHz)

  • Real-time level: Monitor audio levels during recording

  • Echo cancellation: Remove echo when used with playback

  • Segment recording: Record specific portions for practice apps

Use it for:

  • Voice recording apps: Capture voice memos, podcasts

  • Karaoke apps: Record vocals along with backing track

  • Practice apps: Record student performances for analysis

  • Audio analysis: Feed audio to pitch detection in real-time

Quick Start

Kotlin

val recorder = SonixRecorder.create("/path/to/output.m4a")
recorder.start()
// ... record for a while ...
recorder.stop()
recorder.release()

Swift

let recorder = SonixRecorder.create(outputPath: "/path/to/output.m4a")
recorder.start()
// ... record for a while ...
recorder.stop()
recorder.release()

Usage Tiers

Tier 1: Zero-Config (80% of users)

Kotlin

val recorder = SonixRecorder.create("/path/to/output.m4a")
recorder.start()
// ...
recorder.stop()

Swift

let recorder = SonixRecorder.create(outputPath: "/path/to/output.m4a")
recorder.start()
// ...
recorder.stop()

Tier 2: With Config (15% of users)

Kotlin

val config = SonixRecorderConfig.Builder()
.preset(SonixRecorderConfig.STANDARD)
.format(AudioFormat.MP3)
.echoCancellation(true)
.onRecordingStarted { println("Started!") }
.onRecordingStopped { path -> println("Saved to: $path") }
.build()
val recorder = SonixRecorder.create("/path/to/output.mp3", config)

Swift

let config = SonixRecorderConfig.Builder()
.preset(.standard)
.format(.mp3)
.echoCancellation(true)
.onRecordingStarted { print("Started!") }
.onRecordingStopped { path in print("Saved to: \(path)") }
.build()
let recorder = SonixRecorder.create(outputPath: "/path/to/output.mp3", config: config)

Tier 3: Real-time Audio Access (5% of users)

Kotlin

// Access raw audio buffers for real-time processing
recorder.audioBuffers.collect { buffer ->
val samples = buffer.toFloatArray()
pitchDetector.detect(samples, buffer.sampleRate)
}

Swift

// Access raw audio buffers for real-time processing
for await buffer in recorder.audioBuffers {
let samples = buffer.toFloatArray()
pitchDetector.detect(samples: samples, sampleRate: buffer.sampleRate)
}

Platform Notes

iOS

  • Requires microphone permission in Info.plist

  • Audio session automatically configured for recording

  • Hardware sample rate may differ from requested (check actualSampleRate)

  • Echo cancellation uses iOS AEC

Android

  • Requires RECORD_AUDIO permission

  • Audio focus handled automatically

  • Sample rate depends on device capabilities

  • Echo cancellation uses Android AEC

Common Pitfalls

  1. Forgetting to release: Call recorder.release() to free resources

  2. Missing permissions: Ensure microphone permission is granted before recording

  3. Wrong file extension: Extension determines format; .m4a = M4A, .mp3 = MP3

  4. Not calling stop: Recording continues until stop() is called

  5. Ignoring actualSampleRate: Hardware may use different rate than requested

See also

Configuration options for recording

For playing recorded audio

CalibraLiveEval

For coordinated recording with live evaluation

CalibraPitch

For pitch detection on recorded audio

Types

Link copied to clipboard
object Companion
Link copied to clipboard

Listener interface for recording events. Alternative to StateFlow observation and Builder callbacks.

Properties

Link copied to clipboard

The actual sample rate being used by the hardware. On iOS, this may differ from the configured rate. Use this value for encoding to ensure correct playback speed.

Link copied to clipboard
val audioBuffers: SharedFlow<AudioBuffer>

Raw audio buffer flow for advanced use cases (visualization, analysis). Each buffer contains PCM data that can be converted to floats.

Link copied to clipboard

Number of buffers currently available in the pool. Use this to monitor zero-allocation audio processing health.

Link copied to clipboard

Whether the buffer pool was ever exhausted during recording. If true, the pool size may need to be increased for optimal real-time performance. This is critical for Calibra DSP integration where allocations cause latency spikes.

Link copied to clipboard
val duration: StateFlow<Long>

Recording duration in milliseconds

Link copied to clipboard
val error: StateFlow<SonixError?>

Error state, null if no error

Link copied to clipboard
val isRecording: StateFlow<Boolean>

Whether currently recording

Link copied to clipboard

Most recent audio buffer for polling-style access. Prefer audioBuffers flow for reactive processing.

Link copied to clipboard
val level: StateFlow<Float>

Audio level from 0.0 (silence) to 1.0 (loud) - updated in real-time

Link copied to clipboard
val state: StateFlow<RecordingState>

Full recording state machine

Link copied to clipboard

Playback-synchronized time when using playback sync. Returns recording duration if no sync provider is set.

Functions

Link copied to clipboard

Clear all segment data (for retry).

Link copied to clipboard

Get all recorded segments in this session.

Link copied to clipboard
fun release()

Release all resources

Link copied to clipboard

Set playback provider for timeline synchronization. Can be changed during recording.

Link copied to clipboard

Set a listener for recording events.

Link copied to clipboard
fun start()

Start recording

Link copied to clipboard
fun startRecordingSegment(segmentIndex: Int)

Start recording a segment within the current session. Requires enableSegmentRecording() in Builder.

Link copied to clipboard
fun stop()

Stop recording and save to file

Link copied to clipboard
suspend fun stopRecordingSegment(segmentIndex: Int): String?

Stop recording segment and save to file.

Link copied to clipboard
fun syncWithPlaybackTime(playbackTimeMs: Long)

Sync recording timeline with current playback position. Call after seeking in backing track.