Kodio 0.1.5 Help

Recording

Kodio provides two approaches to recording: a simple one-liner for timed recording, and a more flexible Recorder class for manual control.

Timed recording

The simplest way to record audio is with Kodio.record(). Pass a duration and Kodio handles the rest—starting, stopping, and packaging the audio into a recording.

val recording = Kodio.record(duration = 5.seconds)

You can also specify a quality preset to optimize for your use case:

val recording = Kodio.record( duration = 5.seconds, quality = AudioQuality.High // 48 kHz stereo )

Manual control

When you need to control when recording starts and stops (for example, based on user interaction), use the callback form of Kodio.record():

val recording = Kodio.record { recorder -> recorder.start() waitForUserStop() // Your app logic recorder.stop() recorder.getRecording() }

The lambda receives a Recorder instance and returns whatever the lambda returns—typically the recording itself.

Using Recorder directly

For maximum control, create a Recorder instance directly. This is useful when you need to:

  • Start and stop recording multiple times

  • Access live audio data

  • Manage the recorder's lifecycle explicitly

val recorder = Kodio.recorder(quality = AudioQuality.Standard) recorder.use { r -> r.start() delay(5.seconds) r.stop() r.getRecording()?.saveAs(Path("audio.wav")) }

The use extension ensures resources are properly released, even if an exception occurs.

Live audio processing

The Recorder provides a liveAudioFlow that emits audio chunks in real-time while recording. This is perfect for visualizations like waveforms or level meters.

recorder.liveAudioFlow?.collect { chunk -> val amplitude = calculateAmplitude(chunk) updateWaveform(amplitude) }

Pause / resume

Use recorder.pause() to halt capture and recorder.resume() to continue appending to the same recording — the data captured before the pause is preserved as part of one continuous AudioRecording:

val recorder = Kodio.recorder(quality = AudioQuality.Standard) recorder.use { r -> r.start() waitForUserPause() r.pause() // capture stops; previously captured chunks remain waitForUserResume() r.resume() // continues appending to the same buffer waitForUserStop() r.stop() r.getRecording()!! }

Each platform exposes a native pause primitive when available (Android AudioRecord.stop()/startRecording(), JVM TargetDataLine.stop()/start(), iOS AVAudioEngine.pause(), macOS AudioQueuePause, Web AudioWorklet.disconnect()), so resume is fast and doesn't re-acquire the microphone.

Stitching independent recordings

If you produced separate AudioRecording values (e.g. from disjoint Recorder.use { … } blocks), combine them with AudioRecording.concat:

val full = AudioRecording.concat(firstRecording, secondRecording) full.saveAs(Path("voice_note.wav"))

concat accepts segments with different formats — they are converted to a common target format (the first segment's format by default) using AudioFlow.convertAudio. See GitHub issue #24 for the original discussion.

Recorder API reference

Properties

isRecording: Boolean

true while actively recording audio.

hasRecording: Boolean

true if a recording is available via getRecording().

quality: AudioQuality

The quality preset used for this recorder.

format: AudioFormat

The audio format of this recorder. Before recording starts, returns the requested format from quality. After recording starts, returns the actual negotiated format from the platform (which may differ if the exact format is unsupported).

liveAudioFlow: Flow<ByteArray>?

Real-time audio data while recording. May be null on some platforms.

stateFlow: StateFlow<State>

Observable state changes for reactive UIs.

Methods

start()

Begin recording audio. Throws IllegalStateException if the recorder is already in the Stopped state — call reset() first or stitch segments via AudioRecording.concat().

pause()

Pause capture without losing audio captured so far. Use resume() to continue.

resume()

Resume a previously paused recording, appending to the same audio buffer.

stop()

Stop recording. The recording becomes available via getRecording().

toggle()

Start if stopped, stop if recording. Convenient for single-button UIs.

reset()

Discard the current recording and prepare for a new one. Required before calling start() a second time on the same recorder.

release()

Release all resources. Called automatically when using use {}.

getRecording(): AudioRecording?

Get the completed recording, or null if none available.

Last modified: 25 April 2026