[SwiftUI] AVAudioRecorder로 녹음 구현하기

양재현·2026년 2월 17일

앱에서 녹음 기능을 구현하기 위해 AVAudioRecorder 에 대해 알아보려고 한다.

AVAudioRecorder

AVAudioRecorder는 애플의 AVFoundation 프레임워크에 포함된 클래스로, 기기의 마이크를 통해 들어오는 오디오 신호를 실제 파일로 저장할 때 사용하는 "녹음기 객체"다.


*주요 역할

1. 연결 : 마이크와 앱 사이의 통로를 열어 소리를 받아온다.

2. 변환 : 아날로그 소리 신호를 우리가 지정한 디지털 포맷(AAC, PCM 등)으로 변환한다.

3. 저장 : 변환된 데이터를 기기 내부(Document 폴더 등)에 파일 형태로 기록한다.


녹음을 하기 위해서는 우선 권한 설정을 해주어야 한다.

권한설정

Info.plist 에서 Privacy - Microphone Usage Description 권한을 추가해준다.

AudioManager

import AVFoundation

@Observable
class AudioManager {
    var audioRecorder: AVAudioRecorder? // 녹음을 담당하는 객체
    var audioPlayer: AVAudioPlayer?     // 재생을 담당하는 객체
    var isRecording = false             // 현재 녹음 중인지 상태값
    var recordedFileURL: URL?           // 녹음된 파일이 저장된 경로

    // [1] 마이크 권한 요청
    func requestPermission() {
        AVAudioApplication.requestRecordPermission { granted in
            print("마이크 권한 허용 여부: \(granted)")
        }
    }

    // [2] 녹음 시작
    func startRecording() {
        let session = AVAudioSession.sharedInstance()
        
        do {
            // 녹음 세션 설정: 재생(play)과 녹음(record)을 동시에 지원하며, 소리를 스피커로 출력하도록 설정
            try session.setCategory(.playAndRecord, mode: .default, options: .defaultToSpeaker)
            try session.setActive(true)
            
            // 저장 경로 설정: 앱 내 'Documents' 폴더에 my_recording.m4a 이름으로 저장
            let documentPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
            recordedFileURL = documentPath.appendingPathComponent("my_recording.m4a")
            
            // 녹음 설정 (포맷, 샘플 레이트, 채널 등)
            let settings: [String: Any] = [
                AVFormatIDKey: Int(kAudioFormatMPEG4AAC), // AAC 포맷
                AVSampleRateKey: 44100,                   // 44.1kHz 샘플링
                AVNumberOfChannelsKey: 1,                 // 모노 녹음
                AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
            ]
            
            // Recorder 초기화 및 녹음 시작
            audioRecorder = try AVAudioRecorder(url: recordedFileURL!, settings: settings)
            audioRecorder?.prepareToRecord()
            audioRecorder?.record()
            isRecording = true
        } catch {
            print("녹음 시작 실패: \(error.localizedDescription)")
        }
    }

    // [3] 녹음 중단
    func stopRecording() {
        audioRecorder?.stop()
        isRecording = false
    }

    // [4] 녹음 파일 재생
    func startPlaying() {
        guard let url = recordedFileURL else { return }
        
        do {
            // 재생 시에는 세션을 재생(playback) 전용 모드로 변경하여 음질 최적화
            try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
            audioPlayer = try AVAudioPlayer(contentsOf: url)
            audioPlayer?.play()
        } catch {
            print("재생 실패: \(error.localizedDescription)")
        }
    }
}

핵심은 녹음 시작 메서드 func startRecording() 인데 녹음이 어떤 과정을 거치는지 보겠다.

1. 녹음 세션 설정 : 재생(play)과 녹음(record)을 동시에 지원하며, 소리를 스피커로 출력하도록 세션을 설정해준다.

2. 저장 경로 설정 : 앱 내 'Documents' 폴더에 my_recording.m4a 이름으로 녹음본을 저장해준다.

3. 세밀한 녹음 설정 : 포맷, 샘플 레이트, 채널 등을 설정하는데 각각 이렇게 된다.

  • 포맷 : 용량이 작은 m4a(AAC)로 할지, 무손실인 wav(PCM)로 할지 결정
  • 샘플 레이트 : 44100Hz44100Hz(CD 음질) 등 소리의 해상도 설정
  • 채널 : 모노(1)로 할지 스테레오(2)로 할지 선택

4. Recorder 초기화 및 녹음 시작

View

import SwiftUI

struct RecordingView: View {
    // AudioManager 인스턴스 생성
    @State private var audioManager = AudioManager()
    
    var body: some View {
        VStack(spacing: 50) {
            // 현재 상태 표시
            Text(audioManager.isRecording ? "녹음 중..." : "대기 중")
                .font(.title)
                .bold()
                .foregroundColor(audioManager.isRecording ? .red : .primary)

            HStack(spacing: 40) {
                // 녹음 및 중지 버튼
                Button(action: {
                    if audioManager.isRecording {
                        audioManager.stopRecording()
                    } else {
                        audioManager.startRecording()
                    }
                }) {
                    VStack {
                        Image(systemName: audioManager.isRecording ? "stop.circle.fill" : "circle.fill")
                            .resizable()
                            .frame(width: 80, height: 80)
                            .foregroundColor(.red)
                        Text(audioManager.isRecording ? "중지" : "녹음")
                    }
                }

                // 재생 버튼
                Button(action: {
                    audioManager.startPlaying()
                }) {
                    VStack {
                        Image(systemName: "play.circle.fill")
                            .resizable()
                            .frame(width: 80, height: 80)
                            // 파일이 없거나 녹음 중일 때는 비활성화 색상(gray) 처리
                            .foregroundColor(audioManager.recordedFileURL == nil || audioManager.isRecording ? .gray : .blue)
                        Text("재생")
                    }
                }
                // 녹음 중이거나 파일이 없으면 버튼 비활성화
                .disabled(audioManager.recordedFileURL == nil || audioManager.isRecording)
            }
        }
        .padding()
        // 뷰가 나타날 때 마이크 권한 확인
        .onAppear {
            audioManager.requestPermission()
        }
    }
}

#Preview {
    RecordingView()
}

간단한 녹음 예제를 구현해보았다.

🍎 참고

https://developer.apple.com/documentation/avfaudio/avaudiorecorder

0개의 댓글