webrtc入门:10.Kurento流程分析
Kurento
我们通常成他为 Kurento media server
,简称为kms
,他是webrtc
下的媒体服务器。kms
像我们上一节使用的那样,我们会对kms
的流程进行简单的介绍。
kms
是基于GStreamer
下进行开发的,有关GStreamer
开发可以找相应的资料。我们还是依照两个依据,一个是sdp
,另外一个是ice
。
sdp的生成
在上一个例子中,我们使用的是kms
中java
的api
,kms
和java的api
也是通过socket进行通讯的。通过JsonRpc
来进行通讯,比如processOffer
是通过反射的方式invoke
调用到目标函数。
void
SdpEndpointImpl::invoke (std::shared_ptr<MediaObjectImpl> obj, const std::string &methodName, const Json::Value ¶ms, Json::Value &response)
{
...if (methodName == "processOffer") {kurento::JsonSerializer s (false);SdpEndpointMethodProcessOffer method;JsonSerializer responseSerializer (true);std::string ret;s.JsonValue = params;method.Serialize (s);ret = method.invoke (std::dynamic_pointer_cast<SdpEndpoint> (obj) );responseSerializer.SerializeNVP (ret);response = responseSerializer.JsonValue["ret"];return;}
...SessionEndpointImpl::invoke (obj, methodName, params, response);
}
具体看看调用的是哪个函数:
std::string SdpEndpointImpl::processOffer (const std::string &offer)
{GstSDPMessage *offerSdp = nullptr, *result = nullptr;std::string offerSdpStr;bool expected = false;if (offer.empty () ) {throw KurentoException (SDP_PARSE_ERROR, "Empty offer not valid");}offerSdp = str_to_sdp (offer);if (!offerInProcess.compare_exchange_strong (expected, true) ) {//the endpoint is already negotiatedthrow KurentoException (SDP_END_POINT_ALREADY_NEGOTIATED,"Endpoint already negotiated");}g_signal_emit_by_name (element, "process-offer", sessId.c_str (), offerSdp,&result);gst_sdp_message_free (offerSdp);if (result == nullptr) {offerInProcess = false;throw KurentoException (SDP_END_POINT_PROCESS_OFFER_ERROR,"Error processing offer");}sdp_to_str (offerSdpStr, result);gst_sdp_message_free (result);try {MediaSessionStarted event (shared_from_this (),MediaSessionStarted::getName ());sigcSignalEmit(signalMediaSessionStarted, event);} catch (const std::bad_weak_ptr &e) {// shared_from_this()GST_ERROR ("BUG creating %s: %s", MediaSessionStarted::getName ().c_str (),e.what ());}GST_INFO("creating sdp: %s",offerSdpStr.c_str());return offerSdpStr;
}
g_signal_emit_by_name (element, "process-offer"
调用了process-offer
的信号,其实是调用到了kms_sdp_session_process_offer
函数。接着调用到底层kms_sdp_agent_generate_answer
。
static GstSDPMessage *
kms_sdp_agent_generate_answer (KmsSdpAgent * agent,const GstSDPMessage * offer, GError ** error)
{....
GST_INFO("gst_sdp_message_new");if (gst_sdp_message_new (&answer) != GST_SDP_OK) {g_set_error_literal (error, KMS_SDP_AGENT_ERROR, SDP_AGENT_INVALID_STATE,"Can not allocate SDP answer");goto end;}if (!kms_sdp_agent_set_default_session_attributes (answer, error)) {goto end;}if (!kms_sdp_agent_set_origin (answer, &o, error)) {goto end;}...return answer;
}
gst_sdp_message_new
是GStreamer
的底层生成sdp
函数了。
ice
ice的生成使用的是 地方库libnice
,可以参考这里。
对于kms
来说,他是一种模块化的加载方式,自动会加载class_init
的函数。通过kms_ice_nice_agent_new_candidate_full
后,再到 kms_ice_nice_agent_new_candidate_full
的函数。
static char *
kms_ice_nice_agent_get_candidate_sdp_string (NiceAgent * agent,NiceCandidate * candidate)
{//printf("nice_agent_generate_local_candidate_sdp\r\n");gchar *str = nice_agent_generate_local_candidate_sdp (agent, candidate);gchar *cand = g_strconcat (SDP_CANDIDATE_ATTR, ":",(str + SDP_CANDIDATE_ATTR_LEN), NULL);g_free (str);return cand;
}
nice_agent_generate_local_candidate_sdp
函数,就是libnice
的底层函数了。
生成的ice,通过socket发走:
sigc::connection conn = signalIceCandidateFound.connect ([ &, wh] (IceCandidateFound event) {//std::cout <<"android pp WebRtcEndpointImpl::connect IceCandidateFound event: "<<"signalIceCandidateFound " << std::endl;std::shared_ptr<EventHandler> lh = wh.lock();if (!lh)return;std::shared_ptr<IceCandidateFound> ev_ref (new IceCandidateFound(event));auto object = this->shared_from_this();lh->sendEventAsync ([ev_ref, object, lh] {JsonSerializer s (true);s.Serialize ("data", ev_ref.get());s.Serialize ("object", object.get());s.JsonValue["type"] = "IceCandidateFound";lh->sendEvent (s.JsonValue);});});
如何连接
创建通道,在这个通道中进行数据的连接。
static void
rtp_ssrc_demux_new_ssrc_pad (GstElement * ssrcdemux, guint ssrc, GstPad * pad,KmsBaseRtpSession * self)
{GST_INFO("rtp_ssrc_demux_new_ssrc_pad");const gchar *rtp_pad_name = GST_OBJECT_NAME (pad);gchar *rtcp_pad_name;const GstSDPMedia *media;GstPad *src, *sink;GST_INFO_OBJECT (self, "pad: %" GST_PTR_FORMAT " ssrc: %" G_GUINT32_FORMAT,pad, ssrc);KMS_SDP_SESSION_LOCK (self);if (self->remote_audio_ssrc == ssrc|| ssrcs_are_mapped (ssrcdemux, self->local_audio_ssrc, ssrc)) {media = self->audio_neg;} else if (self->remote_video_ssrc == ssrc|| ssrcs_are_mapped (ssrcdemux, self->local_video_ssrc, ssrc)) {media = self->video_neg;} else {if (kms_i_rtp_session_manager_custom_ssrc_management (self->manager, self,ssrcdemux, ssrc, pad)) {goto end;} else {GST_WARNING_OBJECT (pad,"Ignoring media from non-matching SSRC: %" G_GUINT32_FORMAT, ssrc);media = NULL;}}/* RTP */sink = kms_i_rtp_session_manager_request_rtp_sink (self->manager, self, media);kms_base_rtp_session_link_pads (pad, sink);g_object_unref (sink);/* RTCP */rtcp_pad_name = g_strconcat ("rtcp_", rtp_pad_name, NULL);src = gst_element_get_static_pad (ssrcdemux, rtcp_pad_name);g_free (rtcp_pad_name);sink = kms_i_rtp_session_manager_request_rtcp_sink (self->manager, self, media);kms_base_rtp_session_link_pads (src, sink);g_object_unref (src);g_object_unref (sink);end:KMS_SDP_SESSION_UNLOCK (self);
}
完成了数据的交换。
webrtc入门:10.Kurento流程分析相关推荐
- 技术宝典 | WebRTC ADM 源码流程分析
导读: 本文主要基于 WebRTC release-72 源码及云信音视频团队积累的相关经验而成,主要分析以下问题: ADM(Audio Device Manager)的架构如何?ADM(Audio ...
- WebRTC ADM 源码流程分析
导读: 本文主要基于 WebRTC release-72 源码及云信音视频团队积累的相关经验而成,主要分析以下问题: ADM(Audio Device Manager)的架构如何?ADM(Audio ...
- WebRTC视频数据流程分析
本文来自<WebRTC Native开发实战>书籍作者许建林在LiveVideoStack线上分享中的内容,详细分析总结 WebRTC 的视频数据流程,并对大型项目如何快速上手:分析方法, ...
- GEF入门实例_总结_04_Eclipse插件启动流程分析
一.前言 本文承接上一节:GEF入门实例_总结_03_显示菜单和工具栏 注意到app目录下的6个类文件. 这6个文件对RCP应用程序而言非常重要,可能我们现在对这几个文件的理解还是云里雾里,这一节我们 ...
- webrtc入门:8.coturn流程
对于局域网中的webrtc是不需要coturn,因为他们自己进行视频流的传输,但通常的应用场景,在同一个局域网下概率是比较低的,因此我们需要把流推到服务器上,另外一端在从服务器把流拉下来.coturn ...
- axios从入门到源码分析 -http-xhr
axios从入门到源码分析 1 HTTP相关 1.1.MDN文档 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Overview 1.2. HTT ...
- 通过一款早期代码抽取壳入门学习 so 层分析
1. 前言 文章开始需要提下的就是,在如今看雪论坛的用户一发关于安卓加固的文章动辄就是有关脱壳机.vmp.函数级指令抽取或者各大厂商的加固等技术的情况下,为何我要发一个代码抽取壳的分析,并且还是早期的 ...
- webrtc 入门第二章 音视频录制
webrtc 入门第二章 音视频录制 一.介绍 1.媒体录制原理 在很多场景中回放音视频资源的需求是非常重要的例如会议,直播授课等.任何媒体形式的表情都可进行录制,如 ,,等.其中内容更加自由用户 ...
- 微信支付:支付流程分析、微信扫码支付(HttpClient)、微信支付二维码生成、检测支付状态、订单状态操作准备工作、支付信息回调、MQ处理支付回调状态、定时处理订单状态
微信支付 微信支付开发的整体思路 生成支付二维码 查询支付状态(微信的服务器) 实现订单状态的修改.删除订单 支付状态回查->微信服务器将支付状态返回给支付微服务 MQ处理支付回调状态 Rabb ...
最新文章
- oracle adf 使用,ORACLE ADF 问题总结
- rhel 5 检测软件awstats,cacti,ntop搭建
- hdu 1087 Super Jumping! Jumping! Jumping! 动态规划
- jsonwebtoken jwt token 简单加密
- [android] 练习使用ListView(二)
- 英伟达CUDA 10终于开放下载了
- Eclipse如何重置窗口
- J2SE基础夯实系列之正则表达式Java
- 在内网中使用maven_使用nexus搭建内网maven镜像
- 抖音短视频去水印网址 视频消重后,火山还是鉴别出来了
- Excel:带有相关单元格引用的Python xlwings复制粘贴公式
- Ping其他电脑ping不通的解决方法
- 星星之火可以燎原鸿蒙,余承东:没有人能够熄灭满天星光 星星之火可以燎原...
- 你有什么经验一定要分享给初入职场的新人?
- 题目52:输入两个正整数m和n,判断m和n是否互质(即最大公约数为1),是则输出Yes,否则输出No。
- vue中使用$refs获取不到DOM元素
- 什么是推力圆锥滚子轴承呢?
- MyEclipse下使用xdoclet自动生成hdm文件
- 关于如何使用xposed来hook某支付软件
- 【DP~最大子立方体】吃西瓜
热门文章
- c语言诺手还是强,LOL小马评价余小C诺手,C皇不混还很强
- cad中怎么随意移动图形_Cad中如何移动图形?AutoCAD移动图形的图文操作流程
- 气传导耳机哪家好、气传导耳机品牌推荐
- 2019如何操作亚马逊无货源店群?如何开店运营?
- Xshell7 和 Xftp7要继续使用此程序,您必须应用最新的更新或者使用新版本
- 实现单例模式四种方法--java
- 【前端44_前后端交互_跨域】前端解决:JSONP、后端解决:CORS 、后端代理
- u大师u盘装系统win7_怎么使用u盘装win7系统
- 利用python,将python语法代码翻译成js语法代码
- Unity中的UGUI源码解析之事件系统(2)-EventSystem组件