جارٍ مشاركة إدخال الصوت

يأتي إدخال الصوت عادةً من الميكروفون المدمَج أو ميكروفون خارجي أو واجهة صوتية متصلة بالجهاز. ويمكن أن يكون مصدر الإدخال الصوتي أيضًا من محادثة هاتفية.

في بعض الأحيان، قد يريد تطبيقان أو أكثر "التقاط" الإدخال الصوتي نفسه. ربما يؤدي مهام مختلفة. على سبيل المثال، قد تكون بعض التطبيقات التي تتلقّى الصوت "مسجّلة"، مثل مسجل صوتي بسيط، في حين قد تكون تطبيقات أخرى "مستمعًا"، مثل "مساعد Google" أو خدمة تسهيل الاستخدام التي تستجيب للأوامر الصوتية.

وفي كلتا الحالتَين، تريد هذه التطبيقات تلقّي إدخال صوتي. في هذه الصفحة، نستخدم مصطلح "التسجيل" بغض النظر عمّا إذا كان أحد التطبيقات يُسجّل الصوت أو يستمع إليه فقط.

إذا أراد تطبيقان أو أكثر تسجيل الصوت في الوقت نفسه، قد تحدث مشكلة في إرسال إشارة الصوت من المصدر نفسه إلى جميع التطبيقات. توضِّح هذه الصفحة كيفية مشاركة نظام Android لمدخلات الصوت بين تطبيقات متعددة تسجِّل الصوت.

السلوك في الإصدارات الأقدم من Android 10

قبل الإصدار 10 من Android، كان بإمكان تطبيق واحد فقط تسجيل بث الصوت المُدخل في كل مرة. إذا كان أحد التطبيقات يسجّل الصوت أو يستمع إليه، يمكن لتطبيقك إنشاء عنصر AudioRecord، ولكن ستظهر رسالة خطأ عند استدعاء AudioRecord.startRecording() ولن يبدأ التسجيل.

كان هناك استثناء واحد لهذه القاعدة، وهو عندما يكون لدى تطبيق مميّز (مثل "مساعد Google" أو خدمة تسهيل الاستخدام) الإذن android.permission.CAPTURE_AUDIO_HOTWORD وكان يستخدم مصدر صوت من النوع HOTWORD. في هذه الحالة، يمكن لتطبيق آخر بدء التسجيل. عند حدوث ذلك، تم إنهاء التطبيق المزوّد بامتيازات وتلقّى التطبيق الجديد الإدخال.

تم إجراء تغيير آخر في Android 9: يمكن للتطبيقات التي تعمل في المقدّمة فقط (أو الخدمة التي تعمل في المقدّمة) تسجيل الإدخال الصوتي. عندما بدأ تسجيل تطبيق لا يتضمن خدمة تعمل في المقدّمة أو مكونًا لواجهة المستخدم التي تعمل في المقدّمة، استمرّ التطبيق في العمل، ولكنّه أُخفي كتم الصوت، حتى لو كان التطبيق الوحيد الذي يلتقط الصوت في ذلك الوقت.

سلوك Android 10

كان السلوك قبل Android 10 هو "المستخدم الأقدم هو الأوّل". بعد أن يبدأ أحد التطبيقات في تسجيل الصوت، لا يمكن لأي تطبيقات أخرى الوصول إلى إدخال الصوت إلى أن يتوقف التطبيق عن تسجيل الصوت.

يفرض نظام التشغيل Android 10 مخطط أولوية يمكنه تبديل بث الصوت المُدخل بين التطبيقات أثناء تشغيلها. في معظم الحالات، إذا حصل تطبيق جديد على الإدخال الصوتي، يستمر تشغيل التطبيق الذي كان يُسجّل الصوت سابقًا، ولكنّه يتلقّى صمتًا. في بعض الحالات، يمكن للنظام مواصلة إرسال الصوت إلى كلا التطبيقَين. في ما يلي شرح لسيناريوهات المشاركة المختلفة.

يشبه هذا المخطط الطريقة التي يتعامل بها "تركيز الصوت" مع التطبيقات المتعدّدة التي تتصارع على استخدام مخرج الصوت. ومع ذلك، يتم إدارة تركيز الصوت من خلال الطلبات الآلية للحصول على التركيز وإزالته، في حين يستند أسلوب التبديل بين مصادر الإدخال описан هنا إلى سياسة تحديد الأولويات التي يتم تطبيقها تلقائيًا عندما يبدأ تطبيق جديد في تسجيل الصوت.

لأغراض تسجيل الصوت، يميز Android بين نوعَين من التطبيقات:

  • يُثبِّت المستخدم التطبيقات "العادية".
  • يتم تثبيت التطبيقات "المتميزة" مسبقًا على الجهاز. وتشمل هذه الخدمات "مساعد Google" وجميع خدمات تسهيل الاستخدام.

