OpenSL ES برای اندروید

این صفحه جزئیاتی در مورد اینکه چگونه پیاده سازی NDK OpenSL ES™ با مشخصات مرجع OpenSL ES 1.0.1 متفاوت است، ارائه می دهد. هنگام استفاده از کد نمونه از مشخصات، ممکن است لازم باشد آن را تغییر دهید تا در Android کار کند.

مگر اینکه غیر از این ذکر شده باشد، همه ویژگی ها در Android 2.3 (سطح API 9) و بالاتر در دسترس هستند. برخی از ویژگی‌ها فقط برای Android 4.0 (سطح API 14) در دسترس هستند. این موارد ذکر شده است.

توجه: سند تعریف سازگاری اندروید (CDD) الزامات سخت افزاری و نرم افزاری یک دستگاه Android سازگار را برمی شمرد. برای اطلاعات بیشتر در مورد برنامه سازگاری کلی، به سازگاری Android و برای سند CDD واقعی به CDD مراجعه کنید.

OpenSL ES یک رابط زبان C ارائه می دهد که با استفاده از C++ نیز قابل دسترسی است. ویژگی‌هایی شبیه به بخش‌های صوتی این APIهای جاوا اندروید را نشان می‌دهد:

مانند همه کیت توسعه بومی Android (NDK)، هدف اصلی OpenSL ES برای Android تسهیل اجرای کتابخانه های مشترک برای فراخوانی با استفاده از رابط بومی جاوا ( JNI ) است. NDK برای نوشتن برنامه های C/C++ خالص در نظر گرفته نشده است. با این حال، OpenSL ES یک API با امکانات کامل است، و ما انتظار داریم که بتوانید بیشتر نیازهای صوتی خود را تنها با استفاده از این API انجام دهید، بدون نیاز به کد در حال اجرا در زمان اجرا اندروید.

توجه: اگرچه مبتنی بر OpenSL ES، API صوتی بومی Android (صوت با کارایی بالا) یک پیاده‌سازی منطبق با پروفایل OpenSL ES 1.0.1 (بازی، موسیقی یا تلفن) نیست. این به این دلیل است که اندروید تمام ویژگی های مورد نیاز هیچ یک از پروفایل ها را اجرا نمی کند. هر مورد شناخته شده ای که در آن Android رفتاری متفاوت از مشخصات داشته باشد در صفحه برنامه های افزودنی Android توضیح داده شده است.

ویژگی های به ارث رسیده از مشخصات مرجع

اجرای Android NDK OpenSL ES بسیاری از ویژگی‌ها را از مشخصات مرجع با محدودیت‌های خاصی به ارث می‌برد.

نقاط ورود جهانی

OpenSL ES برای اندروید از تمام نقاط ورودی جهانی در مشخصات اندروید پشتیبانی می کند. این نقاط ورود عبارتند از:

  • slCreateEngine
  • slQueryNumSupportedEngineInterfaces
  • slQuerySupportedEngineInterfaces

اشیاء و رابط ها

جدول زیر اشیاء و رابط هایی را نشان می دهد که پیاده سازی Android NDK OpenSL ES از آنها پشتیبانی می کند. اگر یک بله در سلول ظاهر شود، این ویژگی در این پیاده سازی در دسترس است.

پشتیبانی از Android NDK برای اشیاء و رابط ها.

ویژگی پخش کننده صدا ضبط کننده صدا موتور ترکیب خروجی
تقویت بیس بله خیر خیر بله
صف بافر بله خیر خیر خیر
مکان یاب داده صف بافر بله: منبع خیر خیر خیر
مدیریت رابط پویا بله بله بله بله
ارسال اثر بله خیر خیر خیر
موتور خیر خیر بله خیر
طنین محیطی خیر خیر خیر بله
اکولایزر بله خیر خیر بله
مکان یاب داده دستگاه ورودی/خروجی خیر بله: منبع خیر خیر
استخراج فراداده بله: رمزگشایی به PCM خیر خیر خیر
انفرادی بی صدا بله خیر خیر خیر
شیء بله بله بله بله
یاب مخلوط خروجی بله: سینک خیر خیر خیر
بازی کنید بله خیر خیر خیر
نرخ پخش بله خیر خیر خیر
وضعیت پیش واکشی بله خیر خیر خیر
ریورب از پیش تنظیم شده خیر خیر خیر بله
ضبط کنید خیر بله خیر خیر
جستجو کنید بله خیر خیر خیر
مکان یاب داده URI بله: منبع خیر خیر خیر
مجازی ساز بله خیر خیر بله
حجم بله خیر خیر خیر

