apple/Video, Audio, DRM

AVAudioEngine, AVAudioNode 정리

lgvv 2025. 11. 26. 01:09

AVAudioEngine, AVAudioNode 정리

 

AVAudioEngine과 관련한 내용을 모아서 정리

 

 

목차

  • AVAudioEngine
    • 오디오 렌더링이란?
    • Overview
    • Create an Engine for Audio File Playback
  • AVAudioNode
    • Overview
    • Configuring an Input Format Bus
      • AVAudioNodeBus
      • inputFormat(forBus:)
      • name(forInputBus:)
      • numberOfInputs
    • Creating an Output Format Bus
      • outputFormat(forBus:)
      • name(forOutputBus:)
      • numberOfOutputs
    • Installing and Removing an Audio Tap
      • installTap(onBus:bufferSize:format:block:)
      • removeTap(onBus:)
      • typealias AVAudioNodeTapBlock
    • Getting the Audio Engine for the Node
      • engine
    • Getting Audio Node Properties
      • auAudioUnit
      • latency
      • outputPresentationLatency
    • Resetting the Audio Node
      • reset()
    • Constants
      • typealias AVAudioNodeCompletionHandler

 

AVAudioEngine

 

오디오 노드들의 그래프를 관리하고 재생을 제어하며 실시간 렌더링 제약을 구성하는 객체

 

AVAudioEngine

 

 

 

 


오디오 렌더링이란?

 

오디오 데이터를 처리해서 최종적인 PCM 샘플로 만들어내는 작업

 

여러 Audio Node의 처리 결과를 합치고 이펙트(효과)를 적용하고 믹싱하고 최종적으로 출력할 수 있는 형태로 데이터를 계산해서 생산하는 과정을 의미.

 

실시간 렌더링과 수동 렌더링이 존재

실시간 렌더링의 경우에는 AudioEngine이 자동으로 주기적으로 콜백을 받아 오디오 샘플을 생성

수동 렌더링의 경우에는 앱이 직접 오디오 엔진에 렌더링을 요청해서 오디오 샘플을 생성해서 다 빠르게 처리할 수 있음.

 

 

 

 

Overview

 

오디오 엔진 객체는 AVAudioNode 인스턴스를 포함하며 이를 서로 연결해 오디오 처리 체인을 구성

 

Overview

 

 

런타임 동안 오디오 노드를 연결하거나 연결 해제하고 제거할 수 있지만 몇 가지 제한이 존재.

채널 수가 서로 다르거나 믹서(mixer)인 오디오 노드를 제거하면 그래프가 깨질 수 있으며, 믹서의 상위(upstream)에 있는 노드만 재연결해야 함.

 

기본적으로 Audio Engine은 연결된 오디오 기기로 실시간 렌더링을 수행.

실시간 또는 실시간보다 더 빠르게 렌더링해야 하는 경우, 엔진을 수동 렌더링 모드(manual rendering mode)로 설정할 수 있음.

 

이 모드에서 엔진은 오디오 기기와의 연결을 끊고 앱이 직접 렌더링을 제어함.

 

Create an Engine for Audio File Playback

 

 

오디오 파일 재생을 위한 순서

  • 1. 오디오 파일을 재생하기 위해서는 우선 읽기 모드로 열 수 있는 파일을 기반으로 AVAudioFile 객체를 생성
  • 2. 오디오 엔진(AVAudioEngine) 객체와 AVAudioPlayerNode 인스턴스를 만들고 플레이어 노드를 엔진에 attach
  • 3. 플레이어 노드를 오디오 엔진의 output node에 연결(connect)
  • 4. 오디오 엔진은 오디오 출력을 담당하는 output node를 통해 사운드를 재생
    • 4-1. output node는 엔진에서 처음 접근할 때 자동으로 생성되는 싱글턴(singleton)
  • 5. 오디오 파일 전체를 재생하도록 스케줄하고, 재생이 완료되면 콜백을 통해 앱에 알려줌.
  • 6. 오디오를 재생하기 전에 AudioEngine을 시작
  • 7. 재생이 완료되면 오디오 플레이어 노드랑 오디오 엔진을 정지.

 

샘플코드

