إضافة ميزة "الصوت المكاني" إلى تطبيق الواقع المعزّز

أجهزة XR المعنيّة
تساعدك هذه الإرشادات في إنشاء تجارب لهذه الأنواع من أجهزة الواقع الممتد.
سماعات رأس بنظام الواقع الممتد
نظارات الواقع الممتد السلكية

تتيح لك ميزات الصوت المكاني في Jetpack SceneCore تصميم تجارب صوتية غامرة ضمن تطبيقات Android XR.

تحاكي ميزة "الصوت المكاني" طريقة سماع المستخدمين للأصوات في بيئة ثلاثية الأبعاد. تخلق هذه التقنية إحساسًا بأنّ الصوت يأتي من جميع الاتجاهات، بما في ذلك من فوق المستخدم ومن تحته. ويتم ذلك من خلال محاكاة مكبّر صوت افتراضي واحد أو أكثر في مواقع محددة في المساحة الثلاثية الأبعاد.

يتم تلقائيًا تحويل الصوت في التطبيقات الحالية التي لم يتم تصميمها أو تعديلها لنظام Android XR إلى صوت مكاني. عندما يتنقّل المستخدم في المساحة، سيصدر كل صوت التطبيق من اللوحة التي يتم عرض واجهة مستخدم التطبيق عليها. على سبيل المثال، إذا رنّ موقّت من تطبيق ساعة، سيصدر الصوت من موضع لوحة التطبيق. سيعدّل نظام التشغيل Android XR الصوت تلقائيًا ليكون أكثر واقعية. على سبيل المثال، ستؤثر المسافة المحسوسة بين لوحة التطبيق والمستخدم بشكل طفيف في مستوى صوت المحتوى الصوتي، ما يمنح المستخدم إحساسًا أكبر بالواقعية.

لمزيد من المعلومات حول كيفية عرض التطبيقات الحالية للصوت المكاني، يمكنك الاطّلاع على مقالة إضافة صوت استريو وصوت محيطي إلى تطبيقك في هذه الصفحة.

إذا كنت بصدد تحسين تطبيقك لتجربة الواقع الممتد، يوفّر Jetpack SceneCore أدوات لتخصيص الصوت المكاني بشكل متقدّم. يمكنك تحديد موضع الأصوات بدقة في البيئة الثلاثية الأبعاد، واستخدام الصوت المجسم للحصول على مجالات صوتية واقعية، والاستفادة من ميزة الدمج المضمّنة للصوت المحيطي.

أنواع الصوت المكاني المتاحة في Android XR

يتوافق Android XR مع الصوت الموضعي وصوت الاستيريو والصوت المحيطي والصوت المجسم.

الصوت الموضعي

يمكن ضبط موضع الصوت المكاني ليتم تشغيله من نقطة معيّنة في المساحة الثلاثية الأبعاد. على سبيل المثال، يمكنك عرض تصميم ثلاثي الأبعاد لكلب ينبح في زاوية بيئتك الافتراضية. يمكن أن يكون لديك عناصر متعددة تصدر صوتًا من كل من مواضعها. لعرض الصوت المكاني، يجب أن تكون الملفات أحادية أو استريو.

صوت الاستيريو المكاني والصوت المحيطي

تتوافق جميع تنسيقات الوسائط على Android مع الصوت الموضعي وصوت الاستيريو والصوت المحيطي. بالإضافة إلى هذه التنسيقات، قد تتوافق أجهزة Android XR مع تنسيقات الصوت Dolby Atmos وDolby Digital وDolby Digital+.

يشير صوت الاستريو إلى تنسيقات الصوت التي تتضمّن قناتين، بينما يشير الصوت المحيطي إلى تنسيقات الصوت التي تتضمّن أكثر من قناتين، مثل إعدادات الصوت المحيطي 5.1 أو الصوت المحيطي 7.1. ترتبط بيانات الصوت لكل قناة بمكبر صوت واحد. على سبيل المثال، عند تشغيل الموسيقى بصوت استيريو، قد تبث قناة مكبّر الصوت الأيسر مقاطع آلات موسيقية مختلفة عن تلك التي تبثها قناة مكبّر الصوت الأيمن.

يُستخدَم الصوت المحيطي غالبًا في الأفلام والبرامج التلفزيونية لتعزيز الواقعية والانغماس في المحتوى من خلال استخدام قنوات مكبّرات صوت متعددة. على سبيل المثال، غالبًا ما يتم تشغيل الحوار من قناة مكبّر الصوت المركزي، بينما قد يستخدم صوت طائرة هليكوبتر تحلّق قنوات مختلفة بالتسلسل لإعطاء الإحساس بأنّ الطائرة تحلّق حول المساحة الثلاثية الأبعاد.

محتوى صوتي متعدد الاتجاهات

الصوت المجسم (أو الصوت المحيطي) هو بمثابة صندوق سماوي للصوت، ويوفّر تجربة صوتية غامرة للمستخدمين. استخدِم الصوت المجسم الشامل للأصوات البيئية في الخلفية أو في سيناريوهات أخرى تريد فيها محاكاة مجال صوتي كروي كامل يحيط بالمستمع. يتوافق نظام التشغيل Android XR مع تنسيق الصوت المحيطي AmbiX في الصوت المحيطي من الدرجة الأولى والثانية والثالثة. ننصحك باستخدام نوعَي الملفات Opus (.ogg) وPCM/Wave (.wav).

