WebRTC系列-APM参数设置及AudioOption

1. 上层接口设置

音频的相关参数需要在创建audioTrack的时候就去设置,在iOS端(Android类似设置的方式如下:

 NSDictionary *mandatoryConstraints  = @{};
        NSDictionary *optionalConstraints  = @{ @"googEchoCancellation"   : openEc?kRTCMediaConstraintsValueTrue:kRTCMediaConstraintsValueFalse,
                                             @"googAutoGainControl"     : openGc?kRTCMediaConstraintsValueTrue:kRTCMediaConstraintsValueFalse,
                                             @"googNoiseSuppression"    :(!openNoise)?kRTCMediaConstraintsValueTrue:kRTCMediaConstraintsValueFalse,};
//    ,@"ios_force_software_aec_HACK"
    RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatoryConstraints
                                                                             optionalConstraints:optionalConstraints];
                                                                              RTCMediaConstraints *constraints = [self defaultMediaAudioConstraintsWithOpenEc:_openEc openGC:_openGc noise:_openNs];
        RTCAudioSource *source = [_factory audioSourceWithConstraints:constraints];

上面三个参数一次是

  • googEchoCancellation 是AEC也就是回声消除
  • googAutoGainControl 是AGC 也就是增益控制
  • googNoiseSuppression 也就是NS 噪声控制
    其中ios提供了强制开启AEC的参数ios_force_software_aec_HACK,但是在参数转换的时候并没有效果,如何让这个参数有效在下节分析;
    当然在iOS端上面的参数都有没有效果的,这个在后面分析设置apm参数的时候再说为啥;
    Android按照上面设置是可以生效,也就是可以作为apm的参数使用;

1.1 参数转换

在iOS端设置完次参数后会在RTCPeerConnectionFactory的audioSourceWithConstraints方法中转换,实现如下:

cricket::AudioOptions options;
  CopyConstraintsIntoAudioOptions(nativeConstraints.get(), &options);

可以看到这里参数转换的核心调用是CopyConstraintsIntoAudioOptions方法,这个方法在media_constaints.cc中,实现如下:

