Jetpack SceneCore 中的空間音訊功能可讓您在 Android XR 應用程式中打造沉浸式音訊體驗。
空間音訊可模擬使用者在 3D 環境中感知聲音的方式。它會產生從各個方向 (包括使用者上方和下方) 傳來的聲音感覺。系統會在 3D 空間的特定位置模擬一或多個「虛擬喇叭」。
對於未針對 Android XR 設計或修改的現有應用程式,其音訊會在 Android XR 中自動以空間化方式呈現。當使用者在空間中移動時,所有應用程式音訊都會從應用程式 UI 算繪的面板中傳出。舉例來說,如果鬧鐘應用程式中的計時器響起,音訊會像是從應用程式面板位置傳出。Android XR 會自動變更音效,以便呈現位置真實感。舉例來說,應用程式面板與使用者之間的距離會微妙地影響音量,讓音效更逼真。
如要進一步瞭解現有應用程式如何算繪空間音訊,請參閱本頁的「在應用程式中新增立體聲和環場音效」一文。
如果您要針對 XR 最佳化應用程式,Jetpack SceneCore 提供進階空間音訊自訂工具。您可以在 3D 環境中精確定位聲音、使用環場音效打造逼真的音場,並善用內建的環繞音效整合功能。
Android XR 提供的空間音效類型
Android XR 支援定位、立體聲、環場音效和環場音訊。
空間音訊
位置音訊可從 3D 空間中的特定點播放。舉例來說,您可以使用3D 模型,讓狗在虛擬環境的角落吠叫。您可以讓多個實體從各自的位置發出聲音。如要算繪定位音訊,檔案必須是單聲道或立體聲。
空間化立體聲和環場音效
系統支援所有 Android 媒體格式,可提供定位、立體聲和環場音效。
立體聲音訊是指兩個聲道的音訊格式,環場音效則是指超過兩個聲道的音訊格式,例如 5.1 環場音效 或 7.1 環場音效 設定。每個聲道都有一個音訊資料,舉例來說,在立體聲播放音樂時,左聲道可能會發出不同於右聲道的樂器音軌。
環場音效經常用於電影和電視節目,透過多個喇叭管道提升真實感和臨場感。舉例來說,對話通常會從中間喇叭頻道播放,而直升機飛行的聲音可能會依序使用不同的頻道,讓你感覺到直升機在 3D 空間中飛行。
環場音訊
Ambisonic 音訊 (或稱 Ambisonics) 就像音訊的「天空盒」,可為使用者提供身歷其境的音效。使用環繞聲處理背景環境音效,或在其他情況下模擬環繞聽眾的完整球形音場。Android XR 支援第一、第二和第三階環繞聲的 AmbiX 環繞聲音訊格式。建議使用 Opus (.ogg
) 和 PCM/Wave (.wav
) 檔案類型。
搭配 Jetpack SceneCore 使用空間音訊
使用 Jetpack SceneCore 實作空間音訊功能時,需要檢查空間功能,並選擇用於載入空間音訊的 API。
檢查空間功能
使用空間音訊功能前,請確認 Session
支援空間音訊。在下列各節的所有程式碼片段中,會先檢查功能,再嘗試播放空間化音訊。
載入空間音訊
您可以使用下列任一 API 載入空間音訊,以便在 Jetpack SceneCore 中使用。
SoundPool
:適用於大小小於 1 MB 的短音效,這些音效會提前載入,且可重複使用。這是為位置音訊載入音訊的絕佳方式。ExoPlayer
:適合用於載入音樂和影片等立體聲和環繞音訊內容。也允許背景媒體播放。MediaPlayer
:提供最簡單的 ambisonic 音訊載入方式。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
}
程式碼的重點
- 如同位置音訊範例,第一步是使用
getSpatialCapabilities()
檢查目前是否支援位置音訊功能。 - 將 contentType 設為 CONTENT_TYPE_MUSIC,並將 usage 設為 USAGE_MEDIA,系統就會將這個音訊檔案視為環繞音效。
在應用程式中加入環場音效
如要播放環繞聲音場,最簡單的方法是使用 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 和 usage 僅供參考。
AMBISONICS_ORDER_FIRST_ORDER
會向 SceneCore 發出訊號,指出音訊場景檔案定義了四個管道。