אודיו מרחבי

אודיו מרחבי הוא חוויית אודיו סוחפת שמאפשרת למשתמשים להיות במרכז העניינים, כך שהתוכן נשמע מציאותי יותר. הצליל עובר 'מרחביות' כדי ליצור אפקט של האזנה למספר רמקולים, בדומה להגדרת צליל סראונד, אבל דרך אוזניות במקום רמקולים.

לדוגמה, בסרט, הצליל של מכונית עשוי להתחיל מאחורי המשתמש, לנוע קדימה ולדעוך למרחק. בשיחות וידאו, אפשר להפריד בין הקולות ולמקם אותם מסביב למשתמש, וכך קל יותר לזהות את הדוברים.

אם התוכן שלכם משתמש בפורמט אודיו נתמך, אתם יכולים להוסיף אודיו מרחבי לאפליקציה שלכם החל מ-Android 13 (רמת API ‏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().

האפשרות הזו יכולה להיות שימושית אם רוצים לשנות את בחירת הרצועה במהלך ההפעלה באמצעות קריאות חוזרות (callback) של המאזין. לדוגמה, כשמשתמש מחבר או מנתק את האוזניות מהמכשיר, הקריאה החוזרת (callback) של 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 לא בוחר באופן אוטומטי פסקול אודיו שתואם למאפיינים של מכשיר ה-Spatializer. במקום זאת, אפשר להתאים אישית את הלוגיקה של בחירת הטראקים ב-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 כוללת את ההתנהגויות הבאות, שיצרני ציוד מקורי (OEM) יכולים להתאים אישית:

  • האודיו המרחבי זמין רק בתוכן מרובה ערוצים, ולא בתוכן סטריאו. אם אתם לא משתמשים ב-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)