بخش بعدی محدودیت های برخی از این ویژگی ها را توضیح می دهد.

محدودیت ها

محدودیت های خاصی برای ویژگی های جدول 1 اعمال می شود. این محدودیت ها تفاوت هایی را با مشخصات مرجع نشان می دهد. بقیه این بخش اطلاعاتی در مورد این تفاوت ها ارائه می دهد.

مدیریت رابط پویا

OpenSL ES برای Android از RemoveInterface یا ResumeInterface پشتیبانی نمی کند.

ترکیبات افکت: Reverb محیط و Reverb از پیش تعیین شده

شما نمی توانید هر دو Reverb محیطی و Reverb از پیش تعیین شده را در یک ترکیب خروجی داشته باشید.

اگر پلتفرم تخمین بزند که بار CPU خیلی زیاد است، ممکن است درخواست‌های اثر را نادیده بگیرد.

ارسال اثر

SetSendLevel() از یک سطح ارسال در هر پخش کننده صوتی پشتیبانی می کند.

طنین محیطی

Environmental Reverb از فیلدهای reflectionsDelay ، reflectionsLevel یا reverbDelay در ساختار SLEnvironmentalReverbSettings پشتیبانی نمی کند.

فرمت داده MIME

می توانید از فرمت داده MIME فقط با مکان یاب داده URI و فقط برای پخش کننده صوتی استفاده کنید. شما نمی توانید از این فرمت داده برای ضبط صدا استفاده کنید.

اجرای Android OpenSL ES از شما می‌خواهد که mimeType به NULL یا یک رشته معتبر UTF-8 مقداردهی اولیه کنید. همچنین باید containerType به مقدار معتبر مقداردهی کنید. در غیاب ملاحظات دیگر، مانند قابل حمل بودن به دیگر اجراها یا قالب‌های محتوایی که برنامه نمی‌تواند با هدر شناسایی کند، توصیه می‌کنیم mimeType روی NULL و containerType روی SL_CONTAINERTYPE_UNSPECIFIED تنظیم کنید.

OpenSL ES برای اندروید از فرمت های صوتی زیر پشتیبانی می کند، تا زمانی که پلتفرم اندروید از آنها نیز پشتیبانی کند:

  • WAV PCM.
  • WAV alaw.
  • WAV ulaw.
  • MP3 Ogg Vorbis.
  • AAC LC.
  • HE-AACv1 (AAC+).
  • HE-AACv2 (AAC+ پیشرفته).
  • AMR.
  • FLAC.

توجه: برای فهرستی از قالب‌های صوتی که Android پشتیبانی می‌کند، به قالب‌های رسانه پشتیبانی شده مراجعه کنید.

محدودیت‌های زیر برای مدیریت این قالب‌ها و سایر قالب‌ها در اجرای OpenSL ES اعمال می‌شود:

  • فرمت های AAC باید در یک ظرف MP4 یا ADTS قرار گیرند.
  • OpenSL ES برای Android از MIDI پشتیبانی نمی کند.
  • WMA بخشی از AOSP نیست و ما سازگاری آن را با OpenSL ES برای Android تأیید نکرده‌ایم.
  • اجرای Android NDK OpenSL ES از پخش مستقیم DRM یا محتوای رمزگذاری شده پشتیبانی نمی کند. برای پخش محتوای صوتی محافظت شده، باید قبل از پخش، آن را در برنامه خود رمزگشایی کنید و برنامه شما هر گونه محدودیت DRM را اعمال کند.

OpenSL ES برای Android از روش های زیر برای دستکاری اشیا پشتیبانی نمی کند:

  • Resume()
  • RegisterCallback()
  • AbortAsyncOperation()
  • SetPriority()
  • GetPriority()
  • SetLossOfControlInterfaces()

