เพิ่มเสียงรอบทิศทางลงในแอป XR

ฟีเจอร์เสียงรอบทิศทางใน Jetpack SceneCore ช่วยให้คุณสร้างประสบการณ์เสียงสมจริงภายในแอปพลิเคชัน Android XR ได้

เสียงรอบทิศทางจะจำลองวิธีที่ผู้ใช้รับรู้เสียงในสภาพแวดล้อม 3 มิติ ซึ่งจะสร้างความรู้สึกว่าเสียงมาจากทุกทิศทาง รวมถึงเหนือและใต้ผู้ใช้ โดยระบบจะจำลอง "ผู้พูดเสมือนจริง" อย่างน้อย 1 คนในตำแหน่งที่เจาะจงในพื้นที่ 3 มิติ

แอปที่มีอยู่ซึ่งไม่ได้ออกแบบหรือแก้ไขสำหรับ Android XR จะมีระบบจัดเสียงให้เป็นเสียงรอบทิศทางโดยอัตโนมัติใน Android XR เมื่อผู้ใช้ย้ายไปรอบๆ พื้นที่ทำงาน เสียงของแอปทั้งหมดจะส่งออกมาจากแผงที่มีการแสดงผล UI ของแอป เช่น หากตัวจับเวลาจากแอปนาฬิกาดังขึ้น เสียงจะดูเหมือนมาจากตำแหน่งของแผงแอป Android XR จะเปลี่ยนเสียงให้สมจริงตามตำแหน่งโดยอัตโนมัติ ตัวอย่างเช่น ระยะทางที่รับรู้ระหว่างแผงแอปกับผู้ใช้จะส่งผลต่อระดับเสียงเล็กน้อยเพื่อให้รู้สึกสมจริงยิ่งขึ้น

ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีที่แอปที่มีอยู่แสดงผลเสียงเชิงพื้นที่ได้ที่เพิ่มเสียงสเตอริโอและเสียงเซอร์ราวด์ลงในแอปในหน้านี้

หากคุณเพิ่มประสิทธิภาพแอปสำหรับ XR อยู่ Jetpack SceneCore มีเครื่องมือสำหรับการปรับแต่งเสียงรอบทิศทางขั้นสูง คุณสามารถวางตำแหน่งเสียงในสภาพแวดล้อม 3 มิติได้อย่างแม่นยำ ใช้เสียงแบบแอมบิโซนิกส (Ambisonics) เพื่อสนามเสียงสมจริง และใช้ประโยชน์จากการผสานรวมเสียงเซอร์ราวด์ในตัว

ประเภทเสียงรอบทิศทางที่มีใน Android XR

Android XR รองรับเสียงแบบตำแหน่ง สเตอริโอ เซอร์ราวด์ และแอมบิโซนิก

เสียงตามตำแหน่ง

เสียงตามตำแหน่งสามารถกำหนดตำแหน่งให้เล่นจากจุดใดจุดหนึ่งในพื้นที่ 3 มิติ เช่น คุณอาจมีโมเดล 3 มิติของสุนัขที่กำลังเห่าอยู่ที่มุมของสภาพแวดล้อมเสมือนจริง คุณมีเอนทิตีหลายรายการที่ส่งเสียงจากตําแหน่งที่เกี่ยวข้องแต่ละตําแหน่งได้ หากต้องการแสดงผลเสียงตามตำแหน่ง ไฟล์ต้องเป็นแบบโมโนหรือสเตอริโอ

เสียงสเตอริโอและเสียงเซอร์ราวด์แบบสมจริง

รองรับรูปแบบสื่อ Android ทั้งหมดสำหรับเสียงตำแหน่ง สเตอริโอ และเซอร์ราวด์

เสียงสเตอริโอหมายถึงรูปแบบเสียงที่มี 2 ช่อง และเสียงเซอร์ราวด์หมายถึงรูปแบบเสียงที่มีมากกว่า 2 ช่อง เช่น การกำหนดค่าเสียงเซอร์ราวด์ 5.1 หรือเสียงเซอร์ราวด์ 7.1 ข้อมูลเสียงของช่องแต่ละช่องจะเชื่อมโยงกับลำโพง 1 ตัว เช่น เมื่อเล่นเพลงแบบสเตอริโอ ช่องลำโพงด้านซ้ายอาจส่งเสียงแทร็กเครื่องดนตรีที่แตกต่างจากด้านขวา

