시스템 디자인SYSTEM DESIGN
학습 시작하기 →
AUDIO & RECOVERY

긴 녹음 중 앱이 멈춘다면, 기록을 어떻게 남길까?

녹음 시간 표시보다 중요한 것은 실제로 재생할 수 있는 구간과 미완료 구간을 구분하는 일입니다.

앞의 녹음 조각은 닫혀 있고 마지막 조각은 열린 상태로 표현한 개념 이미지
내용의 흐름을 표현한 개념 이미지

긴 녹음에서 중요한 것은 앱이 한 번도 멈추지 않는다고 믿는 일이 아닙니다. 이미 안전하게 저장된 구간과 아직 쓰는 중인 구간을 구별하고, 다시 열었을 때 각각의 상태를 확인할 수 있게 만드는 것이 핵심입니다. 녹음 파일 하나만 오래 열어 두면 마지막 순간의 문제가 전체 기록을 읽기 어렵게 만들 수 있습니다.

이 글은 Android 녹음·전사 앱 Long STT Android의 공개 코드와 테스트를 사례로 설명합니다. 모든 휴대전화·모든 장애에서 녹음이 복구된다는 뜻은 아닙니다. 다만 저장 단위를 나누고 상태를 남기는 설계가 왜 유용한지, 사용자가 무엇을 확인해야 하는지 구체적으로 살펴볼 수 있습니다.

한 파일을 끝까지 쓰는 방식의 약점

가정해 보겠습니다. 90분 회의를 녹음하면서 앱이 단일 오디오 파일에 계속 데이터를 씁니다. 종료 버튼을 누르고 파일을 정상적으로 닫을 때까지는 파일 내용과 메타데이터가 완성되지 않을 수 있습니다. 이때 배터리 부족이나 프로세스 종료처럼 예기치 않은 중단이 생기면 “90분을 녹음했다”는 화면 표시와 “재생 가능한 파일이 남았다”는 결과가 달라질 수 있습니다. 이 상황은 설명용 가정이며 실제 장애 재현 기록은 아닙니다.

위험을 줄이는 한 방법은 녹음을 여러 조각, 즉 청크(chunk)로 나누는 것입니다. 예를 들어 첫 구간을 확정한 뒤 다음 구간을 쓰면, 뒤쪽 구간에서 문제가 생겨도 앞쪽의 확정된 구간을 별도로 판단할 수 있습니다. Long STT Android는 기본 20분 단위로 구간을 전환합니다. 이 숫자는 해당 앱의 기본 설정이지 모든 녹음 앱에 권장되는 보편적 정답이 아닙니다. 구간이 너무 길면 중단 시 확인해야 할 미완료 범위가 커지고, 너무 짧으면 파일과 전환 작업이 늘어납니다.

작성 중인 파일을 검사·확정하고 재시작 시 체크포인트와 대조하는 네 단계 도식
Long STT Android의 공개 코드 구조를 독자용으로 단순화했습니다.

중요한 것은 ‘나누었다’보다 언제 한 조각을 완료로 간주하는가입니다. 파일 이름만 바뀌었다고 바로 정상 파일은 아닙니다. 실제 구현은 작성 중인 파일을 .part로 구분하고, 확정할 때 오디오 형식과 내용을 검사한 뒤 최종 파일로 옮기고 SHA-256 해시를 남깁니다. 비어 있거나 형식이 맞지 않는 파일은 정상 목록에 섞지 않고 격리합니다. 이 절차 덕분에 화면이 단순히 파일 존재 여부만 보고 “완료”라고 말하지 않게 됩니다.

녹음 파일과 진행 상태는 다른 기록입니다

오디오 파일에는 소리가 담깁니다. 하지만 그 파일이 몇 번째 구간인지, 지금 쓰는 중인지, 이미 검사를 마쳤는지는 별도의 상태 정보가 필요합니다. Long STT Android의 세션 체크포인트는 이러한 구간 상태를 WRITING, READY, QUARANTINED, MISSING처럼 나눕니다. 체크포인트 저장에는 Android의 AtomicFile을 사용합니다. 파일 본문과 상태표를 분리해 관리한다는 점이 핵심입니다.

여기서 ‘원자적’이라는 말은 오디오 전체가 마법처럼 한 번에 저장된다는 뜻이 아닙니다. 상태 파일을 갱신하는 도중 앱이 중단되더라도 반쯤 쓴 상태표를 정본으로 오인할 위험을 낮추는 방법입니다. 오디오 파일의 유효성 검사는 따로 해야 합니다. 체크포인트에 READY라고 적혀 있어도 해당 파일이 없어졌거나 손상됐다면 현재 상태를 다시 확인해야 합니다.

