XR 앱에 공간 오디오 추가

Jetpack SceneCore의 공간 오디오 기능을 사용하면 Android XR 애플리케이션 내에서 몰입도 높은 오디오 환경을 만들 수 있습니다.

공간 오디오는 사용자가 3D 환경에서 소리를 인식하는 방식을 시뮬레이션합니다. 사용자 위와 아래를 비롯한 모든 방향에서 소리가 발산되는 느낌을 만듭니다. 시스템은 3D 공간의 특정 위치에 하나 이상의 '가상 스피커'를 시뮬레이션하여 이를 실행합니다.

Android XR용으로 설계되거나 수정되지 않은 기존 앱의 오디오는 Android XR에서 자동으로 스페이스화됩니다. 사용자가 스페이스를 이동하면 앱의 UI가 렌더링되는 패널에서 모든 앱 오디오가 내보내집니다. 예를 들어 시계 앱에서 타이머가 울리면 앱 패널 위치에서 소리가 나는 것처럼 들립니다. Android XR은 위치적 사실감을 위해 사운드를 자동으로 변경합니다. 예를 들어 앱 패널과 사용자 간의 인식된 거리는 오디오 볼륨에 미묘하게 영향을 미쳐 더 실감 나게 느껴집니다.

기존 앱에서 공간 오디오를 렌더링하는 방법에 관한 자세한 내용은 이 페이지의 앱에 스테레오 및 서라운드 사운드 추가를 참고하세요.

XR용으로 앱을 최적화하는 경우 Jetpack SceneCore는 고급 공간 오디오 맞춤설정을 위한 도구를 제공합니다. 3D 환경에서 소리를 정확하게 배치하고, 사실적인 음장에 앰비소닉 오디오를 사용하고, 내장된 서라운드 사운드 통합을 활용할 수 있습니다.

Android XR에서 사용할 수 있는 공간 음향 유형

Android XR은 위치, 스테레오, 서라운드 사운드, 앰비소닉 오디오를 지원합니다.

위치 오디오

위치 오디오는 3D 공간의 특정 지점에서 재생되도록 배치할 수 있습니다. 예를 들어 가상 환경의 한쪽 구석에서 짖는 강아지의 3D 모델을 만들 수 있습니다. 각 위치에서 소리를 내도록 여러 항목을 만들 수 있습니다. 위치 오디오를 렌더링하려면 파일이 모노 또는 스테레오여야 합니다.

공간화된 스테레오 및 서라운드 사운드

모든 Android 미디어 형식은 위치, 스테레오, 서라운드 사운드에 지원됩니다.

스테레오 오디오는 채널이 2개인 오디오 형식을 말하며 서라운드 사운드는 5.1 서라운드 사운드 또는 7.1 서라운드 사운드 구성과 같이 채널이 2개 이상인 오디오 형식을 말합니다. 각 채널의 음원 데이터는 한 명의 화자와 연결됩니다. 예를 들어 스테레오로 음악을 재생할 때 왼쪽 스피커 채널은 오른쪽과 다른 악기 트랙을 내보낼 수 있습니다.

서라운드 사운드는 영화와 TV 프로그램에서 여러 스피커 채널을 사용하여 현실감과 몰입감을 높이는 데 자주 사용됩니다. 예를 들어 대화는 중앙 스피커 채널에서 재생되는 경우가 많지만 헬리콥터가 날아가는 소리는 헬리콥터가 3D 공간을 날아다니는 듯한 느낌을 주기 위해 여러 채널을 차례로 사용할 수 있습니다.

앰비소닉 오디오

앰비소닉 오디오 (또는 앰비소닉스)는 오디오의 스카이박스와 같으며 사용자에게 몰입도 높은 사운드스케이프를 제공합니다. 배경 환경 소리나 청취자를 둘러싼 전체 구형 음장 효과를 재현하려는 다른 시나리오에 앰비소닉스를 사용하세요. Android XR은 1차, 2차, 3차 앰비소닉에서 AmbiX 앰비소닉 오디오 형식을 지원합니다. Opus (.ogg) 및 PCM/Wave (.wav) 파일 형식이 좋습니다.

Jetpack SceneCore로 공간 음향 사용

Jetpack SceneCore로 공간 음향을 구현하려면 공간 기능을 확인하고 공간 음향을 로드할 API를 선택해야 합니다.

공간 기능 확인

