Android 音频降噪 webrtc 去回声

使用webrtc 处理降噪,去回声,增益,均衡等

MainActivity代码:

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.SeekBar;


/**
 * Desc:
 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    SeekBar skbVolume;//控制音量大小
    boolean isProcessing = true;//判断是否录放
    boolean isRecording = false;//判断是否录放
    static final int FREQUENCY = 44100;
    static final int CHANNELCONFIGURATION = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    static final int AUDIOENCODING = AudioFormat.ENCODING_PCM_16BIT;
    int recBufSize, playBufSize;
    AudioRecord audioRecord;
    AudioTrack audioTrack;
    private WebrtcProcessor mProcessor;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //获得录音缓存大小
        recBufSize = AudioRecord.getMinBufferSize(FREQUENCY, CHANNELCONFIGURATION, AUDIOENCODING);
        Log.e("", "recBufSize:" + recBufSize);
        //获得播放缓存大小
        playBufSize = AudioTrack.getMinBufferSize(FREQUENCY, CHANNELCONFIGURATION, AUDIOENCODING);

        //创建录音和播放实例
        audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, FREQUENCY, CHANNELCONFIGURATION, AUDIOENCODING, recBufSize);
        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, FREQUENCY, CHANNELCONFIGURATION, AUDIOENCODING, playBufSize, AudioTrack.MODE_STREAM);

        findViewById(R.id.btnRecord).setOnClickListener(this);
        findViewById(R.id.btnStop).setOnClickListener(this);

        skbVolume = (SeekBar) this.findViewById(R.id.skbVolume);
        skbVolume.setMax(100);//音量调节的最高值
        skbVolume.setProgress(50);//seekbar的位置
        audioTrack.setStereoVolume(0.3f,0.3f);//设置当前音量
        skbVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                float vol = (float) (seekBar.getProgress()) / (float) (seekBar.getMax());
                audioTrack.setStereoVolume(vol, vol);//设置音量
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
            }

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            }
        });
        ((CheckBox) findViewById(R.id.cb_ap)).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

            @Override
            public void onCheckedChanged(CompoundButton view, boolean checked) {
                isProcessing = checked;
            }
        });
        initProccesor();
    }

    @Override
    protected void onDestroy() {

        releaseProcessor();

        android.os.Process.killProcess(android.os.Process.myPid());
        super.onDestroy();
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btnRecord) {
            isRecording = true;
            //启动线程,开始录音和一边播放
            new RecordPlayThread().start();

        } else if (v.getId() == R.id.btnStop) {
            isRecording = false;
        }
    }

    class RecordPlayThread extends Thread {
        public void run() {
            try {
                short[] buffer = new short[recBufSize / 2];
                audioRecord.startRecording();//开始录制
                audioTrack.play();//开始播放
                while (isRecording) {
                    //第一步:从MIC保存数据到缓冲区
                    int bufferReadResult = audioRecord.read(buffer, 0, recBufSize / 2);
                    short[] tmpBuf_src = new short[bufferReadResult];
                    System.arraycopy(buffer, 0, tmpBuf_src, 0, bufferReadResult);
                    //第二步:进行处理
                    if (isProcessing) {
                        processData(tmpBuf_src);
                    }
                    //写入数据即播放
                    audioTrack.write(tmpBuf_src, 0, tmpBuf_src.length);
                }
                audioTrack.stop();
                audioRecord.stop();
            } catch (Exception t) {
                t.printStackTrace();
            }
        }
    }

    ;

    /**
     * 初始化降噪
     */
    private void initProccesor() {
        mProcessor = new WebrtcProcessor();
        mProcessor.init(FREQUENCY);
    }

    /**
     * 释放降噪资源
     */
    private void releaseProcessor() {
        if (mProcessor != null) {
            mProcessor.release();
        }
    }

    /**
     * 处理需要降噪的音频数据
     *
     * @param data
     */
    private void processData(byte[] data) {
        if (mProcessor != null) {
            mProcessor.processNoise(data);
        }
    }

    /**
     * 处理需要降噪的音频数据
     *
     * @param data
     */
    private void processData(short[] data) {
        if (mProcessor != null) {
            mProcessor.processNoise(data);
        }
    }

}

主演实现降噪的 WebrtcProcessor 代码:


import android.util.Log;


/**
 * Desc:
 */
public class WebrtcProcessor {
    static {
        try {
            //加载降噪库
            System.loadLibrary("webrtc");
        } catch (UnsatisfiedLinkError e) {
            Log.e("TAG", e.getMessage());
        }

    }

    /**
     * 处理降噪
     *
     * @param data
     */
    public void processNoise(byte[] data) {
        if (data == null) return;
        int newDataLength = data.length / 2;
        if (data.length % 2 == 1) {
            newDataLength += 1;
        }
        //此处是将字节数据转换为short数据
        short[] newData = new short[newDataLength];
        for (int i = 0; i < newDataLength; i++) {
            byte low = 0;
            byte high = 0;
            if (2 * i < data.length) {
                low = data[2 * i];
            }
            if ((2 * i + 1) < data.length) {
                high = data[2 * i + 1];
            }
            newData[i] = (short) (((high << 8) & 0xff00) | (low & 0x00ff));
        }

        // 交给底层处理
        processNoise(newData);
        //处理完之后, 又将short数据转换为字节数据
        for (int i = 0; i < newDataLength; i++) {
            if (2 * i < data.length) {
                data[2 * i] = (byte) (newData[i] & 0xff);
            }
            if ((2 * i + 1) < data.length) {
                data[2 * i + 1] = (byte) ((newData[i] >> 8) & 0xff);
            }
        }

    }

    /**
     * 初始化降噪设置
     *
     * @param sampleRate 采样率
     * @return 是否初始化成功
     */
    public native boolean init(int sampleRate);

    /**
     * 处理降噪
     *
     * @param data
     * @return
     */
    public native boolean processNoise(short[] data);

    /**
     * 释放降噪资源
     */
    public native void release();
}

主要是根据以上两个类实现的,更多数据请查看源码:

https://download.csdn.net/download/xiaozhu2623/10772244

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值