佛山市制作网站,深圳建设局官网站,成都优化教育百度推广,电子商务网站前台业务系统主要是提示#xff1a;文章写完后#xff0c;目录可以自动生成#xff0c;如何生成可参考右边的帮助文档 文章目录
前言一、libdatachannel库的下载和build二、开始使用 1.2.引入库3.开始使用 总结 前言
使用c开发webrtc在互联网上留下的资料甚少#xff0c;经过我一段时间的探… 提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档 文章目录
前言一、libdatachannel库的下载和build二、开始使用 1.2.引入库3.开始使用 总结 前言
使用c开发webrtc在互联网上留下的资料甚少经过我一段时间的探索有大概这几种可以用于c进行webrtc开发的方法。 1.c webrtc native 开发这个开发方法很麻烦编译这个库十分麻烦索性网上还留有部分资料可供参考但是因为我是想在嵌入式上部署webrtc所以没有考虑这个方法。 2.kvs webrtc c sdk 库二次开发利用amazon给出的用于aws的sdk我们编译生成静态库后可以抛弃掉其中信令服务器等内容利用里面ice部分媒体传输部分完成自己的功能的开发。优点是这个库的对外api的介绍写的挺清楚缺点是kvs的github社区里面的问题基本都是使用它的整套服务过程中提出的问题对于单独提取它的一些库来完成自己功能过程中遇到的问题很少可能你在自己魔改的过程中遇到奇奇怪怪的问题里面一点线索都找不到。其次这是一个c库对外的api写的挺清楚但是遇到bug后你阅读源码的过程中大量的c代码会让你很难受。并且该库依赖大量的第三方库编译过程比webrtc native舒适不少但还是会遇到各种问题尤其是你想要交叉编译到嵌入式板子上时可能这个过程更会让你难受。关于使用这个库开发自己的webrtc的中文资料也挺少推荐这篇博客 嵌入式中实现webrtc的方式 这条路我是跟着这篇文章做过一阵但是最后还是失败了如果有人这个方法做出来可以告诉我 3.libdatachannel库这个库很轻量级简单make就可以虽然看名字这个库似乎只能用于datachannel但实际他是支持媒体传输的代码质量很高缺点是要c17但是我的嵌入式板子刚好支持c17于是就这样使用下来了体验很不错基本上使用库遇到的问题你都能在github的issue中找到解决的方法。
一、libdatachannel库的下载和build
没什么好说的因为这个库真的很轻量级我甚至没有交叉编译我直接在嵌入式板子上编译最终都通过了。 make就完事了中间可能会遇到openssl库的一个问题google一下就能解决问题。 build教学
二、开始使用
1.
如果直接使用的话你在make之后再make install一下大概就会把相关需要的文件放在系统的某个目录下了你可以把include和lib自己拿出来放到项目文件夹中或者你再cmake中指明库在系统哪个地方也行不懂的可以问chatgpt适当的提示词可以让gpt很快地解决你的问题。除此之外你还需要自己include一个json库你喜欢的任意一种cjson库都行。
2.引入库 就像这样引入这些库吧。最重要的是rtc.hpp别把它忘了就好
3.开始使用
大家可以照看github中examples的代码自己读自己改出一版自己的webrtc接下来我来用我自己的代码来做一个简单的教学内容在代码中的注释展现
#include ../include/rtc/rtc.hpp
#include iostream
#include json.hpp
#include memory
#include arpa/inet.h
#include netinet/in.h
#include sys/socket.h
typedef int SOCKET;
static std::string from;
static std::string to;
static std::string sessionid;using std::string;
using std::shared_ptr;
using std::weak_ptr;
using std::cout ;
using std::endl;
const int BUFFER_SIZE 2048;
template class T weak_ptrT make_weak_ptr(shared_ptrT ptr) { return ptr; }
shared_ptrrtc::PeerConnection pc;
rtc::WebSocket ws;
using nlohmann::json;
int main()
{// std::cout hehe std::endl;//Debug的程度一般设置为Debug就行Verbose会展示网络的具体细节rtc::InitLogger(rtc::LogLevel::Verbose);bool flag false;//ws开启ws.onOpen([flag]() {std::cout WebSocket open std::endl;flag true;});//socket绑定这一段代码非必须如果你阅读了github中examples的相关内容你应该会理解这么做是在干嘛SOCKET sock socket(AF_INET, SOCK_DGRAM, 0);struct sockaddr_in addr {};addr.sin_family AF_INET;addr.sin_addr.s_addr inet_addr(127.0.0.1);addr.sin_port htons(6000);if (bind(sock, reinterpret_castconst sockaddr *(addr), sizeof(addr)) 0)throw std::runtime_error(Failed to bind UDP socket on 127.0.0.1:6000);int rcvBufSize 212992;setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_castconst char *(rcvBufSize),sizeof(rcvBufSize));//设置websocket的回调函数,里面相关的json报文解析要按照你自己的信令服务器来进行设置//我来说说里面比较重要的东西//1.setRemoteDescription需要你传入sdp和type的string注意当你没有持有offer时这时里面会//自动调用setLocalDescription然后开始产生你的对offer的answer//对应于js中的写法就相当于setremotedescription后自动调用了CreateAnswer//而你自己获得answer后却不会产生自己的sdpws.onMessage([](auto data) {// data holds either std::string or rtc::binaryif (!std::holds_alternativestd::string(data))return;// cout 1111 endl;std::string ndata std::getstd::string(data);std::cout got data ndata std::endl;json message json::parse(ndata);std::string type message[type].getstd::string();// cout 2222 endl;if (type offer) {std::cout get offer std::endl;std::string sdp message[data][description][sdp].getstd::string();std::cout get sdp: sdp std::endl;pc-setRemoteDescription(rtc::Description(sdp, type));} else if(type answer){std::cout get answer std::endl;std::string sdp message[data][description][sdp].getstd::string();std::cout get sdp: sdp std::endl;pc-setRemoteDescription(rtc::Description(sdp, type));}else if (type candidate) {auto candidate message[data][candidate][candidate].getstd::string();auto mid message[data][candidate][sdpMid].getstd::string();// auto mid message[mid].getstd::string();std::cout get candidate:candidate std::endl;pc-addRemoteCandidate(rtc::Candidate(candidate, mid));}});////ws连接,如果你是主动发送offer方请务必等ws连接完毕后再进行后续否则可能会出现ws还未连接但是已经收集完description并尝试发送了ws.open(your own websocket url);// int cnt;while(!flag){;}//stun服务器和turn服务器的设置如果你要设置turn其实直接写一个turn地址就够了这个turn也会用作stun//并且你不用在ip中指明是turn还是stun当你设置有密码和账号后,就会认为是turn了rtc::Configuration config;// config.iceServers.emplace_back(stun.l.google.com:19302);config.iceServers.emplace_back(url);// const rtc::IceServer turnServer(ip, port, name, password);// config.iceServers.emplace_back(turnServer);//简单的媒体trackrtc::Description::Video media(video, rtc::Description::Direction::SendOnly);media.addH264Codec(96);media.addSSRC( rtc::SSRC(45), video-send );pc std::make_sharedrtc::PeerConnection(config);auto track pc-addTrack(media);// pc-createdata//收集本地candidate回调每收集到一个就会发送一个pc-onLocalCandidate([](rtc::Candidate candidate) {std::cout Local Candidate: std::endl;std::cout std::string(candidate) std::endl std::endl;// std::cout std::string(candidate.mid()) std::endl;json message;message[type] candidate;message[data][from] 1433;message[data][to] 1453;message[data][candidate][candidate] std::string(candidate);message[data][candidate][sdpMid] candidate.mid();message[data][session_id] 1453-1433;ws.send(message.dump());});//ice状态pc-onStateChange([](rtc::PeerConnection::State state) {std::cout [State: state ] std::endl;});//本地sdppc-onLocalDescription([](rtc::Description sdp){auto description pc-localDescription();json message;message[type] description-typeString();message[data][to] 1453;message[data][from] 1433;message[data][description][sdp] string(description.value());message[data][description][type] description-typeString();message[data][session_id] 1453-1433;message[data][media] video;std::cout send answer json :message.dump() std::endl;ws.send(message.dump());});
//没什么大用告知candidate收集状态pc-onGatheringStateChange([](rtc::PeerConnection::GatheringState state) {cout Gathering State: state endl;if (state rtc::PeerConnection::GatheringState::Complete) {std::cout gather ok std::endl;}});
// pc-setLocalDescription();// pc-onTrack)// const std::string label test;// std::cout Creating DataChannel with label label std::endl;// auto dc pc-createDataChannel(label);// dc-onOpen([wdc make_weak_ptr(dc)]() {// // std::cout DataChannel from id open std::endl;// if (auto dc wdc.lock())// dc-send(Hello from wl);// });// dc-onClosed([]() { std::cout DataChannel from closed std::endl; });// dc-onMessage([wdc make_weak_ptr(dc)](auto data) {// // data holds either std::string or rtc::binary// if (std::holds_alternativestd::string(data))// std::cout Message from peer received: std::getstd::string(data)// std::endl;// else// std::cout Binary message from peer // received, size std::getrtc::binary(data).size() std::endl;// });char buffer[2048];int len;while ((len recv(sock, buffer, BUFFER_SIZE, 0)) 0) {if (len sizeof(rtc::RtpHeader) || !track-isOpen())continue;std::cout send buffer: len std::endl;auto rtp reinterpret_castrtc::RtpHeader *(buffer);rtp-setSsrc(rtc::SSRC(45));track-send(reinterpret_castconst std::byte *(buffer), len);}// while(1);return 0;
}总结
libdatachannel是一个很好用的webrtc库经过测试它的协议栈能和firefox和flutter-webrtc兼容