其必要性在于: 1 能够显著减少服务器压力负担 2 随着国内带宽上传能力增加,非对称网络上传视频可能大大提升 3 减少服务费用
2、前提条件1、由于p2p链接需要很多条件限制,因此并非所有网络方式能够打通p2p方式的链接,我们限制在cone net p2p上进行网关程序间分发。 2、限制udp方式分发流 3、限制联通和电信这类4g网络只能使用turn方式。
3、程序架构1、udp服务器-主服务器 2、udp服务器-分发中转服务器 3、分发架构路由 4、ps读写构造器客户端进行解包,渲染 5、存储器 —部署在p2p的各端可进行 6、sip gb28181 ----信令服务 7、rtsp proxy 8、webrtc proxy 9、redis 订阅发布 10、tcpserver 可选 流程为: a)在sip 接收到命令之后,可以invite相应的邀请流进入,这一部分不使用p2p方式,和webrtc本身所使用的方式一致,信令为直接tcp服务或者udp服务的传输,可以使用传统udp服务sip 5060端口。 b) 客户端负责打洞,根据分发配置信令来给服务器来通知,这时stun服务必须由分发内容。 c)打洞完毕(成功),信令服务sdp协议中可以加入接收rtp服务地址 d)传输开始
层次关系以及所需要的协议等等如下图所示
分发功能 —config 分发配置 —config 路由
sipserver —gb28181 分发信令服务器 rtp ps 分析器 — 投屏协议 — DLNA协议
p2p 服务 —传统的stun和turn服务器是可选项 更佳的配置是得到分析,p2p 打洞探测如果为对称立刻进行转发服务。
3.3 程序制作 给出udpserver的声明,p2p udp server如果使用非异步方式一定要使用多个线程接收,在接收线程中使用recvfrom来得到客户端的外网地址,才能帮助双方打通。
#include "c_decode.h"
#include "c_thread.h"
#include "c_sock.h"
#include
using namespace std;
typedef struct _RTP_HEAD
{
unsigned char version : 2;
unsigned char padding : 1;
unsigned char extension : 1;
unsigned char count : 4;
unsigned char marker : 1;
unsigned char payload : 7;
uint16_t sn; //16bits
uint32_t ts; //32
uint32_t ssrc; //32
uint32_t csrc; //32
}RTP_HEAD, *pRTP_HEAD;
typedef struct _RTCP_HEAD
{
unsigned char version : 2;
unsigned char padding : 1;
unsigned char count : 5;
unsigned char payload; //8bits
uint16_t length; //16bits
uint32_t ssrc; //5,6,7,8 char
}RTCP_HEAD, *pRTCP_HEAD;
//NACK报文是类型为205的RTCP 扩展反馈报文,在RFC4585中定义。
class c_udp:public c_thread
{
private:
queue _memcache;
private:
c_sock _udpserver;
unsigned int _port;
H264DecoderContext* _decoder;
public:
c_udp(void);
~c_udp(void);
void Run();
void StartReceive(unsigned int port,H264DecoderContext *decoder);
void StopServer();
memory_cache * GetBufferToDecode();
protected:
void HandlePacket(char * buffer, int len);
};
给出一个常用的thread class,以上udp 从thread类继承
#include
#include
#include
#include
#include
using namespace std;
class c_thread
{
private:
//线程
thread _thread;
//等待信号
std::mutex _signal_mutex;
std::condition_variable _cond;
protected:
//char _running = false;
char _stop = true;
//锁定运行状态
std::mutex _mutex;
public:
c_thread()
{}
virtual ~c_thread()
{}
public:
char * status(){
return &_stop;
}
void Join()
{
if (_thread.joinable())
_thread.join();
}
bool IsStop()
{
return _stop == 1 ? true : false;
}
void WaitForSignal()
{
std::unique_lock ul(_signal_mutex);
_cond.wait(ul);
}
void Notify()
{
_cond.notify_one();
}
virtual int Start()
{
if (_stop == 1)//非運行中
{
_stop = 0;
_thread = std::thread(std::bind(&c_thread::Run, this));
return 0;
}
return -1;
}
virtual void Stop()
{
_stop = 1; // true;
}
virtual void Run() = 0;
};
#endif
线程内容就放在run函数中,主线程做收包使用,记录配对的地址和路由,才能做到分发。
其他内容待续。。。。