func execute() throws {
    let audioFile = try AVAudioFile(forReading: URL(string: "")!)
    let audioEngine = AVAudioEngine()
    let playerNode = AVAudioPlayerNode()
    
    // AVAudioEngine 객체와 AVAudioPlayerNode 인스턴스를 만들고 플레이어 노드를 엔진에 attach
    audioEngine.attach(playerNode)
    
    
    // 플레이어 노드를 출력 노드에 연결
    audioEngine.connect(
        playerNode,
        to: audioEngine.outputNode,
        format: audioFile.processingFormat
    )
    
    // 오디오 파일 전체를 재생하도록 스케줄하고, 재생이 완료되면 콜백을 통해 앱에 알려줌.
    playerNode.scheduleFile(
        audioFile,
        at: nil,
        completionCallbackType: .dataPlayedBack
    ) { _ in
        /* Handle any work that's necessary after playback. */
    }
    
    // 오디오를 재생하기 전에 AudioEngine을 시작
    try audioEngine.start()
    playerNode.play()
    
    // 재생이 완료되면 오디오 플레이어 노드랑 오디오 엔진을 정지.
    playerNode.stop()
    audioEngine.stop()
}

 

 

 

AVAudioNode

 

오디오 생성, 처리 또는 입출력(I/O) 블록에 사용하는 객체

iOS 8.0+
iPadOS 8.0+
Mac Catalyst 13.1+
macOS 10.10+
tvOS 9.0+
visionOS 1.0+
watchOS 2.0+

 

 

 

Overview

 

AVAudioEngine 객체는 오디오 노드 인스턴스를 포함하며, 이 기본 클래스는 공통 기능을 제공

AVAudioEngine 객체의 인스턴스는 엔진에 연결되지 않으면 실질적인 기능을 수행하지 않음.

 

노드는 입력(input)과 출력(output) 버스(bus)를 가지며, 이 버스들이 연결 지점 역할을 함.

이펙트(effect) 노드는 하나의 입력 버스와 하나의 출력 버스를 가짐

믹서(mixer) 노드는 여러 입력 버스와 하나의 출력 버스를 가짐

 

각 버스는 프레임워크가 샘플 레이트(sample rate)와 채널 수(channel count)로 표현하는 포맷(format)을 포함

노드 간 연결 시 포맷은 정확히 일치해야 하고 AVAudioMixerNode와 AVAudioOutputNode는 예외

 

 

Configuring an Input Format Bus

 

AVAudioNodeBus

  • AVAudioNode의 버스 인덱스
  • AVAudioNode 객체는 여러 개의 입력 및 출력 버스를 가질 수 있음.
  • AVAudioNodeBus는 버스를 0부터 시작하는 인덱스로 표현.
public typealias AVAudioNodeBus = Int

 

 

inputFormat(forBus:)

  • 지정한 bus의 입력 포맷을 가져옴
  • 해당 버스의 입력 포맷을 나타내는 AVAudioFormat 인스턴스를 반환
func inputFormat(forBus bus: AVAudioNodeBus) -> AVAudioFormat

 

 

name(forInputBus:)

  • 지정한 입력 버스의 이름을 가져옴
  • 오디오 노드의 입력 버스
  • 인풋 버스의 이름
func name(forInputBus bus: AVAudioNodeBus) -> String?

 

 

numberOfInputs

  • 인풋 버스의 수
var numberOfInputs: Int { get }

 

 

Creating an Output Format Bus

 

outputFormat(forBus:)

  • 지정한 버스의 출력 포맷
func outputFormat(forBus bus: AVAudioNodeBus) -> AVAudioFormat

 

 

 

name(forOutputBus:)

  • 지정한 출력 버스의 이름을 가져옴
func name(forOutputBus bus: AVAudioNodeBus) -> String?

 

 

numberOfOutputs

  • 노드의 출력 버스 수 
var numberOfOutputs: Int { get }

 

 

 

Installing and Removing an Audio Tap

 