استخدام ميزة "الصوت المكاني" مع Jetpack SceneCore

يتضمّن تنفيذ ميزة "الصوت المكاني" باستخدام Jetpack SceneCore التحقّق من توفّر إمكانات الصوت المكاني واختيار واجهة برمجة تطبيقات لتحميل الصوت المكاني.

التحقّق من إمكانات العرض المكاني

قبل استخدام ميزات "الصوت المكاني"، تأكَّد من أنّ Session يتوافق مع هذه الميزة. في جميع مقتطفات الرموز البرمجية في الأقسام التالية، يتم التحقّق من الإمكانات قبل محاولة تشغيل الصوت المكاني.

تحميل الصوت المكاني

يمكنك استخدام أي من واجهات برمجة التطبيقات التالية لتحميل الصوت المكاني لاستخدامه في Jetpack SceneCore.

  • SoundPool: مثالية للمؤثرات الصوتية القصيرة التي يقل حجمها عن 1 ميغابايت، ويتم تحميلها مسبقًا ويمكن استخدامها بشكل متكرر. هذه طريقة رائعة لتحميل الصوت المكاني.
  • ExoPlayer: مثالي لتحميل محتوى صوتي مجسّم ومحيطي، مثل الموسيقى والفيديو. يسمح أيضًا بتشغيل الوسائط في الخلفية.
  • MediaPlayer: يوفّر أبسط طريقة لتحميل الصوت المجسم.
  • AudioTrack: يوفّر أكبر قدر من التحكّم في طريقة تحميل بيانات الصوت. يسمح بكتابة مخازن مؤقتة للصوت مباشرةً أو إذا كنت قد ركّبت أو فككت ترميز ملفاتك الصوتية.

التحقّق من توافق تنسيق الوسائط

تتوافق بعض تنسيقات الوسائط مع نظام التشغيل Android. ومع ذلك، قد يتوافق جهاز Android XR معيّن مع صيغ إضافية، مثل Dolby Atmos. للاستعلام عن إمكانية استخدام تنسيق الوسائط، استخدِم AudioCapabilities في ExoPlayer:

val audioCapabilities = AudioCapabilities.getCapabilities(context, androidx.media3.common.AudioAttributes.DEFAULT, null)
if (audioCapabilities.supportsEncoding(C.ENCODING_AC3)) {
    // Device supports playback of the Dolby Digital media format.
}
if (audioCapabilities.supportsEncoding(C.ENCODING_E_AC3)) {
    // Device supports playback of the Dolby Digital Plus media format.
}
if (audioCapabilities.supportsEncoding(C.ENCODING_E_AC3_JOC)) {
    // Device supports playback of the Dolby Digital Plus with Dolby Atmos media format.
}

قد يتضمّن التحقّق من هذه الإمكانات حظر المكالمات، ويجب عدم طلبها في سلسلة التعليمات الرئيسية.

إضافة صوت موضعي إلى تطبيقك

يتم تحديد مصادر الصوت الموضعي من خلال PointSourceParams وEntity مرتبط. يحدّد موضع Entity واتجاهه المكان الذي يتم فيه عرض PointSourceParams في المساحة الثلاثية الأبعاد.

مثال على الصوت الموضعي

يحمّل المثال التالي ملفًا صوتيًا لمؤثر صوتي في مجموعة أصوات ويشغّله في موضع Entity.

// Check spatial capabilities before using spatial audio
if (session.scene.spatialCapabilities.contains(SpatialCapability.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 = PointSourceParams(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 = session,
                soundPool = soundPool,
                soundID = pointSoundId,
                params = pointSource,
                volume = maxVolume,
                priority = lowPriority,
                loop = infiniteLoop,
                rate = normalSpeed
            )
        }
    }
} else {
    // The session does not have spatial audio capabilities
}

نقاط رئيسية حول الرمز

  • الخطوة الأولى هي التحقّق مما إذا كانت إمكانات "الصوت المكاني" متاحة حاليًا باستخدام spatialCapabilities.
  • يؤدي ضبط 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 (session.scene.spatialCapabilities.contains(SpatialCapability.SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val pointSourceAttributes = PointSourceParams(session.scene.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.setPointSourceParams(
        session,
        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 (session.scene.spatialCapabilities.contains(SpatialCapability.SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val soundFieldAttributes =
        SoundFieldAttributes(SpatializerConstants.AmbisonicsOrder.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(
        session,
        mediaPlayer,
        soundFieldAttributes
    )

    mediaPlayer.setAudioAttributes(audioAttributes)
    mediaPlayer.prepare()
    mediaPlayer.start()
} else {
    // The session does not have spatial audio capabilities
}

نقاط رئيسية بشأن الرمز

  • كما هو الحال مع المقتطفات السابقة، تتمثّل الخطوة الأولى في التحقّق من توفّر إمكانات "الصوت المكاني" باستخدام hasCapability().
  • إنّ contentType والاستخدام هما لأغراض إعلامية فقط.
  • تشير AMBISONICS_ORDER_FIRST_ORDER إلى SceneCore بأنّ ملف مجال الصوت يحدّد أربع قنوات.