• Nenhum resultado encontrado

5.2 Processamento de ´ audio em tempo real em Android

5.2.1 Fontes de sinais de ´ audio

O n´ıvel de abstra¸c˜ao proporcionado pela utiliza¸c˜ao da API em Java em um sistema operacional baseado em Linux (e portanto nos padr˜oes POSIX14) permite o acesso a diversas fontes de sinais de ´audio. Algumas limita¸c˜oes s˜ao impostas pelo esquema de permiss˜oes do sistema mas, como veremos, n˜ao impedem a implementa¸c˜ao de alternativas para acesso `as diversas fontes de sinais.

Poss´ıveis fontes de sinais de ´audio s˜ao: arquivos de ´audio (representados por diversos tipos de codifica¸c˜ao), microfones (`as vezes h´a mais de um microfone em um dispositivo) e sinais transmitidos por rede (Wi-Fi, 3G, etc). Cada tipo de fonte ser´a descrita separadamente a seguir.

Obtendo sinais de ´audio do microfone

O acesso ao sinal de ´audio capturado pelo microfone ´e feito atrav´es da classe AudioRecord15, que permite a configura¸c˜ao de diversos parˆametros para acesso a um buffer com os valores das amostras. Ao instanciar um objeto desta classe, devem ser informados a forma de acesso ao mi- crofone (detalhada a seguir), a taxa de amostragem desejada, o n´umero de canais, o formato das amostras de ´audio (8 ou 16 bits) e o tamanho do buffer onde ser˜ao escritas as amostras.

O microfone de um aparelho m´ovel ´e geralmente utilizado para capturar a voz do usu´ario em diferentes situa¸c˜oes como, por exemplo, durante uma chamada, durante a grava¸c˜ao de lembretes ou para processamento por aplicativos de reconhecimento de voz. ´E por causa dessa diversidade de aplica¸c˜oes que ´e necess´ario informar ao construtor da classe AudioRecord a forma de acesso a cada

14http://standards.ieee.org/develop/wg/POSIX.html

microfone. As op¸c˜oes poss´ıveis s˜ao valores constantes da classe MediaRecorder.AudioSource16, est˜ao sujeitas a disponibilidade em cada modelo de aparelho, e s˜ao as seguintes:

• MIC: ´Audio bruto do microfone.

• CAMCORDER: ´Audio bruto capturado de um microfone com a mesma orienta¸c˜ao da cˆamera (se dispon´ıvel).

• VOICE DOWNLINK: ´Audio bruto recebido durante uma chamada. • VOICE UPLINK: ´Audio bruto enviado durante uma chamada.

• VOICE CALL: Soma dos sinais de ´audio brutos enviado e recebido durante uma chamada. • VOICE COMMUNICATION: ´Audio do microfone, pr´e-processado para comunica¸c˜ao por voz,

ou seja, submetido a processos de cancelamento de eco, controle de ganho autom´atico, entre outros.

• VOICE RECOGNITION: ´Audio do microfone, pr´e-processado para reconhecimento de voz. Um exemplo de como pode ser feita a instancia¸c˜ao de um objeto da classe AudioRecord pode ser visto a seguir:

1 AudioRecord recorder = new AudioRecord(

2 AudioSource.MIC, // - Fonte de audio.

3 44100, // - Taxa de amostragem (Hz).

4 AudioFormat.CHANNEL_IN_MONO, // - Configuracao de numero de canais. 5 AudioFormat.ENCODING_PCM_16BIT, // - Codificacao das amostras.

6 AudioRecord.getMinBufferSize( // - Tamanho do buffer de audio (neste caso, o

7 44100, // minimo para a configuracao atual).

8 AudioFormat.CHANNEL_IN_MONO, 9 AudioFormat.ENCODING_PCM_16BIT));

Instancia¸c˜ao de AudioRecord

Vale comentar que a configura¸c˜ao de grava¸c˜ao com taxa de amostragem igual a 44.100 Hz, n´umero de canais igual a 1 e codifica¸c˜ao em PCM 16 bits ´e a ´unica que tem garantia de funci- onamento em todos os dispositivos. Note tamb´em que existe um tamanho m´ınimo para o buffer de ´audio (utilizado internamente pelo gravador), que pode ser obtido atrav´es do m´etodo est´atico AudioRecord.getMinBufferSize(). Apesar da existˆencia de um tamanho m´ınimo para este buffer interno de ´audio, ´e importante saber que n˜ao h´a garantia de grava¸c˜ao sem perda de amostras se o sistema estiver com muita carga.

