یادداشت‌های برنامه‌نویسی OpenSL ES

هشدار: OpenSL ES منسوخ شده است. توسعه‌دهندگان باید از کتابخانه متن‌باز Oboe که در GitHub دردسترس است استفاده کنند. Oboe یک داده‌پوش C++‎ است که یک API ارائه می‌دهد که بسیار شبیه به AAudio است. Oboe وقتی AAudio دردسترس باشد آن را فراخوانی می‌کند و اگر AAudio دردسترس نباشد، به OpenSL ES برمی‌گردد.

یادداشت‌های این بخش مکمل مشخصات OpenSL ES 1.0.1 هستند.

مقداردهی اولیه اشیاء و میانای کاربری

دو جنبه از مدل برنامه‌نویسی OpenSL ES که ممکن است برای توسعه‌دهندگان جدید ناآشنا باشد، تمایز بین اشیاء و میانجی‌ها و توالی مقداردهی اولیه است.

به‌طور خلاصه، شیء OpenSL ES شبیه به مفهوم شیء در زبان‌های برنامه‌نویسی مانند Java و C++‎ است، با این تفاوت که شیء OpenSL ES فقط ازطریق میاناهای مرتبط با آن قابل‌مشاهده است. این شامل رابط اولیه برای همه اشیاء، به‌نام SLObjectItf، می‌شود. هیچ دسته‌ای برای خود شیء وجود ندارد، فقط یک دسته برای میانای SLObjectItf شیء وجود دارد.

یک شیء OpenSL ES ابتدا ایجاد می‌شود، که یک SLObjectItf برمی‌گرداند، سپس تحقق می‌یابد. این شبیه به الگوی برنامه‌نویسی رایج است که ابتدا یک شیء را می‌سازد (که هرگز نباید ناموفق باشد، مگر به‌دلیل کمبود حافظه یا پارامترهای نامعتبر)، و سپس مقداردهی اولیه را تکمیل می‌کند (که ممکن است به‌دلیل کمبود منابع ناموفق باشد). مرحله تحقق به پیاده‌سازی مکانی منطقی می‌دهد تا درصورت نیاز منابع بیشتری را اختصاص دهد.

به‌عنوان بخشی از API برای ایجاد یک شیء، برنامه آرایه‌ای از میاناهای موردنظر را مشخص می‌کند که قصد دارد بعداً آن‌ها را به‌دست آورد. توجه داشته باشید که این آرایه به‌طور خودکار واسط‌ها را دریافت نمی‌کند؛ بلکه صرفاً نشان‌دهنده قصد دریافت آن‌ها در آینده است. میاناهای ضمنی یا صریح از یکدیگر متمایز می‌شوند. اگر قرار است واسط صریحی بعداً دریافت شود، باید در آرایه فهرست شود. نیازی نیست که رابط ضمنی در آرایه ایجاد شیء فهرست شود، اما فهرست کردن آن در آنجا ضرری ندارد. OpenSL ES نوع دیگری از میانای به نام پویا دارد که لازم نیست در آرایه ایجاد شیء مشخص شود و می‌توان آن را بعداز ایجاد شیء اضافه کرد. پیاده‌سازی Android ویژگی راحتی را برای اجتناب از این پیچیدگی ارائه می‌دهد که در میاناهای پویا در ایجاد شیء شرح داده شده است.

پس‌از ایجاد و تحقق شیء، برنامه باید بااستفاده از GetInterface در SLObjectItf اولیه، میاناهایی برای هر ویژگی موردنیاز خود دریافت کند.

درنهایت، شیء ازطریق میاناهای آن برای استفاده دردسترس است، اما توجه داشته باشید که برخی‌از اشیاء به راه‌اندازی بیشتری نیاز دارند. به‌ویژه، پخش‌کننده صوتی با منبع داده URI برای تشخیص خطاهای اتصال به آماده‌سازی بیشتری نیاز دارد. برای جزئیات، بخش پیش‌واکشی پخش‌کننده صوتی را ببینید.

پس‌از اینکه کار برنامه‌تان با شیء تمام شد، باید آن را به‌طور صریح ازبین ببرید؛ بخش ازبین بردن را در زیر ببینید.

