Wie konvertiert Android die gesammelten Audio-PCM-Dateien in WAV und speichert sie?

1.Android-Audiosammlung

Berechtigungen hinzufügen

<uses-permission android:name="android.permission.RECORD_AUDIO" />

Dynamische Anwendungsberechtigungen

Einführung der Berechtigungsanwendungsbibliothek

implementation 'com.permissionx.guolindev:permissionx:1.4.0'

Teil des Codes, um eine Genehmigung zu beantragen

PermissionX.init(this).permissions(Manifest.permission.RECORD_AUDIO)
            .request { _, _, _ -> 
    //TODO 申请成功之后的代码写在这里
 }

AudioRecorder initialisieren

Die Parameter, die eingestellt werden müssen, sind: Audioquelle, Abtastrate, Anzahl der Kanäle, Datentyp, minimaler Puffer

Die Größe des minimalen Puffers verwendet die AudioRecord.getMinBufferSize-Schnittstelle und gibt diesen Wert entsprechend der Abtastrate, Anzahl der Kanäle und des Datentyps zurück;

private const val SAMPLE_RATE_IN_HZ_16K = 16000
private var minBufferSize = 1280
private var audioRecord: AudioRecord? = null
private var captureThread: Thread? = null
private var isRunning = false
private var isFloats = false

fun start(isFloats: Boolean) {
    this.isFloats = isFloats
    minBufferSize = AudioRecord.getMinBufferSize(
        SAMPLE_RATE_IN_HZ_16K,
        AudioFormat.CHANNEL_IN_MONO,
        if (isFloats) AudioFormat.ENCODING_PCM_FLOAT else AudioFormat.ENCODING_PCM_16BIT
    )
    audioRecord = AudioRecord(
        MediaRecorder.AudioSource.VOICE_COMMUNICATION,
        SAMPLE_RATE_IN_HZ_16K,
        AudioFormat.CHANNEL_IN_MONO,
        AudioFormat.ENCODING_PCM_FLOAT,
        minBufferSize
    )
    audioRecord!!.startRecording()
    isRunning = true
}

Die Formate, die während der Audiosammlung eingestellt werden können, sind:

public static final int ENCODING_DEFAULT = 1;
// These values must be kept in sync with core/jni/android_
// Also sync av/services/audiopolicy/managerdefault/ConfigP
/** Audio data format: PCM 16 bit per sample. Guaranteed to
public static final int ENCODING_PCM_16BIT = 2;
/** Audio data format: PCM 8 bit per sample. Not guaranteed
public static final int ENCODING_PCM_8BIT = 3;
/** Audio data format: single-precision floating-point per 
public static final int ENCODING_PCM_FLOAT = 4;
/** Audio data format: AC-3 compressed, also known as Dolby
public static final int ENCODING_AC3 = 5;
/** Audio data format: E-AC-3 compressed, also known as Dol
public static final int ENCODING_E_AC3 = 6;
    /** Audio data format: DTS compressed */
public static final int ENCODING_DTS = 7;
    /** Audio data format: DTS HD compressed */
public static final int ENCODING_DTS_HD = 8;
    /** Audio data format: MP3 compressed */
public static final int ENCODING_MP3 = 9;
    /** Audio data format: AAC LC compressed */
public static final int ENCODING_AAC_LC = 10;
    /** Audio data format: AAC HE V1 compressed */
public static final int ENCODING_AAC_HE_V1 = 11;
    /** Audio data format: AAC HE V2 compressed */
public static final int ENCODING_AAC_HE_V2 = 12;

Daten sammeln beginnen

fun capture(listener: OnReadListener) {
    captureThread = Thread {
        while (isRunning) {
            var nReadBytes: Int
            if (isFloats) {
                val data = FloatArray(minBufferSize)
                nReadBytes =
                    audioRecord!!.read(data, 0, minBufferSize, AudioRecord.READ_BLOCKING)
                listener.read(nReadBytes, data)
            } else {
                val data = ByteArray(minBufferSize)
                nReadBytes =
                    audioRecord!!.read(data, 0, minBufferSize)
                listener.read(nReadBytes, data)
            }
        }
    }
    captureThread!!.start()
}