بالإضافة إلى ذلك، يتم التعامل مع التطبيق بشكل مختلف إذا كان يستخدم مصدرًا صوتيًا "حساسًا للخصوصية": CAMCORDER أو VOICE_COMMUNICATION.

في ما يلي قواعد تحديد الأولوية لاستخدام الإدخال الصوتي ومشاركته:

  • تكون التطبيقات المميّزة ذات أولوية أعلى من التطبيقات العادية.
  • تكون التطبيقات التي تعرض واجهة مستخدم مرئية في المقدّمة ذات أولوية أعلى من التطبيقات التي تعمل في الخلفية.
  • تكون التطبيقات التي تلتقط الصوت من مصدر حسّاس للخصوصية لها أولوية أعلى من التطبيقات التي لا تفعل ذلك.
  • لا يمكن لتطبيقين عاديين التقاط صوت في الوقت نفسه.
  • في بعض الحالات، يمكن لتطبيق مفوَّض مشاركة الإدخال الصوتي مع تطبيق آخر.
  • إذا كان هناك تطبيقان في الخلفية لهما الأولوية نفسها يسجّلان الصوت، يكون للتطبيق الذي تم تشغيله مؤخرًا أولوية أعلى.

مشاركة السيناريوهات

عندما يحاول تطبيقان تسجيل الصوت، قد يتمكّن كلاهما من تلقّي إشارة الإدخال، أو قد يتلقّى أحدهما صوتًا صامتًا.

هناك أربعة سيناريوهات رئيسية:

  • "مساعد Google" + تطبيق عادي
  • خدمة أدوات تسهيل الاستخدام + تطبيق عادي
  • تطبيقان عاديان
  • مكالمة صوتية + تطبيق عادي

"مساعد Google" + تطبيق عادي

"مساعد Google" هو تطبيق مفوَّض لأنّه مثبَّت مسبقًا ويحمل دور RoleManager.ROLE_ASSISTANT. ويتم التعامل بالطريقة نفسها مع أي تطبيق آخر مثبَّت مسبقًا لديه هذا الدور.

يشارك Android المحتوى الصوتي الذي يتم إدخاله وفقًا للقواعد التالية:

  • بإمكان "مساعد Google" استقبال صوت (بغض النظر عمّا إذا كان في المقدّمة أو الخلفية) ما لم يلتقط الصوت من قبل تطبيق آخر يستخدم مصدر صوت يراعي الخصوصية.

  • يتلقّى التطبيق الصوت ما لم يكن لدى "مساعد Google" عنصر واجهة مستخدم مرئي في أعلى الشاشة.

يُرجى العِلم أنّ كلا التطبيقَين لا يتلقّيان الصوت إلا عندما يكون "مساعد Google" في الخلفية ولا يُسجِّل التطبيق الآخر الصوت من مصدر صوت حسّاس للخصوصية.

خدمة أدوات تسهيل الاستخدام + تطبيق عادي

يتطلّب AccessibilityService بيانًا صارمًا.

يشارك Android المحتوى الصوتي الذي يتم إدخاله وفقًا للقواعد التالية:

  • إذا كانت واجهة المستخدم الخاصة بالخدمة في أعلى الشاشة، ستتلقّى كل من الخدمة والتطبيق إدخالًا صوتيًا. يقدّم هذا السلوك وظائف مثل التحكّم في مكالمة صوتية أو تسجيل فيديو باستخدام الطلبات الصوتية.

  • إذا لم تكن الخدمة في أعلى الصفحة، يتم التعامل مع هذه الحالة كما هو الحال مع حالة التطبيقَين العادية أدناه.

تطبيقان عاديان

عندما يسجِّل تطبيقان الصوت في الوقت نفسه، يتلقّى تطبيق واحد فقط الصوت ويتلقّى الآخر صمتًا.

يشارك Android المحتوى الصوتي الذي يتم إدخاله وفقًا للقواعد التالية:

  • إذا لم يكن أي من التطبيقَين حسّاسًا من حيث الخصوصية، يتلقّى التطبيق الذي يعرض واجهة المستخدم في أعلى الشاشة الصوت. إذا لم يكن أي من التطبيقين يشتمل على واجهة مستخدم، فهذا يعني أن التطبيق الذي بدأ التقاط آخر صوت يتلقَّى الصوت.
  • إذا كان أحد التطبيقات حسّاسًا من حيث الخصوصية، سيتلقّى محتوى صوتيًا وسيكون المحتوى في التطبيق الآخر صامتًا حتى إذا كان يتضمّن واجهة مستخدم في أعلى الشاشة أو بدأ بالتقاط الصوت مؤخرًا.
  • وإذا كان كِلا التطبيقين حساسَين للخصوصية، يبدأ التطبيق الذي بدأ التقاط الصوت حديثًا يتلقّى التطبيق الآخر في كتم الصوت.