پیش‌واکشی پخش‌کننده صوتی

برای پخش‌کننده صوتی با منبع داده URI، Object::Realize منابع را اختصاص می‌دهد اما به منبع داده متصل نمی‌شود (آماده‌سازی) یا پیش‌واکشی داده‌ها را شروع نمی‌کند. این رویدادها زمانی رخ می‌دهند که وضعیت پخش‌کننده روی SL_PLAYSTATE_PAUSED یا SL_PLAYSTATE_PLAYING تنظیم شده باشد.

ممکن است برخی‌از اطلاعات تا اواخر این توالی همچنان نامشخص باشد. به‌طور خاص، در ابتدا Player::GetDuration، SL_TIME_UNKNOWN را برمی‌گرداند و MuteSolo::GetChannelCount یا با موفقیت با تعداد کانال صفر برمی‌گردد یا نتیجه خطا SL_RESULT_PRECONDITIONS_VIOLATED را برمی‌گرداند. این میاناهای برنامه‌سازی کاربردی مقادیر مناسب را پس‌از مشخص شدن برمی‌گردانند.

سایر ویژگی‌هایی که در ابتدا ناشناخته هستند شامل نرخ نمونه‌برداری و نوع واقعی محتوای رسانه براساس بررسی سرصفحه محتوا (برخلاف نوع MIME مشخص‌شده توسط برنامه و نوع محفظه) است. این‌ها نیز بعداً درطول آماده‌سازی/واکشی اولیه تعیین می‌شوند، اما هیچ میانای برنامه‌سازی کاربردی‌ای برای بازیابی آن‌ها وجود ندارد.

میانای وضعیت پیش‌واکشی برای تشخیص زمان دردسترس بودن همه اطلاعات مفید است، یا برنامه‌تان می‌تواند به‌طور دوره‌ای نظرسنجی کند. توجه داشته باشید که برخی اطلاعات، مانند مدت زمان پخش جریانی MP3، ممکن است هرگز مشخص نشود.

واسط وضعیت واکشی اولیه برای شناسایی خطاها نیز مفید است. یک فراخوانی برگشتی ثبت کنید و حداقل رویدادهای SL_PREFETCHEVENT_FILLLEVELCHANGE و SL_PREFETCHEVENT_STATUSCHANGE را فعال کنید. اگر هر دو این رویدادها به‌طور هم‌زمان ارسال شوند، و PrefetchStatus::GetFillLevel سطح صفر را گزارش کند، و PrefetchStatus::GetPrefetchStatus مقدار SL_PREFETCHSTATUS_UNDERFLOW را گزارش کند، دراین‌صورت این نشان‌دهنده خطای غیرقابل‌بازیابی در منبع داده است. این شامل عدم توانایی در اتصال به منبع داده می‌شود، زیرا نام فایل محلی وجود ندارد یا URI شبکه نامعتبر است.

انتظار می‌رود نسخه بعدی OpenSL ES پشتیبانی صریح‌تری برای رسیدگی به خطاها در منبع داده اضافه کند. بااین‌حال، برای سازگاری دودویی در آینده، قصد داریم به پشتیبانی از روش فعلی برای گزارش خطای غیرقابل‌بازیابی ادامه دهیم.

به‌طور خلاصه، توالی کد توصیه‌شده عبارت است از:

  1. Engine::CreateAudioPlayer
  2. Object:Realize
  3. Object::GetInterface برای SL_IID_PREFETCHSTATUS
  4. PrefetchStatus::SetCallbackEventsMask
  5. PrefetchStatus::SetFillUpdatePeriod
  6. PrefetchStatus::RegisterCallback
  7. Object::GetInterface برای SL_IID_PLAY
  8. Play::SetPlayState تا SL_PLAYSTATE_PAUSED، یا SL_PLAYSTATE_PLAYING

توجه: آماده‌سازی و واکشی پیشاپیش در اینجا انجام می‌شود؛ در این مدت، تماس برگشتی شما با به‌روزرسانی‌های دوره‌ای وضعیت فراخوانده می‌شود.

