#include #include #include #include "timing.h" #include "log/logger.h" #include "common.h" #include #include #include "alsa_dev.h" #include "agcm.h" using namespace toolkit; #define MIX_AUDIO_CHANNELS 2 #define MIX_AUDIO_RATE 48000 #define MIX_AUDIO_SAMPLES (10 * MIX_AUDIO_RATE / 1000) struct audio_buf_t { uint8_t* data; int index; int size; }; struct CallContext { // RtmpConfig rtmp; std::thread *rtmp_thread; std::thread *alsa_thread; std::mutex *mutex; std::vector *list; webrtc::AudioProcessing *apm_agc; webrtc::AudioProcessing *apm_ns; webrtc::StreamConfig *rtc_stream_config; alsa::AlsaDev *alsa; alsa::Config *alsa_config; LegacyAgc *agcModule; bool running; }; webrtc::AudioProcessing::Config webtcConfigInit() { webrtc::AudioProcessing::Config apmConfig; apmConfig.pipeline.maximum_internal_processing_rate = MIX_AUDIO_RATE; apmConfig.pipeline.multi_channel_capture = true; apmConfig.pipeline.multi_channel_render = true; //PreAmplifier apmConfig.pre_amplifier.enabled = false; apmConfig.pre_amplifier.fixed_gain_factor = 0.7f; //HighPassFilter apmConfig.high_pass_filter.enabled = true; apmConfig.high_pass_filter.apply_in_full_band = false; //EchoCanceller apmConfig.echo_canceller.enabled = false; apmConfig.echo_canceller.mobile_mode = false; apmConfig.echo_canceller.export_linear_aec_output = false; apmConfig.echo_canceller.enforce_high_pass_filtering = false; //NoiseSuppression apmConfig.noise_suppression.enabled = true; apmConfig.noise_suppression.level = webrtc::AudioProcessing::Config::NoiseSuppression::kVeryHigh; apmConfig.noise_suppression.analyze_linear_aec_output_when_available = false; //TransientSuppression apmConfig.transient_suppression.enabled = false; //VoiceDetection apmConfig.voice_detection.enabled = true; //GainController1 apmConfig.gain_controller1.enabled = true; // kAdaptiveAnalog 自适应模拟模式 // kAdaptiveDigital 自适应数字增益模式 // kFixedDigital 固定数字增益模式 apmConfig.gain_controller1.mode = webrtc::AudioProcessing::Config::GainController1::kFixedDigital; apmConfig.gain_controller1.target_level_dbfs = 6; // 目标音量 apmConfig.gain_controller1.compression_gain_db = 60; // 增益能力 apmConfig.gain_controller1.enable_limiter = true; // 压限器开关 apmConfig.gain_controller1.analog_level_minimum = 0; apmConfig.gain_controller1.analog_level_maximum = 255; apmConfig.gain_controller1.analog_gain_controller.enabled = false; // apmConfig.gain_controller1.analog_gain_controller.startup_min_volume = webrtc::kAgcStartupMinVolume; apmConfig.gain_controller1.analog_gain_controller.startup_min_volume = 0; apmConfig.gain_controller1.analog_gain_controller.clipped_level_min = 0; apmConfig.gain_controller1.analog_gain_controller.enable_agc2_level_estimator = false; apmConfig.gain_controller1.analog_gain_controller.enable_digital_adaptive = false; //GainController2 apmConfig.gain_controller2.enabled = false; apmConfig.gain_controller2.fixed_digital.gain_db = 0.f; apmConfig.gain_controller2.adaptive_digital.enabled = true; apmConfig.gain_controller2.adaptive_digital.vad_probability_attack = 1.f; apmConfig.gain_controller2.adaptive_digital.level_estimator = webrtc::AudioProcessing::Config::GainController2::kRms; apmConfig.gain_controller2.adaptive_digital.level_estimator_adjacent_speech_frames_threshold = 1; apmConfig.gain_controller2.adaptive_digital.use_saturation_protector = true; apmConfig.gain_controller2.adaptive_digital.initial_saturation_margin_db = 20.f; apmConfig.gain_controller2.adaptive_digital.extra_saturation_margin_db = 2.f; apmConfig.gain_controller2.adaptive_digital.gain_applier_adjacent_speech_frames_threshold = 1; apmConfig.gain_controller2.adaptive_digital.max_gain_change_db_per_second = 3.f; apmConfig.gain_controller2.adaptive_digital.max_output_noise_level_dbfs = -50.f; //ResidualEchoDetector apmConfig.residual_echo_detector.enabled = false; //LevelEstimation apmConfig.level_estimation.enabled = false; return apmConfig; } void capture_thread(CallContext *ctx); int main() { //初始化日志系统 Logger::Instance().add(std::make_shared ()); Logger::Instance().add(std::make_shared()); Logger::Instance().setWriter(std::make_shared()); // webrtc初始化 webrtc::AudioProcessing *apm = webrtc::AudioProcessingBuilder().Create(); if (!apm) { PrintI("create apm failed.\n"); return -1; } webrtc::AudioProcessing::Config config = webtcConfigInit(); apm->ApplyConfig(config); apm->Initialize(); config.gain_controller1.enabled = false; config.gain_controller1.analog_gain_controller.enabled = false; config.noise_suppression.enabled = true; config.noise_suppression.level = config.noise_suppression.kVeryHigh; webrtc::AudioProcessing *apm_ns = webrtc::AudioProcessingBuilder().Create(); apm_ns->ApplyConfig(config); apm_ns->Initialize(); webrtc::StreamConfig streamConfig; streamConfig.set_has_keyboard(false); streamConfig.set_num_channels(MIX_AUDIO_CHANNELS); streamConfig.set_sample_rate_hz(MIX_AUDIO_RATE); // agc module LegacyAgc *agcInst = (LegacyAgc *)agc_init(MIX_AUDIO_RATE, kAgcModeAdaptiveDigital, 9, 3); InfoL << "gain db: " << config.gain_controller1.compression_gain_db << ", target db:" << config.gain_controller1.target_level_dbfs; // alsa设备参数 alsa::Config alsaConfig; sprintf(alsaConfig.device, "default"); alsaConfig.period_time = MIX_AUDIO_SAMPLES * 1000000 / MIX_AUDIO_RATE; alsaConfig.buffer_time = 5 * alsaConfig.period_time; alsaConfig.channels = MIX_AUDIO_CHANNELS; alsaConfig.format = SND_PCM_FORMAT_S16_LE; alsaConfig.rate = MIX_AUDIO_RATE; // CallContext recordCtx; recordCtx.mutex = new std::mutex; recordCtx.list = new std::vector(); recordCtx.apm_agc = apm; recordCtx.apm_ns = apm_ns; recordCtx.rtc_stream_config = &streamConfig; recordCtx.alsa_config = &alsaConfig; recordCtx.agcModule = agcInst; char c; bool quit = false; while ((c = getchar()) != EOF && !quit) { switch (c) { case 'q': { break; } case 's': { recordCtx.running = true; recordCtx.alsa_thread = new std::thread(capture_thread, &recordCtx); break; } } } return 0; } void capture_thread(CallContext *ctx) { // 声卡初始化 alsa::AlsaDev usbCaptureDev; if (usbCaptureDev.applyConfig(*ctx->alsa_config) < 0) { PrintE("alsa config failed.\n"); return ; } if (usbCaptureDev.init(SND_PCM_STREAM_CAPTURE) < 0) { PrintE("alsa init failed.\n"); return ; } PrintI("alsa init: %s\n", usbCaptureDev.configToString()); ctx->alsa = &usbCaptureDev; uint8_t *capData = nullptr; int buffer_size = usbCaptureDev.getFrames() * usbCaptureDev.getFrameSize(); capData = (uint8_t *)malloc(buffer_size); assert(capData); FILE *record_fp = fopen("/root/agc_record.pcm", "wb"); FILE *agc_fp = fopen("/root/agc_out.pcm", "wb"); FILE *scale_fp = fopen("/root/agc_scale.pcm", "wb"); InfoL << "-------------- start ----------------"; uint8_t *agcBuf = (uint8_t *)malloc(buffer_size); while (ctx->running) { // 采集 // t_capture = gettimeofday(); size_t read_size = usbCaptureDev.read(capData, buffer_size); PrintI("alsa read %d\n", read_size); if (read_size <= 0) { msleep(1); continue; } // alsa::vol_scaler_run((int16_t *)capData, buffer_size/2, 100); fwrite(capData, 1, buffer_size, record_fp); // { // int samples = 160; // int times = usbCaptureDev.getFrames() * 2 / samples; // int16_t *in = (int16_t *)capData; // int16_t *out = (int16_t *)agcBuf; // for (int i = 0; i < times; ++i) { // agc_process(ctx->agcModule, in + i*samples, out + i*samples, MIX_AUDIO_RATE, samples); // } // memcpy(capData, agcBuf, buffer_size); // } // 降噪 { // std::unique_lock lck(*ctx->mutex); // t_process = gettimeofday(); ctx->apm_agc->ProcessStream((int16_t *)capData, *ctx->rtc_stream_config, *ctx->rtc_stream_config, (int16_t *)capData); // ctx->apm_ns->ProcessStream((int16_t *)capData, *ctx->rtc_stream_config, *ctx->rtc_stream_config, (int16_t *)capData); } fwrite(capData, 1, buffer_size, agc_fp); memset(capData, 0, buffer_size); // alsa::vol_scaler_run((int16_t *)capData, buffer_size / 2, 100); // fwrite(capData, 1, buffer_size, scale_fp); } usbCaptureDev.destory(); if (capData) free(capData); ctx->alsa = nullptr; }