A leitura do valor das amostras ´e feita atrav´es do m´etodo de instˆancia AudioRecord.read(), que recebe como argumentos um buffer para onde devem ser copiadas as amostras, o valor do ´ındice a partir do qual os dados devem ser escritos no buffer e a quantidade de amostras a serem lidas do microfone. As amostras s˜ao codificadas como ´audio PCM e portanto s˜ao representadas por s´ımbolos do tipo byte (com valores entre -128 e 127) ou short (com valores entre -32768 e 32767), e portanto algum cuidado tem que ser tomado quando do processamento destas amostras para que n˜ao haja problemas com os limites de cada tipo de representa¸c˜ao.

Um exemplo de m´etodo para leitura dos valores de amostras do microfone e escrita em um buffer para posterior processamento pode ser visto abaixo:

5.2 PROCESSAMENTO DE ´AUDIO EM TEMPO REAL EM ANDROID 79

1 public void readLoop(short[] inputBuffer, int readBlockSize) { 2 while (isRunning) {

3 recorder.read(

4 inputBuffer, // - buffer para as amostras.

5 ((j++) % buffer.length) * readBlockSize, // - indice para escrita no buffer.

6 readBlockSize); // - tamanho do bloco lido.

7 }

8 }

Note que seguidas leituras de blocos de tamanho readBlockSize ser˜ao feitas, at´e que a

vari´avel de controle isRunning seja tornada falsa para interromper a leitura. O valor de readBlockSize ser´a discutido na se¸c˜ao 5.2.2, assim como a quest˜ao da convers˜ao de representa¸c˜ao PCM para ponto flutuante e vice-versa.

Gravando o sinal do microfone em um arquivo

Existe uma op¸c˜ao de mais alto n´ıvel para capturar, codificar (com perdas) e armazenar o sinal do microfone, sem no entanto permitir o acesso ao valor das amostras em tempo real. A classe MediaRecorder17, dispon´ıvel na API do Android, pode ser utilizada para gravar o sinal do microfone em um arquivo codificado em AMR (otimizado para codifica¸c˜ao de fala), MPEG4 ou 3GPP (utilizado em plataformas com acesso a redes 3G). Estes arquivos podem ser posteriormente abertos para leitura e processamento.

Algumas desvantagens desta abordagem s˜ao que todos os formatos s˜ao propriet´arios, o que limita as possibilidades de uso, al´em de utilizarem modelos de compacta¸c˜ao com perdas. A alterna- tiva para armazenar o sinal de ´audio bruto ´e fazer a leitura da entrada com a classe AudioRecord, da forma descrita anteriormente, e implementar algum formato de representa¸c˜ao sem perdas, como por exemplo FLAC ou WAV.

Obtendo sinais de ´audio a partir de arquivos

A API do Android n˜ao oferece suporte `a leitura e decodifica¸c˜ao de arquivos de ´audio ou v´ıdeo para acesso e manipula¸c˜ao do valor das amostras do sinal. A alternativa que resta aos desenvolve- dores de aplica¸c˜oes ´e implementar bibliotecas espec´ıficas para os tipos de arquivo que utilizam.

Para o contexto deste trabalho foi desenvolvida uma classe chamada AudioStream, na qual foi encapsulado todo o acesso a sinais de ´audio. O acesso ao sinal de ´audio do microfone ´e feito atrav´es de uma subclasse chamada MicStream, e o acesso a sinais armazenados em arquivos WAV, por sua vez, ´e feito atrav´es de uma outra subclasse chamada WavStream.

Uma vez que todo o acesso a um sinal de ´audio est´a encapsulado, ´e poss´ıvel responsabilizar a classe AudioStream tamb´em pela manipula¸c˜ao e reprodu¸c˜ao do sinal de ´audio. As pr´oximas se¸c˜oes discutem a forma de implementa¸c˜ao deste mecanismo utilizada neste trabalho.