نابود کردن

هنگام خروج از برنامه‌تان، حتماً همه اشیاء را ازبین ببرید. اشیاء باید به ترتیب معکوس ایجادشان ازبین بروند، زیرا ازبین بردن شیئی که اشیاء وابسته دارد ایمن نیست. برای مثال، به این ترتیب ازبین ببرید: پخش‌کننده‌ها و ضبط‌کننده‌های صدا، ترکیب خروجی، و سپس درنهایت موتور.

OpenSL ES از جمع‌آوری خودکار زباله یا شمارش مرجع میاناها پشتیبانی نمی‌کند. پس‌از فراخوانی Object::Destroy، همه واسط‌های موجود که از شیء مربوطه مشتق شده‌اند تعریف‌نشده می‌شوند.

پیاده‌سازی Android OpenSL ES استفاده نادرست از این میانجی‌ها را شناسایی نمی‌کند. ادامه استفاده از چنین میاناهایی پس‌از نابود شدن شیء می‌تواند باعث ازکار افتادن برنامه شما یا رفتار غیرقابل‌پیش‌بینی آن شود.

توصیه می‌کنیم که هم میانای شیء اصلی و هم همه میاناهای مرتبط را به‌عنوان بخشی از توالی تخریب شیء خود به‌طور صریح روی NULL تنظیم کنید، که از سوءاستفاده تصادفی از دسته میانای قدیمی جلوگیری می‌کند.

چرخش استریو

وقتی از Volume::EnableStereoPosition برای فعال کردن چرخش استریو منبع مونو استفاده می‌شود، کاهش ۳ دسی‌بلی در کل سطح قدرت صدا وجود دارد. این کار برای این لازم است که سطح کل توان صدا ثابت بماند، زیرا منبع از یک کانال به کانال دیگر منتقل می‌شود. بنابراین، فقط درصورت نیاز، موقعیت‌یابی استریو را فعال کنید. برای اطلاعات بیشتر، مقاله ویکی‌پدیا درباره حرکت افقی صدا را ببینید.

فراخوانی‌های برگشتی و رشته‌ها

رسیدگی‌کننده‌های بازخوانی معمولاً به‌صورت هم‌زمان وقتی که پیاده‌سازی رویدادی را شناسایی می‌کند فراخوانده می‌شوند. این نقطه نسبت به برنامه ناهمگام است، بنابراین باید از سازوکار همگام‌سازی غیرمسدودکننده برای کنترل دسترسی به متغیرهای هم‌رسانی‌شده بین برنامه و رسیدگی‌کننده بازخوانی استفاده کنید. در کد نمونه، مثلاً برای صف‌های میان‌گیری، برای سادگی، یا این همگام‌سازی را حذف کرده‌ایم یا از همگام‌سازی مسدودکننده استفاده کرده‌ایم. بااین‌حال، همگام‌سازی مناسب غیرمسدودکننده برای هر کد تولیدی حیاتی است.

رسیدگی‌کننده‌های بازخوانی از رشته‌های غیربرنامه‌ای داخلی که به زمان اجرای Android متصل نیستند فراخوانده می‌شوند، بنابراین واجدشرایط استفاده از JNI نیستند. چون این رشته‌های داخلی برای یکپارچگی پیاده‌سازی OpenSL ES حیاتی هستند، یک رسیدگی‌کننده بازخوانی نیز نباید مسدود شود یا کار بیش‌ازحد انجام دهد.

اگر رسیدگی‌کننده بازخوانی شما نیاز به استفاده از JNI دارد یا کاری را اجرا می‌کند که با بازخوانی متناسب نیست، رسیدگی‌کننده باید رویدادی را برای پردازش رشته دیگری پست کند. نمونه‌هایی از بار کاری قابل‌قبول فراخوانی بازگشتی شامل رندر کردن و صف‌بندی میان‌گیر خروجی بعدی (برای AudioPlayer)، پردازش میان‌گیر ورودی تازه پرشده و صف‌بندی میان‌گیر خالی بعدی (برای AudioRecorder)، یا میاناهای برنامه‌سازی کاربردی ساده مانند اکثر خانواده Get است. بخش عملکرد را در زیر درباره حجم کاری ببینید.

