WebRTC线程的退出销毁不了的问题分析的流程

WebRTC线程的退出销毁不了的问题分析的流程


WebRTC专题开嗨鸭 !!!

一、 WebRTC 线程模型和网络

1、WebRTC中线程模型和常见线程模型介绍

2、WebRTC网络PhysicalSocketServer之WSAEventselect模型使用

3、WebRTC线程的退出销毁不了的问题分析的流程

二、 WebRTC媒体协商

1、WebRTC媒体协商之CreatePeerConnectionFactory、CreatePeerConnection、CreateOffer

三、 WebRTC 音频数据采集

四、 WebRTC 音频引擎(编解码和3A算法)

五、 WebRTC 视频数据采集

六、 WebRTC 视频引擎( 编解码)

七、 WebRTC 网络传输

八、 WebRTC服务质量(Qos)

九、 NetEQ

十、 Simulcast与SVC

前言

WebRTC是音视频行业的标杆, 如果要学习音视频, WebRTC是进入音视频行业最好方法, 里面可以有成熟方案, 例如:音频中3A 算法、网络评估、自适应码流、Simulcast、SVC等等 , 非常适合刚刚进入音视频行业小伙伴哈_ 我也是哦, 以后再音视频行业长期打算的小伙伴的学习项目。 里面有大量知识点


提示:以下是本篇文章正文内容,下面案例可供参考

一、WebRTC 三大线程销毁了, 但是main函数还是没有退出的问题复现

main 函数中连接mediasoup服务器进行推流哈的流程代码

const char* config_filename = "client.cfg";
	if (argc > 1)
	{
		config_filename = argv[1];
	}
	signal(SIGINT, signalHandler);
	signal(SIGTERM, signalHandler);
	std::thread m_thread;
	int32_t  count = 0;
	if (!ccloud_rendering_mgr.init(config_filename))
	{
		// error
		return -1;
	}
	printf("init ok  2... \n");
	while (true)
	{
		printf("main loop ........ \n");
		m_thread = std::thread(
			[=]() {
			printf("child ->  loop ........ \n");
			ccloud_rendering_mgr.Loop();
			printf("child ->  loop exit ........ \n");
		}
		);
		printf("main [g_thread_count = %d] loop min 2... \n", g_thread_count);
		std::this_thread::sleep_for(std::chrono::seconds(30));
		printf("main [g_thread_count = %d][] loop min 2... \n", g_thread_count);
		ccloud_rendering_mgr.Destroy();
		
		++count;
		if (m_thread.joinable())
		{
			m_thread.join();
		}
		if (count < 10)
		{
			break;
		}
	}
	//mediasoupclient::Handler::all_close();
	printf("all stop\n");
	//std::this_thread::sleep_for(std::chrono::seconds(10));
	
	all_stop();
	printf("+++++++++++++++++ all stop ok !!! \n");
	//std::this_thread::sleep_for(std::chrono::seconds(5));
	
	
	//std::this_thread::sleep_for(std::chrono::minutes(1));
	//webrtc::GlobalTaskQueueFactory()
	//while (true)
	{
		printf("main [g_thread_count = %d] ====================loop min 2... \n", g_thread_count);
		std::this_thread::sleep_for(std::chrono::seconds(10));
		printf("main exit [g_thread_count = %d] ====================loop min 2... \n", g_thread_count);
		
	}
	return 0;
	

在all_stop函数中进行三大线程销毁 (workerThread、signalingThread、networkThread)

三大线程是全局的线程哈


if (!networkThread || !signalingThread || !workerThread)
			{
				networkThread = rtc::Thread::CreateWithSocketServer();
				signalingThread = rtc::Thread::Create();
				workerThread = rtc::Thread::Create();
				networkThread->SetName("network_thread", nullptr);
				signalingThread->SetName("signaling_thread", nullptr);
				workerThread->SetName("worker_thread", nullptr);
			}
			g_thread_count += 3;
			/*this->networkThread->SetName("network_thread", nullptr);
			this->signalingThread->SetName("signaling_thread", nullptr);
			this->workerThread->SetName("worker_thread", nullptr);*/
			static bool load = false;
			if (! load)
			{
				load = true;
				networkThread->Start(); 
				signalingThread->Start();
				workerThread->Start();
				//MSC_THROW_INVALID_STATE_ERROR("thread start errored");
			}