فرمت داده PCM

PCM تنها فرمت داده ای است که می توانید با صف های بافر استفاده کنید. تنظیمات پخش PCM پشتیبانی شده دارای ویژگی های زیر است:

  • 8 بیت بدون علامت یا 16 بیت امضا شده.
  • مونو یا استریو.
  • سفارش بایت انددینی کوچک.
  • نرخ های نمونه:
    • 8000 هرتز
    • 11025 هرتز
    • 12000 هرتز
    • 16000 هرتز
    • 22050 هرتز
    • 24000 هرتز
    • 32000 هرتز
    • 44100 هرتز
    • 48000 هرتز

تنظیماتی که OpenSL ES برای Android برای ضبط پشتیبانی می‌کند وابسته به دستگاه است. معمولاً 16000 هرتز مونو/16 بیتی بدون توجه به دستگاه در دسترس است.

مقدار فیلد samplesPerSec با وجود نام گمراه کننده، بر حسب میلی هرتز است. برای جلوگیری از استفاده تصادفی از مقدار اشتباه، توصیه می کنیم این فیلد را با استفاده از یکی از ثابت های نمادین تعریف شده برای این منظور، مانند SL_SAMPLINGRATE_44_1 مقداردهی اولیه کنید.

Android نسخه 5.0 (سطح API 21) و بالاتر از داده های ممیز شناور پشتیبانی می کند.

نرخ پخش

نرخ بازپخش OpenSL ES نشان دهنده سرعتی است که یک شی داده ها را با هزارم سرعت معمولی یا در هر مایل ارائه می کند. به عنوان مثال، نرخ پخش 1000 در هر مایل 1000/1000 یا سرعت عادی است. محدوده نرخ یک بازه بسته است که طیفی از نرخ های پخش ممکن را بیان می کند.

پشتیبانی از محدوده نرخ پخش و سایر قابلیت ها ممکن است بسته به نسخه پلتفرم و اجرا متفاوت باشد. برنامه شما می تواند با استفاده از PlaybackRate::GetRateRange() یا PlaybackRate::GetCapabilitiesOfRate() این قابلیت ها را در زمان اجرا تعیین کند.

یک دستگاه معمولاً از محدوده نرخ یکسانی برای منبع داده در قالب PCM و محدوده نرخ واحد 1000 در هر مایل تا 1000 در هر میلی را برای سایر فرمت ها پشتیبانی می کند. یعنی محدوده نرخ واحد در واقع یک مقدار واحد است.

ضبط کنید

OpenSL ES برای Android از رویدادهای SL_RECORDEVENT_HEADATLIMIT یا SL_RECORDEVENT_HEADMOVING پشتیبانی نمی‌کند.

جستجو کنید

متد SetLoop() حلقه کردن کل فایل را فعال می کند. برای فعال کردن حلقه، پارامتر startPos را روی 0 و پارامتر endPos روی SL_TIME_UNKNOWN تنظیم کنید.

مکان یاب داده صف بافر

یک پخش کننده یا ضبط کننده صوتی با مکان یاب داده برای صف بافر فقط از فرمت داده PCM پشتیبانی می کند.

یاب داده دستگاه ورودی/خروجی

OpenSL ES برای Android تنها زمانی از استفاده از مکان یاب داده دستگاه I/O پشتیبانی می کند که مکان یاب را به عنوان منبع داده برای Engine::CreateAudioRecorder() مشخص کرده باشید. مکان یاب داده دستگاه را با استفاده از مقادیر موجود در قطعه کد زیر راه اندازی کنید:

SLDataLocator_IODevice loc_dev =
  {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
  SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};

مکان یاب داده URI

OpenSL ES برای Android فقط می تواند از مکان یاب داده URI با فرمت داده MIME و فقط برای پخش کننده صوتی استفاده کند. شما نمی توانید از یک یاب داده URI برای ضبط صدا استفاده کنید. URI فقط می تواند از طرح های http: و file: استفاده کند. طرح‌های دیگر، مانند https: ftp: یا content: مجاز نیستند.

ما پشتیبانی از rtsp: با صدا را در پلتفرم Android تأیید نکرده ایم.

