目录
2.1 framework/include/cnstream_eventbus.hpp
2.2 framework/src/cnstream_eventbus.cpp
看一下https://github.dev/Cambricon/CNStream中EventBus原理以及代码分析。
1 CNStream中消息机制整体介绍
在CNStream流处理多路并发Pipeline框架中,不同模块之间或者说不同线程之间需要传递一些信息或者说事件,比如⽆效、错误、警告、EOS(End of Stream)、停⽌,数据流错误等消息,在CNStream流处理多路并发Pipeline框架中是通过EventBus模式来处理事件的,主要包括三个部分
- 事件源(Event Source):将消息发布到事件总线上。
- 事件总线(EventBus):事件发布到总线上时被监听器接收。
- 事件监听器(Observer/Listener):监听器订阅事件。
cnstream::Event 类是模块和 pipepline 之间通信的基本单元,即事件。事件由四个部分组成:事件类型、消息、发布事件的模块、发布事件的线程号。消息类型包括:⽆效、错误、警告、EOS(End ofStream)、停⽌,数据流错误,以及⼀个预留类型。cnstream::Event 类 在 cnstream_eventbus.hpp ⽂ 件 定 义,cnstream_eventbus.hpp ⽂ 件 存 放 在framework/core/include ⽂件夹下。
cnstream::EventBus 类是各个模块与 pipeline 通信的事件总线。各模块发布事件到总线上,由总线监听器接收。⼀条事件总线可以拥有多个监听器。每条 pipeline 有⼀条事件总线及对应的⼀个默认事件监听器。pipeline 会对事件总线进⾏轮询,收到事件后分发给监听器。cnstream::EventBus 类 在 cnstream_eventbus.hpp ⽂ 件 中 定 义, 主 要 接 ⼝ 如 下。cnstream_eventbus.hpp ⽂件存放在 framework/core/include ⽂件夹下。
2 CNStream中EventBus主要代码
2.1 framework/include/cnstream_eventbus.hpp
/*************************************************************************
* Copyright (C) [2019] by Cambricon, Inc. All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*************************************************************************/
#ifndef CNSTREAM_EVENT_BUS_HPP_
#define CNSTREAM_EVENT_BUS_HPP_
/**
* @file cnstream_eventbus.hpp
*
* This file contains a declaration of the EventBus class.
*/
#include <atomic>
#include <functional>
#include <list>
#include <mutex>
#include <string>
#include <thread>
#include <utility>
#include "cnstream_common.hpp"
#include "util/cnstream_queue.hpp"
namespace cnstream {
class Pipeline;
/*!
* @enum EventType
*
* @brief Enumeration variables describing the type of event.
*/
enum class EventType {
EVENT_INVALID, /*!< An invalid event type. */
EVENT_ERROR, /*!< An error event. */
EVENT_WARNING, /*!< A warning event. */
EVENT_EOS, /*!< An EOS event. */
EVENT_STOP, /*!< A stop event. */
EVENT_STREAM_ERROR, /*!< A stream error event. */
EVENT_TYPE_END /*!< Reserved for users custom events. */
};
/**
* @enum EventHandleFlag
*
* @brief Enumeration variables describing the way how bus watchers handle an event.
*/
enum class EventHandleFlag {
EVENT_HANDLE_NULL, /*!< The event is not handled. */
EVENT_HANDLE_INTERCEPTION, /*!< The event has been handled and other bus watchers needn't to handle it. */
EVENT_HANDLE_SYNCED, /*!< The event has been handled and other bus watchers are going to handle it. */
EVENT_HANDLE_STOP /*!< The event has been handled and bus watchers stop all other events' processing. */
};
/**
* @struct Event
*
* @brief The Event is a structure describing the event information.
*/
struct Event {
EventType type; ///< The event type.
std::string stream_id; ///< The stream that posts this event.
std::string message_id; ///< The message type id.
std::string message; ///< More detailed messages describing the event.
std::string module_name; ///< The module that posts this event.
std::thread::id thread_id; ///< The thread ID from which the event is posted.
};
/**
* @brief Defines an alias of bus watcher function.
*
* @param[in] event The event is polled from the event bus.
*
* @return Returns the flag that specifies how the event is handled.
*/
using BusWatcher = std::function<EventHandleFlag(const Event &)>;
/**
* @class EventBus
*
* @brief EventBus is a class that transmits events from modules to a pipeline.
*/
class EventBus : private NonCopyable {
public:
friend class Pipeline;
/**
* @brief Destructor. A destructor to destruct event bus.
*
* @return No return value.
*/
~EventBus();
/**
* @brief Starts an event bus thread.
*
* @return Returns true if start successfully, otherwise false.
*/
bool Start();
/**
* @brief Stops an event bus thread.
*
* @return No return values.
*/
void Stop();
/**
* @brief Adds a watcher to the event bus.
*
* @param[in] func The bus watcher to be added.
*
* @return The number of bus watchers that has been added to this event bus.
*/
uint32_t AddBusWatch(BusWatcher func);
/**
* @brief Posts an event to a bus.
*
* @param[in] event The event to be posted.
*
* @return Returns true if this function run successfully. Otherwise, returns false.
*/
bool PostEvent(Event event);
#ifndef UNIT_TEST
private: // NOLINT
#else
Event PollEventToTest();
#endif
EventBus() = default;
/**
* @brief Polls an event from a bus.
*
* @return Returns the event.
*
* @note This function is blocked until an event availabe or the bus stopped.
*/
Event PollEvent();
/**
* @brief Gets all bus watchers from the event bus.
*
* @return A list with pairs of bus watcher and module.
*/
const std::list<BusWatcher> &GetBusWatchers() const;
/**
* @brief Removes all bus watchers.
*
* @return No return value.
*/
void ClearAllWatchers();
/**
* @brief Checks if the event bus is running.
*
* @return Returns true if the event bus is running. Otherwise, returns false.
*/
bool IsRunning();
void EventLoop();
private:
mutable std::mutex watcher_mtx_;
ThreadSafeQueue<Event> queue_;
#ifdef UNIT_TEST
ThreadSafeQueue<Event> test_eventq_;
bool unit_test = true;
#endif
std::list<BusWatcher> bus_watchers_;
std::thread event_thread_;
std::atomic<bool> running_{false};
}; // class EventBus
} // namespace cnstream
#endif // CNSTREAM_EVENT_BUS_HPP_
2.2 framework/src/cnstream_eventbus.cpp
/*************************************************************************
* Copyright (C) [2019] by Cambricon, Inc. All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*************************************************************************/
#include "cnstream_eventbus.hpp"
#include <list>
#include <memory>
#include <thread>
#include <utility>
#include "cnstream_pipeline.hpp"
namespace cnstream {
EventBus::~EventBus() { Stop(); }
bool EventBus::IsRunning() { return running_.load(); }
bool EventBus::Start() {
running_.store(true);
event_thread_ = std::thread(&EventBus::EventLoop, this);
return true;
}
void EventBus::Stop() {
if (IsRunning()) {
running_.store(false);
if (event_thread_.joinable()) {
event_thread_.join();
}
}
}
// @return The number of bus watchers that has been added to this event bus.
uint32_t EventBus::AddBusWatch(BusWatcher func) {
std::lock_guard<std::mutex> lk(watcher_mtx_);
bus_watchers_.push_front(func);
return bus_watchers_.size();
}
void EventBus::ClearAllWatchers() {
std::lock_guard<std::mutex> lk(watcher_mtx_);
bus_watchers_.clear();
}
const std::list<BusWatcher> &EventBus::GetBusWatchers() const {
std::lock_guard<std::mutex> lk(watcher_mtx_);
return bus_watchers_;
}
bool EventBus::PostEvent(Event event) {
if (!running_.load()) {
LOGW(CORE) << "Post event failed, pipeline not running";
return false;
}
// LOGI(CORE) << "Receieve event from [" << event.module->GetName() << "] :" << event.message;
queue_.Push(event);
#ifdef UNIT_TEST
if (unit_test) {
test_eventq_.Push(event);
unit_test = false;
}
#endif
return true;
}
Event EventBus::PollEvent() {
Event event;
event.type = EventType::EVENT_INVALID;
while (running_.load()) {
if (queue_.WaitAndTryPop(event, std::chrono::milliseconds(100))) {
break;
}
}
if (!running_.load()) event.type = EventType::EVENT_STOP;
return event;
}
void EventBus::EventLoop() {
const std::list<BusWatcher> &kWatchers = GetBusWatchers();
EventHandleFlag flag = EventHandleFlag::EVENT_HANDLE_NULL;
// start loop
while (IsRunning()) {
Event event = PollEvent();
if (event.type == EventType::EVENT_INVALID) {
LOGI(CORE) << "[EventLoop] event type is invalid";
break;
} else if (event.type == EventType::EVENT_STOP) {
LOGI(CORE) << "[EventLoop] Get stop event";
break;
}
std::unique_lock<std::mutex> lk(watcher_mtx_);
for (auto &watcher : kWatchers) {
flag = watcher(event);
if (flag == EventHandleFlag::EVENT_HANDLE_INTERCEPTION || flag == EventHandleFlag::EVENT_HANDLE_STOP) {
break;
}
}
if (flag == EventHandleFlag::EVENT_HANDLE_STOP) {
break;
}
}
LOGI(CORE) << "Event bus exit.";
}
#ifdef UNIT_TEST
Event EventBus::PollEventToTest() {
Event event;
event.type = EventType::EVENT_INVALID;
while (running_.load()) {
if (test_eventq_.WaitAndTryPop(event, std::chrono::milliseconds(100))) {
break;
}
}
if (!running_.load()) event.type = EventType::EVENT_STOP;
return event;
}
#endif
} // namespace cnstream
3 CNStream中EventBus代码分析、机制介绍
首先在Pipeline类里面就会有这样一个成员
std::unique_ptr<EventBus> event_bus_ = nullptr;
然后反过来,在EventBus类里面又把Pipeline声明成了友元类,这样pipeline可以直接调用EventBus的函数进行相应的操作。
/**
* @class EventBus
*
* @brief EventBus is a class that transmits events from modules to a pipeline.
*/
class EventBus : private NonCopyable {
public:
friend class Pipeline;
然后在Pipeline的构造函数里面会创建EventBus,并且调用AddBusWatch函数。
Pipeline::Pipeline(const std::string& name) : name_(name) {
// stream message handle thread
exit_msg_loop_ = false;
smsg_thread_ = std::thread(&Pipeline::StreamMsgHandleFunc, this);
event_bus_.reset(new (std::nothrow) EventBus());
LOGF_IF(CORE, nullptr == event_bus_) << "Pipeline::Pipeline() failed to alloc EventBus";
GetEventBus()->AddBusWatch(std::bind(&Pipeline::DefaultBusWatch, this, std::placeholders::_1));
idxManager_.reset(new (std::nothrow) IdxManager());
LOGF_IF(CORE, nullptr == idxManager_) << "Pipeline::Pipeline() failed to alloc IdxManager";
graph_.reset(new (std::nothrow) CNGraph<NodeContext>());
LOGF_IF(CORE, nullptr == graph_) << "Pipeline::Pipeline() failed to alloc CNGraph";
}
这里是给他添加了一个默认的watch函数
GetEventBus()->AddBusWatch(std::bind(&Pipeline::DefaultBusWatch, this, std::placeholders::_1));
这个默认的watch函数其实就是用来处理event的
EventHandleFlag Pipeline::DefaultBusWatch(const Event& event) {
StreamMsg smsg;
EventHandleFlag ret;
switch (event.type) {
case EventType::EVENT_ERROR:
smsg.type = StreamMsgType::ERROR_MSG;
smsg.module_name = event.module_name;
smsg.stream_id = event.stream_id;
UpdateByStreamMsg(smsg);
LOGE(CORE) << "[" << event.module_name << "]: " << event.message;
ret = EventHandleFlag::EVENT_HANDLE_STOP;
break;
case EventType::EVENT_WARNING:
LOGW(CORE) << "[" << event.module_name << "]: " << event.message;
ret = EventHandleFlag::EVENT_HANDLE_SYNCED;
break;
case EventType::EVENT_STOP:
LOGI(CORE) << "[" << event.module_name << "]: " << event.message;
ret = EventHandleFlag::EVENT_HANDLE_STOP;
break;
case EventType::EVENT_EOS: {
VLOG2(CORE) << "Pipeline received eos from module " + event.module_name << " of stream " << event.stream_id;
ret = EventHandleFlag::EVENT_HANDLE_SYNCED;
break;
}
case EventType::EVENT_STREAM_ERROR: {
smsg.type = StreamMsgType::STREAM_ERR_MSG;
smsg.message_id = event.message_id;
smsg.message = event.message;
smsg.module_name = event.module_name;
smsg.stream_id = event.stream_id;
UpdateByStreamMsg(smsg);
VLOG2(CORE) << "Pipeline received stream error from module " + event.module_name << " of stream "
<< event.stream_id;
ret = EventHandleFlag::EVENT_HANDLE_SYNCED;
break;
}
case EventType::EVENT_INVALID:
LOGE(CORE) << "[" << event.module_name << "]: " << event.message;
default:
ret = EventHandleFlag::EVENT_HANDLE_NULL;
break;
}
return ret;
}
除了上面的默认的watch函数,我们自己还会在外层再添加一个自己的watch函数
int build_pipeline(string const& config) {
s_pipeline = std::shared_ptr<Pipeline>(new Pipeline("TACLPipeline"), [](Pipeline* pipeline) { pipeline->Stop(); });
if (s_pipeline == nullptr) {
return ERROR_ALLOC_MEMORY;
}
//build pipeline
if (!s_pipeline->BuildPipelineByJSONFile(config)) {
LOGE(SESSION_MGR) << "Build pipeline failed.";
return EXIT_FAILURE;
}
//message observer
static MsgObserver msg_observer(s_pipeline.get(), g_source_name);
s_pipeline->SetStreamMsgObserver(reinterpret_cast<cnstream::StreamMsgObserver*>(&msg_observer));
s_pipeline->GetEventBus()->AddBusWatch([&](const Event & event)->EventHandleFlag{
if(event.module_name == "TuringPipeline/decode/source" && EventType::EVENT_EOS == event.type){
LOGI(SESSION_MGR) << "recv bus event: " << static_cast<int8_t>(event.type) << "_" << event.module_name << "_" << event.stream_id << "_" << event.message;
{
std::string run_msg_str;
std::unique_lock<std::mutex> locker(s_session_locker);
auto it = s_task_sessions.find(event.stream_id);
if (it != s_task_sessions.end()) {
LOGE(SESSION_MGR) << event.stream_id << "stream interruption!!!!!!!!!!";
//如果是文件就直接停止,如果不是文件就进入重连机制
if(it->second->get_video_type() == EFILE)
{
it->second->stop(g_source_name);
run_msg_str = it->second->post_end_mark();
LOGI(SESSION_MGR) << "run msg is: " << run_msg_str;
//puglish msg
cnstream::ActiveMQ* activemq_run_msg = dynamic_cast<cnstream::ActiveMQ*>(s_pipeline->GetModule(g_activemq_name));
if (activemq_run_msg != nullptr && run_msg_str != "") {
activemq_run_msg->PublishEvent(run_msg_str);
}
s_task_sessions.erase(it->first);
}
else if(it->second->get_s_state_() != S_USER_CLOSE)
{
it->second->set_s_state_(S_EXCEPTION_CLOSE);
}
}
}
}
});
//start pipeline
if (!s_pipeline->Start()) {
LOGE(SESSION_MGR) << "Pipeline start failed.";
return EXIT_FAILURE;
}
return ERROR_OK;
}
然后比如某个module会调用PostEvent推送event
void FileHandlerImpl::Loop() {
if (!SetCurrentDevice(param_.device_id)) return;
if (!PrepareResources()) {
ClearResources();
if (nullptr != module_) {
Event e;
e.type = EventType::EVENT_STREAM_ERROR;
e.module_name = module_->GetName();
e.message = "Prepare codec resources failed.";
e.stream_id = stream_id_;
e.thread_id = std::this_thread::get_id();
module_->PostEvent(e);
}
LOGE(SOURCE) << "[FileHandlerImpl] Loop(): [" << stream_id_ << "]: PrepareResources failed.";
return;
}
set_thread_name("demux_decode");
FrController controller(handle_param_.framerate);
if (handle_param_.framerate > 0) controller.Start();
VLOG1(SOURCE) << "[FileHandlerImpl] Loop(): [" << stream_id_ << "]: DecoderLoop";
while (running_.load()) {
if (!Process()) {
break;
}
if (handle_param_.framerate > 0) controller.Control();
}
VLOG1(SOURCE) << "[FileHandlerImpl] Loop(): [" << stream_id_ << "]: DecoderLoop Exit.";
ClearResources();
}
然后module的PostEvent又调用总线的PostEvent
bool Module::PostEvent(Event e) {
RwLockReadGuard guard(container_lock_);
if (container_) {
return container_->GetEventBus()->PostEvent(e);
} else {
LOGW(CORE) << "[" << GetName() << "] module's container is not set";
return false;
}
}
然后这个PostEvent其实就是把event放到队列ThreadSafeQueue<Event> queue_;里面
bool EventBus::PostEvent(Event event) {
if (!running_.load()) {
LOGW(CORE) << "Post event failed, pipeline not running";
return false;
}
// LOGI(CORE) << "Receieve event from [" << event.module->GetName() << "] :" << event.message;
queue_.Push(event);
#ifdef UNIT_TEST
if (unit_test) {
test_eventq_.Push(event);
unit_test = false;
}
#endif
return true;
}
然后其实在程序刚开始启动的时候,有
bool EventBus::Start() {
running_.store(true);
event_thread_ = std::thread(&EventBus::EventLoop, this);
return true;
}
然后
void EventBus::EventLoop() {
const std::list<BusWatcher> &kWatchers = GetBusWatchers();
EventHandleFlag flag = EventHandleFlag::EVENT_HANDLE_NULL;
// start loop
while (IsRunning()) {
Event event = PollEvent();
if (event.type == EventType::EVENT_INVALID) {
LOGI(CORE) << "[EventLoop] event type is invalid";
break;
} else if (event.type == EventType::EVENT_STOP) {
LOGI(CORE) << "[EventLoop] Get stop event";
break;
}
std::unique_lock<std::mutex> lk(watcher_mtx_);
for (auto &watcher : kWatchers) {
flag = watcher(event);
if (flag == EventHandleFlag::EVENT_HANDLE_INTERCEPTION || flag == EventHandleFlag::EVENT_HANDLE_STOP) {
break;
}
}
if (flag == EventHandleFlag::EVENT_HANDLE_STOP) {
break;
}
}
LOGI(CORE) << "Event bus exit.";
}
可以看到在这个循环里面,会从队列中PollEvent出来event然后调用watch函数,这里的const std::list<BusWatcher> &kWatchers = GetBusWatchers();就是前面增加的两个watch函数,一个是默认的watch函数,一个是我们用户自己定义的watch函数。
下面再回去,分别看一下这两个watch函数,首先看默认的watch函数
EventHandleFlag Pipeline::DefaultBusWatch(const Event& event) {
StreamMsg smsg;
EventHandleFlag ret;
switch (event.type) {
case EventType::EVENT_ERROR:
smsg.type = StreamMsgType::ERROR_MSG;
smsg.module_name = event.module_name;
smsg.stream_id = event.stream_id;
UpdateByStreamMsg(smsg);
LOGE(CORE) << "[" << event.module_name << "]: " << event.message;
ret = EventHandleFlag::EVENT_HANDLE_STOP;
break;
case EventType::EVENT_WARNING:
LOGW(CORE) << "[" << event.module_name << "]: " << event.message;
ret = EventHandleFlag::EVENT_HANDLE_SYNCED;
break;
case EventType::EVENT_STOP:
LOGI(CORE) << "[" << event.module_name << "]: " << event.message;
ret = EventHandleFlag::EVENT_HANDLE_STOP;
break;
case EventType::EVENT_EOS: {
VLOG2(CORE) << "Pipeline received eos from module " + event.module_name << " of stream " << event.stream_id;
ret = EventHandleFlag::EVENT_HANDLE_SYNCED;
break;
}
case EventType::EVENT_STREAM_ERROR: {
smsg.type = StreamMsgType::STREAM_ERR_MSG;
smsg.message_id = event.message_id;
smsg.message = event.message;
smsg.module_name = event.module_name;
smsg.stream_id = event.stream_id;
UpdateByStreamMsg(smsg);
VLOG2(CORE) << "Pipeline received stream error from module " + event.module_name << " of stream "
<< event.stream_id;
ret = EventHandleFlag::EVENT_HANDLE_SYNCED;
break;
}
case EventType::EVENT_INVALID:
LOGE(CORE) << "[" << event.module_name << "]: " << event.message;
default:
ret = EventHandleFlag::EVENT_HANDLE_NULL;
break;
}
return ret;
}
在这个watch函数里面有个UpdateByStreamMsg,
void Pipeline::UpdateByStreamMsg(const StreamMsg& msg) {
VLOG2(CORE) << "[" << GetName() << "] "
<< "stream: " << msg.stream_id << " got message: " << static_cast<std::size_t>(msg.type);
msgq_.Push(msg);
}
这里是把msgpush到了队列里面, ThreadSafeQueue<StreamMsg> msgq_;
然后其实在Pipeline的构造函数里面起了一个线程StreamMsgHandleFunc
Pipeline::Pipeline(const std::string& name) : name_(name) {
// stream message handle thread
exit_msg_loop_ = false;
smsg_thread_ = std::thread(&Pipeline::StreamMsgHandleFunc, this);
event_bus_.reset(new (std::nothrow) EventBus());
LOGF_IF(CORE, nullptr == event_bus_) << "Pipeline::Pipeline() failed to alloc EventBus";
GetEventBus()->AddBusWatch(std::bind(&Pipeline::DefaultBusWatch, this, std::placeholders::_1));
idxManager_.reset(new (std::nothrow) IdxManager());
LOGF_IF(CORE, nullptr == idxManager_) << "Pipeline::Pipeline() failed to alloc IdxManager";
graph_.reset(new (std::nothrow) CNGraph<NodeContext>());
LOGF_IF(CORE, nullptr == graph_) << "Pipeline::Pipeline() failed to alloc CNGraph";
}
然后在这个线程里面就会从ThreadSafeQueue<StreamMsg> msgq_;里面不断的取出msg然后进行处理
void Pipeline::StreamMsgHandleFunc() {
while (!exit_msg_loop_) {
StreamMsg msg;
while (!exit_msg_loop_ && !msgq_.WaitAndTryPop(msg, std::chrono::milliseconds(200))) {
}
if (exit_msg_loop_) {
LOGI(CORE) << "[" << GetName() << "] stop updating stream message";
return;
}
switch (msg.type) {
case StreamMsgType::EOS_MSG:
case StreamMsgType::ERROR_MSG:
case StreamMsgType::STREAM_ERR_MSG:
case StreamMsgType::FRAME_ERR_MSG:
case StreamMsgType::USER_MSG0:
case StreamMsgType::USER_MSG1:
case StreamMsgType::USER_MSG2:
case StreamMsgType::USER_MSG3:
case StreamMsgType::USER_MSG4:
case StreamMsgType::USER_MSG5:
case StreamMsgType::USER_MSG6:
case StreamMsgType::USER_MSG7:
case StreamMsgType::USER_MSG8:
case StreamMsgType::USER_MSG9:
VLOG2(CORE) << "[" << GetName() << "] "
<< "stream: " << msg.stream_id << " notify message: " << static_cast<std::size_t>(msg.type);
if (smsg_observer_) {
smsg_observer_->Update(msg);
}
break;
default:
break;
}
}
}
然后注意其中的smsg_observer_->Update(msg);,这个是我们自己定义的观察者函数,
class MsgObserver : cnstream::StreamMsgObserver {
public:
MsgObserver(cnstream::Pipeline* pipeline, std::string source_name) :
pipeline_(pipeline),
source_name_(source_name) {}
void Update(const cnstream::StreamMsg& smsg) override {
switch (smsg.type) {
case cnstream::StreamMsgType::EOS_MSG:
LOGI(SESSION_MGR) << "[" << pipeline_->GetName() << "] received EOS message from stream: [" << smsg.stream_id << "]";
//task_session_remove(smsg.stream_id);
break;
case cnstream::StreamMsgType::STREAM_ERR_MSG:
LOGW(SESSION_MGR) << "[" << pipeline_->GetName() << "] received stream error from stream: " << smsg.stream_id
<< ", remove it from pipeline.";
if (!smsg.message_id.empty()) {
post_run_msg(smsg);
}
break;
case cnstream::StreamMsgType::ERROR_MSG:
LOGE(SESSION_MGR) << "[" << pipeline_->GetName() << "] received ERROR_MSG";
break;
case cnstream::StreamMsgType::FRAME_ERR_MSG:
LOGW(SESSION_MGR) << "[" << pipeline_->GetName() << "] received frame error from stream: " << smsg.stream_id
<< ", pts: " << smsg.pts << ".";
break;
default:
LOGE(SESSION_MGR) << "[" << pipeline_->GetName() << "] unkonw message type.";
break;
}
}
private:
void task_session_remove(string const& stream_id) {
std::lock_guard<std::mutex> logcker(s_session_locker);
auto iter = s_task_sessions.find(stream_id);
if (iter != s_task_sessions.end()) {
if (iter->second->get_video_type() == VideoType::EFILE)
{
s_task_sessions.erase(iter);
LOGI(SESSION_MGR) << "task session mgr remove Task ID succeed: " << stream_id;
}
}
else {
LOGI(SESSION_MGR) << "task session mgr remvoe Task ID Failed, not find Task ID: " << stream_id;
}
}
private:
cnstream::Pipeline* pipeline_ = nullptr;
std::string source_name_;
};
所以这就相当于在update函数里面根据msg的不同类型做不同的处理。
然后再看另一个我们自己的第二个watch函数。
s_pipeline->GetEventBus()->AddBusWatch([&](const Event & event)->EventHandleFlag{
if(event.module_name == "TuringPipeline/decode/source" && EventType::EVENT_EOS == event.type){
LOGI(SESSION_MGR) << "recv bus event: " << static_cast<int8_t>(event.type) << "_" << event.module_name << "_" << event.stream_id << "_" << event.message;
{
std::string run_msg_str;
std::unique_lock<std::mutex> locker(s_session_locker);
auto it = s_task_sessions.find(event.stream_id);
if (it != s_task_sessions.end()) {
LOGE(SESSION_MGR) << event.stream_id << "stream interruption!!!!!!!!!!";
//如果是文件就直接停止,如果不是文件就进入重连机制
if(it->second->get_video_type() == EFILE)
{
it->second->stop(g_source_name);
run_msg_str = it->second->post_end_mark();
LOGI(SESSION_MGR) << "run msg is: " << run_msg_str;
//puglish msg
cnstream::ActiveMQ* activemq_run_msg = dynamic_cast<cnstream::ActiveMQ*>(s_pipeline->GetModule(g_activemq_name));
if (activemq_run_msg != nullptr && run_msg_str != "") {
activemq_run_msg->PublishEvent(run_msg_str);
}
s_task_sessions.erase(it->first);
}
else if(it->second->get_s_state_() != S_USER_CLOSE)
{
it->second->set_s_state_(S_EXCEPTION_CLOSE);
}
}
}
}
});
这个函数里面不需要将msg发给观察者了,直接在这里面做我们想做的处理。
参考文献:
手写EventBus(观察者模式、源码阅读、反射) - 简书
CNStream流处理多路并发Pipeline框架整体介绍-CSDN博客
寒武纪CNStream用户手册 — 寒武纪CNStream用户手册 6.2.0 文档
C++内存池Memory Pool的高级实现、代码详解、CMake构建工程、应用实例-CSDN博客
aclStream流处理多路并发Pipeline框架中VEncode Module代码调用流程整理、类的层次关系整理、回调函数赋值和调用流程整理-CSDN博客
aclStream流处理多路并发Pipeline框架中 视频解码 代码调用流程整理、类的层次关系整理、回调函数赋值和调用流程整理-CSDN博客
GitHub - gelldur/EventBus: A lightweight and very fast event bus / event framework for C++17