O Android implementa a pausa AudioRecord, continua a função de gravação Gravação AudioRecord

Existem duas implementações de gravação no Android, usando MediaRecorder e AudioRecord respectivamente. Infelizmente, nenhuma das duas implementações possui uma API de pausa.

1. A ideia do MediaRecorder para realizar a pausa é gerar um arquivo toda vez que você clicar em pausar, usar um array para salvar o caminho do arquivo, e ao final unir todos os arquivos correspondentes ao caminho no array para gerar um arquivo de gravação concluído, mas tente encontrar MediaRecorder Cada arquivo gravado tem um arquivo de cabeçalho e a voz mesclada não pode ser reproduzida normalmente sem saber o formato do arquivo de cabeçalho.

Finalmente, AudioRecord foi escolhido para implementação. AudioRecord suporta processamento de fluxo de arquivo em tempo real, e o arquivo de formato PCM original gravado é um arquivo vazio sem arquivos de cabeçalho de tarefa. Depois de mesclar os dados, é simples.

2. A ideia principal é ler continuamente o fluxo do arquivo de áudio enquanto a gravação está sendo gravada e adicionar conteúdo ao arquivo continuamente, parar de adicionar conteúdo ao arquivo após pressionar a pausa e continuar adicionando ao caminho getRecordSdcardPCMFile ao clicar em iniciar novamente o conteúdo até final da gravação

while (status == recodificação) {

audioRecord.read(b, 0, b.length);

//向文件中追加内容

mRandomAccessFile.seek(mRandomAccessFile.length());

mRandomAccessFile.write(b, 0, b.length);

//LogUtils.e("buff大小:" + b.length);

}

A seguir está o código de implementação completo

public class AudioRecoderTool {

public static int recodEnd =0;//Termina ou não inicia

public static int recoding =1;//正在录音

public static int recodPasue =2;//暂停中

//Entrada de áudio - microfone

private final static int AUDIO_INPUT = MediaRecorder.AudioSource.MIC;

//采用频率

//44100 é o padrão atual, mas alguns dispositivos ainda suportam 22050, 16000, 11025

//A frequência de amostragem é geralmente dividida em três níveis: 22,05KHz, 44,1KHz e 48KHz

private final static int AUDIO_SAMPLE_RATE =16000;

//声道 单声道 // 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道

private final static int AUDIO_CHANNEL = AudioFormat.CHANNEL_IN_STEREO;

//编码

private final static int AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;

// 缓冲区字节大小

private int bufferSizeInBytes =0;

//录音对象

private AudioRecord audioRecord;

//文件名

private String fileName;

//录音状态

private int status = recodEnd;

//线程池

private ExecutorService mExecutorService;

private OnAudioStatusUpdateListener audioStatusUpdateListener;

private long startTime;

public AudioRecoderTool() {

mExecutorService = Executors.newCachedThreadPool();

}

private void initAudio()

{

// obtém o tamanho do buffer em bytes

    bufferSizeInBytes = AudioRecord.getMinBufferSize(AUDIO_SAMPLE_RATE,

            AUDIO_CHANNEL, AUDIO_ENCODING);

    audioRecord =new AudioRecord(AUDIO_INPUT, AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING, bufferSizeInBytes);

}

private final Manipulador mHandler =novo Manipulador();

private Runnable mUpdateMicStatusTimer =new Runnable() {

public void run() {

if(status == recodificação)

atualizarMicStatus();

    }

};

private int SPACE =100;// 间隔取样时间

/**
  • Atualizar duração da gravação

*/

private void updateMicStatus() {

if (audioRecord !=null) {

if (null != audioStatusUpdateListener) {

audioStatusUpdateListener.onUpdate(0, System.currentTimeMillis() - startTime);

        }

mHandler.postDelayed(mUpdateMicStatusTimer, ESPAÇO);

    }

}

public void setOnAudioStatusUpdateListener(OnAudioStatusUpdateListener audioStatusUpdateListener) {

this.audioStatusUpdateListener = audioStatusUpdateListener;

}

/**

  • comece a gravar

*/

public void startRecord(final String fileName) {

this.fileName = fileName;

    if (audioRecord==null) {

initAudio();

    }

if(status == recodificação)

{

LogUtils.e("Gravando~");

    }

estado = recodificação;

    Log.d("AudioRecorder", "===startRecord===" + audioRecord.getState());

    /* 获取开始时间* */

    startTime = System.currentTimeMillis();

    updateMicStatus();

    //使用线程池管理线程

    mExecutorService.execute(new Runnable() {

@Sobrepor

public void run() {

writeDataTOFile(arquivo);

        }

});

}

/**

  • pausar gravação

*/

public void pauseRecord() {

status = recodPasue;

    if(audioStatusUpdateListener !=null)

{

audioStatusUpdateListener.onUpdate(0,System.currentTimeMillis() - startTime);

        audioStatusUpdateListener.onStop(fileName);

    }

}

/**

  • pare de gravar

*/

public void stopRecord() {

Log.d(“Gravador de Áudio”, “=stopRecord=”);

    if (status == recodEnd) {

LogUtils.e("gravação não iniciada");

    }else if(status == recodPasue){//暂停状态下直接释放资源

        audioRecord.stop();

        status = recodEnd;

        release();

    }else

    {

//No estado de gravação, será liberado no método writeDataTOFile

        status = recodEnd;

    }

}

/**

  • liberar recursos

*/

public void release() {

Log.d(“Gravador de Áudio”, “=liberar=”);

    if (audioRecord !=null) {

audioRecord.release();

        audioRecord =null;

    }

if(audioStatusUpdateListener !=null)

{

audioStatusUpdateListener.onUpdate(0,System.currentTimeMillis() - startTime);

        audioStatusUpdateListener.onStop(fileName);

    }

status = recodEnd;

}

/**

  • cancelar gravação

*/

public void canel() {

nomeArquivo =nulo;

    if (audioRecord !=null) {

audioRecord.release();

        audioRecord =null;

    }

status = recodEnd;

}

/**

  • gravar informações de áudio no arquivo

*/

private void writeDataTOFile(String currentFileName) {

RandomAccessFile mRandomAccessFile =null;

    try {

mRandomAccessFile =novo RandomAccessFile(novo Arquivo(

FileUtils.getRecordSdcardPCMFile(currentFileName)), “rw”);

        byte[] b =new byte[bufferSizeInBytes /4];

        //开始录制音频

        audioRecord.startRecording();

        //判断是否正在录制

        status = recoding;

        while (status == recoding) {

audioRecord.read(b, 0, b.length);

            //向文件中追加内容

            mRandomAccessFile.seek(mRandomAccessFile.length());

            mRandomAccessFile.write(b, 0, b.length);

            //LogUtils.e("buff大小:" + b.length);

        }

// pare de gravar

        audioRecord.stop();

        mRandomAccessFile.close();

        //释放资源

        if(status == recodEnd)

liberar();

        LogUtils.e("保存成功");

    }catch (FileNotFoundException e) {

// TODO Bloco catch gerado automaticamente

        e.printStackTrace();

    }catch (IOException e) {

// TODO Bloco catch gerado automaticamente

        LogUtils.e("异常关闭文件流");

        e.printStackTrace();

    }

}

interface pública OnAudioStatusUpdateListener {

/**

  • gravação...

  • @param db som atual decibel

  • @param tempo de gravação de tempo

*/

