Design Evolution and Best Practices for Android Audio Recorder in the FluentSpeak App

This article details the evolution of the Android Recorder used in the FluentSpeak app, covering API choices, AudioFocus handling, processing patterns, encountered challenges such as encoder blocking, testing difficulties, and native crashes, and presents solutions like ProcessThread, AudioProcessor abstraction, WavFileRecorder, and ServiceWrapper to improve reliability and extensibility.

Liulishuo Tech Team
Liulishuo Tech Team
Liulishuo Tech Team
Design Evolution and Best Practices for Android Audio Recorder in the FluentSpeak App

The FluentSpeak app has relied on a long‑standing Recorder class that records audio while scoring user speech, producing a score report and audio file.

Android Recorder Selection Android provides two Java‑level recorder APIs: MediaRecorder (produces encoded files) and AudioRecorder (provides raw PCM data). The app needs PCM for custom processing.

AudioFocus Handling When recording starts, any ongoing playback should be paused; therefore handling AudioFocus is recommended to avoid conflicts with other audio sources.

Basic AudioRecorder Usage Pattern 1. Create Recorder, Encoder, and Scorer on a dedicated Recorder thread. 2. Loop to read PCM data from AudioRecorder and feed it to Encoder and Scorer. 3. On external stop, set a run flag to false, exit the loop, close Encoder and Scorer, and save results. 4. Release all resources.

Problems Encountered - Encoder and Scorer processing blocks in the loop caused buffer overruns, leading to lost audio data and scoring errors. - Feature growth required supporting multiple audio formats and varied scoring logic, making the Recorder code increasingly complex. - Testing was hard because the Recorder depended on actual Android hardware; reproducing recordings reliably was difficult. - Native NDK components (Encoder/Scorer) could crash, risking the whole app.

Solutions Implemented - Added a ProcessThread so Encoder and Scorer run separately, preventing the Recorder thread from being blocked. - Introduced an AudioProcessor abstraction to unify Encoder and Scorer handling; the Recorder now delegates processing to injected AudioProcessor instances. - Created WavFileRecorder to simulate recordings from files, enabling fast, repeatable tests without hardware. - Developed IAudioProcessorService (AIDL) to run AudioProcessor in a separate Service process; native crashes only kill the service process, leaving the main app stable.

Summary of Practices 1. Process PCM data on a separate thread to avoid data loss. 2. Abstract processing logic into AudioProcessor for modularity. 3. Use WavFileRecorder for file‑based testing. 4. Run AudioProcessor in a separate Service via AIDL to isolate native crashes.

The resulting implementation is packaged as LingoRecorder , which demonstrates these patterns.

mobile developmentnativeAndroidAudioProcessorAudioRecorder
Liulishuo Tech Team
Written by

Liulishuo Tech Team

Help everyone become a global citizen!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.