1인 창업 일지 #24 메트로놈 버그 수정 완료

Hyunjun By Hyunjun 2025년 10월 13일

메트로놈 앱 개발 과정: 정확한 타이밍을 찾아서

메트로놈 앱에서 안드로이드의 경우에만 초창기부터 아래와 같은 상황이 있었습니다.

1단계: Flutter AudioPlayers의 한계 발견

문제 상황

  • 프로덕션 환경에서 메트로놈이 버벅이는 현상 발생
  • 광고 로직과 메트로놈이 Flutter 메인 스레드를 공유
  • Dart Timer의 부정확한 스케줄링으로 박자가 점점 어긋남

2단계: Isolate 분리 시도

개선 결과

  • ✅ UI 렉 문제 해결 – 광고 로딩과 독립적으로 동작
  • ❌ 타이밍 정확도는 여전히 부족 – Flutter AudioPlayers 자체의 구조적 한계

3단계: 네이티브 전환 결정

문제 인식

  • Flutter 레벨에서는 정밀한 오디오 타이밍 제어 불가능
  • 하드웨어 기반 정확한 스케줄링이 필요
  • Android 네이티브로 완전 이전 결정

4단계: AudioTrack 1차 시도

시도와 좌절

  • AudioTrack은 가장 정확한 타이밍 제공
  • 그러나 Raw PCM 데이터만 지원 – WAV 파일을 직접 로드하는 API 없음
  • WAV 헤더 파싱, PCM 추출, 리샘플링 등 복잡한 전처리 필요
  • 빠른 개발을 위해 일단 보류

5단계: Thread.sleep + SoundPool 임시 구현

선택 이유

  • SoundPool은 WAV 파일을 쉽게 로드: soundPool.load(R.raw.click)
  • 구현이 단순하여 빠른 배포 가능
  • Thread.sleep으로 타이밍 제어 시도

미스터리한 문제 발생

  • 🤔 디버그 빌드에서는 완벽하게 작동
  • 릴리즈 빌드나 배포 후 실제 사용 환경에서 박자가 애매하게 어긋남
  • 특정 기기에서 더욱 심각한 현상
  • 재현이 일관되지 않아 디버깅 어려움

원인 분석

  • 릴리즈 빌드의 최적화 옵션이 타이밍에 영향
  • 프로덕션 환경의 다양한 백그라운드 프로세스
  • Thread.sleep의 OS 스케줄링 의존성 (기기마다 다른 동작)
  • 디버그 모드와 릴리즈 모드의 스레드 우선순위 차이

6단계: AudioTrack + WAV 파서 최종 구현

해결 과정

  • WAV 파일을 PCM으로 변환하는 커스텀 로더 개발
  • WAV 헤더 파싱 (44 bytes)
  • 16-bit PCM 데이터 추출
  • Little-endian 변환 처리
  • AudioTrack의 버퍼 기반 정밀 재생 활용

최종 결과

  • ✅ 하드웨어 타이머 기반 정확한 타이밍
  • ✅ 커스텀 WAV 사운드 적용 가능
  • ✅ 광고/UI와 완전히 독립적인 동작
  • 디버그/릴리즈 빌드 모두 일관된 정확도
  • ✅ 모든 기기에서 안정적인 동작

핵심 교훈

“디버그에서 잘 되는데 배포하면 안 되는” 전형적인 타이밍 이슈였습니다. Thread.sleep처럼 OS에 의존하는 방식은 환경에 따라 불안정하며, 메트로놈처럼 정확성이 핵심인 앱에서는 AudioTrack + 커스텀 구현과 같은 하드웨어 기반 솔루션이 유일한 정답이었습니다.

마지막으로

달력 앱을 개발 중이며, 추가적으로, 쇼핑몰 앱을 만들 기회가 생겨 우선적으로 구현 예정입니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

목차