L'input audio di solito proviene dal microfono integrato, da un microfono esterno o da un'interfaccia audio collegata al dispositivo. L'input audio può anche provenire da una conversazione telefonica.
A volte due o più app potrebbero voler "acquisire" lo stesso input audio. Potrebbero svolgere attività diverse. Ad esempio, alcune app che ricevono l'audio potrebbero "registrare", come un semplice registratore vocale, mentre altre app potrebbero "ascoltare", come l'Assistente Google o un servizio di accessibilità che risponde ai comandi vocali.
In entrambi i casi, queste app vogliono ricevere l'input audio. In questa pagina, utilizziamo il termine "acquisizione" indipendentemente dal fatto che un'app stia registrando o solo ascoltando.
Se due o più app vogliono acquisire l'audio contemporaneamente, potrebbe esserci un problema con la trasmissione del segnale audio dalla stessa sorgente a tutte le app. Questa pagina descrive in che modo il sistema Android condivide l'input audio tra più app che acquisiscono audio.
Comportamento precedente ad Android 10
Prima di Android 10, lo stream audio di input poteva essere acquisito da una sola app alla volta. Se un'app stava già registrando o ascoltando l'audio, la tua app poteva creare un oggetto AudioRecord, ma veniva restituito un errore quando chiamavi AudioRecord.startRecording() e la registrazione non veniva avviata.
Un'eccezione a questa regola si verificava quando un'app con privilegi (come l'Assistente Google o un servizio di accessibilità) disponeva dell'autorizzazione android.permission.CAPTURE_AUDIO_HOTWORD e utilizzava una sorgente audio di tipo HOTWORD. In questo caso, un'altra app potrebbe avviare la registrazione. In questo caso, l'app con privilegi è stata terminata e la nuova app ha acquisito l'input.
In Android 9 è stata aggiunta un'altra modifica: solo le app in esecuzione in primo piano (o un servizio in primo piano) potevano acquisire l'input audio. Quando un'app senza un servizio in primo piano o un componente UI in primo piano iniziava l'acquisizione, l'app continuava a funzionare, ma riceveva silenzio, anche se era l'unica app ad acquisire audio in quel momento.
Comportamento di Android 10
Il comportamento precedente ad Android 10 è "primo arrivato, primo servito". Una volta che un'app inizia ad acquisire l'audio, nessun'altra app può accedere all'input audio finché l'app che acquisisce l'audio non si interrompe.
Android 10 impone uno schema di priorità che può cambiare lo stream audio di input tra le app mentre sono in esecuzione. Nella maggior parte dei casi, se una nuova app acquisisce l'input audio, l'app che lo acquisiva in precedenza continua a funzionare, ma non riceve alcun suono. In alcuni casi, il sistema può continuare a trasmettere l'audio a entrambe le app. Di seguito sono illustrati i vari scenari di condivisione.
Questo schema è simile al modo in cui l'audio focus gestisce più app che competono per l'utilizzo dell'output audio. Tuttavia, l'audio focus è gestito da richieste programmatiche per acquisire e rilasciare il focus, mentre lo schema di cambio di input descritto qui si basa su una policy di assegnazione delle priorità che viene applicata automaticamente ogni volta che una nuova app inizia ad acquisire l'audio.
Ai fini dell'acquisizione dell'audio, Android distingue due tipi di app:
- Le app "ordinarie" vengono installate dall'utente.
- Le app "con privilegi" sono preinstallate sul dispositivo. Questi includono l'Assistente Google e tutti i servizi di accessibilità.
Inoltre, un'app viene trattata in modo diverso se utilizza una sorgente audio "sensibile alla privacy": CAMCORDER o VOICE_COMMUNICATION.
Le regole di priorità per l'utilizzo e la condivisione dell'input audio sono le seguenti:
- Le app con privilegi hanno una priorità maggiore rispetto alle app ordinarie.
- Le app con UI in primo piano visibili hanno una priorità maggiore rispetto alle app in background.
- Le app che acquisiscono l'audio da una sorgente sensibile alla privacy hanno una priorità maggiore rispetto alle app che non lo fanno.
- Due app normali non possono mai acquisire l'audio contemporaneamente.
- In alcune situazioni, un'app con privilegi può condividere l'input audio con un'altra app.
- Se due app in background con la stessa priorità acquisiscono audio, l'ultima avviata ha la priorità più alta.
Scenari di condivisione
Quando due app tentano di acquisire l'audio, entrambe potrebbero essere in grado di ricevere il segnale di input oppure una delle due potrebbe ricevere il silenzio.
Esistono quattro scenari principali:
- Assistente + app ordinaria
- Servizio di accessibilità + app ordinaria
- Due app normali
- Chiamata vocale + app normale
Assistente + app ordinaria
L'assistente è un'app con privilegi perché è preinstallata e ha il ruolo RoleManager.ROLE_ASSISTANT. Qualsiasi altra app preinstallata con questo ruolo viene trattata in modo simile.
Android condivide l'audio di input in base alle seguenti regole:
L'assistente può ricevere l'audio (indipendentemente dal fatto che sia in primo piano o in background), a meno che un'altra app che utilizza una sorgente audio sensibile alla privacy non stia già acquisendo l'audio.
L'app riceve l'audio, a meno che l'assistente non abbia un componente UI visibile nella parte superiore dello schermo.
Tieni presente che entrambe le app ricevono l'audio solo quando l'assistente è in background e l'altra app non acquisisce da una sorgente audio sensibile alla privacy.
Servizio di accessibilità + app ordinaria
Un AccessibilityService richiede una dichiarazione rigorosa.
Android condivide l'audio di input in base alle seguenti regole:
Se la UI del servizio è in primo piano, sia il servizio sia l'app ricevono l'input audio. Questo comportamento offre funzionalità come il controllo di una chiamata vocale o l'acquisizione di video con i comandi vocali.
Se il servizio non è in primo piano, questo caso viene trattato come il normale caso di due app riportato di seguito.
Due app normali
Quando due app acquisiscono contemporaneamente, solo una riceve l'audio, mentre l'altra riceve il silenzio.
Android condivide l'audio di input in base a queste regole:
- Se nessuna delle due app è sensibile alla privacy, l'app con un'interfaccia utente in primo piano riceve l'audio. Se nessuna delle due app ha un'UI, l'audio viene ricevuto da quella che ha avviato l'acquisizione più di recente.
- Se una delle app è sensibile alla privacy, riceve l'audio e l'altra app riceve il silenzio anche se ha un'UI in primo piano o ha iniziato l'acquisizione più di recente.
- Se entrambe le app sono sensibili alla privacy, l'app che ha iniziato l'acquisizione più di recente riceve l'audio e l'altra riceve il silenzio.
Chiamata vocale + app normale
Una chiamata vocale è attiva se la modalità audio restituita da
AudioManager.getMode() è MODE_IN_CALL o
MODE_IN_COMMUNICATION.
Android condivide l'audio di input in base alle seguenti regole:
- La chiamata riceve sempre l'audio.
- L'app può acquisire l'audio se è un servizio di accessibilità.
L'app può acquisire la chiamata vocale se è un'app con privilegi (preinstallata) con l'autorizzazione
CAPTURE_AUDIO_OUTPUT.Per acquisire l'uplink (TX), il downlink (RX) o entrambi della chiamata vocale, l'app deve specificare le sorgenti audio
MediaRecorder.AudioSource.VOICE_UPLINKoMediaRecorder.AudioSource.VOICE_DOWNLINKe/o il dispositivoAudioDeviceInfo.TYPE_TELEPHONY.
Comportamento di Android 11
Android 11 (livello API 30) rispetta lo schema di priorità di Android 10 descritto sopra. Inoltre, fornisce nuovi metodi in AudioRecord, MediaRecorder e AAudioStream che attivano e disattivano la possibilità di acquisire l'audio contemporaneamente, indipendentemente dal caso d'uso selezionato.
I nuovi metodi sono:
AudioRecord.Builder.setPrivacySensitive()AudioRecord.isPrivacySensitive()MediaRecorder.setPrivacySensitive()MediaRecorder.isPrivacySensitive()AAudioStreamBuilder_setPrivacySensitive()AAudioStream_isPrivacySensitive()
Quando setPrivacySensitive() è true, il caso d'uso di acquisizione è privato e nemmeno un assistente con privilegi può acquisire contemporaneamente. Questa impostazione sostituisce il comportamento predefinito che dipende dalla sorgente audio. Ad esempio, VOICE_COMMUNICATION è privato per impostazione predefinita, ma UNPROCESSED non lo è.
Modifiche alla configurazione
Quando più app acquisiscono l'audio contemporaneamente, solo una o due sono "attive" (ricevono l'audio); le altre sono disattivate (ricevono silenzio). Quando le app attive cambiano, il framework audio potrebbe riconfigurare i percorsi audio in base a queste regole:
- Il dispositivo di input audio per ogni app attiva potrebbe cambiare (ad esempio, dal microfono integrato a un paio di cuffie Bluetooth collegate).
- Viene attivata la pre-elaborazione associata all'app attiva con la priorità più alta. Tutte le altre pre-elaborazioni vengono ignorate.
Poiché un'app attiva potrebbe essere disattivata quando un'app con priorità più alta diventa attiva, puoi registrare un AudioManager.AudioRecordingCallback sull'oggetto AudioRecord o MediaRecorder per ricevere una notifica quando la configurazione cambia. Le possibili modifiche potrebbero essere:
- Acquisizione con audio disattivato o riattivato
- Dispositivo modificato
- Pre-elaborazione modificata
- Le proprietà dello stream sono cambiate (frequenza di campionamento, maschera del canale, formato di campionamento)
Devi chiamare AudioRecord.registerAudioRecordingCallback() prima di avviare l'acquisizione. Il callback viene eseguito solo quando l'app riceve l'audio e si verifica una modifica.
Il metodo onRecordingConfigChanged() restituisce un AudioRecordingConfiguration contenente lo stato di acquisizione audio corrente.
Utilizza i seguenti metodi per scoprire di più sulla modifica:
isClientSilenced()- Restituisce true se l'audio restituito al client è attualmente disattivato a causa della policy di acquisizione.
getAudioDevice()- Restituisce il dispositivo audio attivo.
getEffects()- Restituisce l'effetto di pre-elaborazione attivo. Tieni presente che l'effetto attivo potrebbe non essere lo stesso di quello restituito da
getClientEffects()se il client non è l'app attiva con la priorità più alta. getFormat()- Restituisce le proprietà dello stream. Tieni presente che i dati audio effettivi ricevuti dal client rispettano sempre il formato richiesto restituito da
getClientFormat(). Il framework esegue automaticamente la conversione necessaria di ricampionamento, canale e formato dal formato utilizzato nell'interfaccia hardware al formato specificato dal client. AudioRecord.getActiveRecordingConfiguration()- Restituisce la configurazione di registrazione attiva.
Puoi ottenere una visualizzazione generale di tutte le registrazioni attive sul dispositivo chiamando
AudioManager.getActiveRecordingConfigurations().