זמן אחזור של אודיו

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

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

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

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

מדידת זמן האחזור

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

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

כדי למדוד את זמן האחזור של האודיו הלוך ושוב על ידי יצירת אפליקציה שמייצרת אות אודיו, מקשיבה לאות הזה ומודדת את משך הזמן שחולף מהשליחה ועד לקבלתו.

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

שיטות מומלצות לצמצום זמן האחזור

אימות של ביצועי האודיו

מסמך הגדרת התאימות של Android (CDD) סופר את החומרה והתוכנה הדרישות של מכשיר Android תואם. ראו תאימות ל-Android לקבלת מידע נוסף על תוכנית התאימות הכוללת, וגם CDD למסמך ה-CDD עצמו.

ב-CDD, זמן האחזור הלוך ושוב מוגדר כ-20 אלפיות שנייה או פחות (למרות שמוזיקאים בדרך כלל נדרשות 10 אלפיות השנייה). הסיבה לכך היא שיש תרחישים חשובים לדוגמה שמופעלים על ידי 20 אלפיות השנייה

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

הקריטריונים לדיווח על הסימונים האלה מוגדרים ב-CDD בסעיפים 5.6 זמן אחזור אודיו וגם 5.10 אודיו מקצועי.

כך בודקים את התכונות האלו ב-Java:

Kotlin

val hasLowLatencyFeature: Boolean =
        packageManager.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY)

val hasProFeature: Boolean =
        packageManager.hasSystemFeature(PackageManager.FEATURE_AUDIO_PRO)

Java

boolean hasLowLatencyFeature =
    getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY);

boolean hasProFeature =
    getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_PRO);

לגבי הקשר בין תכונות האודיו, android.hardware.audio.low_latency היא דרישה מוקדמת ל-android.hardware.audio.pro. מכשיר יכול להטמיע android.hardware.audio.low_latency ולא android.hardware.audio.pro, אבל לא ולהיפך.

אין להניח הנחות לגבי ביצועי האודיו

היזהרו מההנחות הבאות כדי למנוע בעיות בזמן האחזור:

  • אל תניח שהרמקולים והמיקרופונים שמשמשים במכשירים ניידים הם בדרך כלל טובים אקוסטיקה. בגלל גודלן הקטן, האקוסטיקה בדרך כלל ירודה ולכן עיבוד האותות כדי לשפר את איכות הסאונד. עיבוד האותות הזה כולל זמן אחזור.
  • אל תניח שהקריאות החוזרות של הקלט והפלט מסונכרנות. לקלט סימולטני והפלט, handlers נפרדים להשלמת תורים במאגר הנתונים הזמני משמשים לכל צד. אין ערובה לסדר היחסי של הקריאות החוזרות (callback) או הסנכרון של שעוני האודיו, גם כששני הצדדים משתמשים באותו קצב דגימה. האפליקציה צריכה לאחסן את הנתונים במאגר נתונים זמני עם סנכרון תקין של מאגר נתונים זמני.
  • אל תניח שקצב הדגימה בפועל תואם בדיוק לתדירות הדגימה הנומית. עבור לדוגמה, אם תדירות הדגימה הנומית היא 48,000 Hz, זה בסדר ששעון האודיו יתקדם בקצב קצת שונה מזה של מערכת ההפעלה CLOCK_MONOTONIC. הסיבה לכך היא שעוני המערכת והאודיו עשויים להגיע מקריסטלים שונים.
  • אל תניחו שקצב הדגימה של ההפעלה בפועל תואם בדיוק לדוגמת הצילום בפועל במיוחד אם נקודות הקצה נמצאות בנתיבים נפרדים. לדוגמה, אם אתם מצלמים מתוך המיקרופון במכשיר בקצב דגימה נומינלי של 48,000 Hz, שפועל באודיו ב-USB בתדירויות דגימה נומינליות של 48,000 Hz, סביר להניח שקצבי הדגימה בפועל יהיו מעט שונים שתי רשתות נוירונים זו מול זו.

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

קיצור זמן האחזור של הקלט

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

  • אם האפליקציה עוקבת אחר הקלט, יש להציע למשתמשים להשתמש באוזניות (לדוגמה, על ידי הצגת המסך הכי טוב עם אוזניות בהפעלה הראשונה). הערה ששימוש באוזניות בלבד לא מבטיח שזמן האחזור יהיה קצר ככל האפשר. יכול להיות שתצטרכו: לבצע פעולות אחרות כדי להסיר עיבוד אותות לא רצוי מנתיב האודיו, למשל באמצעות הגדרה קבועה מראש של VOICE_RECOGNITION בזמן ההקלטה.
  • להיות מוכנים לטפל בקצבי דגימה נומריים של 44,100 ו-48,000 Hz כפי שדווח על ידי getProperty(String) עבור PROPERTY_OUTPUT_TARGET_RATE. שיעורי דגימה אחרים אפשריים, אך הם נדירים.
  • צריך להיות מוכנים לטפל בנפח האחסון הזמני שדווח על ידי getProperty(String) עבור PROPERTY_OUTPUT_FRAMES_PER_BUFFER. גדלים אופייניים של מאגרי נתונים זמניים כוללים 96, 128, 160, 192, 240, 256 או 512 פריימים, אבל ייתכנו ערכים אחרים.

קיצור זמן האחזור של הפלט

שימוש בתדירות הדגימה האופטימלית כשיוצרים נגן אודיו

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

