L'input audio proviene solitamente dal microfono integrato, da un microfono esterno o da un'interfaccia audio collegata al dispositivo. L'input audio può provenire anche 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 audio potrebbero essere "in registrazione", come un semplice registratore vocale, mentre altre app potrebbero essere "in ascolto", come l'Assistente Google o un servizio di accessibilità che risponde ai comandi vocali.
In entrambi i casi, queste app vogliono ricevere 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 audio contemporaneamente, potrebbe esserci un problema con la distribuzione del segnale audio dalla stessa origine a tutte. 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 solo da un'app alla
volta. Se un'app stava già registrando o ascoltando l'audio, la tua app potrebbe
creare un oggetto AudioRecord
, ma verrà restituito un errore quando chiami
AudioRecord.startRecording()
e la registrazione non verrà 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 iniziare a registrare. Quando ciò è accaduto, l'app
con privilegi è stata chiusa 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 essere eseguita, ma non riceveva audio, anche se era l'unica app che acquisiva 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 sta acquisendo l'audio non si arresta.
Android 10 impone uno schema di priorità che può cambiare il flusso audio di input tra le app durante l'esecuzione. Nella maggior parte dei casi, se una nuova app acquisisce l'input audio, l'app che acquisiva in precedenza continua a essere eseguita, ma riceve silenzio. In alcuni casi, il sistema può continuare a riprodurre l'audio in entrambe le app. Di seguito sono illustrati i vari scenari di condivisione.
Questo schema è simile al modo in cui la messa a fuoco audio gestisce più app che competono per l'utilizzo dell'output audio. Tuttavia, la messa a fuoco dell'audio viene gestita da richieste programmatiche per ottenere e rilasciare la messa a fuoco, mentre lo schema di commutazione dell'input descritto qui si basa su una norma di assegnazione delle priorità che viene applicata automaticamente ogni volta che una nuova app inizia ad acquisire audio.
Ai fini dell'acquisizione audio, Android distingue due tipi di app:
- Le app "normali" 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 assegnazione delle priorità per l'utilizzo e la condivisione dell'input audio sono le seguenti:
- Le app con privilegi hanno una priorità maggiore rispetto alle app comuni.
- Le app con UI di primo piano visibili hanno una priorità maggiore rispetto alle app in background.
- Le app che acquisiscono audio da una fonte sensibile alla privacy hanno una priorità maggiore rispetto alle app che non lo fanno.
- Due app ordinarie non possono mai acquisire 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 una priorità più alta.
Scenari di condivisione
Quando due app tentano di acquisire 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 normale
- Servizio di accessibilità + app ordinaria
- Due app comuni
- Chiamata vocale + app normale
Assistente + app normale
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 a queste regole:
L'assistente può ricevere 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 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 audio 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 a queste regole:
Se l'interfaccia utente del servizio è in primo piano, sia il servizio che l'app ricevono l'input audio. Questo comportamento offre funzionalità come il controllo di una chiamata vocale o dell'acquisizione 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 comuni
Quando due app acquisiscono contemporaneamente, solo una riceve l'audio, mentre l'altra non riceve nulla.
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'interfaccia utente, quella che ha iniziato la registrazione più di recente riceve l'audio.
- Se una delle app è sensibile alla privacy, riceve l'audio, mentre l'altra app non riceve nulla, anche se ha un'interfaccia utente 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, mentre 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 a queste regole:
- La chiamata riceve sempre l'audio.
- L'app può acquisire audio se è un servizio di accessibilità.
L'app può acquisire la chiamata vocale se è un'app privilegiata (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_UPLINK
oMediaRecorder.AudioSource.VOICE_DOWNLINK
, e/o il dispositivoAudioDeviceInfo.TYPE_TELEPHONY
.
Comportamento di Android 11
Android 11 (livello API 30) rispetta lo schema di priorità di Android 10
descritto sopra. Fornisce inoltre nuovi metodi in AudioRecord
, MediaRecorder
e
AAudioStream
che attivano e disattivano la possibilità di acquisire 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
, lo scenario di utilizzo dell'acquisizione è privato e anche
un assistente con privilegi non può acquisire contemporaneamente. Questa impostazione sostituisce il
comportamento predefinito che dipende dalla sorgente audio. Ad esempio,
VOICE_COMMUNICATION
è privato per impostazione predefinita, ma UNPROCESSED
no.
Modifiche alla configurazione
Quando più app acquisiscono audio contemporaneamente, solo una o due sono "attive" (ricevono 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 headset Bluetooth collegato).
- Viene attivato il pre-elaborazione associato all'app attiva con la priorità più alta. Tutte le altre pre-elaborazioni vengono ignorate.
Poiché un'app attiva potrebbe essere silenziata 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 silenziata o non silenziata
- Dispositivo cambiato
- Pre-elaborazione modificata
- Proprietà dello stream modificate (frequenza di campionamento, maschera dei canali, formato del campione)
Devi chiamare
AudioRecord.registerAudioRecordingCallback()
prima dell'inizio dell'acquisizione.
Il callback viene eseguito solo quando l'app riceve audio e si verifica una modifica.
Il metodo onRecordingConfigChanged()
restituisce un AudioRecordingConfiguration
contenente lo stato attuale dell'acquisizione audio. Utilizza i seguenti
metodi per scoprire di più sulla modifica:
isClientSilenced()
- Restituisce true se l'audio restituito al client è attualmente silenziato a causa delle norme 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 quelli restituiti 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 panoramica generale di tutte le registrazioni attive sul dispositivo chiamando
AudioManager.getActiveRecordingConfigurations()
.