서라운드 오디오 기능을 사용하기 전에 Session에서 서라운드 오디오를 지원하는지 확인하세요. 다음 섹션의 모든 코드 스니펫에서는 공간화된 오디오를 재생하기 전에 기능이 확인됩니다.

공간 음향 로드

다음 API 중 하나를 사용하여 Jetpack SceneCore에서 사용할 공간 오디오를 로드할 수 있습니다.

  • SoundPool: 크기가 1MB 미만인 짧은 음향 효과에 적합하며, 사전에 로드되며 사운드를 반복적으로 사용할 수 있습니다. 이는 위치 오디오의 오디오를 로드하는 좋은 방법입니다.
  • ExoPlayer: 음악 및 동영상과 같은 스테레오 및 서라운드 사운드 콘텐츠를 로드하는 데 적합합니다. 백그라운드 미디어 재생도 허용합니다.
  • MediaPlayer: 앰비소닉 오디오를 로드하는 가장 간단한 방법을 제공합니다.
  • AudioTrack: 오디오 데이터를 로드하는 방법을 가장 세부적으로 제어할 수 있습니다. 오디오 버퍼를 직접 쓰거나 자체 오디오 파일을 합성하거나 디코딩한 경우 허용됩니다.

앱에 위치 오디오 추가

위치 음원 소스는 PointSourceAttributes 및 연결된 Entity로 정의됩니다. Entity의 위치와 방향에 따라 PointSourceAttribute가 3D 공간에서 렌더링되는 위치가 결정됩니다.

위치 오디오 예시

다음 예에서는 음향 효과 오디오 파일을 사운드 풀에 로드하고 Entity 위치에서 재생합니다.

// Check spatial capabilities before using spatial audio
if (xrSession.getSpatialCapabilities().hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val maxVolume = 1F
    val lowPriority = 0
    val infiniteLoop = -1
    val normalSpeed = 1F

    val soundPool = SoundPool.Builder()
        .setAudioAttributes(
            AudioAttributes.Builder()
                .setContentType(CONTENT_TYPE_SONIFICATION)
                .setUsage(USAGE_ASSISTANCE_SONIFICATION)
                .build()
        )
        .build()

    val pointSource = PointSourceAttributes(entity)

    val soundEffect = appContext.assets.openFd("sounds/tiger_16db.mp3")
    val pointSoundId = soundPool.load(soundEffect, lowPriority)

    soundPool.setOnLoadCompleteListener{ soundPool, sampleId, status ->
        //wait for the sound file to be loaded into the soundPool
        if (status == 0){

            SpatialSoundPool.play(
                session = xrSession,
                soundPool = soundPool,
                soundID = pointSoundId,
                attributes = pointSource,
                volume = maxVolume,
                priority = lowPriority,
                loop = infiniteLoop,
                rate = normalSpeed
            )
        }
    }
} else {
    // The session does not have spatial audio capabilities
}

코드에 관한 주요 사항

  • 첫 번째 단계는 getSpatialCapabilities()를 사용하여 현재 공간 음향 기능을 사용할 수 있는지 확인하는 것입니다.
  • contentType을 CONTENT_TYPE_SONIFICATION로, usage를 USAGE_ASSISTANCE_SONIFICATION로 설정하면 시스템에서 이 오디오 파일을 음향 효과로 처리합니다.
  • 위 예에서는 편의상 코드를 함께 유지하기 위해 오디오 파일을 사용하기 직전에 풀에 로드합니다. 앱을 로드할 때 모든 음향 효과를 비동기식으로 로드하여 필요한 경우 모든 오디오 파일을 풀에서 사용할 수 있도록 하는 것이 좋습니다.

앱에 스테레오 및 서라운드 사운드 추가

앱에 스테레오 및 서라운드 사운드를 추가하는 데 권장되는 방법은 Exoplayer를 사용하는 것입니다. Exoplayer에서 공간 음향을 사용하는 방법에 관한 자세한 내용은 공간 음향 가이드를 참고하세요.

스테레오 및 서라운드 사운드 스피커 배치

서라운드 사운드 스피커 배치에서는 가상 서라운드 사운드 스피커가 중앙 스피커를 기준으로 배치되고 표준 ITU 구성에 따라 사용자 주변에 배치됩니다.