installTap(onBus:bufferSize:format:block:)

  • 지정한 버스에 오디오 탭(audio tap)을 설치해 노드의 출력을 녹음, 모니터링, 관찰 할 수 있음.
  • 엔진이 실행 중일 때도 탭을 설치하거나 제거할 수 있음.
  • 하나의 버스에는 한 개의 탭만 설치할 수 있음.
  • bus
    • 탭을 연결한 출력 버스
  • bufferSize
    • 들어오는 오디오 버퍼의 크기 (실제 구현에서는 다른 크기 선택 가능)
  • format
    • nil이 아닌 경우에 지정한 출력 버스에 해당 포맷 지정
    • 이미 연결된 상태의 출력 버스에 탭을 연결하면 오류가 발생
    • 탭과 연결 포맷 둘 다 nil이 아닌 경우에 두 포맷을 동일해야 하며, 그렇지 않은 경우에는 나중에 적용된 포맷이 이전 포맷을 덮어씀.
    • AVAudioOutputNode의 경우 탭 포맷은 반드시 nil로 지정해야 함.
  • tapBlock
    • 오디오 버퍼를 처리하기 위해 프레임워크가 호출하는 블록
    • 프레임워크는 tapBlock메인 스레드가 아닌 다른 스레드에서 호출할 수 있음.

 

func installTap(
    onBus bus: AVAudioNodeBus,
    bufferSize: AVAudioFrameCount,
    format: AVAudioFormat?,
    block tapBlock: @escaping AVAudioNodeTapBlock
)

 

 

removeTap(onBus:)

  • 지정한 버스의 오디오 탭을 제거
func removeTap(onBus bus: AVAudioNodeBus)

 

 

 

AVAudioNodeTapBlock

  • 오디오 노드의 출력을 복사하여 받는 블록(block)
  • 프레임워크는 tapBlock 메인 스레드가 아닌 다른 스레드에서 호출할 수 있음.
  • buffer
    • 시스템이 오디오 노드의 출력에서 캡처한 오디오 버퍼
  • when
    • 시스템이 해당 버퍼를 캡처한 시점
typealias AVAudioNodeTapBlock = (AVAudioPCMBuffer, AVAudioTime) -> Void

 

 

 

Getting the Audio Engine for the Node

 

engine

  • 해당 노드를 관리하는 Audio Engine 존재하는 경우
var engine: AVAudioEngine?

 

 

 

Getting the Latest Node Render Time

 

lastRenderTime

  • 가장 최근의 렌더링 시간
  • 엔진이 실행 중이 아니거나 노드를 입력(input) 혹은 출력(output) 노드에 연결하지 않은 경우 이 값은 nil
var lastRenderTime: AVAudioTime? { get }

 

 

Getting Audio Node Properties

 

auAudioUnit

  • Audio Unit 객체로 구현체의 오디오 유닛을 래핑하거나 기반
  • 앱이 오디오 유닛을 패키징하는 방식에 따라 구현체의 오디오 유닛을 래핑(wrap)하거나 기반(underlie)으로 하는 AUAudioUnit을 제공
    • 엔진 상태와 충돌할 수 있는 작업(초기화 상태 변경, 스트림 포맷 변경, 채널 레이아웃 변경, 다른 오디오 유닛과의 연결 변경 등)은 직접 수행하지 말것
  • 앱은 이를 통해 커스텀 속성을 제어하고, 프리셋을 선택하며, 파라미터를 변경할 수 있음.
var auAudioUnit: AUAudioUnit { get }

 

 

 

latency

  • 노드의 processing latency 시간
  • 이 latency는 신호 처리로 인한 딜레이를 나타내어 값이 0인 경우에 latency가 없거나 알 수 없는 경우
var latency: TimeInterval { get }

 

 

 

outputPresentationLatency

  • 노드 이후(render downstream)의 최대 렌더 파이프라인 지연 시간
  • 이 지연은 노드의 출력에서 오디오가 실제로 재생되기까지 걸리는 최대 시간을 나타냄
var outputPresentationLatency: TimeInterval { get }

 

 

Resetting the Audio Node

 

  • reset()
    • 오디오 유닛의 이전 처리 상태를 초기화

 

Constants

 

  • AVAudioNodeCompletionHandler
    • 오디오 노드에서 사용하는 일반적인 콜백 핸들러

 

 

AVAudioNode에는 이와 별개로 다른 노드들도 존재

 

 

 

(참고)

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

'apple > Video, Audio, DRM' 카테고리의 다른 글

AVAudioFormat 정리  (0) 2025.11.24
AudioStreamBasicDescription 정리  (0) 2025.11.24
AVAudioPCMBuffer 정리  (0) 2025.11.24
Adaptive Bit Streaming  (0) 2025.10.23
[HLS] Creating a Multivariant Playlist  (0) 2024.12.05