ساختارهای داده

اندروید از این ساختارهای داده OpenSL ES 1.0.1 پشتیبانی می کند:

  • SLDataFormat_MIME
  • SLDataFormat_PCM
  • SLDataLocator_BufferQueue
  • SLDataLocator_IODevice
  • SLDataLocator_OutputMix
  • SLDataLocator_URI
  • SLDataSink
  • SLDataSource
  • SLEngineOption
  • SLEnvironmentalReverbSettings
  • SLInterfaceID

پیکربندی پلت فرم

OpenSL ES برای اندروید برای برنامه های چند رشته ای طراحی شده است و ایمن است. از یک موتور در هر برنامه و حداکثر 32 شی در هر موتور پشتیبانی می کند. حافظه دستگاه و CPU موجود ممکن است تعداد قابل استفاده اشیاء را محدودتر کند.

این گزینه های موتور شناخته شده اند، اما توسط slCreateEngine نادیده گرفته می شوند:

  • SL_ENGINEOPTION_THREADSAFE
  • SL_ENGINEOPTION_LOSSOFCONTROL

OpenMAX AL و OpenSL ES ممکن است با هم در یک برنامه استفاده شوند. در این مورد، یک شی موتور مشترک در داخل وجود دارد و محدودیت 32 شی بین OpenMAX AL و OpenSL ES مشترک است. برنامه باید هر دو موتور را ایجاد کند، از هر دو موتور استفاده کند و در نهایت هر دو موتور را نابود کند. پیاده‌سازی یک تعداد مرجع روی موتور مشترک نگه می‌دارد تا در طول عملیات تخریب دوم به درستی از بین برود.

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

یادداشت های برنامه نویسی OpenSL ES اطلاعات تکمیلی را برای اطمینان از اجرای صحیح OpenSL ES فراهم می کند.

توجه: برای راحتی شما، یک کپی از مشخصات OpenSL ES 1.0.1 با NDK در docs/opensles/OpenSL_ES_Specification_1.0.1.pdf قرار داده ایم.

مسائل پلتفرم

این بخش مسائل شناخته شده را در نسخه اولیه پلتفرم که از این API ها پشتیبانی می کند، توضیح می دهد.

مدیریت رابط پویا

DynamicInterfaceManagement::AddInterface کار نمی کند. در عوض، همانطور که در کد مثال برای reverb محیطی نشان داده شده است، رابط موجود در آرایه را که به Create() ارسال می شود، مشخص کنید.

برای نسخه های آینده OpenSL ES برنامه ریزی کنید

APIهای صوتی با کارایی بالا اندروید بر اساس گروه Khronos OpenSL ES 1.0.1 هستند. Khronos نسخه اصلاح شده 1.1 استاندارد را منتشر کرده است. نسخه اصلاح شده شامل ویژگی های جدید، شفاف سازی، تصحیح اشتباهات تایپی و برخی ناسازگاری ها است. بیشتر ناسازگاری‌های مورد انتظار نسبتاً جزئی هستند یا در مناطقی از OpenSL ES هستند که توسط Android پشتیبانی نمی‌شوند.

برنامه‌ای که با این نسخه توسعه یافته است باید روی نسخه‌های بعدی پلتفرم Android کار کند، مشروط بر اینکه دستورالعمل‌هایی را که در بخش Plan for binar compatibility در زیر آمده است، دنبال کنید.

توجه: سازگاری منبع آینده یک هدف نیست. یعنی اگر به نسخه جدیدتر NDK ارتقا دهید، ممکن است لازم باشد کد منبع برنامه خود را تغییر دهید تا با API جدید مطابقت داشته باشد. ما انتظار داریم که اکثر این تغییرات جزئی باشد. جزئیات را در زیر ببینید

برای سازگاری باینری برنامه ریزی کنید

ما توصیه می کنیم که برنامه شما این دستورالعمل ها را برای بهبود سازگاری باینری در آینده دنبال کند:

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

توجه: برای جزئیات بیشتر به بخش رفتار صف بافر در زیر مراجعه کنید.

برای سازگاری منبع برنامه ریزی کنید