توجه داشته باشید که عکس این موضوع ایمن است: رشته برنامه Android که وارد JNI شده است مجاز است مستقیماً میاناهای برنامه‌سازی کاربردی OpenSL ES را فراخوانی کند، ازجمله آن‌هایی که مسدود می‌کنند. بااین‌حال، فراخوانی‌های مسدودکننده از رشته اصلی توصیه نمی‌شود، زیرا ممکن است منجر به برنامه پاسخ نمی‌دهد (ANR) شود.

تصمیم‌گیری درباره رشته‌ای که رسیدگی‌کننده بازخوانی را فراخوانی می‌کند تا حد زیادی به پیاده‌سازی واگذار می‌شود. دلیل این انعطاف‌پذیری، امکان بهینه‌سازی‌های آینده، به‌ویژه در دستگاه‌های چندهسته‌ای است.

تضمین نمی‌شود که رشته‌ای که رسیدگی‌کننده بازخوانی روی آن اجرا می‌شود در تماس‌های مختلف هویت یکسانی داشته باشد. بنابراین، به pthread_t برگردانده‌شده توسط pthread_self() یا pid_t برگردانده‌شده توسط gettid() برای سازگار بودن در تماس‌ها اتکا نکنید. به همین دلیل، از میاناهای برنامه‌سازی کاربردی فضای ذخیره‌سازی محلی رشته (TLS) مانند pthread_setspecific() و pthread_getspecific() از یک فراخوانی برگشتی استفاده نکنید.

این پیاده‌سازی تضمین می‌کند که فراخوانی‌های هم‌زمان از یک نوع، برای یک شیء، رخ نمی‌دهد. بااین‌حال، فراخوانی‌های برگشتی هم‌زمان از انواع مختلف برای یک شیء در رشته‌های مختلف امکان‌پذیر است.

عملکرد

ازآنجایی‌که OpenSL ES یک میانای برنامه‌سازی کاربردی C بومی است، رشته‌های برنامه غیرزمان اجرا که OpenSL ES را فراخوانی می‌کنند، سربار مرتبط با زمان اجرا مانند وقفه‌های جمع‌آوری زباله ندارند. به‌استثنای یک مورد که در زیر شرح داده شده است، استفاده از OpenSL ES هیچ مزیت عملکردی دیگری ندارد. به‌ویژه، استفاده از OpenSL ES بهبودهایی مانند تأخیر صوتی کمتر و اولویت زمان‌بندی بالاتر نسبت‌به آنچه پلاتفرم به‌طور کلی ارائه می‌دهد را تضمین نمی‌کند. ازسوی دیگر، با ادامه تکامل پلاتفرم Android و پیاده‌سازی‌های خاص دستگاه، یک برنامه OpenSL ES می‌تواند انتظار داشته باشد که از هرگونه بهبود عملکرد سیستم در آینده بهره‌مند شود.

یکی از این تحولات، پشتیبانی از کاهش تأخیر خروجی صوتی است. زیربنای کاهش تأخیر خروجی ابتدا در Android 4.1 (سطح API‏ ۱۶) گنجانده شد و سپس پیشرفت مداوم در Android 4.2 (سطح API‏ ۱۷) رخ داد. این بهبودها ازطریق OpenSL ES برای پیاده‌سازی‌های دستگاهی که ادعای ویژگی android.hardware.audio.low_latency را دارند دردسترس است. اگر دستگاه این ویژگی را ادعا نکند اما از Android 2.3 (سطح میانای برنامه‌سازی کاربردی ۹) یا بالاتر پشتیبانی کند، همچنان می‌توانید از میاناهای برنامه‌سازی کاربردی OpenSL ES استفاده کنید اما تأخیر خروجی ممکن است بیشتر باشد. مسیر تأخیر خروجی پایین‌تر فقط درصورتی استفاده می‌شود که برنامه اندازه میان‌گیر و نرخ نمونه‌ای را درخواست کند که با پیکربندی خروجی بومی دستگاه سازگار باشد. این پارامترها مختص دستگاه هستند و باید طبق توضیحات زیر دریافت شوند.

