קלט האודיו מגיע בדרך כלל מהמיקרופון המובנה, ממיקרופון חיצוני או מממשק אודיו שמחובר למכשיר. קלט אודיו יכול להגיע גם משיחה בטלפון.
לפעמים שתי אפליקציות או יותר רוצות "לתעד" את אותו קלט אודיו. יכול להיות שהם מבצעים משימות שונות. לדוגמה, אפליקציות מסוימות שמקבלות אודיו עשויות 'להקליט', כמו מכשיר הקלטה פשוט, ואילו אפליקציות אחרות עשויות 'להקשיב', כמו Google Assistant או שירות נגישות שמגיב לפקודות קוליות.
בכל מקרה, האפליקציות האלה רוצות לקבל קלט אודיו. במהלך הדף הזה אנחנו משתמשים במונח 'תיעוד', גם אם האפליקציה מתעדת וגם אם היא רק מקשיבה.
אם שתי אפליקציות או יותר רוצות לתעד אודיו בו-זמנית, יכולה להיות בעיה בהעברת אות האודיו מאותו מקור לכל האפליקציות. בדף הזה מוסבר איך מערכת Android משתפת קלט אודיו בין כמה אפליקציות שמצלמות אודיו.
התנהגות לפני Android 10
לפני Android 10, רק אפליקציה אחת בכל פעם יכולה הייתה לתעד את סטרימינג האודיו של הקלט. אם אפליקציה כלשהי כבר הקליטה או הקשתה אודיו, האפליקציה שלכם כן תוכל ליצור אובייקט AudioRecord
, אבל תוחזר הודעת שגיאה כשתפעילו את השיטה AudioRecord.startRecording()
וההקלטה לא תתחיל.
חריג אחד לכלל הזה היה כשאפליקציה בעלת הרשאות (כמו Google Assistant או שירות נגישות) קיבלה את ההרשאה android.permission.CAPTURE_AUDIO_HOTWORD
והשתמשה במקורות אודיו מסוג HOTWORD
. במקרה כזה, אפליקציה אחרת עשויה להתחיל להקליט. במקרה כזה, האפליקציה עם ההרשאות הסתיימה והאפליקציה החדשה תיעדה את הקלט.
עוד שינוי נוסף נוסף ב-Android 9: רק אפליקציות שפועלות בחזית (או שירות בחזית) יכולות לתעד את קלט האודיו. כשאפליקציה ללא שירות שפועל בחזית או רכיב ממשק משתמש בחזית התחילה לצלם, האפליקציה המשיכה לפעול אבל קיבלה שתיקה, גם אם היא הייתה האפליקציה היחידה שצילמה אודיו באותו זמן.
התנהגות ב-Android 10
לפני Android 10, ההתנהגות הייתה 'כל הקודם זוכה'. אחרי שאפליקציה מתחילה לצלם אודיו, לאפליקציות אחרות אין גישה לקלט האודיו עד שהאפליקציה שמצלמת אודיו תפסיק.
ב-Android 10 יש תוכנית עדיפות שיכולה להעביר את מקור האודיו בין אפליקציות בזמן שהן פועלות. ברוב המקרים, אם אפליקציה חדשה מקבלת את קלט האודיו, האפליקציה שצילמה קודם ממשיכה לפעול אבל מקבלת שתיקה. במקרים מסוימים, המערכת יכולה להמשיך להעביר אודיו לשתי האפליקציות. בהמשך מוסבר על תרחישים השיתוף השונים.
הסכימה הזו דומה לאופן שבו התכונה 'מיקוד אודיו' מטפלת בכמה אפליקציות שמתחרות על השימוש בפלט האודיו. עם זאת, ההתמקדות באודיו מנוהלת באמצעות בקשות פרוגרמטיות לקבלת התמקדות ולהסרת התמקדות, ואילו הסכימה למעבר בין מקורות הקלט שמתוארת כאן מבוססת על מדיניות תעדוף שחלה באופן אוטומטי בכל פעם שאפליקציה חדשה מתחילה לצלם אודיו.
לצורך הקלטת אודיו, מערכת Android מבדילה בין שני סוגים של אפליקציות:
- אפליקציות 'רגילות' מותקנות על ידי המשתמש.
- אפליקציות 'בעלות הרשאות' מותקנות מראש במכשיר. אלה כוללים את Google Assistant ואת כל שירותי הנגישות.
בנוסף, המערכת מתייחסת לאפליקציה באופן שונה אם היא משתמשת במקור אודיו 'רגיש לפרטיות': CAMCORDER
או VOICE_COMMUNICATION
.
אלה כללי העדיפות לשימוש בשדה הקלט של האודיו ולשיתוף שלו:
- לאפליקציות עם הרשאות יש עדיפות גבוהה יותר מאפליקציות רגילות.
- לאפליקציות עם ממשקי משתמש גלויים בחזית יש עדיפות גבוהה יותר מאפליקציות ברקע.
- לאפליקציות שמצלמות אודיו ממקור רגיש לפרטיות יש עדיפות גבוהה יותר מאשר לאפליקציות שלא עושות זאת.
- שתי אפליקציות רגילות לא יכולות לצלם אודיו בו-זמנית.
- במקרים מסוימים, אפליקציה עם הרשאות יכולה לשתף קלט אודיו עם אפליקציה אחרת.
- אם שתי אפליקציות ברקע עם אותה עדיפות מתעדות אודיו, לאפליקציה האחרונה שהופעלתי תהיה עדיפות גבוהה יותר.
תרחישים של שיתוף
כששתי אפליקציות מנסו לצלם אודיו, יכול להיות ששתיהן הצליחו לקבל את אותות הקלט, או שרק אחת מהן קיבלה שתיקה.
יש ארבעה תרחישים עיקריים:
- Assistant + אפליקציה רגילה
- שירות נגישות + אפליקציה רגילה
- שתי אפליקציות רגילות
- שיחה קולית + אפליקציה רגילה
Assistant + אפליקציה רגילה
Assistant היא אפליקציה בעלת הרשאות כי היא מותקנת מראש ויש לה את התפקיד RoleManager.ROLE_ASSISTANT
.
כל אפליקציה מותקנת מראש עם התפקיד הזה מטופלת באופן דומה.
Android משתף את אודיו הקלט לפי הכללים הבאים:
Assistant יכולה לקבל אודיו (לא משנה אם הוא בחזית או ברקע) אלא אם אפליקציה אחרת שמשתמשת במקור אודיו רגיש לפרטיות כבר מתעדת.
האפליקציה מקבלת אודיו, אלא אם ל-Assistant יש רכיב ממשק משתמש גלוי בחלק העליון של המסך.
לתשומת ליבכם: שתי האפליקציות מקבלות אודיו רק כש-Assistant פועלת ברקע והאפליקציה השנייה לא מתעדת מקור אודיו רגיש לפרטיות.
שירות נגישות + אפליקציה רגילה
ל-AccessibilityService
נדרשת הצהרה קפדנית.
Android משתף את אודיו הקלט לפי הכללים הבאים:
אם ממשק המשתמש של השירות נמצא בחלק העליון, גם השירות וגם האפליקציה מקבלים קלט אודיו. ההתנהגות הזו מאפשרת פונקציונליות כמו שליטה בשיחה קולית או בצילומי וידאו באמצעות פקודות קוליות.
אם השירות לא מופיע בחלק העליון, המערכת תתייחס למקרה הזה כמו למקרה הרגיל של שתי אפליקציות שמתואר בהמשך.
שתי אפליקציות רגילות
כששתי אפליקציות מתעדות בו-זמנית, רק באחת מהן מתקבל אודיו ובשנייה מתקבל שקט.
Android משתף את אודיו הקלט לפי הכללים הבאים:
- אם אף אחת מהאפליקציות לא רגישת לפרטיות, האפליקציה עם ממשק המשתמש בחלק העליון תקבל את האודיו. אם לאף אחת מהאפליקציות אין ממשק משתמש, האודיו יועבר לאפליקציה שהתחילה את הצילום לאחרונה.
- אם אחת מהאפליקציות רגישת לפרטיות, היא תקבל אודיו והאפליקציה השנייה תקבל שתיקה, גם אם יש לה ממשק משתמש בחלק העליון או שהיא התחילה לצלם לאחרונה.
- אם שתי האפליקציות רגישות לפרטיות, האפליקציה שהתחילה לצלם לאחרונה תקבל אודיו והאפליקציה השנייה תקבל שתיקה.
שיחה קולית + אפליקציה רגילה
שיחת קול פעילה אם מצב האודיו שמוחזר על ידי AudioManager.getMode()
הוא MODE_IN_CALL
או MODE_IN_COMMUNICATION
.
Android משתף את אודיו הקלט לפי הכללים הבאים:
- תמיד יש אודיו בשיחה.
- האפליקציה יכולה לתעד אודיו אם היא שירות נגישות.
האפליקציה יכולה לתעד את השיחה הקולית אם היא אפליקציה בעלת הרשאות (שהותקנה מראש) עם ההרשאה
CAPTURE_AUDIO_OUTPUT
.כדי לתעד את ה-uplink (TX) או ה-downlink (RX) של שיחת הקול, או את שניהם, האפליקציה צריכה לציין את מקורות האודיו
MediaRecorder.AudioSource.VOICE_UPLINK
אוMediaRecorder.AudioSource.VOICE_DOWNLINK
, ו/או את המכשירAudioDeviceInfo.TYPE_TELEPHONY
.
ההתנהגות ב-Android 11
ב-Android 11 (רמת API 30) חל הסדר העדיפויות של Android 10 שמתואר למעלה. בנוסף, היא מספקת שיטות חדשות ב-AudioRecord
, ב-MediaRecorder
וב-AAudioStream
שמאפשרות להשבית ולהפעיל את היכולת לצלם אודיו בו-זמנית, ללא קשר לתרחיש לדוגמה שנבחר.
אלה השיטות החדשות:
AudioRecord.Builder.setPrivacySensitive()
AudioRecord.isPrivacySensitive()
MediaRecorder.setPrivacySensitive()
MediaRecorder.isPrivacySensitive()
AAudioStreamBuilder_setPrivacySensitive()
AAudioStream_isPrivacySensitive()
כשהערך של setPrivacySensitive()
הוא true
, תרחיש השימוש בצילום הוא פרטי ואפילו Assistant עם הרשאות לא יכולה לצלם בו-זמנית. ההגדרה הזו מבטלת את התנהגות ברירת המחדל, שמשתנה בהתאם למקור האודיו. לדוגמה, כברירת מחדל, VOICE_COMMUNICATION
הוא פרטי אבל UNPROCESSED
לא.
שינויים בהגדרות
כשמספר אפליקציות מתעדות אודיו בו-זמנית, רק אחת או שתיים מהן הן 'פעילות' (מקבלות אודיו). שאר האפליקציות מושתקות (מקבלות שתיקה). כשהאפליקציות הפעילות משתנות, מסגרת האודיו עשויה להגדיר מחדש את נתיבי האודיו לפי הכללים הבאים:
- ייתכן שמכשיר קלט האודיו של כל אפליקציה פעילה ישתנה (לדוגמה, מהמיקרופון המובנה לאוזניות Bluetooth מחוברות).
- העיבוד המקדים שמשויך לאפליקציה הפעילה עם העדיפות הגבוהה ביותר מופעל. המערכת מתעלמת מכל עיבוד מקדים אחר.
מכיוון שאפליקציה פעילה עשויה להשתתק כשאפליקציה עם תעדוף גבוה יותר הופכת לפעילה, אפשר לרשום AudioManager.AudioRecordingCallback באובייקט AudioRecord
או MediaRecorder
כדי לקבל התראה כשההגדרה משתנה.
השינויים האפשריים יכולים להיות:
- לצלם כשהשיחה מושתקת או כשהיא לא מושתקת
- המכשיר השתנה
- עיבוד מקדים השתנה
- מאפייני הסטרימינג השתנו (קצב דגימה, מסכת ערוץ, פורמט דגימה)
צריך להתקשר למזהה AudioRecord.registerAudioRecordingCallback()
לפני שמתחילים את הצילום.
הקריאה החוזרת מבוצעת רק כשהאפליקציה מקבלת אודיו ומתרחשים שינויים.
השיטה onRecordingConfigChanged()
מחזירה AudioRecordingConfiguration
שמכיל את מצב הצילום הנוכחי של האודיו. תוכלו להיעזר בשיטות הבאות כדי לקבל מידע על השינוי:
isClientSilenced()
- הפונקציה מחזירה את הערך true אם האודיו שהוחזר ללקוח מושתק כרגע בגלל מדיניות הצילום.
getAudioDevice()
- החזרת מכשיר האודיו הפעיל.
getEffects()
- מחזירה את אפקט העיבוד המקדים הפעיל. שימו לב: יכול להיות שהאפקט הפעיל לא יהיה זהה לאפקטים שמוחזרים על ידי
getClientEffects()
אם הלקוח הוא לא האפליקציה הפעילה עם העדיפות הגבוהה ביותר. getFormat()
- החזרת מאפייני הסטרימינג. שימו לב שנתוני האודיו בפועל שהלקוח מקבל תמיד תואמים לפורמט הנדרש שמוחזרים על ידי
getClientFormat()
. המסגרת מבצעת באופן אוטומטי את ההמרות הנדרשות של הדגימה מחדש, הערוץ והפורמט מהפורמט שבו נעשה שימוש בממשק החומרה לפורמט שצוין על ידי הלקוח. AudioRecord.getActiveRecordingConfiguration()
.- מחזירה את הגדרת הצילום הפעילה.
כדי לקבל תצוגה כללית של כל ההקלטות הפעילות במכשיר, אפשר להפעיל את הפקודה AudioManager.getActiveRecordingConfigurations()
.