مكالمة صوتية + تطبيق عادي

تكون المكالمة الصوتية نشطة إذا كان وضع الصوت الذي يعرضه الرمز AudioManager.getMode() هو MODE_IN_CALL أو MODE_IN_COMMUNICATION.

يشارك Android المحتوى الصوتي الذي يتم إدخاله وفقًا للقواعد التالية:

سلوك Android 11

يتّبع الإصدار 11 من نظام التشغيل Android (المستوى 30 لواجهة برمجة التطبيقات) مخطّط الأولوية في الإصدار 10 من Android описан أعلاه. وتوفّر أيضًا طرقًا جديدة في AudioRecord وMediaRecorder و AAudioStream تتيح تفعيل إمكانية تسجيل الصوت في الوقت نفسه أو إيقافها، بغض النظر عن حالة الاستخدام المحدّدة.

في ما يلي الطرق الجديدة:

عندما يكون setPrivacySensitive() هو true، تكون حالة استخدام الالتقاط خاصة ولا يمكن حتى لتطبيق "مساعد Google" المفوَّض التقاط البيانات بشكل متزامن. يلغِي هذا الإعداد السلوك التلقائي الذي يعتمد على مصدر الصوت. على سبيل المثال، VOICE_COMMUNICATION خاصة تلقائيًا ولكن UNPROCESSED ليست كذلك.

تغييرات الإعدادات

عندما تلتقط عدة تطبيقات الصوت في الوقت نفسه، يكون تطبيق واحد أو تطبيقان فقط "نشطَين" (يتلقّيان الصوت)، ويتم كتم صوت التطبيقات الأخرى (لا يتلقّى أي صوت). عند تغيير التطبيقات النشطة، قد يعيد إطار العمل الصوتي ضبط مسارات الصوت وفقًا للقواعد التالية:

  • قد يتغير جهاز إدخال الصوت لكل تطبيق نشط (على سبيل المثال، من الميكروفون المدمج إلى سماعة رأس بلوتوث المرفقة).
  • تم تفعيل المعالجة المسبقة المرتبطة بالتطبيق النشط ذي الأولوية القصوى. ويتم تجاهل كل المعالجة المسبقة الأخرى.

بما أنّه قد يتم كتم صوت تطبيق نشط عندما يصبح تطبيق ذو أولوية أعلى نشطًا، يمكنك تسجيل AudioManager.AudioRecordingCallback في AudioRecord أو MediaRecorder لتلقّي إشعار عند تغيير الإعدادات. يمكن أن تكون التغييرات المحتملة على النحو التالي:

  • تسجيل الصوت مع كتمه أو بدون كتمه
  • تم تغيير الجهاز
  • تم تغيير المعالجة المسبقة
  • تغيّرت خصائص مصدر البيانات (معدّل أخذ العينات وقناع القناة وتنسيق العيّنة)

يجب الاتصال برقم AudioRecord.registerAudioRecordingCallback() قبل بدء عملية الالتقاط. لا يتم تنفيذ طلب إعادة الاتصال إلا عندما يتلقّى التطبيق الصوت ويحدث تغيير.

تُرجع الطريقة onRecordingConfigChanged() AudioRecordingConfiguration يحتوي على حالة تسجيل الصوت الحالية. استخدم الطرق التالية لمعرفة المزيد عن التغيير:

isClientSilenced()
يعرض القيمة "صحيح" إذا كان يتم كتم صوت المقطع الصوتي الذي يتم إرجاعه إلى العميل حاليًا بسبب سياسة التسجيل.
getAudioDevice()
عرض الجهاز السماعي النشط
getEffects()
عرض التأثير النشط قبل المعالجة. يُرجى العِلم أنّ التأثير النشط قد لا يكون مطابقًا للتأثير الذي تم عرضه من خلال getClientEffects() إذا لم يكن البرنامج هو التطبيق النشط ذي الأولوية القصوى.
getFormat()
تعرض خصائص مصدر البيانات. يُرجى العِلم أنّ بيانات الصوت الفعلية التي يتلقّاها العميل تلتزم دائمًا بالتنسيق المطلوب الذي يعرضه getClientFormat(). يُجري إطار العمل تلقائيًا عمليات إعادة أخذ العينات والتحويل اللازمة للقنوات والتنسيقات من التنسيق المستخدَم في واجهة الجهاز إلى التنسيق الذي يحدّده العميل.
AudioRecord.getActiveRecordingConfiguration().
عرض إعدادات التسجيل النشطة.

يمكنك الحصول على عرض عام لجميع التسجيلات النشطة على الجهاز من خلال الاتصال بالرقم AudioManager.getActiveRecordingConfigurations().