ב-Java אפשר לקבל את תדירות הדגימה האופטימלית מ-AudioManager, כפי שמוצג בדוגמה הבאה קוד לדוגמה:

Kotlin

val am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
val sampleRateStr: String? = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE)
var sampleRate: Int = sampleRateStr?.let { str ->
    Integer.parseInt(str).takeUnless { it == 0 }
} ?: 44100 // Use a default value if property not found

Java

AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
String sampleRateStr = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
int sampleRate = Integer.parseInt(sampleRateStr);
if (sampleRate == 0) sampleRate = 44100; // Use a default value if property not found

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

// create buffer queue audio player
void Java_com_example_audio_generatetone_MainActivity_createBufferQueueAudioPlayer
        (JNIEnv* env, jclass clazz, jint sampleRate, jint framesPerBuffer)
{
   ...
   // specify the audio source format
   SLDataFormat_PCM format_pcm;
   format_pcm.numChannels = 2;
   format_pcm.samplesPerSec = (SLuint32) sampleRate * 1000;
   ...
}

הערה: samplesPerSec מתייחס לשיעור הדגימה לכל ערוץ ב- מילי-הרץ (1 Hz = 1,000 mHz).

שימוש בגודל האופטימלי של מאגר הנתונים הזמני כדי להוסיף נתוני אודיו לתור

אפשר לקבל את הגודל האופטימלי של מאגר הנתונים הזמני באופן דומה לקצב הדגימה האופטימלי באמצעות הפונקציה AudioManager API:

Kotlin

val am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
val framesPerBuffer: String? = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER)
var framesPerBufferInt: Int = framesPerBuffer?.let { str ->
    Integer.parseInt(str).takeUnless { it == 0 }
} ?: 256 // Use default

Java

AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
int framesPerBufferInt = Integer.parseInt(framesPerBuffer);
if (framesPerBufferInt == 0) framesPerBufferInt = 256; // Use default

המאפיין PROPERTY_OUTPUT_FRAMES_PER_BUFFER מציין את מספר פריימים של האודיו שמאגר הנתונים הזמני של HAL (Hardware Abstraction Layer). עליך ליצור את האודיו אגירת נתונים כך שיכילו כפולה מדויקת של המספר הזה. אם השתמשתם במספר הנכון של פריימים של אודיו, הקריאות החוזרות מתרחשות במרווחי זמן קבועים, וכך מפחיתות את הרעידות.

חשוב להשתמש ב-API כדי לקבוע את הגודל של מאגר הנתונים הזמני ולא להשתמש בערך שמופיע בתוך הקוד, כי הגודל של מאגר הנתונים הזמני ב-HAL שונה בכל המכשירים ומגרסאות ה-build של Android.

לא להוסיף ממשקי פלט שכוללות עיבוד אותות

המיקסר המהיר תומך רק בממשקים הבאים:

  • SL_IID_ANDROIDSIMPLEBUFFERQUEUE
  • SL_IID_VOLUME
  • SL_IID_MUTESOLO

אסור להשתמש בממשקים האלה כי הם כרוכים בעיבוד אותות ויגרמו הבקשה שלכם לדחייה מהירה:

  • SL_IID_BASSBOOST
  • SL_IID_EFFECTSEND
  • SL_IID_ENVIRONMENTALREVERB
  • SL_IID_EQUALIZER
  • SL_IID_PLAYBACKRATE
  • SL_IID_PRESETREVERB
  • SL_IID_VIRTUALIZER
  • SL_IID_ANDROIDEFFECT
  • SL_IID_ANDROIDEFFECTSEND

כשיוצרים את הנגן, חשוב להוסיף רק ממשקים מהירים, כפי שמוצג לדוגמה:

const SLInterfaceID interface_ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME };

איך לוודא שנעשה שימוש במסלול עם זמן אחזור קצר

כדי לוודא שקיבלתם בהצלחה מסלול עם זמן אחזור קצר, צריך לבצע את השלבים הבאים:

  1. מפעילים את האפליקציה ומריצים את הפקודה הבאה:
  2. adb shell ps | grep your_app_name
    
  3. מומלץ לרשום לפניכם את מזהה התהליך של האפליקציה.
  4. עכשיו אפשר להשמיע אודיו מהאפליקציה. יעמדו לרשותכם כ-3 שניות כדי להריץ את מהפקודה הבאה מהטרמינל:
  5. adb shell dumpsys media.audio_flinger
    
  6. סורקים את מזהה התהליך. אם מופיע F בעמודה Name, מדובר ב טראק עם זמן אחזור קצר (ה-F מייצג את המסלול המהיר).

קיצור זמן האחזור של תהליך ההכנה

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

#define CHANNELS 1
static short* silenceBuffer;
int numSamples = frames * CHANNELS;
silenceBuffer = malloc(sizeof(*silenceBuffer) * numSamples);
    for (i = 0; i<numSamples; i++) {
        silenceBuffer[i] = 0;
    }

בנקודה שבה אמור להיות הפקת אודיו, אפשר לעבור להוספת חוצצים לתור נתוני אודיו אמיתיים.

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

קוד לדוגמה נוסף

כדי להוריד אפליקציה לדוגמה שמציגה את זמן האחזור של האודיו: דגימות NDK.

למידע נוסף

  1. זמן אחזור של אודיו למפתחי אפליקציות
  2. שותפים ביצירת זמן האחזור של האודיו
  3. מדידת זמן האחזור של האודיו
  4. חימום אודיו
  5. זמן אחזור (אודיו)
  6. זמן עיכוב הלוך ושוב