ระบบเสียงเซอร์ราวด์มักใช้ในภาพยนตร์และรายการทีวีเพื่อเพิ่มความสมจริงและประสบการณ์การรับชมด้วยการใช้ช่องลำโพงหลายช่อง ตัวอย่างเช่น เสียงสนทนามักจะเล่นจากช่องลำโพงกลาง ส่วนเสียงเฮลิคอปเตอร์บินอาจใช้ช่องต่างๆ ตามลำดับเพื่อให้รู้สึกว่าเฮลิคอปเตอร์กำลังบินอยู่รอบๆ พื้นที่ 3 มิติ

เสียงแบบแอมบิโซนิก

เสียง Ambisonic (หรือ Ambisonics) เปรียบเสมือนสกายบ็อกซ์สำหรับเสียง ซึ่งจะสร้างบรรยากาศเสียงที่สมจริงให้แก่ผู้ใช้ ใช้แอมบิโซนิกส์สำหรับเสียงสภาพแวดล้อมในเบื้องหลังหรือสถานการณ์อื่นๆ ที่ต้องการจำลองสนามเสียงแบบทรงกลมรอบตัวผู้ฟัง Android XR รองรับรูปแบบเสียงแบบแอมบิโซนิก AmbiX ในรูปแบบแอมบิโซนิกลำดับที่ 1, 2 และ 3 เราขอแนะนําให้ใช้ไฟล์ประเภท Opus (.ogg) และ PCM/Wave (.wav)

ใช้เสียงรอบทิศทางกับ Jetpack SceneCore

การใช้เสียงรอบทิศทางกับ Jetpack SceneCore เกี่ยวข้องกับการตรวจสอบความสามารถของเสียงรอบทิศทางและการเลือก API สำหรับการโหลดเสียงรอบทิศทาง

ตรวจสอบความสามารถเชิงพื้นที่

ก่อนใช้ฟีเจอร์เสียงรอบทิศทาง ให้ตรวจสอบว่า Session รองรับเสียงรอบทิศทาง ข้อมูลโค้ดทั้งหมดในส่วนต่อไปนี้จะตรวจสอบความสามารถก่อนพยายามเล่นเสียงแบบเสียงรอบทิศทาง

โหลดเสียงรอบทิศทาง

คุณใช้ API ต่อไปนี้เพื่อโหลดเสียงรอบทิศทางเพื่อใช้ใน Jetpack SceneCore ได้

  • SoundPool: เหมาะสำหรับซาวด์เอฟเฟกต์สั้นๆ ที่มีขนาดน้อยกว่า 1 MB ระบบจะโหลดซาวด์เอฟเฟกต์เหล่านี้ไว้ล่วงหน้าและสามารถนำเสียงไปใช้ซ้ำได้ วิธีนี้เป็นวิธีที่ยอดเยี่ยมในการโหลดเสียงสำหรับเสียงตามตำแหน่ง
  • ExoPlayer: เหมาะสำหรับการโหลดเนื้อหาเสียงสเตอริโอและเสียงเซอร์ราวด์ เช่น เพลงและวิดีโอ รวมถึงอนุญาตให้เล่นสื่อในเบื้องหลังด้วย
  • MediaPlayer: แสดงวิธีที่ง่ายที่สุดในการโหลดเสียงแบบแอมบิโซนิก
  • AudioTrack: ให้การควบคุมวิธีโหลดข้อมูลเสียงมากที่สุด อนุญาตให้เขียนบัฟเฟอร์เสียงโดยตรง หรือในกรณีที่คุณสังเคราะห์หรือถอดรหัสไฟล์เสียงของคุณเอง

เพิ่มเสียงตามตำแหน่งลงในแอป

แหล่งเสียงตามตำแหน่งจะกำหนดโดย PointSourceAttributes และ Entity ที่เชื่อมโยง ตำแหน่งและการวางแนวของ Entity จะกำหนดตำแหน่งที่ระบบจะแสดงผล PointSourceAttribute ในเชิงพื้นที่ 3 มิติ

ตัวอย่างเสียงตามตำแหน่ง