/



if (signalingThread)
	{
		signalingThread->Stop();

	}
	if (workerThread)
	{
		workerThread->Stop();
	}
	if (networkThread)
	{
		networkThread->Stop();
	}

运行后程序退不出了, 中线程情况图

在这里插入图片描述

线程分类

  1. main主线线程
  2. waitforWorkViaWorkFactory工作线程(7个线程)
  3. sogou线程(2个线程)
  4. rtc_low_prio线程音频录制维护功能(LOW) (1个线程)
  5. AudioDeviceBufferTimer音频buffer缓冲区线程(1个线程)

二、 分析问题解决的方法

正常情况退出代码分析

mediasoupclient::Handler::GetNativeRtpCapabilities(nullptr);
	 workerThread->Stop();
	 signalingThread->Stop();
	 networkThread->Stop();
	 //while (true)
	 {
		 printf("sleep  2 seconds ....\n");

		 std::this_thread::sleep_for(std::chrono::seconds(50));
	 }
	  

线程图
在这里插入图片描述

线程分为 两大类分别是

main线程wiat线程是正常的

我先是卸载搜狗输入了,然后SogouPy.ime线程没有了、 好奇??? (sogouPy玩的hook技术呢)
然后查音频线程停止的函数 rtc-low-prio 是channel_manager_中音频引擎中创建的 创建init中创建在析构中停止线程的,但是我发现析构中调用不会调用函数还是什么的 ??然后我就自动调用停止音频的录制后线程就退出哈 在peerconnectionfactory调用了StopAecDump音频录制的函数然后就正常退出哈

WebRtcVoiceEngine::WebRtcVoiceEngine(
    webrtc::TaskQueueFactory* task_queue_factory,
    webrtc::AudioDeviceModule* adm,
    const rtc::scoped_refptr<webrtc::AudioEncoderFactory>& encoder_factory,
    const rtc::scoped_refptr<webrtc::AudioDecoderFactory>& decoder_factory,
    rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer,
    rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing)
    : task_queue_factory_(task_queue_factory),
      adm_(adm),
      encoder_factory_(encoder_factory),
      decoder_factory_(decoder_factory),
      audio_mixer_(audio_mixer),
      apm_(audio_processing) {
  // This may be called from any thread, so detach thread checkers.
  worker_thread_checker_.Detach();
  signal_thread_checker_.Detach();
  RTC_LOG(LS_INFO) << "WebRtcVoiceEngine::WebRtcVoiceEngine";
  RTC_DCHECK(decoder_factory);
  RTC_DCHECK(encoder_factory);
  RTC_DCHECK(audio_processing);
  // The rest of our initialization will happen in Init.
}

