תוספים ל-Android

אזהרה: OpenSL ES הוצאה משימוש. מפתחים צריכים להשתמש בספריית Oboe בקוד פתוח שזמינה ב-GitHub. Oboe הוא מעטפת של C++‎ שמספקת ממשק API שדומה מאוד ל-AAudio. אבוב קורא לאודיו כשהאודיו מופעל זמין, וחוזר ל-OpenSL ES אם אודיו לא זמין.

OpenSL ES ל-Android מרחיב את מפרט OpenSL ES כך שיתאים למפרט של OpenSL ES Android, ולנצל את העוצמה והגמישות של פלטפורמת Android.

ההגדרה של ה-API לתוספים ל-Android נמצאת בקובץ OpenSLES_Android.h ובקובצי הכותרות שהוא כולל. פרטים על התוספים האלה מופיעים ב-OpenSLES_Android.h. קובץ זה נמצא מתחת לרמה הבסיסית (root) של ההתקנה, ספריית sysroot/usr/include/SLES. אלא אם צוין אחרת, כל הממשקים הם מפורשים.

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

בטבלה הבאה מפורטים הממשקים ומאתרי הנתונים הספציפיים ל-Android שנתמכים ב-Android OpenSL ES לכל סוג אובייקט. הערכים Yes בתאים מציינים את הממשקים ומאתרי הנתונים שזמינים לכל סוג אובייקט.

תכונה נגן אודיו הקלטת אודיו מנוע תמהיל הפלט
תור במאגר נתונים זמני (buffer queue) ב-Android כן: מקור (פענוח) לא לא לא
הגדרת Android כן כן לא לא
אפקט Android כן לא לא כן
יכולות האפקטים ב-Android לא לא כן לא
שליחת אפקטים ב-Android כן לא לא לא
תור פשוט במאגר נתונים זמני (buffer queue) ב-Android כן: מקור (הפעלה) או יעד (פענוח) כן לא לא
מאתר הנתונים בתור מאגר הנתונים הזמני ב-Android כן: מקור (פענוח) לא לא לא
כלי לאיתור נתונים של תיאור קובץ ב-Android כן: מקור לא לא לא
תוסף לאיתור נתונים של תור פשוט במאגר נתונים זמני ב-Android כן: מקור (הפעלה) או יעד (פענוח) כן: כיור לא לא

ממשק התצורה של Android

ממשק התצורה של Android מספק אמצעי להגדיר פרמטרים ספציפיים לפלטפורמה של אובייקטים. הממשק הזה שונה מממשקים אחרים של OpenSL ES 1.0.1, כי האפליקציה יכולה להשתמש בו לפני יצירה של אובייקט תואם. כך תוכלו להגדיר את האובייקט לפני היצירה שלו. קובץ כותרת של OpenSLES_AndroidConfiguration.h, שנמצא בכתובת /sysroot/usr/include/SLES, מתעד את ערכי ומפתחות התצורה הזמינים הבאים:

  • סוג הסטרימינג לנגני אודיו (ברירת מחדל: SL_ANDROID_STREAM_MEDIA).
  • הקלטת פרופיל לרשמקולים (ברירת מחדל: SL_ANDROID_RECORDING_PRESET_GENERIC).

קטע הקוד הבא מציג דוגמה לאופן שבו מגדירים את הסוג של שידור האודיו ל-Android באודיו שחקן:

// CreateAudioPlayer and specify SL_IID_ANDROIDCONFIGURATION
// in the required interface ID array. Do not realize player yet.
// ...
SLAndroidConfigurationItf playerConfig;
result = (*playerObject)->GetInterface(playerObject,
    SL_IID_ANDROIDCONFIGURATION, &playerConfig);