이 설계에서는 완료된 조각과 미완료 조각을 같은 이름으로 덮어쓰지 않는 것도 중요합니다. .part는 아직 검증되지 않은 작업물이고, 확정된 파일은 재생과 후속 전사의 후보입니다. 해시는 내용이 이후 바뀌지 않았는지 확인하는 단서가 됩니다. 해시가 있다고 소리의 품질이나 발화의 정확성이 보증되는 것은 아닙니다. ‘바이트가 같은가’와 ‘내용이 유용한가’는 서로 다른 질문이기 때문입니다.

다시 실행했을 때는 무엇을 해야 할까요?

앱이 재시작됐을 때 이전 프로세스가 남긴 .part가 보인다고 곧장 완성 파일로 취급하면 위험합니다. 반대로 무조건 삭제하면 살릴 수 있는 구간에 대한 단서까지 잃을 수 있습니다. 사례 앱은 시작 시 체크포인트와 관리 폴더를 대조하는 복구 경로를 둡니다. 체크포인트가 없는 .part나 정상 상태로 확정할 수 없는 조각은 격리하고, 이미 확정된 조각은 별도로 유지하는 방향입니다.

코드의 테스트도 이 경계를 확인합니다. 유효한 .part가 최종 파일로 바뀌며 해시가 기록되는 경우, 0바이트 파일과 확장자만 그럴듯한 파일이 격리되는 경우, 재시작 시 미완료 체크포인트와 .part를 안전한 종료 상태로 옮기는 경우를 각각 검사합니다. 이는 해당 테스트 조건의 결과이지 모든 실제 기기에서 전원 차단을 반복해 무손실을 입증했다는 말이 아닙니다.

기본 20분 단위 저장 안내가 표시된 Long STT Android 녹음 준비 화면
공개 저장소의 데이터 격리용 deviceTest 화면이며 실제 장애 재현 장면은 아닙니다.

녹음 화면에 “기본 20분 단위로 나누어 저장”이라는 안내가 있는 이유도 여기에 있습니다. 위 이미지는 저장소가 공개한 데이터 격리용 deviceTest 앱의 녹음 준비 화면입니다. 실제 장애 당시의 사진이나 녹음 성공 인증 화면이 아닙니다. 독자는 이 안내를 보고 “20분마다 무조건 모든 소리가 안전하다”고 해석하기보다, 보관함에서 확정 구간과 전체 길이를 다시 확인해야 합니다.

사용자가 직접 확인할 순서

앱이 예기치 않게 닫혔다면 먼저 같은 파일을 반복해서 재생하거나 이름을 바꾸기보다 앱을 정상적으로 다시 열어 보관함 상태를 확인하는 편이 좋습니다. 다음 순서는 이 사례에서 도출한 확인 절차이며, 모든 녹음 앱의 메뉴 이름이 같지는 않습니다.

  1. 기록 자체가 목록에 있는지 확인합니다. 회의 제목이나 시작 시각만 보지 말고, 오디오가 실제로 연결됐는지 확인합니다.
  2. 완료된 구간 수와 길이를 확인합니다. 예상한 녹음 시간과 크게 다르면 누락된 뒤쪽 구간이 없는지 살펴봅니다.
  3. 중간과 끝부분을 재생해 봅니다. 파일이 존재해도 무음·끊김·잘못된 입력 장치 같은 품질 문제는 별도로 확인해야 합니다.
  4. 미완료 또는 격리 표시가 있으면 원본을 보존합니다. 앱이 제공하는 안전한 내보내기·문의 경로가 있다면 그 절차를 따르고, 정체를 모르는 .part를 임의로 최종 파일처럼 바꾸지 않습니다.
  5. 전사 결과는 오디오와 구분해 확인합니다. 소리 파일이 살아 있어도 전사가 아직 끝나지 않았을 수 있습니다. 반대로 전사 텍스트만 보고 원본 오디오가 보존됐다고 가정해서도 안 됩니다.
재시작 후 목록·길이·중간과 끝부분 재생을 확인하는 세 단계 점검표
파일 구조 검사와 실제 소리가 담겼는지 확인하는 일은 별개입니다.

특히 녹음 중 전화 통화, 블루투스 마이크 전환, 저장 공간 부족이 있었다면 그 시점 전후를 들어보는 것이 유용합니다. 사례 앱은 입력 장치 변경 시 현재 구간을 안전하게 마감한 뒤 새 구간으로 넘어가는 경로를 둡니다. 그래도 마이크 전환 순간의 실제 소리가 어떻게 들리는지는 기기와 상황에 따라 별도의 청취 확인이 필요합니다. 소프트웨어가 파일 구조를 검사하는 것과 사용자가 원하는 발화가 모두 들어갔는지는 같지 않습니다.