از Android 4.2 (سطح میانای برنامه‌سازی کاربردی ۱۷)، برنامه می‌تواند برای نرخ نمونه خروجی بهینه یا بومی پلاتفرم و اندازه میان‌گیر برای جریان خروجی اصلی دستگاه درخواست دهد. وقتی با آزمایش ویژگی که به‌تازگی ذکر شد ترکیب شود، برنامه اکنون می‌تواند خودش را به‌طور مناسب برای خروجی با تأخیر کمتر در دستگاه‌هایی که ادعای پشتیبانی دارند پیکربندی کند.

برای Android 4.2 (سطح میانای برنامه‌سازی کاربردی ۱۷) و نسخه‌های قدیمی‌تر، برای تأخیر کمتر، تعداد میان‌گیر دو یا بیشتر لازم است. از Android 4.3 (سطح API‏ ۱۸) به بعد، تعداد میان‌گیر یک برای تأخیر کمتر کافی است.

همه میاناهای OpenSL ES برای جلوه‌های خروجی مانع از مسیر تأخیر کمتر می‌شوند.

توالی توصیه‌شده به‌صورت زیر است:

  1. برای تأیید استفاده از OpenSL ES، سطح میانای برنامه‌سازی کاربردی ۹ یا بالاتر را بررسی کنید.
  2. بااستفاده از کدی مانند این، ویژگی android.hardware.audio.low_latency را بررسی کنید:

    کاتلین

    import android.content.pm.PackageManager
    ...
    val pm: PackageManager = context.packageManager
    val claimsFeature: Boolean = pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY)

    جاوا

    import android.content.pm.PackageManager;
    ...
    PackageManager pm = getContext().getPackageManager();
    boolean claimsFeature = pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY);
  3. برای تأیید استفاده از android.media.AudioManager.getProperty()، سطح میانای برنامه‌سازی کاربردی ۱۷ یا بالاتر را بررسی کنید.
  4. بااستفاده از کدی مانند این، نرخ نمونه خروجی بومی یا بهینه و اندازه میان‌گیر را برای جریان خروجی اصلی این دستگاه دریافت کنید:

    کاتلین

    import android.media.AudioManager
    ...
    val am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
    val sampleRate: String = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE)
    val framesPerBuffer: String = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER)

    جاوا

    import android.media.AudioManager;
    ...
    AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    String sampleRate = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
    String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
    توجه داشته باشید که sampleRate و framesPerBuffer رشته هستند. ابتدا null را بررسی کنید و سپس بااستفاده از Integer.parseInt() به int تبدیل کنید.
  5. اکنون از OpenSL ES برای ایجاد AudioPlayer با داده‌یاب صف میان‌گیر PCM استفاده کنید.

توجه: می‌توانید از برنامه آزمایشی Audio Buffer Size برای تعیین اندازه میان‌گیر بومی و نرخ نمونه‌برداری برای برنامه‌های صوتی OpenSL ES در دستگاه صوتی‌تان استفاده کنید. همچنین می‌توانید برای مشاهده نمونه‌های audio-buffer-size به GitHub مراجعه کنید.

تعداد پخش‌کننده‌های صوتی با تأخیر کمتر محدود است. اگر برنامه شما به بیش‌از چند منبع صوتی نیاز دارد، ترکیب کردن صدا را در سطح برنامه درنظر بگیرید. حتماً پخش‌کننده‌های صوتی را وقتی فعالیتتان موقتاً متوقف می‌شود ازبین ببرید، زیرا آن‌ها منابعی جهانی هستند که با برنامه‌های دیگر هم‌رسانی می‌شوند.

برای جلوگیری از اشکالات صوتی، رسیدگی‌کننده بازخوانی صف میان‌گیری باید در یک پنجره زمانی کوچک و قابل‌پیش‌بینی اجرا شود. این معمولاً به این معنی است که هیچ مسدودسازی نامحدودی در mutexها، شرایط، یا عملیات ورودی/خروجی وجود ندارد. درعوض، قفل‌های آزمایشی، قفل‌ها و انتظار با زمان‌بندی، و الگوریتم‌های غیرمسدودکننده را درنظر بگیرید.

