WebRTC的TaskQueue源码分析
随着WebRTC的更新,很多新的特性被添加了进来,例如更完善的线程检查机制、任务处理等。本文对其中的TaskQueue进行简单分析,主要是因为自己闲着无聊,文章内容多有不妥之处,欢迎大家批评指正。
TaskQueue作用
TaskQueue的中文翻译是“任务队列”,顾名思义,它的作用就是把一些“任务”存储在队列中,然后再从队列中取出任务并执行。由于队列是FIFO,所以任务队列具有有序性。
代码提供的接口是PostTask(std::unique_ptr task):
void TaskQueue::PostTask(std::unique_ptr<QueuedTask> task) {
return TaskQueue::impl_->PostTask(std::move(task));
}
PostTask作用是将任务传递给TaskQueue::impl_ ,impl_ 是TaskQueue中的内部类Impl的实例,当任务传递至Impl中的PostTask函数后,会将任务推送至队列pending_中。
void TaskQueue::Impl::PostTask(std::unique_ptr<QueuedTask> task) {
rtc::CritScope lock(&pending_lock_);
pending_.push(std::move(task));
::SetEvent(in_queue_);
}
TaskQueue使用例子
下面,以音频编解码任务为例,观察TaskQueue的使用过程,代码见Channel.cc文件。
在VoIP过程中,发送端需要将原始采集音频进行压缩后再进行传输,接收端需要将压缩音频解码后进行播放。在WebRTC中,把编/解码一帧音频看成一个任务。Channel类中包含一个TaskQueue对象encoder_queue_,。当捕捉到一帧原始音频后,会被回调至Channel中的ProcessAndEncodeAudio函数,
void Channel::ProcessAndEncodeAudio;
ProcessAndEncodeAudio函数对音频帧audio_frame进行判断、处理后,将会执行
encoder_queue_->PostTask(std::unique_ptr<rtc::QueuedTask>(
new ProcessAndEncodeAudioTask(std::move(audio_frame), this)));
这样,就把编码一帧音频的任务放到了任务队列中encoder_queue_,然后ProcessAndEncodeAudioTask会被异步执行。当有很多帧音频被放进encoder_queue__中之后,由于队列的FIFO特性,会将音频帧按照采集顺序依次进行编码。
TaskQueue讨论
TaskQueue的设计很巧妙,把一个个Closure放进队列中,然后在执行线程中把任务Closure取出后执行。
这样能够保证同一个TaskQueue对象中的任务,都会在一个线程内执行,并且具有先后顺序。此外,处理不同类型的任务,只要new出不同的TaskQueue对象就可以,十分方便,这是因为TaskQueue中队列存储的是Closure,而不是具体的对象或指针。