همانطور که گفته شد، ناسازگاری کد منبع در نسخه بعدی OpenSL ES از گروه Khronos انتظار می رود. زمینه های احتمالی تغییر عبارتند از:

  • انتظار می‌رود رابط صف بافر تغییرات قابل‌توجهی داشته باشد، به‌ویژه در زمینه‌های BufferQueue::Enqueue ، لیست پارامترهای slBufferQueueCallback و نام فیلد SLBufferQueueState.playIndex . توصیه می کنیم کد برنامه شما به جای آن از صف های بافر ساده اندروید استفاده کند. در کد مثالی که به همراه NDK ارائه شده است، به همین دلیل از صف بافر ساده اندروید برای پخش استفاده کرده ایم. (ما همچنین از صف بافر ساده اندروید برای ضبط و رمزگشایی به PCM استفاده می‌کنیم، اما این به این دلیل است که OpenSL ES 1.0.1 استاندارد از ضبط یا رمزگشایی در یک سینک داده صف بافر پشتیبانی نمی‌کند.)
  • به پارامترهای ورودی که توسط مرجع ارسال می شوند و به فیلدهای ساختار SLchar * که به عنوان مقادیر ورودی استفاده می شود، مقدار const اضافه می شود. این نباید نیازی به تغییر در کد شما داشته باشد.
  • جایگزینی از انواع بدون علامت برای برخی از پارامترهایی که در حال حاضر امضا شده اند وجود خواهد داشت. ممکن است لازم باشد نوع پارامتر را از SLint32 به SLuint32 یا مشابه تغییر دهید، یا یک Cast اضافه کنید.
  • Equalizer::GetPresetName به جای برگرداندن اشاره گر به حافظه پیاده سازی، رشته را در حافظه برنامه کپی می کند. این یک تغییر قابل توجه خواهد بود، بنابراین توصیه می کنیم یا از فراخوانی این روش خودداری کنید یا استفاده خود را از آن جدا کنید.
  • فیلدهای اضافی در انواع ساختار وجود خواهد داشت. برای پارامترهای خروجی، این فیلدهای جدید را می توان نادیده گرفت، اما برای پارامترهای ورودی، فیلدهای جدید باید مقداردهی اولیه شوند. خوشبختانه انتظار می رود همه این فیلدها در مناطقی باشند که توسط اندروید پشتیبانی نمی شوند.
  • GUID های رابط تغییر خواهند کرد. برای جلوگیری از وابستگی به رابط ها با نام نمادین به جای GUID مراجعه کنید.
  • SLchar از unsigned char به char تغییر می کند. این در درجه اول بر روی مکان یاب داده URI و فرمت داده MIME تأثیر می گذارد.
  • SLDataFormat_MIME.mimeType به pMimeType و SLDataLocator_URI.URI به pURI تغییر نام خواهد داد. توصیه می کنیم ساختارهای داده SLDataFormat_MIME و SLDataLocator_URI را با استفاده از یک لیست مقادیر جدا شده با کاما و به جای نام فیلد، مقداردهی اولیه کنید تا کد خود را از این تغییر جدا کنید. این تکنیک در کد مثال استفاده شده است.
  • SL_DATAFORMAT_PCM به برنامه اجازه نمی دهد که نمایش داده ها را به صورت عدد صحیح امضا شده، عدد صحیح بدون علامت یا ممیز شناور مشخص کند. پیاده سازی اندروید فرض می کند که داده های 8 بیتی عدد صحیح بدون علامت و 16 بیتی عدد صحیح امضا شده است. علاوه بر این، فیلد samplesPerSec یک نام اشتباه است، زیرا واحدهای واقعی میلی هرتز هستند. انتظار می‌رود این مشکلات در نسخه بعدی OpenSL ES مورد بررسی قرار گیرند، که یک قالب داده توسعه‌یافته PCM را معرفی می‌کند که به برنامه اجازه می‌دهد به صراحت نمایش را مشخص کند و نام فیلد را تصحیح کند. از آنجایی که این یک قالب داده جدید خواهد بود و قالب داده PCM فعلی همچنان در دسترس خواهد بود (اگرچه منسوخ شده است)، نباید نیاز به تغییر فوری در کد شما داشته باشد.