    public void onUpdate(double db, long time);

    /**
  • pare de gravar

  • @param filePath salvar caminho

*/

    public void onStop(String filePath);

}

}

Como o arquivo gravado é um arquivo PCM, não pode ser reproduzido diretamente. Para ser compatível com IOS e considerar o tamanho do arquivo, o formato .aac com conteúdo menor ao mesmo tempo é selecionado.

A biblioteca android-aac-enc é usada aqui, você pode pesquisar e baixá-la no git.

Por ser uma biblioteca C, ela precisa do NDK para compilar a pasta jni antes de poder ser usada normalmente. O comando para gerar o arquivo de cabeçalho em jni está anexado aqui. Parece que o comando javah foi cancelado após a versão JDK10. Aqui , o arquivo de cabeçalho é gerado usando java xxxx.java -h . O comando gera o arquivo de cabeçalho .h e deve ser executado no diretório raiz do arquivo xxxx.java.

Arraste o arquivo .h gerado acima (o arquivo apontado pela seta vermelha abaixo) para o diretório raiz jni

O conteúdo do arquivo gerado se parece com isso

Em seguida, crie o arquivo c no diretório raiz jnl

Aqui eu criei aac-enc.c com o mesmo nome de arquivo da biblioteca original de jnl. Se você quiser criar o nome do arquivo você mesmo, modifique o nome do arquivo da seta vermelha na imagem abaixo no Android.mk.

Neste ponto, você pode usar o comando ndk-build para compilar e gerar o arquivo .os.

Em seguida, use o seguinte método para converter o arquivo de gravação PCM em um arquivo .aac

encoder.init(32000, 2, 16000, 16, FileUtils.getRecordSdcardAACFile(currentRptBean.getVoiceFile()));

    //对二进制代码进行编码

    encoder.encode(b);

    //编码完成

    encoder.uninit();

おすすめ

転載: blog.csdn.net/sinat_24112081/article/details/102596292