"الصوت المكاني" هو تجربة صوتية غامرة تضع المستخدمين في قلب الحدث، ما يجعل صوت المحتوى يبدو أكثر واقعية. يتم تحويل الصوت إلى "صوت مكاني" لإنشاء تأثير مكبرات الصوت المتعددة، على غرار إعداد الصوت المحيطي، ولكن من خلال سماعات الرأس بدلاً من ذلك.
على سبيل المثال، في فيلم، قد يبدأ صوت سيارة من خلف المستخدم، ثم يتحرك للأمام، ويتلاشى في المسافة. في محادثة الفيديو، يمكن فصل الأصوات ووضعها حول المستخدم، ما يسهّل التعرّف على المتحدّثين.
إذا كان المحتوى يستخدم تنسيقًا صوتيًا متوافقًا، يمكنك إضافة الصوت المكاني إلى تطبيقك بدءًا من الإصدار 13 من Android (المستوى 33 لواجهة برمجة التطبيقات).
طلب البحث عن الإمكانات
استخدِم فئة Spatializer لطلب البحث عن إمكانات وسلوكيات الصوت المكاني على الجهاز. ابدأ باسترداد
مثيل Spatializer من
AudioManager:
Kotlin
val spatializer = audioManager.spatializer
Java
Spatializer spatializer = AudioManager.getSpatializer();
بعد الحصول على Spatializer، تحقَّق من الشروط الأربعة التي يجب أن تتوفّر
في الجهاز لإخراج الصوت المكاني:
| المعايير | شيك |
|---|---|
| هل يتيح الجهاز ميزة "الصوت المكاني"؟ |
getImmersiveAudioLevel() ليس SPATIALIZER_IMMERSIVE_LEVEL_NONE
|
| هل تتوفّر ميزة "الصوت المكاني"؟ يعتمد توفّر هذه الميزة على مدى توافقها مع توجيه إخراج الصوت الحالي. |
isAvailable() هو true |
| هل ميزة "تحويل الصوت إلى صوت ثلاثي الأبعاد" مفعَّلة؟ | isEnabled() هو true |
| هل يمكن تحويل مقطع صوتي يتضمّن المَعلمات المحدّدة إلى صوت مكاني؟ | canBeSpatialized() هو true |
قد لا يتم استيفاء هذه الشروط، على سبيل المثال، إذا كانت ميزة الصوت المكاني غير متاحة للمقطع الصوتي الحالي أو غير مفعَّلة على جهاز إخراج الصوت كليًا.
تتبُّع حركة الرأس
باستخدام سماعات الرأس المتوافقة، يمكن للمنصة ضبط الصوت المكاني
بناءً على موضع رأس المستخدم. للتحقّق من توفّر أداة تتبُّع حركة الرأس
لمسار إخراج الصوت الحالي، يمكنك استدعاء
isHeadTrackerAvailable().
المحتوى المتوافق
Spatializer.canBeSpatialized()
تشير إلى ما إذا كان يمكن تحويل الصوت الذي يتضمّن السمات المحدّدة إلى صوت مكاني من خلال
توجيه جهاز الإخراج الحالي. تتطلّب هذه الطريقة استخدام AudioAttributes
وAudioFormat، ويتم شرحهما بمزيد من التفصيل أدناه.
AudioAttributes
يصف عنصر AudioAttributes استخدام البث الصوتي (على سبيل المثال، صوت اللعبة أو الوسائط العادية)، بالإضافة إلى سلوكيات التشغيل ونوع المحتوى.
عند استدعاء canBeSpatialized()، استخدِم مثيل
AudioAttributes نفسه الذي تم ضبطه لـ Player. على سبيل المثال، إذا كنت تستخدم مكتبة Jetpack Media3 ولم تخصّص AudioAttributes، استخدِم AudioAttributes.DEFAULT.
إيقاف ميزة "الصوت المكاني"
للإشارة إلى أنّ المحتوى قد تم تحويله إلى صوت مكاني، يمكنك استدعاء
setIsContentSpatialized(true)
كي لا تتم معالجة الصوت مرّتين. بدلاً من ذلك، يمكنك تعديل سلوك الصوت المكاني لإيقافه تمامًا من خلال استدعاء setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER).
AudioFormat
يصف عنصر AudioFormat تفاصيل حول تنسيق المقطع الصوتي وإعدادات القناة.
عند إنشاء مثيل AudioFormat لتمريره إلى canBeSpatialized()،
اضبط الترميز
على تنسيق الإخراج نفسه المتوقّع من برنامج فك الترميز. يجب أيضًا ضبط قناع قناة يتطابق مع إعدادات قناة المحتوى. يُرجى الرجوع إلى قسم السلوك التلقائي للصوت المكاني للحصول على إرشادات حول القيم المحدّدة التي يجب استخدامها.
الاستماع إلى التغييرات في Spatializer
للاستماع إلى التغييرات في حالة Spatializer، يمكنك إضافة مستمع
باستخدام Spatializer.addOnSpatializerStateChangedListener().
وبالمثل، للاستماع إلى التغييرات في مدى توفّر ميزة تتبُّع حركة الرأس،
يمكنك استدعاء Spatializer.addOnHeadTrackerAvailableListener().
قد يكون ذلك مفيدًا إذا أردت تعديل اختيار المقطع الصوتي أثناء التشغيل باستخدام عمليات الاستدعاء الخاصة بالمستمع. على سبيل المثال، عندما يوصّل المستخدم سماعة الرأس بالجهاز أو يفصلها، يشير ردّ الاتصال onSpatializerAvailableChanged إلى ما إذا كان تأثير المجسِّم متاحًا لتوجيه مخرجات الصوت الجديدة. في هذه المرحلة، يمكنك تعديل منطق اختيار المسارات في المشغّل ليتوافق مع الإمكانات الجديدة للجهاز. لمعرفة التفاصيل حول
سلوك اختيار المقاطع الصوتية في ExoPlayer، يُرجى الرجوع إلى قسم ExoPlayer والصوت المكاني.
ExoPlayer والصوت المكاني
تسهّل الإصدارات الحديثة من ExoPlayer استخدام الصوت المكاني. إذا كنت تستخدم
مكتبة ExoPlayer المستقلة (اسم الحزمة com.google.android.exoplayer2)،
يضبط الإصدار 2.17 المنصة لإخراج الصوت المكاني، ويقدّم الإصدار
2.18 قيودًا على عدد القنوات الصوتية.
إذا كنت تستخدم وحدة ExoPlayer من مكتبة Media3 (اسم الحزمة
androidx.media3)، فإنّ الإصدارات 1.0.0-beta01
والإصدارات الأحدث تتضمّن هذه التحديثات نفسها.
بعد تحديث تبعية ExoPlayer إلى أحدث إصدار، يحتاج تطبيقك فقط إلى تضمين محتوى يمكن تحويله إلى صوت مكاني.
قيود عدد القنوات الصوتية
عند استيفاء الشروط الأربعة لميزة "الصوت المكاني"، يختار ExoPlayer مقطعًا صوتيًا متعدد القنوات. وإذا لم يكن متاحًا، يختار ExoPlayer مقطعًا صوتيًا مجسّمًا بدلاً من ذلك.
إذا تغيّرت سمات Spatializer، سيُشغّل ExoPlayer
عملية اختيار مقطع صوتي جديد لاختيار مقطع صوتي يتطابق مع
السمات الحالية. يُرجى العِلم أنّ اختيار هذا المقطع الصوتي الجديد قد يؤدي إلى فترة قصيرة من إعادة التخزين المؤقت.
لإيقاف قيود عدد القنوات الصوتية، اضبط مَعلمات اختيار المقاطع الصوتية على المشغّل كما هو موضّح أدناه:
Kotlin
exoPlayer.trackSelectionParameters = DefaultTrackSelector.Parameters.Builder(context) .setConstrainAudioChannelCountToDeviceCapabilities(false) .build()
Java
exoPlayer.setTrackSelectionParameters( new DefaultTrackSelector.Parameters.Builder(context) .setConstrainAudioChannelCountToDeviceCapabilities(false) .build() );
وبالمثل، يمكنك تعديل معلَمات أداة اختيار المقاطع الصوتية الحالية لإيقاف قيود عدد القنوات الصوتية على النحو التالي:
Kotlin
val trackSelector = DefaultTrackSelector(context) ... trackSelector.parameters = trackSelector.buildUponParameters() .setConstrainAudioChannelCountToDeviceCapabilities(false) .build()
Java
DefaultTrackSelector trackSelector = new DefaultTrackSelector(context); ... trackSelector.setParameters( trackSelector .buildUponParameters() .setConstrainAudioChannelCountToDeviceCapabilities(false) .build() );
عند إيقاف قيود عدد القنوات الصوتية، إذا كان المحتوى يتضمّن عدة مقاطع صوتية، يختار ExoPlayer في البداية المقطع الذي يحتوي على أكبر عدد من القنوات ويمكن تشغيله من الجهاز. على سبيل المثال، إذا كان المحتوى يتضمّن مقطعًا صوتيًا متعدد القنوات ومقطعًا صوتيًا ستيريو، وكان الجهاز يتيح تشغيل كليهما، يختار ExoPlayer المقطع الصوتي المتعدد القنوات. يُرجى الاطّلاع على اختيار المقطع الصوتي للحصول على تفاصيل حول كيفية تخصيص هذا السلوك.
اختيار المقطع الصوتي
عند إيقاف سلوك قيود عدد القنوات الصوتية في ExoPlayer، لا يختار ExoPlayer تلقائيًا مقطعًا صوتيًا يتطابق مع خصائص ميزة "الصوت المكاني" في الجهاز. بدلاً من ذلك، يمكنك تخصيص منطق اختيار المقاطع الصوتية في ExoPlayer من خلال ضبط مَعلمات اختيار المقاطع الصوتية قبل التشغيل أو أثناءه. يختار ExoPlayer تلقائيًا المقاطع الصوتية التي تتطابق مع المقطع الأولي من حيث نوع MIME (الترميز) وعدد القنوات ومعدّل البيانات في الملف الصوتي.
تغيير مَعلمات اختيار المقطع الصوتي
لتغيير معلَمات اختيار المقطع الصوتي في ExoPlayer، استخدِم
Player.setTrackSelectionParameters().
وبالمثل، يمكنك الحصول على مَعلمات ExoPlayer الحالية باستخدام
Player.getTrackSelectionParameters().
على سبيل المثال، لاختيار مقطع صوتي استيريو في منتصف التشغيل:
Kotlin
exoPlayer.trackSelectionParameters = exoPlayer.trackSelectionParameters .buildUpon() .setMaxAudioChannelCount(2) .build()
Java
exoPlayer.setTrackSelectionParameters( exoPlayer.getTrackSelectionParameters() .buildUpon() .setMaxAudioChannelCount(2) .build() );
يُرجى العِلم أنّ تغيير مَعلمات اختيار المقطع الصوتي أثناء التشغيل قد يؤدي إلى انقطاع في التشغيل. يمكنك الاطّلاع على مزيد من المعلومات حول ضبط مَعلمات اختيار المقطع الصوتي للمشغّل في قسم اختيار المقطع الصوتي ضمن مستندات ExoPlayer.
السلوك التلقائي للصوت المكاني
يتضمّن سلوك المعالجة الصوتية المكانية التلقائي في Android السلوكيات التالية التي قد يخصّصها المصنّعون الأصليون للأجهزة:
يتم تحويل المحتوى المتعدد القنوات فقط إلى صوت مكاني، وليس المحتوى الاستيريو. إذا كنت لا تستخدم ExoPlayer، قد تحتاج إلى ضبط الحد الأقصى لعدد القنوات التي يمكن لوحدة فك ترميز الصوت إخراجها على عدد كبير، وذلك حسب تنسيق المحتوى الصوتي المتعدّد القنوات. يضمن ذلك أنّ وحدة فك ترميز الصوت تُخرج تنسيق PCM متعدد القنوات ليتمكّن النظام الأساسي من معالجته.
Kotlin
val mediaFormat = MediaFormat() mediaFormat.setInteger(MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT, 99)
Java
MediaFormat mediaFormat = new MediaFormat(); mediaFormat.setInteger(MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT, 99);
للاطّلاع على مثال عملي، يمكنك مراجعة
MediaCodecAudioRenderer.javaفي ExoPlayer. لإيقاف ميزة "الصوت المكاني" بنفسك، بغض النظر عن تخصيص المصنّع الأصلي للجهاز، يُرجى الاطّلاع على إيقاف ميزة "الصوت المكاني".AudioAttributes: يكون الصوت مؤهلاً لتفعيل ميزة "الصوت المكاني" إذا تم ضبطusageعلىUSAGE_MEDIAأوUSAGE_GAME.AudioFormat: استخدِم قناع قناة يحتوي على الأقل على قنواتAudioFormat.CHANNEL_OUT_QUAD(الأمامية اليسرى والأمامية اليمنى والخلفية اليسرى والخلفية اليمنى) ليكون الصوت مؤهلاً للصوت المكاني. في المثال أدناه، نستخدمAudioFormat.CHANNEL_OUT_5POINT1لمقطع صوتي بنظام 5.1. بالنسبة إلى مقطع صوتي ستيريو، استخدِمAudioFormat.CHANNEL_OUT_STEREO.إذا كنت تستخدم Media3، يمكنك استخدام
Util.getAudioTrackChannelConfig(int channelCount)لتحويل عدد القنوات إلى قناع قناة.بالإضافة إلى ذلك، اضبط الترميز على
AudioFormat.ENCODING_PCM_16BITإذا كنت قد ضبطت وحدة فك الترميز لإخراج PCM متعدد القنوات.Kotlin
val audioFormat = AudioFormat.Builder() .setEncoding(AudioFormat.ENCODING_PCM_16BIT) .setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1) .build()
Java
AudioFormat audioFormat = new AudioFormat.Builder() .setEncoding(AudioFormat.ENCODING_PCM_16BIT) .setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1) .build();
اختبار ميزة "الصوت المكاني"
تأكَّد من تفعيل ميزة "الصوت المكاني" على جهازك الاختباري:
- بالنسبة إلى سماعات الرأس السلكية، انتقِل إلى إعدادات النظام > الصوت والاهتزاز > الصوت المكاني.
- بالنسبة إلى سمّاعات الرأس اللاسلكية، انتقِل إلى إعدادات النظام > الأجهزة المتصلة > رمز الترس لجهازك اللاسلكي > الصوت المكاني.
للتحقّق من توفّر ميزة "الصوت المكاني" لمسار الصوت الحالي، نفِّذ الأمر
adb shell dumpsys audio على جهازك. من المفترض أن تظهر لك المَعلمات التالية في الناتج أثناء تشغيل المحتوى:
Spatial audio:
mHasSpatializerEffect:true (effect present)
isSpatializerEnabled:true (routing dependent)