sigslot - WebRTC中的事件处理机制

写在转载之前的:

webrtc的源码中用到了sigslot机制,可以看看webrtc/examples/peerconnection/client/中的peer_connection_client.cc和peer_connection_client.h代码里是怎么用的。sigslot.h原先位于webrtc/base/下,最新的代码挪到了webrtc/rtc_base/third_party/sigslot/下。依葫芦画瓢,就能够学会怎么去使用它,至少看到别人的代码里有用到它的地方也能够理解。

以下转载内容:

Sigslot 是Sarah Thompson 设计实现的C++ 事件处理的框架,    这套框架非常轻量级,  全部代码只有一个sigslot.h 文件,   其设计也非常出色,  最大限度的将事件和处理机制解耦, 并且保证了线程安全. 

在WebRTC中, sigslot 是其基础的事件处理框架,  在多个模块的消息通知, 响应处理中被使用.  下文, 我们简单的来剖析下sigslot 的原理及其应用.  

在C++中,  普通的事件处理也容易实现, 下面是一个简单的例子,  描述电灯开关工作:

class Switch
{
public:
    virtual void Clicked() = 0;
};
 
class Light
{
public:
    void Toggle();
};
 
class ToggleSwitch : public Switch
{
public:
    ToggleSwitch(Light & light) {
        m_light = light;
    }
    virtual void Clicked() {
        m_light.Toggle();
    }
 
private:
    Light & m_light;
};
 
// how to toggle light 
Light     red, white;
ToggleSwitch sw1(red), sw2(white);
 
sw1.Clicked();
sw2.Clicked();

上面的代码可以工作的很好,   但是有一个弊端是: ToggleSwitch 必须得到Light的引用, 然后去显式调用Light的Toggle函数,   这样的话, Swich 和 Light 之间是紧耦合.   如果我希望未来Switch  可以去控制某个马达(Motor),   将不得不修改代码.      
有一个改进的方案是利用C++的多态, 比如设计一个虚接口:  SwithableItem,  让Motor 和 Light 继承自这个虚接口.    这也是不错的思路.  不过在这里sigslot 利用C++ template, 提供了一种更加优雅的方式,  还是继续来看代码:

class Switch
{
public:
    sigslot::signal0<> Clicked;
};
 
class Light : public sigslot::has_slot<>
{
public:
    void  Toggle();
};
 Switch sw1, sw2;
 Light red, white;
 sw1.Clicked.connect(&red, &Light::Toggle);
 sw2.Clicked.connect(&white, &Light::Toggle);
 sw1.Clicked(); 
 sw2.Clicked();
这段代码的功能跟上面的完全一样,但是最大的区别在于:Switch跟Light之间的绑定关系是在运行期建立的,  跟Swtich 和 Light 本身的设计无关! 这真是令人惊叹的设计! 
关于sigslot的好处,我想已经不必多言.  读者可以去sigslot的主页上下载代码,试着在你的工程中用一下sigslot,仔细阅读理解下其源码,你一定会有所收获!

下面贴一下webrtc中关于sigslot使用的代码片断:

 

class VideoCapturer : public sigslot::has_slots<>,
                      public rtc::VideoSourceInterface<cricket::VideoFrame> {
    ......
          sigslot::signal2<VideoCapturer*, const CapturedFrame*,
                   sigslot::multi_threaded_local> SignalFrameCaptured;
};
void VideoCapturer::Construct() {
  enable_camera_list_ = false;
  capture_state_ = CS_STOPPED;
  SignalFrameCaptured.connect(this, &VideoCapturer::OnFrameCaptured);
  scaled_width_ = 0;
  scaled_height_ = 0;
  enable_video_adapter_ = true;
  // There are lots of video capturers out there that don't call
  // set_frame_factory.  We can either go change all of them, or we
  // can set this default.
  // TODO(pthatcher): Remove this hack and require the frame factory
  // to be passed in the constructor.
  set_frame_factory(new WebRtcVideoFrameFactory());
}
void SignalCapturedFrame(cricket::CapturedFrame* frame) {
    SignalFrameCaptured(this, frame);
}


Reference:

  1   Sigslot 项目主页:  http://sigslot.sourceforge.net/
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章