void CopyConstraintsIntoAudioOptions(const MediaConstraints* constraints,
                                     cricket::AudioOptions* options) {
  if (!constraints) {
    return;
  }
  ConstraintToOptional<bool>(constraints,
                             MediaConstraints::kGoogEchoCancellation,
                             &options->echo_cancellation);
  ConstraintToOptional<bool>(constraints,
        。。。省略
  ConstraintToOptional<bool>(constraints, MediaConstraints::kAutoGainControl,
                             &options->auto_gain_control);
  ConstraintToOptional<bool>(constraints,
          。。。省略
      MediaConstraints::kNoiseSuppression,
                             &options->noise_suppression);
  ConstraintToOptional<bool>(constraints,
   。。。省略
  #if defined(WEBRTC_IOS)
//    // hosten 修改参数
//  ConstraintToOptional<bool>(constraints, MediaConstraints::kiOSForceSoftwareAecHACK,
//    &options->ios_force_software_aec_HACK);
#endif
  if (options->audio_network_adaptor_config) {
    options->audio_network_adaptor = true;
  }
  // end
}

在上述代码中可以看到相关的参数转换成了AudioOptions,赋值给出参options;
在这里上节说的ios_force_software_aec_HACK这个参数如果想生效需要吧按照注释中修改参数那里的方式添加,其中的kiOSForceSoftwareAecHACK,定义如下:

 #if defined(WEBRTC_IOS)
const char MediaConstraints::kiOSForceSoftwareAecHACK[] = "googiOSForceSoftwareAecHACK";
#endif

按照以上方式设置就能让此参数生效;

1.2 参数传递

在audioSourceWithConstraints:方法中转换参数成AudioOptions,后接着调用Factory的CreateAudioSource方法:

rtc::scoped_refptr<AudioSourceInterface>
PeerConnectionFactory::CreateAudioSource(const cricket::AudioOptions& options) {
  rtc::scoped_refptr<LocalAudioSource> source(
      LocalAudioSource::Create(&options));
  return source;
}

这个里面主要是调用LocalAudioSource的Create方法去创建AudioSourceInterface对象;最终options保存在options_属性中;调用栈如下:
在这里插入图片描述

2. AudioOption的传递流程

通过在代码中断点我们可以定位到这个参数首次的使用是在AudioRtpSender的SetSend中调用,如下:

void AudioRtpSender::SetSend() {
 ...省略
  cricket::AudioOptions options;
#if !defined(WEBRTC_CHROMIUM_BUILD) && !defined(WEBRTC_WEBKIT_BUILD)
  if (track_->enabled() && audio_track()->GetSource() &&
      !audio_track()->GetSource()->remote()) {
    options = audio_track()->GetSource()->options();
  }

#endif
  bool track_enabled = track_->enabled();
  bool success = worker_thread_->Invoke<bool>(RTC_FROM_HERE, [&] {
    return voice_media_channel()->SetAudioSend(ssrc_, track_enabled, &options,
                                               sink_adapter_.get());
  });
 
}

可以看到这里从audio_track获取到souce,上一节最后AudioOptions参数最终保存在Source的options_变量;
接着切换到工作线程调用channal的SetAudioSend方法这里的调试堆栈如下:
在这里插入图片描述
在work线程中调用堆栈如下:
在这里插入图片描述
其中WebRtcVoiceEngine的ApplyOptions中最终使用这个参数,参数如下:
在这里插入图片描述
这里和我们上面的OC层接口配置的参数一致;
还有其他调用ApplyOptions的流程这里暂时不做分析,不是主要的流程,后续如果有时间补充;

3. apm参数配置

最终的参数设置是在ApplyOptions方法中,这个方法比较的多且分平台处理,这里分解说明如下:

3.1 AEC的处理

分平台的处理,源码如下:

#if defined(WEBRTC_IOS)
  if (options.ios_force_software_aec_HACK &&
      *options.ios_force_software_aec_HACK) {
    // EC may be forced on for a device known to have non-functioning platform
    // AEC.
    options.echo_cancellation = true;
    options.extended_filter_aec = true;
    RTC_LOG(LS_WARNING)
        << "Force software AEC on iOS. May conflict with platform AEC.";
  } else {
    // On iOS, VPIO provides built-in EC.
    options.echo_cancellation = false;
    options.extended_filter_aec = false;
    RTC_LOG(LS_INFO) << "Always disable AEC on iOS. Use built-in instead.";
  }
#elif defined(WEBRTC_ANDROID)
  ec_mode = webrtc::kEcAecm;
  options.extended_filter_aec = false;
#endif

  // Delay Agnostic AEC automatically turns on EC if not set except on iOS
  // where the feature is not supported.
  bool use_delay_agnostic_aec = false;
#if !defined(WEBRTC_IOS)
  if (options.delay_agnostic_aec) {
    use_delay_agnostic_aec = *options.delay_agnostic_aec;
    if (use_delay_agnostic_aec) {
      options.echo_cancellation = true;
      options.extended_filter_aec = true;
      ec_mode = webrtc::kEcConference;
    }
  }
#endif

对于ios如果启用了ios_force_software_aec_HACK,这里就会设置echo_cancellation为true也就是启用软件的AEC,否则ios这里是直接设置成false,也就是使用VOIP自带的AEC;
对于Android 等其他平台如果开启了delay_agnostic_aec,这里会这直接把echo_cancellation设置为true;

3.2 NS降噪处理

降噪这里也是按照不同平台有不通的处理:
#if defined(WEBRTC_IOS)
  //options.noise_suppression = false;
  options.typing_detection = false;
  options.experimental_ns = false;
  RTC_LOG(LS_INFO) << "Always disable NS on iOS. Use built-in instead.";
#elif defined(WEBRTC_ANDROID)
  options.typing_detection = false;
  options.experimental_ns = false;
#endif

// Set and adjust gain control options.
#if defined(WEBRTC_IOS)
  options.auto_gain_control = false;
  options.experimental_agc = false;
  RTC_LOG(LS_INFO) << "Always disable AGC on iOS. Use built-in instead.";
#elif defined(WEBRTC_ANDROID)
  options.experimental_agc = false;
#endif

对于ios 这里的auto_gain_control默认是设置成false,如果需要启用外部参数控制这里需要注释掉;

4. 各平台ADM接口调用

3A算法在各个的平台都有实现,webrtc这里通过调用ADM的相关方法判断平台是不是支持响应的算法从而是否启用webrtc的3A,其实现如下:

if (options.echo_cancellation) {

    // in combination with Open SL ES audio.
    const bool built_in_aec = adm()->BuiltInAECIsAvailable();
    if (built_in_aec) {
      const bool enable_built_in_aec =
          *options.echo_cancellation && !use_delay_agnostic_aec;
      if (adm()->EnableBuiltInAEC(enable_built_in_aec) == 0 &&
          enable_built_in_aec) {

        options.echo_cancellation = false;
        RTC_LOG(LS_INFO)
            << "Disabling EC since built-in EC will be used instead";
      }
    }
    webrtc::apm_helpers::SetEcStatus(apm(), *options.echo_cancellation,
                                     ec_mode);
  }

  if (options.auto_gain_control) {
    bool built_in_agc_avaliable = adm()->BuiltInAGCIsAvailable();
    if (built_in_agc_avaliable) {
      if (adm()->EnableBuiltInAGC(*options.auto_gain_control) == 0 &&
          *options.auto_gain_control) {
 
        options.auto_gain_control = false;
        RTC_LOG(LS_INFO)
            << "Disabling AGC since built-in AGC will be used instead";
      }
    }
  }

  if (options.noise_suppression) {
    if (adm()->BuiltInNSIsAvailable()) {
      bool builtin_ns = *options.noise_suppression;
      if (adm()->EnableBuiltInNS(builtin_ns) == 0 && builtin_ns) {
        options.noise_suppression = false;
        RTC_LOG(LS_INFO)
            << "Disabling NS since built-in NS will be used instead";
      }
    }
    webrtc::apm_helpers::SetNsStatus(apm(), *options.noise_suppression);
  }

需要说明的是ios的adm是没有实现BuiltInAECIsAvailable,BuiltInAGCIsAvailable等方法的,所以这里都是返回false;
对于其他平台都是先调用对应的buildin方法判断平台是否开启了对应的算法,如果开启了就调用对应的enable关闭;
后续的ApplyConfig参数设置,这里就不做介绍感兴趣的参看源码;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: webrtc-qt-example是一个基于Qt框架开发的WebRTC示例项目。 WebRTC是一种开源的实时通信技术,能够支持音频、视频和数据的实时传输。它通过浏览器之间的端对端连接,实现了高质量的实时通信。 webrtc-qt-example的目的是展示如何使用Qt进行WebRTC开发。Qt是一套跨平台的C++应用程序开发框架,它提供了丰富的工具和库,使开发者能够快速构建可靠的应用程序。 这个示例项目提供了一些基本的功能和界面,使开发者能够了解和学习如何将WebRTC集成到Qt应用程序中。它包含了常见的WebRTC功能,如媒体流捕获、媒体流传输、信令交换等。 通过webrtc-qt-example,开发者可以学习到如何使用Qt的多媒体模块来捕获音频、视频和媒体设备。同时,也可以学习到如何使用Qt的网络模块来进行实时信令交换和流传输。 这个示例项目还提供了一些简单的界面,方便开发者进行测试和调试。开发者可以通过该界面实现与其他WebRTC应用的通信,例如建立视频通话、音频通话等。 总之,webrtc-qt-example是一个非常实用的示例项目,可以帮助开发者快速上手并掌握WebRTC在Qt中的开发。 ### 回答2: webrtc-qt-example是一个基于Qt框架的WebRTC示例应用程序。WebRTC是一种开源项目,它提供了在浏览器之间进行实时通信的能力,包括视频和音频的传输。而webrtc-qt-example则是将这种技术集成到Qt应用程序中的一个示例。 在webrtc-qt-example中,它使用了Qt的多媒体框架和WebRTC提供的API来实现音视频的传输和显示。通过使用WebRTC的API,webrtc-qt-example可以建立点对点的连接,进行音频和视频的实时传输。 webrtc-qt-example中的代码结构清晰,易于理解和扩展。它提供了一些基本的功能,如建立连接、发送和接收音视频流、呼叫取消等。开发者可以根据自己的需求来对这些功能进行定制和扩展。 此外,webrtc-qt-example还支持一些高级特性,如媒体设备的选择、音视频的编码和解码等。开发者可以通过修改代码来选择不同的媒体设备,并且可以使用不同的编码和解码算法来满足自己的需求。 总之,webrtc-qt-example是一个很棒的WebRTC示例应用程序,它可以帮助开发者快速了解和使用WebRTC技术。无论是为了实现实时视频通话、视频会议还是其他需要音视频传输的应用场景,webrtc-qt-example都提供了一个良好的起点,帮助开发者快速上手并实现自己的需求。 ### 回答3: webrtc-qt-example是一个基于Qt框架和WebRTC技术的示例应用。WebRTC是一种用于在Web浏览器上实现实时通信的开源项目,它提供了一套丰富的API和协议,可以实现音视频通话、数据传输以及屏幕共享等功能。 webrtc-qt-example利用Qt框架提供的跨平台能力,结合WebRTC技术,展示了在Qt应用中如何实现实时通信功能。这个示例应用具有以下特点和功能: 1. 界面友好:webrtc-qt-example使用Qt的GUI绘制工具,具有美观、直观的用户界面,便于用户操作和使用。 2. 实时通信:webrtc-qt-example内置了WebRTC的音视频通信功能,可以实现实时的语音和视频通话,支持两个或多个用户之间的通信。 3. 数据传输:除了音视频通话,webrtc-qt-example还支持在通话中传输数据。可以通过编写代码,实现实时文本传输或共享文件等功能。 4. 屏幕共享:webrtc-qt-example还支持屏幕共享功能,可以将自己的屏幕内容分享给其他用户,实现远程协助或在线教育等应用场景。 通过webrtc-qt-example的学习和实践,开发者可以了解并深入理解WebRTC技术的使用方法,以及在Qt框架中的应用。同时,借助webrtc-qt-example提供的示例代码和API文档,开发者可以进一步开发出更加复杂和功能丰富的实时通信应用,满足不同领域的需求。 总之,webrtc-qt-example是一个基于Qt框架和WebRTC技术的示例应用,具备实时音视频通话、数据传输和屏幕共享等功能,适用于开发者学习、实践和开发基于WebRTC的实时通信应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

简简单单lym

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值