ورودی صدا معمولاً از میکروفون داخلی، میکروفون خارجی یا رابط صوتی متصل به دستگاه میآید. ورودی صدا همچنین میتواند از مکالمه تلفنی باشد.
گاهی اوقات ممکن است دو یا چند برنامه هر دو بخواهند ورودی صوتی یکسانی را «ضبط» کنند. آنها ممکن است وظایف متفاوتی انجام دهند. به عنوان مثال، برخی از برنامههایی که صدا را دریافت میکنند ممکن است «ضبط» کنند، مانند یک ضبط صوت ساده، در حالی که سایر برنامهها ممکن است «گوش دهند»، مانند دستیار گوگل یا یک سرویس دسترسی که به دستورات صوتی پاسخ میدهد.
در هر صورت، این برنامهها میخواهند ورودی صوتی دریافت کنند. در سراسر این صفحه، ما از اصطلاح «ضبط» صرف نظر از اینکه برنامه در حال ضبط است یا فقط گوش میدهد، استفاده میکنیم.
اگر دو یا چند برنامه بخواهند همزمان صدا را ضبط کنند، ممکن است در رساندن سیگنال صوتی از یک منبع به همه آنها مشکلی ایجاد شود. این صفحه نحوه اشتراکگذاری ورودی صدا بین چندین برنامه که صدا را ضبط میکنند توسط سیستم اندروید را شرح میدهد.
رفتار قبل از اندروید ۱۰
قبل از اندروید ۱۰، جریان صوتی ورودی فقط میتوانست توسط یک برنامه در یک زمان ضبط شود. اگر برنامهای از قبل در حال ضبط یا گوش دادن به صدا بود، برنامه شما میتوانست یک شیء AudioRecord ایجاد کند، اما هنگام فراخوانی AudioRecord.startRecording() خطایی بازگردانده میشد و ضبط شروع نمیشد.
یک استثنا برای این قانون زمانی بود که یک برنامهی دارای امتیاز (مانند دستیار گوگل یا یک سرویس دسترسی) مجوز android.permission.CAPTURE_AUDIO_HOTWORD را داشت و از یک منبع صوتی از نوع HOTWORD استفاده میکرد. در این حالت، برنامهی دیگری میتوانست ضبط را شروع کند. وقتی این اتفاق میافتاد، برنامهی دارای امتیاز خاتمه مییافت و برنامهی جدید ورودی را ضبط میکرد.
یک تغییر دیگر در اندروید ۹ اضافه شد: فقط برنامههایی که در پیشزمینه (یا یک سرویس پیشزمینه) اجرا میشدند میتوانستند ورودی صدا را ضبط کنند. وقتی برنامهای بدون سرویس پیشزمینه یا مؤلفه رابط کاربری پیشزمینه شروع به ضبط صدا میکرد، برنامه به اجرای خود ادامه میداد اما سکوت دریافت میکرد، حتی اگر تنها برنامهای بود که در آن زمان صدا را ضبط میکرد.
رفتار اندروید ۱۰
قبل از اندروید ۱۰، روال کار به این صورت بود که «هر کسی زودتر درخواست بدهد، زودتر سرویس میگیرد». به محض اینکه یک برنامه شروع به ضبط صدا میکند، هیچ برنامهی دیگری نمیتواند به ورودی صدا دسترسی داشته باشد تا زمانی که برنامهی در حال ضبط صدا متوقف شود.
اندروید ۱۰ یک طرح اولویتبندی اعمال میکند که میتواند جریان صوتی ورودی را بین برنامهها در حین اجرا تغییر دهد. در بیشتر موارد، اگر یک برنامه جدید ورودی صوتی را دریافت کند، برنامه قبلی که صدا را ضبط میکند به اجرا ادامه میدهد، اما سکوت دریافت میکند. در برخی موارد، سیستم میتواند به ارائه صدا به هر دو برنامه ادامه دهد. سناریوهای مختلف اشتراکگذاری در زیر توضیح داده شده است.
این طرح مشابه روشی است که فوکوس صوتی با چندین برنامه که برای استفاده از خروجی صدا رقابت میکنند، مدیریت میکند. با این حال، فوکوس صوتی توسط درخواستهای برنامهریزیشده برای دریافت و آزادسازی فوکوس مدیریت میشود، در حالی که طرح تغییر ورودی که در اینجا شرح داده شده است، مبتنی بر یک سیاست اولویتبندی است که هر زمان که یک برنامه جدید شروع به ضبط صدا میکند، به طور خودکار اعمال میشود.
برای ضبط صدا، اندروید دو نوع برنامه را از هم متمایز میکند:
- برنامههای «معمولی» توسط کاربر نصب میشوند.
- برنامههای «ممتاز» از قبل روی دستگاه نصب شدهاند. این برنامهها شامل دستیار گوگل و تمام سرویسهای دسترسی میشوند.
علاوه بر این، اگر یک برنامه از منبع صوتی «حساس به حریم خصوصی» مانند CAMCORDER یا VOICE_COMMUNICATION استفاده کند، با آن برخورد متفاوتی میشود.
قوانین اولویتبندی برای استفاده و اشتراکگذاری ورودی صوتی به شرح زیر است:
- برنامههای ممتاز اولویت بالاتری نسبت به برنامههای معمولی دارند.
- برنامههایی که رابط کاربری پیشزمینهی قابل مشاهدهای دارند، نسبت به برنامههای پسزمینه اولویت بالاتری دارند.
- برنامههایی که صدا را از یک منبع حساس به حریم خصوصی ضبط میکنند، نسبت به برنامههایی که این کار را نمیکنند، اولویت بالاتری دارند.
- دو برنامه معمولی هرگز نمیتوانند همزمان صدا را ضبط کنند.
- در برخی شرایط، یک برنامهی دارای امتیاز بالا میتواند ورودی صوتی را با برنامهی دیگری به اشتراک بگذارد.
- اگر دو برنامه پسزمینه با اولویت یکسان در حال ضبط صدا باشند، آخرین برنامهای که اجرا شده اولویت بالاتری دارد.
سناریوهای اشتراک گذاری
وقتی دو برنامه سعی در ضبط صدا دارند، ممکن است هر دو بتوانند سیگنال ورودی را دریافت کنند، یا یکی از آنها ممکن است سکوت دریافت کند.
چهار سناریوی اصلی وجود دارد:
- دستیار + برنامه معمولی
- سرویس دسترسی + برنامه معمولی
- دو برنامه معمولی
- تماس صوتی + برنامه معمولی
دستیار + برنامه معمولی
دستیار یک برنامهی ممتاز است زیرا از پیش نصب شده است و نقش RoleManager.ROLE_ASSISTANT را دارد. با هر برنامهی از پیش نصب شدهی دیگری که این نقش را داشته باشد، به طور مشابه رفتار میشود.
اندروید صدای ورودی را طبق این قوانین به اشتراک میگذارد:
دستیار میتواند صدا را دریافت کند (فرقی نمیکند که در پیشزمینه باشد یا پسزمینه)، مگر اینکه برنامهی دیگری که از یک منبع صوتی حساس به حریم خصوصی استفاده میکند، در حال ضبط صدا باشد.
برنامه صدا را دریافت میکند مگر اینکه دستیار یک جزء رابط کاربری قابل مشاهده در بالای صفحه داشته باشد.
توجه داشته باشید که هر دو برنامه فقط زمانی صدا را دریافت میکنند که دستیار در پسزمینه باشد و برنامه دیگر از یک منبع صوتی حساس به حریم خصوصی در حال ضبط نباشد.
سرویس دسترسی + برنامه معمولی
یک AccessibilityService نیاز به یک تعریف دقیق (stric declaration) دارد.
اندروید صدای ورودی را طبق این قوانین به اشتراک میگذارد:
اگر رابط کاربری سرویس در بالا باشد، هم سرویس و هم برنامه ورودی صوتی دریافت میکنند. این رفتار قابلیتهایی مانند کنترل تماس صوتی یا ضبط ویدیو با دستورات صوتی را ارائه میدهد.
اگر سرویس در بالا نباشد، این مورد مانند مورد معمولی دو برنامه در زیر در نظر گرفته میشود.
دو برنامه معمولی
وقتی دو برنامه همزمان در حال ضبط صدا هستند، فقط یکی از برنامهها صدا را دریافت میکند و دیگری سکوت میکند.
اندروید صدای ورودی را طبق این قوانین به اشتراک میگذارد:
- اگر هیچکدام از برنامهها به حریم خصوصی حساس نباشند، برنامهای که رابط کاربری (UI) روی آن قرار دارد، صدا را دریافت میکند. اگر هیچکدام از برنامهها رابط کاربری (UI) نداشته باشند، برنامهای که ضبط صدا را از همه جدیدتر شروع کرده، صدا را دریافت میکند.
- اگر یکی از برنامهها حساس به حریم خصوصی باشد، صدا را دریافت میکند و برنامه دیگر سکوت میکند، حتی اگر رابط کاربری آن فعال باشد یا اخیراً شروع به ضبط صدا کرده باشد.
- اگر هر دو برنامه حساس به حریم خصوصی باشند، برنامهای که اخیراً شروع به ضبط صدا کرده است، صدا را دریافت میکند و برنامه دیگر سکوت میکند.
تماس صوتی + برنامه معمولی
یک تماس صوتی در صورتی فعال است که حالت صوتی برگردانده شده توسط AudioManager.getMode() برابر با MODE_IN_CALL یا MODE_IN_COMMUNICATION باشد.
اندروید صدای ورودی را طبق این قوانین به اشتراک میگذارد:
- تماس همیشه صدا را دریافت میکند.
- اگر برنامه یک سرویس دسترسی باشد، میتواند صدا را ضبط کند.
اگر برنامه، یک برنامهی ممتاز (از پیش نصب شده) با مجوز
CAPTURE_AUDIO_OUTPUTباشد، میتواند تماس صوتی را ضبط کند.برای ضبط لینک بالارونده (TX)، لینک پایینرونده (RX) یا هر دوی تماس صوتی، برنامه باید منابع صوتی
MediaRecorder.AudioSource.VOICE_UPLINKیاMediaRecorder.AudioSource.VOICE_DOWNLINKو/یا دستگاهAudioDeviceInfo.TYPE_TELEPHONYرا مشخص کند.
رفتار اندروید ۱۱
اندروید ۱۱ (سطح API 30) از طرح اولویتبندی اندروید ۱۰ که در بالا توضیح داده شد، پیروی میکند. همچنین متدهای جدیدی در AudioRecord ، MediaRecorder و AAudioStream ارائه میدهد که قابلیت ضبط صدا به طور همزمان را، صرف نظر از مورد استفاده انتخاب شده، فعال و غیرفعال میکنند.
روشهای جدید عبارتند از:
-
AudioRecord.Builder.setPrivacySensitive() -
AudioRecord.isPrivacySensitive() -
MediaRecorder.setPrivacySensitive() -
MediaRecorder.isPrivacySensitive() -
AAudioStreamBuilder_setPrivacySensitive() -
AAudioStream_isPrivacySensitive()
وقتی setPrivacySensitive() true باشد، مورد استفاده برای ضبط صدا خصوصی است و حتی یک دستیار دارای امتیاز هم نمیتواند همزمان ضبط کند. این تنظیم، رفتار پیشفرضی را که به منبع صدا بستگی دارد، لغو میکند. برای مثال، VOICE_COMMUNICATION به طور پیشفرض خصوصی است اما UNPROCESSED اینطور نیست.
تغییرات پیکربندی
وقتی چندین برنامه همزمان در حال ضبط صدا هستند، فقط یک یا دو تا از آنها "فعال" هستند (صدا را دریافت میکنند)؛ بقیه بیصدا هستند (سکوت دریافت میکنند). وقتی برنامههای فعال تغییر میکنند، چارچوب صوتی ممکن است مسیرهای صوتی را طبق این قوانین دوباره پیکربندی کند:
- دستگاه ورودی صدا برای هر برنامه فعال ممکن است تغییر کند (برای مثال، از میکروفون داخلی به یک هدست بلوتوث متصل).
- پیشپردازش مرتبط با برنامهی فعال با بالاترین اولویت فعال است. سایر پیشپردازشها نادیده گرفته میشوند.
از آنجایی که یک برنامه فعال ممکن است هنگام فعال شدن یک برنامه با اولویت بالاتر، بیصدا شود، میتوانید یک AudioManager.AudioRecordingCallback را روی شیء AudioRecord یا MediaRecorder ثبت کنید تا هنگام تغییر پیکربندی مطلع شوید. تغییرات احتمالی میتوانند به شرح زیر باشند:
- ضبط با صدای بیصدا یا بدون صدا
- دستگاه عوض شده
- پیشپردازش تغییر کرد
- ویژگیهای جریان تغییر کرد (نرخ نمونهبرداری، ماسک کانال، فرمت نمونه)
قبل از شروع ضبط، باید AudioRecord.registerAudioRecordingCallback() را فراخوانی کنید. این فراخوانی فقط زمانی اجرا میشود که برنامه صدا را دریافت کند و تغییری رخ دهد.
متد onRecordingConfigChanged() یک AudioRecordingConfiguration برمیگرداند که شامل وضعیت ضبط صدای فعلی است. برای اطلاع از تغییر ایجاد شده از متدهای زیر استفاده کنید:
-
isClientSilenced() - اگر صدای برگردانده شده به کلاینت به دلیل سیاست ضبط، در حال حاضر بیصدا باشد، مقدار true را برمیگرداند.
-
getAudioDevice() - دستگاه صوتی فعال را برمیگرداند.
-
getEffects() - اثر پیشپردازش فعال را برمیگرداند. توجه داشته باشید که اگر کلاینت، برنامهی فعال با بالاترین اولویت نباشد، ممکن است اثر فعال با آنچه توسط
getClientEffects()برگردانده میشود، یکسان نباشد. -
getFormat() - ویژگیهای جریان را برمیگرداند. توجه داشته باشید که دادههای صوتی واقعی دریافت شده توسط کلاینت همیشه از فرمت مورد نیاز برگردانده شده توسط
getClientFormat()پیروی میکنند. این چارچوب به طور خودکار نمونهبرداری مجدد، تبدیل کانال و فرمت لازم را از فرمت مورد استفاده در رابط سختافزاری به فرمت مشخص شده توسط کلاینت انجام میدهد. -
AudioRecord.getActiveRecordingConfiguration(). (فایل صوتی ضبط شده را فعال کن، پیکربندی کن) - پیکربندی ضبط فعال را برمیگرداند.
شما میتوانید با فراخوانی AudioManager.getActiveRecordingConfigurations() نمای کلی از تمام ضبطهای فعال روی دستگاه را مشاهده کنید.