assert(SL_RESULT_SUCCESS == result);
SLint32 streamType = SL_ANDROID_STREAM_ALARM;
result = (*playerConfig)->SetConfiguration(playerConfig,
    SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
assert(SL_RESULT_SUCCESS == result);
// ...
// Now realize the player here.

אפשר להשתמש בקוד דומה כדי להגדיר את ההגדרה המוגדרת מראש למכשיר הקלטת האודיו:

// ... obtain the configuration interface as the first four lines above, then:
SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
result = (*playerConfig)->SetConfiguration(playerConfig,
    RECORDING_PRESET, &presetValue, sizeof(SLuint32));

ממשקי אפקטים ב-Android

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

אפליקציות ניידות צריכות להשתמש בממשקי API של OpenSL ES 1.0.1 ליצירת אפקטים קוליים במקום ב-Android תוספי אפקטים.

כלי לאיתור נתונים של תיאור קובץ ב-Android

הכלי לאיתור נתונים של מתאר קובץ ב-Android מאפשר לציין את המקור לנגן אודיו כמתאר קובץ פתוח עם הרשאת קריאה. פורמט הנתונים חייב להיות MIME.

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

ממשק ומאתר נתונים של תור במאגר נתונים זמני (buffer queue) פשוט ב-Android

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

  • אפשר להשתמש בתור פשוט של מאגר נתונים ב-Android עם מכשירי הקלטת אודיו ונגני אודיו.
  • אפשר להשתמש בפורמט הנתונים PCM רק עם התורים האלה.

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

ההפעלה פועלת באותו אופן. עם זאת, כדי לשמור על תאימות עתידית של קוד המקור, מומלץ להשתמש באפליקציות בתורים פשוטים של מאגרים ב-Android במקום בתורים של מאגרים ב-OpenSL ES 1.0.1.

ההתנהגות של מאגר הנתונים הזמני

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

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

ממשקים דינמיים בזמן יצירת האובייקט

לנוחות, ההטמעה של OpenSL ES 1.0.1 ב-Android מאפשרת לאפליקציה לציין ממשקים דינמיים כשהיא יוצרת אובייקט. זו חלופה לשימוש ב-DynamicInterfaceManagement::AddInterface() כדי להוסיף את הממשקים האלה אחרי יצירת אובייקט.

דיווח על תוספים

יש שלוש שיטות לברר אם הפלטפורמה תומכת בתוספים ל-Android. האלה הן:

  • Engine::QueryNumSupportedExtensions()
  • Engine::QuerySupportedExtension()
  • Engine::IsExtensionSupported()

כל אחת מהשיטות האלה מחזירה את הערך ANDROID_SDK_LEVEL_<API-level>, כאשר API-level הוא רמת ה-API של הפלטפורמה. לדוגמה, ANDROID_SDK_LEVEL_23. כשרמת ה-API של הפלטפורמה היא 9 ומעלה, הפלטפורמה תומכת בתוספים.

פענוח הקוד של אודיו ל-PCM

בקטע הזה מתואר תוסף ספציפי ל-Android שהוצא משימוש ל-OpenSL ES 1.0.1 לפענוח של זרם מקודד ל-PCM ללא הפעלה מיידית. בטבלה הבאה מפורטות המלצות לשימוש בתוסף הזה ובחלופות.

רמת ממשק API: אפשרויות אחרות
15 ומטה קודק קוד פתוח עם רישיון מתאים
16 עד 20 המחלקה MediaCodec או קודק קוד פתוח עם רישיון מתאים
21 ומעלה NDK MediaCodec בקובצי הכותרת של <media/NdkMedia*.h>, הכיתה MediaCodec, או קודק קוד פתוח עם רישיון מתאים

הערה: אין כרגע תיעוד לגרסת ה-NDK של ה-API של MediaCodec. עם זאת, תוכלו לעיין בקטע הקוד לדוגמה של native-codec.

נגן אודיו רגיל מפעיל אודיו במכשיר אודיו, ומציין את תערובת הפלט כבורר הנתונים. ההבדל בין התוסף ל-Android הוא שבמקרה שהאפליקציה ציינה את מקור הנתונים כ-URI או כמאתר נתונים של מתאר קובץ ב-Android שמתואר באמצעות פורמט הנתונים MIME, נגן האודיו פועל כפעמקוד. במקרה כזה, בור הנתונים הוא מאתר נתונים של Android עם תור פשוט של מאגר, שמשתמש בפורמט הנתונים PCM.

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

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

מקור הנתונים מדווח באופן מרומז על סוף מקור הנתונים (EOS) באמצעות האירוע SL_PLAYEVENT_HEADATEND בסוף השידור. אחרי פענוח הקוד של האפליקציה את כל הנתונים שהוא קיבל, הוא לא מבצע קריאות נוספות לקריאה החוזרת (callback) של מאגר הנתונים הזמני של Android.

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

התכונה של OpenSL ES לפענוח PCM של Android תומכת בהשהיה ובדילוג ראשוני; הוא לא תומך בקרת עוצמת הקול, אפקטים, הפעלה בלופ או קצב ההפעלה.

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

הערה: כדי לפענח סטרימינג קודד ל-PCM אבל לא להפעיל אותו באופן מיידי, באפליקציות שפועלות ב-Android 4.x (רמות API 16 עד 20), מומלץ להשתמש בכיתה MediaCodec. לאפליקציות חדשות שפועלות ב-Android 5.0 (רמת API 21) ומעלה, מומלץ להשתמש ב-NDK המקבילה: <NdkMedia*.h>. קובצי הכותרות האלה נמצאים ב- הספרייה media/ מתחת לרמה הבסיסית (root) של ההתקנה.

פענוח קוד של סטרימינג של ADTS AAC ל-PCM

נגן אודיו משמש כמפענח בסטרימינג אם מקור הנתונים הוא מאתר הנתונים בתור מאגר נתונים זמני של Android שמשתמש בפורמט נתוני MIME sink הוא כלי לאיתור נתונים בתור מאגר נתונים פשוט ל-Android, שמשתמש בפורמט של נתוני PCM. מגדירים את פורמט הנתונים של MIME באופן הבא:

  • מאגר: SL_CONTAINERTYPE_RAW
  • מחרוזת סוג MIME: SL_ANDROID_MIME_AACADTS

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

  • מקור האודיו הנדחס הוא שידור של פריימים של AAC שמכילים כותרות ADTS.
  • האפליקציה מנהלת את הסטרימינג הזה. הנתונים לא נמצאים במשאב רשת שהמזהה שלו הוא URI, או בקובץ מקומי שהמזהה שלו הוא מתאר קובץ.

האפליקציה צריכה להוסיף בהתחלה לתור קבוצה של מאגרים מלאים ב-Android. כל מאגר מכיל מסגרת ADTS AAC אחת או יותר. הקריאה החוזרת בתור מאגר הנתונים הזמני ב-Android מופעלת אחרי שכל מאגר נתונים זמני מרוקן. פונקציית הטיפול בהתקשרות החוזרת צריכה למלא מחדש את המאגר ולהוסיף אותו שוב לתור, ואז לחזור. האפליקציה לא צריכה לעקוב אחר מאגרי נתונים זמניים מקודדים; פרמטר הקריאה החוזרת (callback) כוללת מספיק מידע כדי לציין את מאגר הנתונים הזמני שצריך להוסיף לתור. סוף הסטרימינג מסומן באופן מפורש על ידי הוספת פריט EOS לתור. אחרי EOS, לא ניתן להוסיף עוד פריטים לתור.

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

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

למרות הדמיון בשמות, אין דמיון בין Android buffer queue לבין Android simple buffer queue. מקודד הסטרימינג משתמש בשני סוגי תורים של מאגרים: תור מאגר של Android למקור הנתונים ADTS AAC, וכן תור מאגר פשוט של Android לבור נתונים PCM. מידע נוסף על Android simple buffer queue API זמין במאמר Android simple buffer queue data locator and interface. למידע נוסף על ה-API של תור מאגר הנתונים הזמני ב-Android, אפשר לעיין בקובץ index.html ב- בספרייה docs/Additional_library_docs/openmaxal/ מתחת לרמה הבסיסית (root) של ההתקנה.

קביעת הפורמט של נתוני PCM מפוענחים באמצעות מטא-נתונים

הממשק SLMetadataExtractionItf הוא חלק ממפרט העזר. עם זאת, מפתחות המטא-נתונים שמציינים את הפורמט בפועל של נתוני PCM מפוענחים הם ספציפיים Android. מפתחות המטא-נתונים האלה מוגדרים בקובץ הכותרת OpenSLES_AndroidMetadata.h. קובץ הכותרת נמצא ברמה הבסיסית (root) של ההתקנה, במסגרת ספריית /sysroot/usr/include/SLES.

אינדקסי המפתחות של המטא-נתונים זמינים מיד אחרי שההפעלה של השיטה Object::Realize() מסתיימת. אבל הערכים המשויכים לא רק אחרי שהאפליקציה מפענחת את הנתונים המקודדים הראשונים. טובה היא לבצע שאילתה על מדדי המפתח ב-thread הראשי אחרי קריאה ל-method של Object::Realize, ולקרוא את ערכי המטא-נתונים של פורמט ה-PCM בשיטה הפשוטה של Android ה-handler של קריאה חוזרת בתור מאגר נתונים זמני כשקוראים לו בפעם הראשונה. בקוד לדוגמה בחבילת NDK מפורטות דוגמאות לעבודה עם הממשק הזה.

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

נתוני נקודות צפות

אפליקציה שפועלת ב-Android 5.0 (רמת API 21) ואילך יכולה לספק נתונים ל-AudioPlayer בפורמט של נקודה צפה ברמת דיוק יחידה.

בקוד לדוגמה הבא, השיטה Engine::CreateAudioPlayer() יוצרת נגן אודיו שמשתמשת בנתוני נקודה צפה (floating-point):

#include <SLES/OpenSLES_Android.h>
...
SLAndroidDataFormat_PCM_EX pcm;
pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
pcm.numChannels = 2;
pcm.sampleRate = SL_SAMPLINGRATE_44_1;
pcm.bitsPerSample = 32;
pcm.containerSize = 32;
pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
pcm.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
...
SLDataSource audiosrc;
audiosrc.pLocator = ...
audiosrc.pFormat = &pcm;
מידע נוסף על אודיו עם נקודה צפה (floating-point) בדף 'דגימת אודיו'.