Tópicos de áudio e vídeo do Android (2) Use AudioRecord e AudioTrack API para coletar e reproduzir dados de áudio PCM na plataforma Android e realizar a leitura e gravação de arquivos wav de áudio

1. Uso básico de AudioTrack

A classe AudioTrack pode completar a tarefa de saída de dados de áudio na plataforma Android. AudioTrack tem dois modos de carregamento de dados (MODE_STREAM e MODE_STATIC), correspondendo ao modo de carregamento de dados e tipo de fluxo de áudio, correspondendo a dois cenários de uso completamente diferentes.

  • MODE_STREAM: neste modo, os dados de áudio são gravados no AudioTrack por meio de gravação repetida. Isso geralmente é semelhante a gravar dados em um arquivo por meio da chamada de sistema de gravação, mas esta forma de trabalhar requer a cópia dos dados do Buffer fornecido pelo usuário para o Buffer dentro do AudioTrack todas as vezes, o que introduzirá um atraso até certo ponto . Para resolver esse problema, AudioTrack introduziu o segundo modo.
  • MODE_STATIC: Neste modo, você só precisa transferir todos os dados para o buffer interno em AudioTrack por meio de uma chamada de gravação antes de jogar, e você não precisa transferir os dados no subseqüente. Este modo é adequado para arquivos com pequena pegada de memória e requisitos de alta latência, como toques. Mas também tem uma desvantagem, ou seja, você não pode gravar muitos dados de uma vez, caso contrário, o sistema não pode alocar memória suficiente para armazenar todos os dados.

1.1 modo MODE_STATIC

A forma de saída de áudio no modo MODE_STATIC é a seguinte ( Observação: se você usar o modo ESTÁTICO, deve primeiro chamar write para gravar dados e, em seguida, chamar play. ):

Copiar código

public class AudioTrackPlayerDemoActivity extends Activity implementa 
        OnClickListener { 

    private static final String TAG = "AudioTrackPlayerDemoActivity"; 
    botão de botão privado; 
    byte privado [] audioData; 
    AudioTrack audioTrack privado; 

    @Override 
    public void onCreate (Bundle savedInstanceState) { 
        super.onCreate (savedInstanceState); 
        super.setContentView (R.layout.main); 
        this.button = (Botão) super.findViewById (R.id.play); 
        this.button.setOnClickListener (this); 
        this.button.setEnabled (false); 
        new AsyncTask <Void, Void, Void> () { 
            @Override
            protegido Void doInBackground (Void ... params) {
                    }
                tente { 
                    InputStream in = getResources (). openRawResource (R.raw.ding); 
                    tente { 
                        ByteArrayOutputStream out = new ByteArrayOutputStream ( 
                                264848); 
                        para (int b; (b = in.read ())! = -1;) { 
                            out.write (b); 
                        } 
                        Log.d (TAG, "Obteve os dados"); 
                        audioData = out.toByteArray (); 
                    } finalmente { 
                        in.close (); 
                } catch (IOException e) { 
                    Log.wtf (TAG, "Falha ao ler", e);
                } 
                return null; 
            } 

            @Override 
            protected void onPostExecute (Void v) { 
                Log.d (TAG, "Criando trilha ..."); 
                button.setEnabled (true); 
                Log.d (TAG, "Botão habilitado"); 
            } 
        } .execute (); 
    } 

    public void onClick (Exibir visualização) { 
        this.button.setEnabled (false); 
        this.releaseAudioTrack (); 
        this.audioTrack = novo AudioTrack (AudioManager.STREAM_MUSIC, 44100,
        Log.d (TAG, "Gravando dados de áudio ..."); 
                AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
                audioData.length, AudioTrack.MODE_STATIC); 
        this.audioTrack.write (audioData, 0, audioData.length); 
        Log.d (TAG, "Iniciando a reprodução"); 
        audioTrack.play (); 
        Log.d (TAG, "Jogando"); 
        this.button.setEnabled (true); 
    } 

    private void releaseAudioTrack () { 
        if (this.audioTrack! = null) { 
            Log.d (TAG, "Parando"); 
            audioTrack.stop (); 
            Log.d (TAG, "Liberação"); 
            audioTrack.release (); 
            Log.d (TAG, "anulação"); 
        } 
    } 

    public void onPause () { 
        super.onPause ();
        this.releaseAudioTrack (); 
    } 
}

Copiar código

1.2 modo MODE_STREAM

A forma de saída de áudio no modo MODE_STREAM é a seguinte:

Copiar código

