Android implementa la pausa de AudioRecord, continúa grabando la función Grabación de AudioRecord

Hay dos implementaciones de grabación de Android, que usan MediaRecorder y AudioRecord respectivamente. Desafortunadamente, ninguna de las dos implementaciones tiene una API de pausa.

1. La idea de MediaRecorder para realizar la pausa es generar un archivo cada vez que haga clic en pausa, use una matriz para guardar la ruta del archivo y, al final del final, empalme todos los archivos correspondientes a la ruta en la matriz para generar un archivo de grabación completo, pero intente encontrar MediaRecorder Cada archivo grabado tiene un archivo de encabezado, y la voz fusionada no se puede reproducir normalmente sin conocer el formato del archivo de encabezado.

Finalmente, se eligió AudioRecord para la implementación. AudioRecord admite el procesamiento de flujo de archivos en tiempo real, y el archivo de formato PCM original grabado es un archivo simple sin archivos de encabezado de tareas. Después de fusionar los datos, es simple.

2. La idea principal es leer continuamente la transmisión del archivo de audio mientras se graba la grabación y agregar contenido al archivo continuamente, dejar de agregar contenido al archivo después de presionar pausa y continuar agregando contenido a la ruta getRecordSdcardPCMFile al hacer clic en comenzar de nuevo el contenido hasta que el final de la grabacion

while (estado == recodificación) {

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

//向文件中追加内容

mRandomAccessFile.seek(mRandomAccessFile.length());

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

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

}

El siguiente es el código de implementación completado

clase pública AudioRecoderTool {

public static int recodEnd =0;//Finalizar o no iniciar

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

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

//Entrada de audio - micrófono

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

//采用频率

//44100 es el estándar actual, pero algunos dispositivos aún admiten 22050, 16000, 11025

//La frecuencia de muestreo generalmente se divide en tres niveles: 22,05 KHz, 44,1 KHz y 48 KHz

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();

}

initAudio vacío privado ()

{

// obtener el tamaño del búfer en bytes

    bufferSizeInBytes = AudioRecord.getMinBufferSize(AUDIO_SAMPLE_RATE,

            AUDIO_CHANNEL, AUDIO_ENCODING);

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

}

controlador final privado mHandler = nuevo controlador ();

private Runnable mUpdateMicStatusTimer =new Runnable() {

ejecución de vacío público () {

if(estado == grabando)

actualizarEstadoMicrófono();

    }

};

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

/**
  • Actualizar la duración de la grabación

*/

private void updateMicStatus() {

if (grabación de audio! = nulo) {

if (null != audioStatusUpdateListener) {

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

        }

mHandler.postDelayed(mUpdateMicStatusTimer, ESPACIO);

    }

}

public void setOnAudioStatusUpdateListener(OnAudioStatusUpdateListener audioStatusUpdateListener) {

this.audioStatusUpdateListener = audioStatusUpdateListener;

}

/**

  • empezar a grabar

*/

public void startRecord(final String fileName) {

this.fileName = fileName;

    if (audioRecord==null) {

initAudio();

    }

if(estado == grabando)

{

LogUtils.e("Grabando~");

    }

estado = recodificación;

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

    /* 获取开始时间* */

    startTime = System.currentTimeMillis();

    updateMicStatus();

    //使用线程池管理线程

    mExecutorService.execute(new Runnable() {

@Anular

ejecución de vacío público () {

writeDataTOFile(nombre de archivo);

        }

});

}

/**

  • pausar la grabación

*/

public void pauseRecord() {

estado = grabaciónPasue;

    if(audioStatusUpdateListener !=null)

{

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

        audioStatusUpdateListener.onStop(fileName);

    }

}

/**

  • para de grabar

*/

public void stopRecord() {

Log.d(“Grabadora de audio”, “=detenerRegistrar=”);

    if (status == recodEnd) {

LogUtils.e("la grabación no ha comenzado");

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

        audioRecord.stop();

        status = recodEnd;

        release();

    }else

    {

//En el estado de grabación, se liberará en el método writeDataTOFile

        status = recodEnd;

    }

}

/**

  • liberar recursos

*/

public void release() {

Log.d(“Grabadora de audio”, “=liberar=”);

    if (audioRecord !=null) {

audioRecord.release();

        audioRecord =null;

    }

if(audioStatusUpdateListener!=null)

{

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

        audioStatusUpdateListener.onStop(fileName);

    }

estado = finalregistro;

}

/**

  • cancelar grabación

*/

public void canel() {

nombre de archivo = nulo;

    if (audioRecord !=null) {

audioRecord.release();

        audioRecord =null;

    }

estado = finalregistro;

}

/**

  • escribir información de audio en un archivo

*/

private void writeDataTOFile(String currentFileName) {

RandomAccessFile mRandomAccessFile =null;

    try {

mRandomAccessFile =nuevo RandomAccessFile(nuevo archivo(

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

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

        //开始录制音频

        audioRecord.startRecording();

        //判断是否正在录制

        status = recoding;

        while (status == recoding) {

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

            //向文件中追加内容

            mRandomAccessFile.seek(mRandomAccessFile.length());

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

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

        }

// para de grabar

        audioRecord.stop();

        mRandomAccessFile.close();

        //释放资源

        if(status == recodEnd)

liberar();

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

    }catch (FileNotFoundException e) {

// TODO Bloque catch generado automáticamente

        e.printStackTrace();

    }catch (IOException e) {

// TODO Bloque catch generado automáticamente

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

        e.printStackTrace();

    }

}

interfaz pública OnAudioStatusUpdateListener {

/**

  • grabación...

  • @param db sonido actual decibelio

  • @param tiempo tiempo de grabación

*/

    public void onUpdate(double db, long time);

    /**
  • para de grabar

  • @param filePath guardar ruta

*/

    public void onStop(String filePath);

}

}

Debido a que el archivo grabado es un archivo PCM, no se puede reproducir directamente. Para ser compatible con IOS y considerar el tamaño del archivo, se selecciona el formato .aac con contenido más pequeño al mismo tiempo.

La biblioteca android-aac-enc se usa aquí, puede buscarla y descargarla en git.

Debido a que es una biblioteca C, necesita NDK para compilar la carpeta jni antes de que pueda usarse normalmente. El comando para generar el archivo de encabezado en jni se adjunta aquí. Parece que el comando javah se canceló después de la versión JDK10. Aquí , el archivo de encabezado se genera con java xxxx.java -h El comando genera el archivo de encabezado .h y debe ejecutarse en el directorio raíz del archivo xxxx.java.

Arrastre el archivo .h generado arriba (el archivo señalado por la flecha roja a continuación) al directorio raíz de jni

El contenido del archivo generado se ve así

Luego crea el archivo c en el directorio raíz jnl

Aquí creé aac-enc.c con el mismo nombre de archivo que la biblioteca original de jnl. Si desea crear el nombre de archivo usted mismo, modifique el nombre de archivo de la flecha roja en la imagen a continuación en Android.mk.

En este punto, puede usar el comando ndk-build para compilar y generar el archivo .os.

Luego use el siguiente método para convertir el archivo de grabación PCM en un archivo .aac

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

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

    encoder.encode(b);

    //编码完成

    encoder.uninit();

Supongo que te gusta

Origin blog.csdn.net/sinat_24112081/article/details/102596292
Recomendado
Clasificación