Daten-Callback-Schnittstelle

interface OnReadListener {
    fun read(readSize: Int, floatArray: FloatArray)
    fun read(readSize: Int, byteArray: ByteArray)
}

Aufnahme beenden, AudioRecorder schließen

fun stop() {
    isRunning = false
    captureThread!!.interrupt()
    try {
        audioRecord!!.stop()
        audioRecord!!.release()
    } catch (e : Exception) {
        e.printStackTrace()
    }
}

Speichern Sie die PCM-Daten nach den gesammelten Daten

AudioCapture.capture(object : AudioCapture.OnReadListener {
    override fun read(readSize: Int, floatArray: FloatArray) {
        val savePath = getDir(
            "spanner", Context.MODE_PRIVATE
        ).absolutePath + File.separator + "/Music/"
        //保存浮点数据到本地文件
        SaveBytesAsFile.writeFile(floatArray, savePath + "record.pcm")
    }
    override fun read(readSize: Int, byteArray: ByteArray) {
        
    }
})



public class SaveBytesAsFile {

    public SaveBytesAsFile() {
    }

    public void writeFile(byte[] bytes) {
        long time = System.currentTimeMillis();
        String path = Environment.getExternalStorageDirectory() + File.separator + "g711ToAAC.aac";
        try {
            FileOutputStream out = new FileOutputStream(path, true);//指定写到哪个路径中
            FileChannel fileChannel = out.getChannel();
            fileChannel.write(ByteBuffer.wrap(bytes)); //将字节流写入文件中
            fileChannel.force(true);//强制刷新
            fileChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 将流写入口自定义路径
     *
     * @param bytes
     * @param path  ps:快捷回复AAC转PCM之后写入到指定路径   请勿修改
     */
    public static void writeFile(byte[] bytes, String path) {

        try {
            FileOutputStream out = new FileOutputStream(path, true);//指定写到哪个路径中
            FileChannel fileChannel = out.getChannel();
            fileChannel.write(ByteBuffer.wrap(bytes)); //将字节流写入文件中
            fileChannel.force(true);//强制刷新
            fileChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void writeFile(float[] floats, String path) {
        try {
            FileOutputStream fos = new FileOutputStream(path, true);
            DataOutputStream dos = new DataOutputStream(fos);
            for (float f : floats) {
                dos.writeFloat(f);
            }
            dos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2. Konvertieren Sie PCM-Dateien in WAV

Anweisungen zum Abspielen von Fließkomma-Audio

ffplay -f f32be  -ar 16000 -ac 1 -i record.pcm

Verwenden Sie FFMPEG

ffmpeg -f 音频格式 -ar 采样率 -ac 频道数 -i pcm文件名 -ar 采样率 -ac 频道数 wav文件名

Konvertieren Sie hier Fließkomma-PCM-Daten

//浮点型音频PCM转WAV格式音频指令
ffmpeg -f f32be -ar 16000 -ac 1 -i record.pcm -ar 16000 -ac 1 record.wav

Zeigen Sie die Formatanweisungen an, die ffmepg analysieren kann

ffmpeg -formats

DE f32be           PCM 32-bit floating-point big-endian
DE f32le           PCM 32-bit floating-point little-endian
DE f64be           PCM 64-bit floating-point big-endian
DE f64le           PCM 64-bit floating-point little-endian
DE s16be           PCM signed 16-bit big-endian
DE s16le           PCM signed 16-bit little-endian
DE s24be           PCM signed 24-bit big-endian
DE s24le           PCM signed 24-bit little-endian
DE s32be           PCM signed 32-bit big-endian
DE s32le           PCM signed 32-bit little-endian
DE u16be           PCM unsigned 16-bit big-endian
DE u16le           PCM unsigned 16-bit little-endian
DE u24be           PCM unsigned 24-bit big-endian
DE u24le           PCM unsigned 24-bit little-endian
DE u32be           PCM unsigned 32-bit big-endian
DE u32le           PCM unsigned 32-bit little-endian

Guess you like

Origin blog.csdn.net/mozushixin_1/article/details/128580848