ตัวอย่างต่อไปนี้จะโหลดไฟล์เสียงเอฟเฟกต์ลงในพูลเสียงและเล่นที่ตำแหน่ง 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_ASSISTANCE_SONIFICATION จะทำให้ระบบถือว่าไฟล์เสียงนี้เป็นเอฟเฟกต์เสียง
  • ตัวอย่างก่อนหน้านี้จะโหลดไฟล์เสียงลงในพูลทันทีก่อนใช้งานเพื่อเก็บโค้ดไว้ด้วยกันเพื่อความสะดวก คุณควรโหลดเอฟเฟกต์เสียงทั้งหมดแบบไม่พร้อมกันขณะโหลดแอปเพื่อให้ไฟล์เสียงทั้งหมดพร้อมใช้งานในพูลเมื่อคุณต้องการ

เพิ่มเสียงสเตอริโอและเสียงเซอร์ราวด์ลงในแอป

วิธีเพิ่มเสียงสเตอริโอและเสียงเซอร์ราวด์ลงในแอปที่แนะนำคือการใช้ Exoplayer ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้เสียงรอบทิศทางกับ Exoplayer ได้ที่คู่มือเสียงรอบทิศทาง

ตำแหน่งลำโพงสเตอริโอและเสียงเซอร์ราวด์

เมื่อใช้การวางตำแหน่งลำโพงเสียงเซอร์ราวด์ ลำโพงเสียงเซอร์ราวด์เสมือนจริงจะวางตำแหน่งและปรับแนวตามลำโพงกลางรอบตัวผู้ใช้ในการกำหนดค่า ITU มาตรฐาน

โดยค่าเริ่มต้น ลำโพงช่องทางกลางจะวางไว้ที่mainPanelEntity ของแอป ซึ่งรวมถึงแอปบนอุปกรณ์เคลื่อนที่ที่ Android XR ปรับเสียงให้เป็นเสียงรอบทิศทางโดยอัตโนมัติ

สำหรับสเตอริโอ ตำแหน่งลำโพงจะคล้ายกับเสียงเซอร์ราวด์ ยกเว้นมีเฉพาะแชแนลซ้ายและขวาที่วางไว้ด้านซ้ายและขวาของแผงตามลำดับ

หากมีแผงหลายแผงและต้องการเลือกแผงที่จะส่งเสียง หรือหากต้องการให้เสียงสเตอริโอหรือเสียงเซอร์ราวด์แสดงผลตาม Entity อื่น ให้ใช้ PointSourceAttributes เพื่อกำหนดตำแหน่งของแชแนลกลาง ส่วนช่องที่เหลือจะจัดวางตามที่ได้กล่าวไว้ก่อนหน้านี้ ในกรณีเหล่านี้ คุณต้องใช้ MediaPlayer ด้วย

เมื่อผู้ใช้เดินไปรอบๆ พื้นที่เสมือนจริง ลำโพงสเตอริโอและเสียงเซอร์ราวด์จะเคลื่อนไหวและปรับเพื่อให้ลำโพงอยู่ในตำแหน่งที่ดีที่สุดเสมอ

หากคุณกำหนดค่า MediaPlayer หรือ ExoPlayer ให้เล่นเสียงสเตอริโอหรือเสียงเซอร์ราวด์จากเบื้องหลังต่อไป ระบบจะปรับเปลี่ยนตำแหน่งลำโพงเสมือนเมื่อแอปทำงานอยู่เบื้องหลัง เนื่องจากไม่มีแผงหรือจุดอื่นในอวกาศที่จะยึดเสียงไว้ เสียงรอบทิศทางจึงเคลื่อนไหวไปพร้อมกับผู้ใช้ (กล่าวคือ "ล็อกตามศีรษะ")

ตัวอย่างเสียงเซอร์ราวด์

ตัวอย่างต่อไปนี้จะโหลดไฟล์เสียง 5.1 โดยใช้ MediaPlayer และตั้งค่าแชแนลกลางของไฟล์เป็น 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_MEDIA จะช่วยให้ระบบถือว่าไฟล์เสียงนี้เป็นเสียงเซอร์ราวด์

เพิ่มฟิลด์เสียงแบบแอมบิโซนิกลงในแอป

วิธีที่ง่ายที่สุดในการเล่นเสียงแบบแอมบิโซนิกคือโหลดไฟล์ด้วย MediaPlayer เนื่องจากเสียงแอมบิโซนิกใช้กับทั้งซาวด์สเปซ คุณจึงไม่จำเป็นต้องระบุ Entity เพื่อระบุตำแหน่ง แต่ให้สร้างอินสแตนซ์ของ SoundFieldAttributes ที่มีลําดับ Ambisonic ที่เหมาะสมซึ่งระบุจํานวนช่องแทน

ตัวอย่าง 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 ช่อง