前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >理解Janus中的Plugin

理解Janus中的Plugin

作者头像
音视频_李超
发布2020-05-26 22:04:03
1.4K0
发布2020-05-26 22:04:03
举报
文章被收录于专栏:音视频直播技术专家

Janus中的Plugin是其非常重要的一部分内容,今天我们就来对这块内容做一下分析,看看Janus是如何实现Plugin的,以及它的工作原理是怎样的。

Janus的架构模型

Janus的最大特色就是可以以插件的方式对业务模块进行管理,比如当你想实现新业务时,按照Janus Plugin 的要求写一个 Plugin ,然后将它放到指定目录下,Janus 在启动时就可以将它加载到内存中。

下面这张图是Janus的整体架构图:

Janus架构图

从上面这张图我们可以看到,Janus在设计时被分成了两层,即核心层和插件层。核心层主要用于资源的分配(如线程的启动与分配)、底层事件处理、各种WebRTC协议的实现及处理等;插件层用于业务处理,各种传输类型命令的处理等。

从中我们可以知道,这样的架构设计及管理方式特别适合变化比较快的业务模型。因为我们可以随时生成一个新的Janus插件,并将它加载到内存中。

OK,了解了 Janus 的架构,我们再来看看Janus是如何实现插件管理的吧。

Linux 系统下动态库的动态加载

要想真正理解Janus的插件管理,我们首先要知道Linux系统是如何动态加载库的,这是我们理解 Janus 插件管理的基础。

在Linux系统中,动态加载库其实很容易,只要用两个API 就可以了,即 dlopendlsym 。它们的定义如下:

代码语言:javascript
复制
#include <dlfcn.h>

/**
 *  path: 被加载到内存中的动态库路径
 *  mode: RTLD_LAZY,用时加载;RTLD_NOW,立即加载;
 *  return: handle,即被加载的动态库的内存地址
 */
void* dlopen(const char* path, int mode);

/**
 * handle: dlopen 的返回值
 * symbol: 指向动态库中的符号,如函数,变量等
 * return: 返回在内存中的符号地址
 */
void* dlsym(void* handle, const char* symbol);

其中,dlopen 用于将动态库加载到内存中;dlsym 用于查找被加载到内存中的动态库的函数或变量的地址。

接下来我们就使用这两个API 来演示一下如何在 Linux 系统下动态加载库。

要想做这个演示,首先我们要写一个动态库。这个动态库特别简单,就一个函数 add() , 用于加法运算。代码如下:

代码语言:javascript
复制
//源码
#include <stdio.h>
int add(int a, int b){
  return a+b;
}

//编译
gcc -shared -o add.so add.c

通过上面的操作我们就有了一个add.so的动态库。接下来我们再来看看如何使用 dlopendlsym 将上面生成的库动态库加载到内存中,并调用它的 add() 方法吧。具体代码如下:

代码语言:javascript
复制
#include<stdio.h>
#include <dlfcn.h>

typedef int(*FUNC)(int,int);

int main(int argc, char *argv[]){
  void* handler = dlopen("./add.so", RTLD_NOW);
  if(!handler){
    printf("Failed to load so!\n");
    return -1;
  }
  
  FUNC func = (FUNC)dlsym(handler, "add");
  int r = func(10, 20);
  printf("the result is : %d\n", r);

  return 0;
}

//编译
gcc -g -o loadso mytest.c

上面的这段代码是不是很简单?短短的几行代码就向你展示了在 Linux/Mac 系统下动态加载并调用动态库中方法的具体步骤。有了上面的知识,我们再来看Janus的实现就很容易理解它是如何做的了。

Janus 加载Plugin

Janus实现加载插件的代码量很大,但核心代码就那么几行,只要我们将核心代码抽取出来,我们就会发现其实它与我们上面讲的代码几乎是一模一样的。下面我们来看看Janus 是如何动态加载库的吧。

为了方便Janus专门创建了一个目录用于存放插件。在Janus启动时它会遍历该目录,并将目录中的插件一个个动态加载到内存中。经整理后的代码如下:

代码语言:javascript
复制
while((pluginent = readdir(dir))) {
  ......
  g_snprintf(pluginpath, 1024, "%s/%s", path, pluginent->d_name);
  void *plugin = dlopen(pluginpath, RTLD_NOW |   RTLD_GLOBAL);
  ......
  create_p *create = (create_p*) dlsym(plugin, "create");
  ......
  janus_plugin *janus_plugin = create();
  ......
}

上面的这段核心代码是不是与我们上面 Linux 系统下动态库的动态加载 一节介绍的几乎是一样的?所以我们只要把基础知识撑握好了,再看一些复杂的实现时也就不会感觉很难了。

从上面的代码中我们还可以看到,Janus 中的每个插件都实现了create 函数。该函数会返回一个包含多个函数的结构体。这些函数是我们实现Janus插件必须要实现的,它们包括:

  • init(): 该函数是插件的初始化函数,像读取配置文件等操作都应该在这个函数中实现。
  • destroy(): 插件被关闭的时候调用
  • get_api_compatibility(): 该方法只需要返回Janus的API版本即可,用于控制不同Janus版本是否兼容
  • get_version(): 返回版本号(例如 3)
  • get_version_string(): 返回字符串格式的版本号(例如, "v1.0.1")
  • get_description(): 返回插件的详细信息
  • get_name(): 返回插件的短名子
  • get_package():返回插件的唯一包标识 (例如., "janus.plugin.myplugin");
  • create_session(): 在你和对端之间创建一个session
  • handle_message(): 对方发送给你的消息
  • handle_admin_message(): 来自Admin API的消息
  • setup_media(): 告诉你对端的peerConnection已经准备好了
  • incoming_rtp(): 对端发过来的 rtp 包
  • incoming_rtcp(): 对端发过来的 rtcp 消息
  • incoming_data(): 对端通过 SCTP DataChannel 发过来的数据
  • data_ready(): 数据可以通过 SCTP DataChannel 发送了
  • slow_link(): 对端发过来很多 NACKs ,网络路径延迟很大。
  • hangup_media(): 对端的 PeerConnection 关闭了
  • query_session(): 在你与对端的 session中查询指定信息
  • destroy_session(): 消息session

对于一个插件来讲,上面的方法中除了 incoming_rtp 、incoming_rtcp、incoming_data 可以不实现外,其它的方法都必须实现。只有这样当插件被Janus核心层加载之后,就可以被顺利的调用。

小结

本文我重点向你介绍了 Janus 是如何使用和管理Janus插件的。并向你简要的介绍了Janus的架构模型以及要实现一个Janus插件要实现哪些函数。

当然,我们这里只是对Janus 的插件和其要实现的的函数做了一个大体的讲解,很多细节这里并没有讲到,我会在后面的文档中做更详细的介绍 。

参考

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Janus的架构模型
  • Linux 系统下动态库的动态加载
  • Janus 加载Plugin
  • 小结
  • 参考
相关产品与服务
云直播
云直播(Cloud Streaming Services,CSS)为您提供极速、稳定、专业的云端直播处理服务,根据业务的不同直播场景需求,云直播提供了标准直播、快直播、云导播台三种服务,分别针对大规模实时观看、超低延时直播、便捷云端导播的场景,配合腾讯云视立方·直播 SDK,为您提供一站式的音视频直播解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档