测试回声消除APP 里面开启aec agc ns 增益 降噪(带源码)

声效 (Sound Effects) 是一种用来增强声音的技术。声效可以通过各种方式实现,包括声音处理器和数字信号处理等。下面是三种常见的声效处理技术的简要介绍:

自适应回声消除 (Acoustic Echo Cancellation, AEC):AEC 技术主要用于语音通信系统中,可以自动地消除回声。当在通话中使用扬声器时,麦克风可能会捕捉到从扬声器返回的声音,导致回声。AEC 技术能够分析回声信号,并将其从录音中消除,确保清晰的语音通信。

自动增益控制 (Automatic Gain Control, AGC):AGC 技术可以自动调整声音信号的增益,以便在不同的录音环境中保持一致的音量水平。对于声音信号的动态范围较大的情况,AGC 可以防止信号过于强大而导致失真,或者过于微弱而无法听清。

噪音抑制 (Noise Suppression, NS):NS 技术用于减少背景噪音对于声音信号的干扰。在录音中,周围环境的噪音可能会混入到所需的声音中,影响清晰度。NS 技术利用信号处理算法,识别和降低噪音成分,使得声音更加清晰和可听。

这些声效技术通常用于音频通信、音频处理和音频增强等应用。它们可以提供更好的音质和体验,减少噪音干扰,并优化音频的各个方面。

package com.realtop.audioecho.other;

import android.annotation.SuppressLint;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.media.audiofx.AcousticEchoCanceler;
import android.media.audiofx.AudioEffect;
import android.media.audiofx.AutomaticGainControl;
import android.media.audiofx.NoiseSuppressor;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.LinearLayout;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatButton;
import androidx.appcompat.widget.AppCompatCheckBox;
import androidx.appcompat.widget.AppCompatTextView;

public class MainActivity extends AppCompatActivity {

    private static final String LOG_TAG = "other_test_activity";
    private static final String TAG = LOG_TAG;

    private AudioRecord mAudioRecorder = null;
    private AudioTrack mStreamingPlayer = null;

    int bufferSize;

    int chunkSize;
    private AutomaticGainControl agc;

    private NoiseSuppressor suppressor;
    private AcousticEchoCanceler aec;
    private boolean manuallyAttachEffects = false;