WebRtcVoiceEngine::~WebRtcVoiceEngine() {
  RTC_DCHECK(worker_thread_checker_.IsCurrent());
  RTC_LOG(LS_INFO) << "WebRtcVoiceEngine::~WebRtcVoiceEngine";
  if (initialized_) {
    StopAecDump();

    // Stop AudioDevice.
    adm()->StopPlayout();
    adm()->StopRecording();
    adm()->RegisterAudioCallback(nullptr);
    adm()->Terminate();
  }
}
void WebRtcVoiceEngine::Init() {
  RTC_DCHECK(worker_thread_checker_.IsCurrent());
  RTC_LOG(LS_INFO) << "WebRtcVoiceEngine::Init";
  //这边音频采集设备录音线程哈
  // TaskQueue expects to be created/destroyed on the same thread.
  low_priority_worker_queue_.reset(
      new rtc::TaskQueue(task_queue_factory_->CreateTaskQueue(
          "rtc-low-prio", webrtc::TaskQueueFactory::Priority::LOW)));

  // Load our audio codec lists.
  RTC_LOG(LS_INFO) << "Supported send codecs in order of preference:";
  send_codecs_ = CollectCodecs(encoder_factory_->GetSupportedEncoders());
  for (const AudioCodec& codec : send_codecs_) {
    RTC_LOG(LS_INFO) << ToString(codec);
  }

  RTC_LOG(LS_INFO) << "Supported recv codecs in order of preference:";
  recv_codecs_ = CollectCodecs(decoder_factory_->GetSupportedDecoders());
  for (const AudioCodec& codec : recv_codecs_) {
    RTC_LOG(LS_INFO) << ToString(codec);
  }

#if defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
  // No ADM supplied? Create a default one.
  if (!adm_) {
    adm_ = webrtc::AudioDeviceModule::Create(
        webrtc::AudioDeviceModule::kPlatformDefaultAudio, task_queue_factory_);
  }
#endif  // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE
  RTC_CHECK(adm());
  webrtc::adm_helpers::Init(adm());
  webrtc::apm_helpers::Init(apm());

  // Set up AudioState.
  {
    webrtc::AudioState::Config config;
    if (audio_mixer_) {
      config.audio_mixer = audio_mixer_;
    } else {
      config.audio_mixer = webrtc::AudioMixerImpl::Create();
    }
    config.audio_processing = apm_;
    config.audio_device_module = adm_;
    audio_state_ = webrtc::AudioState::Create(config);
  }

  // Connect the ADM to our audio path.
  adm()->RegisterAudioCallback(audio_state()->audio_transport());

  // Set default engine options.
  {
    AudioOptions options;
    options.echo_cancellation = true;
    options.auto_gain_control = true;
    options.noise_suppression = true;
    options.highpass_filter = true;
    options.stereo_swapping = false;
    options.audio_jitter_buffer_max_packets = 200;
    options.audio_jitter_buffer_fast_accelerate = false;
    options.audio_jitter_buffer_min_delay_ms = 0;
    options.audio_jitter_buffer_enable_rtx_handling = false;
    options.typing_detection = true;
    options.experimental_agc = false;
    options.extended_filter_aec = false;
    options.delay_agnostic_aec = false;
    options.experimental_ns = false;
    options.residual_echo_detector = true;
    bool error = ApplyOptions(options);
    RTC_DCHECK(error);
  }

  initialized_ = true;
}

只是我调用StopAecDump函数后线程退出的线程情况


if (peerConnectionFactory)
		{
			peerConnectionFactory->StopAecDump();
		}

在这里插入图片描述

三、 WebRTC中线程介绍

线程类型线程名称全局变量功能所属模块
Threadsignaling_threadsignaling_thread_信令线程,主要负责事件和状态消息处理
Threadworker_threadworker_thread_工作者线程,主要跟各种数据流相关消息处理
Threadnetwork_threadnetwork_thread_网络线程,处理接收网络报文网络
PlatformThreadPacerThreadpacer_thread_ pacer平滑发送报文网络
PlatformThreadVoiceProcessThread_moduleProcessThreadPtr好像是VOD检测?还是会场混音算法? 待确认
PlatformThreadcall_worker_queueworker_queue_音视频网络状态检测资源管理
PlatformThreadModuleProcessThreadmodule_process_thread_挂载定时调用函数资源管理
PlatformThreadEncoderQueueencoder_queue_视频编码视频
PlatformThreadDecodingThreaddecode_thread_视频解码(kHighestPriority)视频
PlatformThreadIncomingVideoStreamincoming_render_queue_视频渲染(HIGH)视频
PlatformThreadAudioEncoderQueueencoder_queue_音频编码音频
CreateThread_hRecThread音频采集音频
CreateThread_hPlayThread音频渲染(解码和渲染在一个线程里)音频
CreateThread_hGetCaptureVolumeThread获取音量参数音频
CreateThread_hSetCaptureVolumeThread配置音频参数音频
PlatformThreadrtc-low-priolow_priority_worker_queue_音频录制维护功能(LOW) 维护
PlatformThreadAudioDeviceBufferTimertask_queue_周期调用LogStats维护
PlatformThreadrtc_event_logtask_queue_维护功能维护

总结

代码项目地址:https://github.com/chensongpoixs/cmediasoup_push

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值