기본적으로 센터 채널 스피커는 앱의 mainPanelEntity에 배치됩니다. 여기에는 Android XR에 의해 자동으로 오디오가 스페이스화된 모바일 앱이 포함됩니다.

스테레오의 경우 스피커 배치는 서라운드 사운드와 비슷하지만 왼쪽과 오른쪽 채널만 각각 패널의 왼쪽과 오른쪽에 배치된다는 점을 제외하고는 동일합니다.

패널이 여러 개 있고 오디오를 내보낼 패널을 선택하려는 경우 또는 스테레오 또는 서라운드 오디오가 다른 Entity를 기준으로 렌더링되도록 하려면 PointSourceAttributes를 사용하여 중앙 채널의 위치를 정의하면 됩니다. 나머지 채널은 앞에서 언급한 대로 배치됩니다. 이러한 경우에는 MediaPlayer도 사용해야 합니다.

사용자가 공간 내에서 이동하면 스테레오 및 서라운드 사운드 가상 스피커가 이동하고 조정되어 스피커가 항상 최적의 위치에 있도록 합니다.

백그라운드에서 스테레오 또는 서라운드 사운드를 계속 재생하도록 MediaPlayer 또는 ExoPlayer를 구성한 경우 앱이 백그라운드로 전환되면 가상 스피커 위치가 변경됩니다. 공간에 사운드를 고정할 패널이나 다른 지점이 없으므로 공간 오디오는 사용자와 함께 이동합니다 (즉, '헤드 잠금').

서라운드 사운드 예시

다음 예에서는 MediaPlayer를 사용하여 5.1 오디오 파일을 로드하고 파일의 센터 채널을 Entity로 설정합니다.

// Check spatial capabilities before using spatial audio
if (xrSession.getSpatialCapabilities().hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val pointSourceAttributes = PointSourceAttributes(xrSession.mainPanelEntity)

    val mediaPlayer = MediaPlayer()

    val fivePointOneAudio = appContext.assets.openFd("sounds/aac_51.ogg")
    mediaPlayer.reset()
    mediaPlayer.setDataSource(fivePointOneAudio)

    val audioAttributes =
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()

    SpatialMediaPlayer.setPointSourceAttributes(
        xrSession,
        mediaPlayer,
        pointSourceAttributes)

    mediaPlayer.setAudioAttributes(audioAttributes)
    mediaPlayer.prepare()
    mediaPlayer.start()

} else {
    // The session does not have spatial audio capabilities
}

코드에 관한 주요 사항

앱에 앰비소닉 음장 추가

앰비소닉 음장 필드를 재생하는 가장 간단한 방법은 MediaPlayer로 파일을 로드하는 것입니다. 앰비소닉 사운드는 전체 사운드스케이프에 적용되므로 위치를 제공하기 위해 Entity를 지정할 필요가 없습니다. 대신 채널 수를 지정하는 적절한 앰비소닉 순서로 SoundFieldAttributes 인스턴스를 만듭니다.

Ambionics 예시

다음 예에서는 MediaPlayer를 사용하여 앰비소닉 음장 필드를 재생합니다.

// Check spatial capabilities before using spatial audio
if (xrSession.getSpatialCapabilities().hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val soundFieldAttributes =
        SoundFieldAttributes(SpatializerConstants.AMBISONICS_ORDER_FIRST_ORDER)

    val mediaPlayer = MediaPlayer()

    val soundFieldAudio = appContext.assets.openFd("sounds/foa_basketball_16bit.wav")

    mediaPlayer.reset()
    mediaPlayer.setDataSource(soundFieldAudio)

    val audioAttributes =
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()

    SpatialMediaPlayer.setSoundFieldAttributes(
        xrSession,
        mediaPlayer,
        soundFieldAttributes)

    mediaPlayer.setAudioAttributes(audioAttributes)
    mediaPlayer.prepare()
    mediaPlayer.start()

} else {
    // The session does not have spatial audio capabilities
}

코드에 관한 주요 사항

  • 이전 스니펫과 마찬가지로 첫 번째 단계는 getSpatialCapabilities()를 사용하여 현재 공간 음향 기능을 사용할 수 있는지 확인하는 것입니다.
  • contentType 및 사용은 정보 제공의 목적으로만 사용됩니다.
  • AMBISONICS_ORDER_FIRST_ORDER: SceneCore에 음장 파일이 4개의 채널을 정의한다고 신호를 보냅니다.