복구 설계가 약속하지 않는 것

이 방식은 손실 가능성을 관리하기 위한 설계이지 절대적인 무손실 보장이 아닙니다. 저장 장치 자체의 고장, 권한 문제, 사용자의 삭제, 마지막 청크를 확정하기 전의 중단, 오디오 입력 실패는 서로 다른 문제입니다. 앱은 일부 상태를 격리하거나 누락으로 표시할 수 있지만 그 표시가 곧 원본을 재구성해 준다는 뜻은 아닙니다. 중요한 회의나 인터뷰라면 사전에 저장 공간·마이크·전원 상태를 확인하고, 가능하면 별도의 백업 녹음 경로도 준비해야 합니다.

이 사례의 요약이나 외부 업로드는 녹음 보존을 위해 반드시 켜야 하는 기능이 아닙니다. 기본적인 녹음·전사 작업은 기기 안에서 처리하도록 설계됐고, 외부 AI 요약·공유·Drive 업로드는 사용자가 선택하는 별도 경계입니다. 녹음 안정성을 설명하면서 선택 기능을 필수 과정으로 섞으면 개인정보 처리와 기능 범위를 동시에 오해하게 됩니다.

핵심은 간단합니다. 완료된 구간은 완료된 것만큼만 믿고, 쓰는 중이던 구간은 다시 검사하며, 화면의 시간 숫자보다 실제 재생 가능한 파일을 확인하세요. 앱 설계자라면 청크 파일, 상태 체크포인트, 재시작 대조, 손상 격리의 경계를 분명히 해야 합니다. 사용자는 보관함에서 구간·길이·끝부분 재생을 확인하는 것으로 그 설계가 자신의 기록에 어떤 결과를 남겼는지 판단할 수 있습니다.

다음 글에서는 다른 종류의 ‘숫자를 믿는 문제’를 다룹니다. AI 코딩 도구의 잔여량이 서로 다르게 보일 때 기간과 관측 시각을 먼저 확인하는 방법입니다.

사례 코드: coreline-ai/long-stt-android · 기준 commit 1dc65374afdec11a6b361b2414557cd47ee51042
확인 파일: README.md, RecorderService.kt, RecordingFileManager.kt, RecordingRecoveryCoordinatorTest.kt.

다음 글: AI 코딩 도구 잔여량이 다르게 보이는 이유 →

MORE ARTICLES

다른 설계 이야기도 읽어보세요

설계 실무

AI 코딩 도구 잔여량이 다르게 보이는 이유는?

같은 40%라도 같은 잔여량은 아닙니다. 대상·기간·시각·출처를 먼저 맞춰 봅니다.

읽어보기 →
설계 실무

지식 그래프의 선이 많다고 모두 사실일까?

보이는 선이 모두 근거는 아닙니다. 관계의 종류와 원문 확인 경로부터 살펴봅니다.

읽어보기 →
설계 실무

로그아웃했는데, 세션은 아직 살아 있을까?

로그인 화면으로 돌아갔다고 끝난 것은 아닙니다. 방금 로그아웃한 세션을 다시 검사해 봤습니다.

읽어보기 →
재현 실험

워커가 죽었는데, 작업은 계속 실행 중이라면?

다시 실행하는 것만으로는 부족합니다. 이전 워커가 늦게 돌아와도 결과를 덮어쓰지 못하게 했습니다.

읽어보기 →
설계 실무

같은 뉴스는 줄이고, 다른 소식은 놓치지 않으려면?

제목이 비슷하다고 지웠더니 후속 소식까지 사라질 수 있습니다. 문서와 사건을 나눠 정리했습니다.

읽어보기 →
설계 실무

로컬에서는 최신인데, 배포하면 왜 이전 뉴스가 보일까?

새로고침부터 누르기 전에, 지금 화면이 어느 데이터를 보여주는지부터 확인했습니다.

읽어보기 →
재현 실험

캐시를 붙였는데 DB가 더 바빠졌다

문제는 저장 공간보다 빈 순간이었습니다. 같은 키를 찾는 100개 요청을 한 번으로 묶어 봤습니다.

읽어보기 →
설계 실무

서비스를 멈추지 않고 DB 컬럼을 바꾸려면?

컬럼 삭제를 맨 마지막으로 미루는 이유. SQL 한 줄보다 먼저 정해야 할 배포 순서를 짚습니다.

읽어보기 →