محاسبه لازم برای ارائه میان‌گیر بعدی (برای AudioPlayer) یا مصرف میان‌گیر قبلی (برای AudioRecord) باید تقریباً برای هر بازخوان همان مقدار زمان ببرد. از الگوریتم‌هایی که در مدت زمان غیرقطعی اجرا می‌شوند یا در محاسباتشان انفجاری هستند اجتناب کنید. محاسبه فراخوانی برگشتی زمانی انفجاری است که زمان واحد پردازش مرکزی صرف‌شده در هر فراخوانی برگشتی مشخص به‌طور قابل‌توجهی بزرگ‌تر از میانگین باشد. به‌طور خلاصه، حالت ایده‌آل این است که زمان اجرای CPU کنترل‌کننده واریانسی نزدیک به صفر داشته باشد و کنترل‌کننده برای زمان‌های نامحدود مسدود نشود.

صدای با تأخیر کمتر فقط برای این خروجی‌ها امکان‌پذیر است:

در برخی‌از دستگاه‌ها، به‌دلیل پردازش سیگنال دیجیتال برای اصلاح و محافظت از بلندگو، تأخیر بلندگو بیشتر از مسیرهای دیگر است.

از Android 5.0 (سطح میانای برنامه‌سازی کاربردی ۲۱)، ورودی صوتی با تأخیر کمتر در دستگاه‌های منتخب پشتیبانی می‌شود. برای بهره‌مندی از این ویژگی، ابتدا تأیید کنید که خروجی با تأخیر کمتر، همان‌طور که در بالا توضیح داده شد، دردسترس است. قابلیت برونداد با تأخیر کمتر پیش‌نیاز ویژگی ورودی با تأخیر کمتر است. سپس، AudioRecorder با همان نرخ نمونه‌برداری و اندازه میان‌گیری که برای خروجی استفاده می‌شود ایجاد کنید. میاناهای OpenSL ES برای جلوه‌های ورودی مانع مسیر تأخیر کمتر می‌شوند. برای تأخیر کمتر باید از پیش‌تنظیم ضبط SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION استفاده شود؛ این پیش‌تنظیم پردازش سیگنال دیجیتال مختص دستگاه را که ممکن است به مسیر ورودی تأخیر اضافه کند غیرفعال می‌کند. برای اطلاعات بیشتر درباره پیش‌تنظیمات ضبط، به بخش میانای پیکربندی Android در بالا مراجعه کنید.

برای ورودی و خروجی هم‌زمان، از گرداننده‌های تکمیل صف میان‌گیری جداگانه برای هر طرف استفاده می‌شود. هیچ تضمینی برای ترتیب نسبی این فراخوانی‌های برگشتی یا همگام‌سازی ساعت‌های صوتی وجود ندارد، حتی زمانی که هر دو طرف از نرخ نمونه یکسانی استفاده می‌کنند. برنامه شما باید داده‌ها را با همگام‌سازی میان‌گیر مناسب میان‌گیری کند.

یکی از پیامدهای ساعت‌های صوتی بالقوه مستقل، نیاز به تبدیل نرخ نمونه‌برداری ناهمگام است. یک تکنیک ساده (اگرچه برای کیفیت صدا ایده‌آل نیست) برای تبدیل نرخ نمونه ناهمگام، تکرار یا حذف نمونه‌ها درصورت نیاز در نزدیکی نقطه عبور از صفر است. تبدیل‌های پیچیده‌تری امکان‌پذیر است.

حالت‌های عملکرد

