AVAudioEngine 음원 재생(mp3,audio)

CodeCat·2024년 9월 5일

IOS Audio

목록 보기
1/2
post-thumbnail

안녕하세요 회사를 다니며 진행했던 프로젝트 중 음원 관련 앱을 만들어본 경험이 있는데 이와 관련하여 개발하면서 많은 어려움을 겪었던 AVAudioEngine에 대해서 작성해보려 합니다.

특히 오디오 엔진 설정부터 재생 시작까지의 과정을 자세히 살펴보겠습니다

AVAudioEngine이란?

iOS 개발자라면 언젠가는 앱에 오디오 기능을 추가해야 할 때가 오는데요

AVAudioEngine으로 음악 재생, 음성 녹음, 실시간 오디오 처리 등 다양한 오디오 관련 작업을 수행해야 할 수 있습니다

이럴 때 우리의 강력한 동반자가 되어줄 프레임워크가 바로 AVAudioEngine입니다

AVAudioEngine은 Apple의 AVFoundation 프레임워크에 포함된 강력한 오디오 처리 시스템으로 복잡한 오디오 처리 작업을 간단하고 효율적으로 수행할 수 있게 해주는 API를 제공합니다

1. 오디오 엔진 구성 요소 설정



var engine_Song: AVAudioEngine?  : 오디오 파일을 읽거나 쓰는 데 사용
var audioFile_Song: AVAudioFile? : 오디오 파일을 읽거나 쓰는 데 사용
var mixerNode_Song: AVAudioMixerNode! : 여러 오디오 소스를 하나로 혼합하는 노드
var mainMixer_Song : AVAudioMixerNode! : 주 믹서 노드로, 최종 오디오 출력을 제어
var inputNode_Song : AVAudioInputNode! : 오디오 입력(: 마이크)을 처리하는 노드
var outputNode_Song : AVAudioOutputNode! : 최종 오디오 출력을 담당하는 노드
var audioFormat_Song: AVAudioFormat! : 오디오 데이터의 형식(샘플 레이트, 채널 수 등)을 정의
var nodePlayer_Song :AVAudioPlayerNode? : 오디오 파일을 재생하는 특수 노드

2. 오디오 세션 설정

try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker, .allowBluetoothA2DP])

저가 개발하던 음원 앱에서는 블루투스와 기본 스피커에서 모두 재생이 가능하게 해야했기에 세션 옵션을 defaultToSpeaker,allowBluetoothA2DP 를 설정 했습니다

playAndRecord

  • 이 카테고리는 오디오 녹음(입력)과 재생(출력)을 모두 허용합니다

options: [.defaultToSpeaker, .allowBluetoothA2DP]

  • defaultToSpeaker: 기본 출력을 내장 스피커로 설정합니다
  • allowBluetoothA2DP: A2DP (Advanced Audio Distribution Profile) 블루투스 장치의 사용을 허용

3. 오디오 엔진 구성

audioFile_Song = try AVAudioFile(forReading: dest) -> dest:  파일 주소 
self.nodePlayer_Song = AVAudioPlayerNode()
self.engine_Song = AVAudioEngine()
self.inputNode_Song = self.engine_Song?.inputNode
self.outputNode_Song = self.engine_Song?.outputNode
self.mainMixer_Song = self.engine_Song!.mainMixerNode
self.mixerNode_Song = AVAudioMixerNode()

오디오 각 구성별로 셋팅을 해주고

self.audioFormat_Song = AVAudioFormat(commonFormat: .pcmFormatFloat32,   
                                                  sampleRate: sampleRate,                    
                                                  interleaved: false)

오디오의 샘플 레이트, 채널 수 등 어떤 셋팅으로 출력할지를 정합니다.

일반적인 sampleRate 값은 48000 Hz로 해주는데 이는 전문 오디오 및 비디오 제작에서 자주 사용해요 참고로 에어팟과 같은 일부 Bluetooth 장치는 24000 Hz (24 kHz)를 사용할 수 있어요!

self.engine_Song?.attach(mixerNode_Song)
self.engine_Song?.attach(nodePlayer_Song!)

이 두 줄의 코드는 AVAudioEngine에 오디오 처리 노드들을 연결하는 과정인데요 쉽게 말해, 오디오 시스템의 부품들을 메인 엔진에 장착하는 것과 같아요

self.engine_Song?.connect(inputNode_Song!, to: mixerNode_Song, format:  audioFormat_Song) 

입력 노드(마이크)의 오디오를 믹서 노드로 연결시켜줘 실시간 오디오 입력을 처리할 수 있게 해줍니다

self.engine_Song?.connect(mixerNode_Song, to: engine_Song!.mainMixerNode, format: audioFormat_Song)

커스텀 믹서 노드를 메인 믹서 노드에 연결(여러 오디오 소스를 혼합한 후 최종 출력)

self.engine_Song?.connect(nodePlayer_Song!, to: engine_Song!.mainMixerNode, format: audioFormat_Song)

오디오 플레이어 노드를 메인 믹서 노드에 연결(오디오 파일 재생에 사용)

do {
    try self.engine_Song?.start()
    print("오디오 엔진이 성공적으로 시작되었습니다.")
} catch {
    print("오디오 엔진 시작 실패: \(error.localizedDescription)")
}

이후 연결된 AVAudioEngine을 실행 시켜주면 되는데요

AVAudioEngine을 실행시키면

  1. 이전에 설정한 모든 오디오 노드와 연결을 활성화
  2. 오디오 신호가 흐르기 시작
  3. 시스템 리소스(CPU, 메모리 등)를 오디오 처리에 할당
  4. iOS 기기의 오디오 세션을 활성화

위와 같은 일들이 진행 됩니다

하지만 아직 nodePlayer_Song를 실행 시키지 않았기때문에 음원 재생이 되지 않은 상태입니다

nodePlayer_Song?.volume = 1.0

음원 플레이 볼륨을 설정하고

if self.engine_Song?.isRunning == false {
    try? self.engine_Song?.start()
}

engine_Song이 시작 상태인지 확인 후

self.nodePlayer_Song!.scheduleFile(self.audioFile_Song!, at: nil, completionCallbackType: .dataRendered) { (callback) in
	print("노래 재생 완료 시 클로저 실행 즉 예약한 음원의 모든 데이터를 읽었을 때 실행 됨")
}

오디오 파일을 재생하도록 예약합니다

self.nodePlayer_Song?.play()

이 후 모든 셋팅을 맞췄다면 이제 음원을 재생하면 재생이 완료 됩니다

다음 포스팅에서는 노래가 종료된 후에 해야 하는 설정들에 대해서 다뤄보도록 하겠습니다!

감사합니다

profile
코드와 고양이의 만남

0개의 댓글