byte [] tempBuffer = novo byte [bufferSize]; 
int readCount = 0; 
while (dis.available ()> 0) { 
    readCount = dis.read (tempBuffer); 
    if (readCount == AudioTrack.ERROR_INVALID_OPERATION || readCount == AudioTrack.ERROR_BAD_VALUE) { 
        continue; 
    } 
    if (readCount! = 0 && readCount! = -1) { 
        audioTrack.play (); 
        audioTrack.write (tempBuffer, 0, readCount); 
    } 

Copiar código

Em segundo lugar, AudioTrack detalhado

 2.1 Tipos de streams de áudio

No construtor AudioTrack, o parâmetro AudioManager.STREAM_MUSIC será exposto. Seu significado está relacionado ao gerenciamento e classificação de streams de áudio pelo sistema Android.

O Android divide o som do sistema em vários tipos de fluxo, os seguintes são alguns mais comuns:

· STREAM_ALARM: som de aviso

· STREAM_MUSIC: Sons musicais, como música, etc.

· STREAM_RING: toque

· STREAM_SYSTEM: sons do sistema, como prompt de bateria fraca, som da tela de bloqueio, etc.

· STREAM_VOCIE_CALL: som de chamada

Nota: Os tipos de divisões acima não têm nada a ver com os dados de áudio em si. Por exemplo, os tipos MUSIC e RING podem ser uma determinada música MP3. Além disso, não há um padrão fixo para a seleção do tipo de fluxo de som. Por exemplo, o toque na visualização do toque pode ser definido para o tipo MÚSICA. A divisão dos tipos de fluxo de áudio está relacionada à estratégia de gerenciamento de áudio do sistema de áudio.

 

2.2 Alocação de buffer e o conceito de Frame

Ao calcular o tamanho da alocação do Buffer, um método que frequentemente usamos é: getMinBufferSize. Esta função determina quanto buffer de dados a camada de aplicativo aloca.

AudioTrack.getMinBufferSize (8000, // 8K pontos de amostragem por segundo                               
        AudioFormat.CHANNEL_CONFIGURATION_STEREO, // 
        AudioFormat.ENCODING_PCM_16BIT de canal duplo                   );

Começando com AudioTrack.getMinBufferSize para rastrear o código, você pode descobrir que há um conceito muito importante no código subjacente: Frame. Quadro é uma unidade usada para descrever a quantidade de dados. Uma unidade de quadro é igual ao número de bytes de um ponto de amostra × o número de canais (por exemplo, PCM16, um quadro de dois canais é igual a 2 × 2 = 4 bytes). Um ponto de amostragem é apenas para um canal, mas na verdade pode haver um ou mais canais. Como uma unidade independente não pode ser usada para representar a quantidade de dados amostrados de uma vez para todos os canais, o conceito de Quadro é introduzido. O tamanho do quadro é o número de bytes de um ponto de amostragem × o número de canais. Além disso, no driver da placa de som atual, seu buffer interno também é alocado e gerenciado usando Frame como uma unidade.

A seguir está o método rastreado até a camada nativa:

Copiar código

// minBufCount representa o número mínimo de buffers, ele usa Frame como a unidade 
   uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSamplingRate); 
    if (minBufCount <2) minBufCount = 2; // Pelo menos dois buffers são necessários 
 
   / / Calcular o número mínimo de quadros 
   uint32_tminFrameCount =                
         (afFrameCount * sampleRateInHertz * minBufCount) / afSamplingRate; 
  // O seguinte calcula o tamanho mínimo do buffer com base no menor FrameCount    
   intminBuffSize = minFrameCount // O método de cálculo está totalmente de acordo com nossa introdução anterior Frame 
           * (audioFormat == javaAudioTrackFields .PCM16? 2: 1) 
           * nbChannels; 
 
    returnminBuffSize;

Copiar código

getMinBufSize considerará de forma abrangente a situação do hardware (por exemplo, se a taxa de amostragem é suportada, o atraso do próprio hardware, etc.) para chegar a um tamanho mínimo de buffer. Geralmente, o tamanho do buffer que alocamos será um múltiplo inteiro dele.

2.3 Processo de construção de AudioTrack

Cada stream de áudio corresponde a uma instância da classe AudioTrack. Cada AudioTrack será registrado no AudioFlinger quando for criado, e o AudioFlinger mixará todas as AudioTracks (Mixer) e depois as enviará para AudioHardware para reprodução. Atualmente, o Android pode mais ao mesmo tempo. Crie 32 fluxos de áudio, ou seja, o Mixer irá processar até 32 fluxos de dados AudioTrack ao mesmo tempo. 

3. Comparação entre AudioTrack e MediaPlayer

Para reproduzir sons, você pode usar MediaPlayer e AudioTrack, os quais fornecem API Java para desenvolvedores de aplicativos usarem. Embora ambos possam reproduzir sons, ainda há uma grande diferença entre os dois.

3.1 Diferença

A maior diferença é que o MediaPlayer pode reproduzir arquivos de som em vários formatos, como MP3, AAC, WAV, OGG, MIDI, etc. O MediaPlayer criará o decodificador de áudio correspondente na camada da estrutura. AudioTrack só pode reproduzir streams PCM decodificados. Se você comparar os formatos de arquivo suportados, AudioTrack só suporta arquivos de áudio em formato wav, porque a maioria dos arquivos de áudio em formato wav são streams PCM. AudioTrack não cria um decodificador, então ele só pode reproduzir arquivos wav que não precisam ser decodificados.

3.2 Contato

O MediaPlayer ainda criará AudioTrack na camada de estrutura, passará o fluxo PCM decodificado para AudioTrack e, em seguida, passará para AudioFlinger para mixagem e, em seguida, passará para o hardware para reprodução, então MediaPlayer inclui AudioTrack.

3.3 SoundPool

Ao entrar em contato com a API de reprodução de áudio do Android, descobri que o SoundPool também pode ser usado para reproduzir áudio. A seguir estão os cenários de uso dos três: MediaPlayer é mais adequado para reproduzir arquivos de música locais ou recursos de streaming online por um longo tempo em segundo plano; SoundPool é adequado para reproduzir clipes de áudio relativamente curtos, como sons de jogos, sons de botões, toques , etc., ele pode reproduzir vários áudios ao mesmo tempo; AudioTrack está mais próximo da camada inferior, fornece recursos de controle muito poderosos, suporta reprodução de baixa latência e é adequado para cenários como streaming de mídia e chamadas de voz VoIP.

Quarto, o código-fonte 

https://github.com/renhui/AudioDemo 

Acho que você gosta

Origin blog.csdn.net/xfb1989/article/details/113348396
Recomendado
Clasificación