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

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

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

إذا كان المحتوى الخاص بك يستخدم تنسيقًا صوتيًا متوافقًا، يمكنك إضافة صوت مكاني إلى تطبيق يبدأ بالإصدار 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)