با شروع Android 7.1 (سطح میانای برنامه‌سازی کاربردی ۲۵)، OpenSL ES روشی را برای مشخص کردن حالت عملکرد برای مسیر صوتی معرفی کرد. گزینه‌ها عبارت‌اند از:

  • ‫SL_ANDROID_PERFORMANCE_NONE: الزامات عملکردی خاصی وجود ندارد. جلوه‌های سخت‌افزاری و نرم‌افزاری را مجاز می‌کند.
  • ‫SL_ANDROID_PERFORMANCE_LATENCY: اولویت به تأخیر داده می‌شود. بدون جلوه‌های سخت‌افزاری یا نرم‌افزاری. این حالت پیش‌فرض است.
  • SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS: اولویت به تأخیر داده می‌شود درحالی‌که همچنان جلوه‌های سخت‌افزاری و نرم‌افزاری مجاز است.
  • SL_ANDROID_PERFORMANCE_POWER_SAVING: اولویت به صرفه‌جویی در مصرف برق داده می‌شود. جلوه‌های سخت‌افزاری و نرم‌افزاری را مجاز می‌کند.

توجه: اگر به مسیر با تأخیر کم نیاز ندارید و می‌خواهید از جلوه‌های صوتی داخلی دستگاه استفاده کنید (برای مثال، برای بهبود کیفیت آکوستیک برای بازپخش ویدیو)، باید حالت عملکرد را صریحاً روی SL_ANDROID_PERFORMANCE_NONE تنظیم کنید.

برای تنظیم حالت عملکرد، باید SetConfiguration را بااستفاده از میانای پیکربندی Android فراخوانی کنید، همان‌طور که در زیر نشان داده شده است:

  // Obtain the Android configuration interface using a previously configured SLObjectItf.
  SLAndroidConfigurationItf configItf = nullptr;
  (*objItf)->GetInterface(objItf, SL_IID_ANDROIDCONFIGURATION, &configItf);

  // Set the performance mode.
  SLuint32 performanceMode = SL_ANDROID_PERFORMANCE_NONE;
    result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
                                                     &performanceMode, sizeof(performanceMode));

امنیت و اجازه‌ها

تا جایی که به اینکه چه کسی می‌تواند چه کاری انجام دهد مربوط می‌شود، امنیت در Android در سطح فرایند انجام می‌شود. کد زبان برنامه‌نویسی Java نمی‌تواند کاری بیشتر از کد بومی انجام دهد، و کد بومی نیز نمی‌تواند کاری بیشتر از کد زبان برنامه‌نویسی Java انجام دهد. تنها تفاوت بین آن‌ها میاناهای برنامه‌سازی کاربردی دردسترس است.

برنامه‌هایی که از OpenSL ES استفاده می‌کنند باید اجازه‌هایی را درخواست کنند که برای میاناهای برنامه‌سازی کاربردی غیربومی مشابه نیاز دارند. برای مثال، اگر برنامه شما صدا ضبط می‌کند، به اجازه android.permission.RECORD_AUDIO نیاز دارد. برنامه‌هایی که از جلوه‌های صوتی استفاده می‌کنند به android.permission.MODIFY_AUDIO_SETTINGS نیاز دارند. برنامه‌هایی که منابع URI شبکه را پخش می‌کنند به android.permission.NETWORK نیاز دارند. برای اطلاعات بیشتر، کار با اجازه‌های سیستم را ببینید.

بسته به نسخه پلاتفرم و پیاده‌سازی، تجزیه‌کننده‌های محتوای رسانه و کدک‌های نرم‌افزاری ممکن است در زمینه برنامه Android که OpenSL ES را فراخوانی می‌کند اجرا شوند (کدک‌های سخت‌افزاری انتزاعی هستند اما به دستگاه وابسته هستند). محتوای بدساخت که برای سوءاستفاده از آسیب‌پذیری‌های تجزیه‌کننده و کدک طراحی شده است، یک بردار حمله شناخته‌شده است. توصیه می‌کنیم رسانه‌ها را فقط از منابع قابل‌اعتماد پخش کنید یا برنامه‌تان را به‌گونه‌ای تقسیم‌بندی کنید که کدی که رسانه‌ها را از منابع غیرقابل‌اعتماد مدیریت می‌کند در محیطی نسبتاً محدود اجرا شود. برای مثال، می‌توانید رسانه‌های منابع غیرقابل‌اعتماد را در فرایندی جداگانه پردازش کنید. اگرچه هر دو فرایند همچنان تحت یک UID اجرا می‌شوند، این جداسازی حمله را دشوارتر می‌کند.