    private boolean isRunning = false;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LinearLayout linearLayout = new LinearLayout(this);
        initView(linearLayout);
        setContentView(linearLayout);
    }

    @SuppressLint("SetTextI18n")
    private void initView(LinearLayout linearLayout) {
        linearLayout.setOrientation(LinearLayout.VERTICAL);
        AppCompatButton button = new AppCompatButton(this);
        AppCompatButton button2 = new AppCompatButton(this);
        AppCompatTextView appCompatTextView = new AppCompatTextView(this);
        AppCompatCheckBox checkBox = new AppCompatCheckBox(this);
        linearLayout.addView(button);
        linearLayout.addView(button2);
        linearLayout.addView(checkBox);
        linearLayout.addView(appCompatTextView);
        AudioEffect.Descriptor[] descriptors = AudioEffect.queryEffects();
        StringBuilder outs = new StringBuilder();
        for (AudioEffect.Descriptor descriptor : descriptors) {
            outs.append("; name:").append(descriptor.name).append("type:")
                    .append(descriptor.type).append("; mode:")
                    .append(descriptor.connectMode)
                    .append("; uuid:").append(descriptor.uuid).append("\n");
        }
        Log.i(TAG, "onCreate: aec:" + outs + "\n" + AudioEffect.EFFECT_TYPE_AEC.toString());
        String msg = "回声降噪:" + AcousticEchoCanceler.isAvailable()
                + "; 增益消除:" + AutomaticGainControl.isAvailable()
                + "; 降噪:" + NoiseSuppressor.isAvailable();
        appCompatTextView.setText(msg + "\n" + outs);
        button.setText("点击录音");
        button2.setText("关闭录音");
        checkBox.setText("是否手动启动echo api");

        button.setOnClickListener(v -> startRecordingAudio());
        button2.setOnClickListener(v -> isRunning = false);
        checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> manuallyAttachEffects = isChecked);
    }

    @SuppressWarnings({"ConstantConditions", "deprecation"})
    @SuppressLint("MissingPermission")
    private void startRecordingAudio() {
        int sampleRate = 44100;
        int channelConfig = AudioFormat.CHANNEL_IN_MONO;
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT;

        chunkSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
        bufferSize = chunkSize * 10;

        int audioSource = MediaRecorder.AudioSource.MIC;

        boolean useVoip = true;
        if (useVoip && !manuallyAttachEffects) {
            audioSource = MediaRecorder.AudioSource.VOICE_COMMUNICATION;
        }

        mAudioRecorder = new AudioRecord(audioSource,
                sampleRate,
                channelConfig,
                audioFormat,
                bufferSize);

        if (useVoip && manuallyAttachEffects) {
            msg("手动开启回声消除效果");
            setupVoipEffects(mAudioRecorder.getAudioSessionId());
        }

        mAudioRecorder.startRecording();

        mStreamingPlayer = new AudioTrack(AudioManager.STREAM_MUSIC,
                sampleRate,
                AudioFormat.CHANNEL_OUT_MONO,
                audioFormat,
                bufferSize,
                AudioTrack.MODE_STREAM,
                mAudioRecorder.getAudioSessionId());

        mStreamingPlayer.play();

        Thread playbackThread = new Thread(this::readAudioData);

        isRunning = true;
        playbackThread.start();

        Log.i(TAG, "startRecordingAudio: AudioEffect-JAVA: create aec start");
        AcousticEchoCanceler.create(mAudioRecorder.getAudioSessionId());
    }

    private void readAudioData() {
        byte[] buffer = new byte[chunkSize];

        while (isRunning) {
            if (mAudioRecorder == null)
                break;

            int bytesRead = mAudioRecorder.read(buffer, 0, chunkSize);
            if (bytesRead > 0) {
                if (mStreamingPlayer == null)
                    break;

                mStreamingPlayer.write(buffer, 0, chunkSize);
            }
        }

        // 录制/播放结束--------------------------------------
        try {
            Thread.sleep(888);

            mStreamingPlayer.flush();
            mStreamingPlayer.stop();
            mStreamingPlayer.release();

            mAudioRecorder.stop();
            mAudioRecorder.release();

            if (agc != null) {
                agc.setEnabled(false);
                agc.release();
                Log.i(TAG, "readAudioData: close agc");
            }

            if (suppressor != null) {
                suppressor.setEnabled(false);
                suppressor.release();
                Log.i(TAG, "readAudioData: close ns");
            }

            if (aec != null) {
                aec.setEnabled(false);
                aec.release();
                Log.i(TAG, "readAudioData: close aec");
            }
            Log.i(TAG, "readAudioData: release ok");
        } catch (Exception e) {
            e.printStackTrace();
            Log.i(TAG, "readAudioData: error:" + e.getMessage());
        }

        msg("录音结束");
    }

    private void msg(String s) {
        new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(MainActivity.this, s, Toast.LENGTH_LONG).show());
    }

    private void setupVoipEffects(int sessionId) {
        if (AutomaticGainControl.isAvailable()) {
            agc = AutomaticGainControl.create(sessionId);

            if (agc != null) {
                if (!agc.getEnabled()) {
                    agc.setEnabled(true);
                    Log.d(LOG_TAG, "AGC is " + (agc.getEnabled() ? "enabled" : "disabled" + " after trying to enable"));
                }
            } else {
                Log.i(TAG, "setupVoipEffects: agc is null");
            }
        }

        if (NoiseSuppressor.isAvailable()) {
            suppressor = NoiseSuppressor.create(sessionId);

            if (suppressor != null) {
                if (!suppressor.getEnabled()) {
                    suppressor.setEnabled(true);
                    Log.d(LOG_TAG, "NS is " + (suppressor.getEnabled() ? "enabled" : "disabled" + " after trying to disable"));
                }
            } else {
                Log.i(TAG, "setupVoipEffects: ns is null");
            }

        }
        if (AcousticEchoCanceler.isAvailable()) {
            aec = AcousticEchoCanceler.create(sessionId);

            if (aec != null) {
                if (!aec.getEnabled()) {
                    aec.setEnabled(true);
                    Log.d(LOG_TAG, "AEC is " + (aec.getEnabled() ? "enabled" : "disabled" + " after trying to disable"));
                }
            } else {
                Log.i(TAG, "setupVoipEffects: aec is null");
            }
        }
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值