generated from zhangwei/Matrixai
297 lines
7.9 KiB
C++
297 lines
7.9 KiB
C++
// PHZ
|
|
// 2018-9-30
|
|
|
|
#include "RtpConnection.h"
|
|
#include "RtspConnection.h"
|
|
#include "SocketUtil.h"
|
|
|
|
using namespace std;
|
|
using namespace xop;
|
|
|
|
RtpConnection::RtpConnection(std::weak_ptr<TcpConnection> rtsp_connection)
|
|
: rtsp_connection_(rtsp_connection)
|
|
{
|
|
std::random_device rd;
|
|
|
|
for(int chn=0; chn<MAX_MEDIA_CHANNEL; chn++) {
|
|
rtpfd_[chn] = 0;
|
|
rtcpfd_[chn] = 0;
|
|
memset(&media_channel_info_[chn], 0, sizeof(media_channel_info_[chn]));
|
|
media_channel_info_[chn].rtp_header.version = RTP_VERSION;
|
|
media_channel_info_[chn].packet_seq = rd()&0xffff;
|
|
media_channel_info_[chn].rtp_header.seq = 0; //htons(1);
|
|
media_channel_info_[chn].rtp_header.ts = htonl(rd());
|
|
media_channel_info_[chn].rtp_header.ssrc = htonl(rd());
|
|
}
|
|
|
|
auto conn = rtsp_connection_.lock();
|
|
rtsp_ip_ = conn->GetIp();
|
|
rtsp_port_ = conn->GetPort();
|
|
}
|
|
|
|
RtpConnection::~RtpConnection()
|
|
{
|
|
for(int chn=0; chn<MAX_MEDIA_CHANNEL; chn++) {
|
|
if(rtpfd_[chn] > 0) {
|
|
SocketUtil::Close(rtpfd_[chn]);
|
|
}
|
|
|
|
if(rtcpfd_[chn] > 0) {
|
|
SocketUtil::Close(rtcpfd_[chn]);
|
|
}
|
|
}
|
|
}
|
|
|
|
int RtpConnection::GetId() const
|
|
{
|
|
auto conn = rtsp_connection_.lock();
|
|
if (!conn) {
|
|
return -1;
|
|
}
|
|
RtspConnection *rtspConn = (RtspConnection *)conn.get();
|
|
return rtspConn->GetId();
|
|
}
|
|
|
|
bool RtpConnection::SetupRtpOverTcp(MediaChannelId channel_id, uint16_t rtp_channel, uint16_t rtcp_channel)
|
|
{
|
|
auto conn = rtsp_connection_.lock();
|
|
if (!conn) {
|
|
return false;
|
|
}
|
|
|
|
media_channel_info_[channel_id].rtp_channel = rtp_channel;
|
|
media_channel_info_[channel_id].rtcp_channel = rtcp_channel;
|
|
rtpfd_[channel_id] = conn->GetSocket();
|
|
rtcpfd_[channel_id] = conn->GetSocket();
|
|
media_channel_info_[channel_id].is_setup = true;
|
|
transport_mode_ = RTP_OVER_TCP;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool RtpConnection::SetupRtpOverUdp(MediaChannelId channel_id, uint16_t rtp_port, uint16_t rtcp_port)
|
|
{
|
|
auto conn = rtsp_connection_.lock();
|
|
if (!conn) {
|
|
return false;
|
|
}
|
|
|
|
if(SocketUtil::GetPeerAddr(conn->GetSocket(), &peer_addr_) < 0) {
|
|
return false;
|
|
}
|
|
|
|
media_channel_info_[channel_id].rtp_port = rtp_port;
|
|
media_channel_info_[channel_id].rtcp_port = rtcp_port;
|
|
|
|
std::random_device rd;
|
|
for (int n = 0; n <= 10; n++) {
|
|
if (n == 10) {
|
|
return false;
|
|
}
|
|
|
|
local_rtp_port_[channel_id] = rd() & 0xfffe;
|
|
local_rtcp_port_[channel_id] =local_rtp_port_[channel_id] + 1;
|
|
|
|
rtpfd_[channel_id] = ::socket(AF_INET, SOCK_DGRAM, 0);
|
|
if(!SocketUtil::Bind(rtpfd_[channel_id], "0.0.0.0", local_rtp_port_[channel_id])) {
|
|
SocketUtil::Close(rtpfd_[channel_id]);
|
|
continue;
|
|
}
|
|
|
|
rtcpfd_[channel_id] = ::socket(AF_INET, SOCK_DGRAM, 0);
|
|
if(!SocketUtil::Bind(rtcpfd_[channel_id], "0.0.0.0", local_rtcp_port_[channel_id])) {
|
|
SocketUtil::Close(rtpfd_[channel_id]);
|
|
SocketUtil::Close(rtcpfd_[channel_id]);
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
SocketUtil::SetSendBufSize(rtpfd_[channel_id], 50*1024);
|
|
|
|
peer_rtp_addr_[channel_id].sin_family = AF_INET;
|
|
peer_rtp_addr_[channel_id].sin_addr.s_addr = peer_addr_.sin_addr.s_addr;
|
|
peer_rtp_addr_[channel_id].sin_port = htons(media_channel_info_[channel_id].rtp_port);
|
|
|
|
peer_rtcp_sddr_[channel_id].sin_family = AF_INET;
|
|
peer_rtcp_sddr_[channel_id].sin_addr.s_addr = peer_addr_.sin_addr.s_addr;
|
|
peer_rtcp_sddr_[channel_id].sin_port = htons(media_channel_info_[channel_id].rtcp_port);
|
|
|
|
media_channel_info_[channel_id].is_setup = true;
|
|
transport_mode_ = RTP_OVER_UDP;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool RtpConnection::SetupRtpOverMulticast(MediaChannelId channel_id, std::string ip, uint16_t port)
|
|
{
|
|
std::random_device rd;
|
|
for (int n = 0; n <= 10; n++) {
|
|
if (n == 10) {
|
|
return false;
|
|
}
|
|
|
|
local_rtp_port_[channel_id] = rd() & 0xfffe;
|
|
rtpfd_[channel_id] = ::socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (!SocketUtil::Bind(rtpfd_[channel_id], "0.0.0.0", local_rtp_port_[channel_id])) {
|
|
SocketUtil::Close(rtpfd_[channel_id]);
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
media_channel_info_[channel_id].rtp_port = port;
|
|
|
|
peer_rtp_addr_[channel_id].sin_family = AF_INET;
|
|
peer_rtp_addr_[channel_id].sin_addr.s_addr = inet_addr(ip.c_str());
|
|
peer_rtp_addr_[channel_id].sin_port = htons(port);
|
|
|
|
media_channel_info_[channel_id].is_setup = true;
|
|
transport_mode_ = RTP_OVER_MULTICAST;
|
|
is_multicast_ = true;
|
|
return true;
|
|
}
|
|
|
|
void RtpConnection::Play()
|
|
{
|
|
for(int chn=0; chn<MAX_MEDIA_CHANNEL; chn++) {
|
|
if (media_channel_info_[chn].is_setup) {
|
|
media_channel_info_[chn].is_play = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void RtpConnection::Record()
|
|
{
|
|
for (int chn=0; chn<MAX_MEDIA_CHANNEL; chn++) {
|
|
if (media_channel_info_[chn].is_setup) {
|
|
media_channel_info_[chn].is_record = true;
|
|
media_channel_info_[chn].is_play = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void RtpConnection::Teardown()
|
|
{
|
|
if(!is_closed_) {
|
|
is_closed_ = true;
|
|
for(int chn=0; chn<MAX_MEDIA_CHANNEL; chn++) {
|
|
media_channel_info_[chn].is_play = false;
|
|
media_channel_info_[chn].is_record = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
string RtpConnection::GetMulticastIp(MediaChannelId channel_id) const
|
|
{
|
|
return std::string(inet_ntoa(peer_rtp_addr_[channel_id].sin_addr));
|
|
}
|
|
|
|
string RtpConnection::GetRtpInfo(const std::string& rtsp_url)
|
|
{
|
|
char buf[2048] = { 0 };
|
|
snprintf(buf, 1024, "RTP-Info: ");
|
|
|
|
int num_channel = 0;
|
|
|
|
auto time_point = chrono::time_point_cast<chrono::milliseconds>(chrono::steady_clock::now());
|
|
auto ts = time_point.time_since_epoch().count();
|
|
for (int chn = 0; chn<MAX_MEDIA_CHANNEL; chn++) {
|
|
uint32_t rtpTime = (uint32_t)(ts*media_channel_info_[chn].clock_rate / 1000);
|
|
if (media_channel_info_[chn].is_setup) {
|
|
if (num_channel != 0) {
|
|
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",");
|
|
}
|
|
|
|
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
|
|
"url=%s/track%d;seq=0;rtptime=%u",
|
|
rtsp_url.c_str(), chn, rtpTime);
|
|
num_channel++;
|
|
}
|
|
}
|
|
|
|
return std::string(buf);
|
|
}
|
|
|
|
void RtpConnection::SetFrameType(uint8_t frame_type)
|
|
{
|
|
frame_type_ = frame_type;
|
|
if(!has_key_frame_ && (frame_type == 0 || frame_type == VIDEO_FRAME_I)) {
|
|
has_key_frame_ = true;
|
|
}
|
|
}
|
|
|
|
void RtpConnection::SetRtpHeader(MediaChannelId channel_id, RtpPacket pkt)
|
|
{
|
|
if((media_channel_info_[channel_id].is_play || media_channel_info_[channel_id].is_record) && has_key_frame_) {
|
|
media_channel_info_[channel_id].rtp_header.marker = pkt.last;
|
|
media_channel_info_[channel_id].rtp_header.ts = htonl(pkt.timestamp);
|
|
media_channel_info_[channel_id].rtp_header.seq = htons(media_channel_info_[channel_id].packet_seq++);
|
|
memcpy(pkt.data.get()+4, &media_channel_info_[channel_id].rtp_header, RTP_HEADER_SIZE);
|
|
}
|
|
}
|
|
|
|
int RtpConnection::SendRtpPacket(MediaChannelId channel_id, RtpPacket pkt)
|
|
{
|
|
if (is_closed_) {
|
|
return -1;
|
|
}
|
|
|
|
auto conn = rtsp_connection_.lock();
|
|
if (!conn) {
|
|
return -1;
|
|
}
|
|
|
|
RtspConnection *rtsp_conn = (RtspConnection *)conn.get();
|
|
|
|
bool ret = rtsp_conn->task_scheduler_->AddTriggerEvent([this, channel_id, pkt] {
|
|
this->SetFrameType(pkt.type);
|
|
this->SetRtpHeader(channel_id, pkt);
|
|
if((media_channel_info_[channel_id].is_play || media_channel_info_[channel_id].is_record) && has_key_frame_ ) {
|
|
if(transport_mode_ == RTP_OVER_TCP) {
|
|
SendRtpOverTcp(channel_id, pkt);
|
|
}
|
|
else {
|
|
SendRtpOverUdp(channel_id, pkt);
|
|
}
|
|
|
|
//media_channel_info_[channel_id].octetCount += pkt.size;
|
|
//media_channel_info_[channel_id].packetCount += 1;
|
|
}
|
|
});
|
|
|
|
return ret ? 0 : -1;
|
|
}
|
|
|
|
int RtpConnection::SendRtpOverTcp(MediaChannelId channel_id, RtpPacket pkt)
|
|
{
|
|
auto conn = rtsp_connection_.lock();
|
|
if (!conn) {
|
|
return -1;
|
|
}
|
|
|
|
uint8_t* rtpPktPtr = pkt.data.get();
|
|
rtpPktPtr[0] = '$';
|
|
rtpPktPtr[1] = (char)media_channel_info_[channel_id].rtp_channel;
|
|
rtpPktPtr[2] = (char)(((pkt.size-4)&0xFF00)>>8);
|
|
rtpPktPtr[3] = (char)((pkt.size -4)&0xFF);
|
|
|
|
conn->Send((char*)rtpPktPtr, pkt.size);
|
|
return pkt.size;
|
|
}
|
|
|
|
int RtpConnection::SendRtpOverUdp(MediaChannelId channel_id, RtpPacket pkt)
|
|
{
|
|
int ret = sendto(rtpfd_[channel_id], (const char*)pkt.data.get()+4, pkt.size-4, 0,
|
|
(struct sockaddr *)&(peer_rtp_addr_[channel_id]), sizeof(struct sockaddr_in));
|
|
|
|
if(ret < 0) {
|
|
Teardown();
|
|
return -1;
|
|
}
|
|
|
|
return ret;
|
|
}
|