1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

rtc publish, with debug code

This commit is contained in:
xiaozhihong 2020-04-23 17:08:21 +08:00
parent c654f1e06e
commit a061d5c3db
11 changed files with 1914 additions and 23 deletions

View file

@ -54,6 +54,7 @@ using namespace std;
#include <srs_app_utility.hpp>
#include <srs_app_config.hpp>
#include <srs_app_rtc.hpp>
#include <srs_app_rtp_queue.hpp>
#include <srs_app_source.hpp>
#include <srs_app_server.hpp>
#include <srs_service_utility.hpp>
@ -123,6 +124,44 @@ static std::vector<std::string> get_candidate_ips()
return candidate_ips;
}
static map<uint32_t, uint64_t> ssrc_lxr;
uint64_t SrsNtp::kMagicNtpFractionalUnit = 1ULL << 32;
SrsNtp::SrsNtp()
{
system_ms_ = 0;
ntp_ = 0;
ntp_second_ = 0;
ntp_fractions_ = 0;
}
SrsNtp::~SrsNtp()
{
}
SrsNtp SrsNtp::from_time_ms(uint64_t ms)
{
SrsNtp srs_ntp;
srs_ntp.system_ms_ = ms;
srs_ntp.ntp_second_ = ms / 1000;
srs_ntp.ntp_fractions_ = (static_cast<double>(ms % 1000 / 1000.0)) * kMagicNtpFractionalUnit;
srs_ntp.ntp_ = (static_cast<uint64_t>(srs_ntp.ntp_second_) << 32) | srs_ntp.ntp_fractions_;
return srs_ntp;
}
SrsNtp SrsNtp::to_time_ms(uint64_t ntp)
{
SrsNtp srs_ntp;
srs_ntp.ntp_ = ntp;
srs_ntp.ntp_second_ = (ntp & 0xFFFFFFFF00000000ULL) >> 32;
srs_ntp.ntp_fractions_ = (ntp & 0x00000000FFFFFFFFULL);
srs_ntp.system_ms_ = (static_cast<uint64_t>(srs_ntp.ntp_second_) * 1000) +
(static_cast<double>(static_cast<uint64_t>(srs_ntp.ntp_fractions_) * 1000.0) / kMagicNtpFractionalUnit);
return srs_ntp;
}
SrsDtlsSession::SrsDtlsSession(SrsRtcSession* s)
{
rtc_session = s;
@ -1415,6 +1454,356 @@ srs_error_t SrsRtcSenderThread::packet_stap_a(SrsSource* source, SrsSharedPtrMes
return err;
}
SrsRtcPublisher::SrsRtcPublisher(SrsRtcSession* session)
{
rtc_session = session;
rtp_h264_demuxer = new SrsRtpH264Demuxer();
rtp_video_queue = new SrsRtpQueue(1000);
rtp_audio_queue = new SrsRtpQueue(100, true);
source = NULL;
}
SrsRtcPublisher::~SrsRtcPublisher()
{
srs_freep(rtp_h264_demuxer);
srs_freep(rtp_video_queue);
srs_freep(rtp_audio_queue);
}
void SrsRtcPublisher::initialize(uint32_t vssrc, uint32_t assrc, SrsRequest request)
{
video_ssrc = vssrc;
audio_ssrc = assrc;
this->request = request;
srs_verbose("video_ssrc=%u, audio_ssrc=%u", video_ssrc, audio_ssrc);
}
srs_error_t SrsRtcPublisher::on_rtp(SrsUdpMuxSocket* skt, char* buf, int nb_buf)
{
srs_error_t err = srs_success;
SrsRtpSharedPacket* rtp_shared_pkt = new SrsRtpSharedPacket();
SrsAutoFree(SrsRtpSharedPacket, rtp_shared_pkt);
if ((err = rtp_shared_pkt->decode(buf, nb_buf)) != srs_success) {
return srs_error_wrap(err, "rtp packet decode failed");
}
uint32_t ssrc = rtp_shared_pkt->rtp_header.get_ssrc();
if (ssrc == audio_ssrc) {
return on_audio(skt, rtp_shared_pkt);
} else if (ssrc == video_ssrc) {
return on_video(skt, rtp_shared_pkt);
}
return srs_error_new(ERROR_RTC_RTP, "unknown ssrc=%u", ssrc);
}
srs_error_t SrsRtcPublisher::on_audio(SrsUdpMuxSocket* skt, SrsRtpSharedPacket* rtp_pkt)
{
srs_error_t err = srs_success;
return err;
vector<uint16_t> nack_seqs;
rtp_audio_queue->nack_.get_nack_seqs(nack_seqs);
vector<uint16_t>::iterator iter = nack_seqs.begin();
while (iter != nack_seqs.end()) {
char buf[1024];
SrsBuffer stream(buf, sizeof(buf));
stream.write_1bytes(0x81);
stream.write_1bytes(kRtpFb);
stream.write_2bytes(3);
stream.write_4bytes(audio_ssrc);
stream.write_4bytes(audio_ssrc);
uint16_t pid = *iter;
uint16_t blp = 0;
srs_verbose("pid=%u", pid);
while (iter + 1 != nack_seqs.end() && (*(iter + 1) - pid <= 15)) {
blp |= (1 << (*(iter + 1) - pid - 1));
srs_verbose("blp=%u", *(iter+1));
++iter;
}
stream.write_2bytes(pid);
stream.write_2bytes(blp);
srs_verbose("nack dump=%s", srs_string_dumps_hex(stream.data(), stream.pos()).c_str());
char protected_buf[kRtpPacketSize];
int nb_protected_buf = stream.pos();
if (rtc_session->dtls_session->protect_rtcp(protected_buf, stream.data(), nb_protected_buf) == srs_success) {
skt->sendto(protected_buf, nb_protected_buf, 0);
//skt->sendto(stream.data(), stream.pos(), 0);
srs_verbose("send nack req, len=%d", nb_protected_buf);
} else {
srs_verbose("send nack failed, because of protect rtcp failed");
}
++iter;
}
rtp_pkt->rtp_payload_header = new SrsRtpOpusHeader();
rtp_pkt->rtp_payload_header->is_first_packet_of_frame = true;
rtp_pkt->rtp_payload_header->is_last_packet_of_frame = true;
rtp_audio_queue->insert(rtp_pkt);
std::vector<std::vector<SrsRtpSharedPacket*> > frames;
rtp_audio_queue->get_and_clean_collected_frames(frames);
for (size_t i = 0; i < frames.size(); ++i) {
if (! frames[i].empty()) {
srs_verbose("collect %d audio frames, seq range %u,%u",
frames.size(), frames[i].front()->rtp_header.get_sequence(), frames[i].back()->rtp_header.get_sequence());
}
for (size_t n = 0; n < frames[i].size(); ++n) {
srs_freep(frames[i][n]);
}
}
return err;
}
srs_error_t SrsRtcPublisher::on_video(SrsUdpMuxSocket* skt, SrsRtpSharedPacket* rtp_pkt)
{
srs_error_t err = srs_success;
vector<uint16_t> nack_seqs;
rtp_video_queue->nack_.get_nack_seqs(nack_seqs);
vector<uint16_t>::iterator iter = nack_seqs.begin();
while (iter != nack_seqs.end()) {
char buf[1024];
SrsBuffer stream(buf, sizeof(buf));
stream.write_1bytes(0x81);
stream.write_1bytes(kRtpFb);
stream.write_2bytes(3);
stream.write_4bytes(video_ssrc);
stream.write_4bytes(video_ssrc);
uint16_t pid = *iter;
uint16_t blp = 0;
srs_verbose("pid=%u", pid);
while (iter + 1 != nack_seqs.end() && (*(iter + 1) - pid <= 15)) {
blp |= (1 << (*(iter + 1) - pid - 1));
srs_verbose("blp=%u", *(iter+1));
++iter;
}
stream.write_2bytes(pid);
stream.write_2bytes(blp);
srs_verbose("nack dump=%s", srs_string_dumps_hex(stream.data(), stream.pos()).c_str());
char protected_buf[kRtpPacketSize];
int nb_protected_buf = stream.pos();
if (rtc_session->dtls_session->protect_rtcp(protected_buf, stream.data(), nb_protected_buf) == srs_success) {
skt->sendto(protected_buf, nb_protected_buf, 0);
//skt->sendto(stream.data(), stream.pos(), 0);
srs_verbose("send nack req, len=%d", nb_protected_buf);
} else {
srs_verbose("send nack failed, because of protect rtcp failed");
}
++iter;
}
rtp_pkt->rtp_payload_header = new SrsRtpH264Header();
if ((err = rtp_h264_demuxer->parse(rtp_pkt)) != srs_success) {
return srs_error_wrap(err, "rtp h264 demux failed");
}
rtp_video_queue->insert(rtp_pkt);
std::vector<std::vector<SrsRtpSharedPacket*> > frames;
rtp_video_queue->get_and_clean_collected_frames(frames);
for (size_t i = 0; i < frames.size(); ++i) {
if (! frames[i].empty()) {
srs_verbose("collect %d video frames, seq range %u,%u", frames.size(), frames[i].front()->rtp_header.get_sequence(), frames[i].back()->rtp_header.get_sequence());
}
int frame_size = 5;
vector<uint32_t> nalu_len;
uint32_t len = 0;
for (size_t n = 0; n < frames[i].size(); ++n) {
SrsRtpH264Header* rtp_h264_header = dynamic_cast<SrsRtpH264Header*>(frames[i][n]->rtp_payload_header);
for (size_t j = 0; j < rtp_h264_header->nalu_offset.size(); ++j) {
if (rtp_h264_header->nalu_type != kFuA) {
uint8_t* p = reinterpret_cast<uint8_t*>(frames[i][n]->rtp_payload() + rtp_h264_header->nalu_offset[j].first);
if (((p[0] & kNalTypeMask) != SrsAvcNaluTypeAccessUnitDelimiter) &&
((p[0] & kNalTypeMask) != SrsAvcNaluTypeSEI) &&
((p[0] & kNalTypeMask) != SrsAvcNaluTypeSPS) &&
((p[0] & kNalTypeMask) != SrsAvcNaluTypePPS)) {
frame_size += rtp_h264_header->nalu_offset[j].second + 4;
nalu_len.push_back(rtp_h264_header->nalu_offset[j].second);
}
} else {
if (frames[i][n]->rtp_payload_header->is_first_packet_of_frame) {
frame_size += 5;
len += 1;
}
frame_size += rtp_h264_header->nalu_offset[j].second;
len += rtp_h264_header->nalu_offset[j].second;
if (frames[i][n]->rtp_payload_header->is_last_packet_of_frame) {
nalu_len.push_back(len);
len = 0;
}
}
}
}
uint8_t* frame = new uint8_t[frame_size];
int frame_len = 5;
bool video_header_change = false;
int64_t timestamp = 0;
bool idr = false;
size_t len_index = 0;
for (size_t n = 0; n < frames[i].size(); ++n) {
SrsRtpH264Header* rtp_h264_header = dynamic_cast<SrsRtpH264Header*>(frames[i][n]->rtp_payload_header);
for (size_t j = 0; j < rtp_h264_header->nalu_offset.size(); ++j) {
timestamp = frames[i][n]->rtp_header.get_timestamp();
uint8_t* p = reinterpret_cast<uint8_t*>(frames[i][n]->rtp_payload() + rtp_h264_header->nalu_offset[j].first);
srs_verbose("nalu_type=%u, %02X", rtp_h264_header->nalu_type, p[0]);
if (rtp_h264_header->nalu_type != kFuA) {
if ((p[0] & kNalTypeMask) == SrsAvcNaluTypeSPS) {
srs_verbose("sps");
string cur_sps = string((char*)p, rtp_h264_header->nalu_offset[j].second);
if (! cur_sps.empty() && sps != cur_sps) {
video_header_change = true;
sps = cur_sps;
}
} else if ((p[0] & kNalTypeMask) == SrsAvcNaluTypePPS) {
srs_verbose("pps");
string cur_pps = string((char*)p, rtp_h264_header->nalu_offset[j].second);
if (! cur_pps.empty() && pps != cur_pps) {
video_header_change = true;
pps = cur_pps;
}
} else if (((p[0] & kNalTypeMask) != SrsAvcNaluTypeAccessUnitDelimiter) && ((p[0] & kNalTypeMask) != SrsAvcNaluTypeSEI)) {
uint32_t len = nalu_len[len_index++];
srs_verbose("nalu len=%u", len);
SrsBuffer stream((char*)frame + frame_len, 4);
stream.write_4bytes(len);
frame_len += 4;
memcpy(frame + frame_len, p, rtp_h264_header->nalu_offset[j].second);
frame_len += rtp_h264_header->nalu_offset[j].second;
}
} else {
if (frames[i][n]->rtp_payload_header->is_first_packet_of_frame) {
uint32_t len = nalu_len[len_index++];
srs_verbose("nalu len=%u", len);
SrsBuffer stream((char*)frame + frame_len, 4);
stream.write_4bytes(len);
frame_len += 4;
frame[frame_len++] = rtp_h264_header->nalu_header;
if ((rtp_h264_header->nalu_header & kNalTypeMask) == SrsAvcNaluTypeIDR) {
srs_verbose("idr");
idr = true;
}
}
memcpy(frame + frame_len, frames[i][n]->rtp_payload() + rtp_h264_header->nalu_offset[j].first,
rtp_h264_header->nalu_offset[j].second);
frame_len += rtp_h264_header->nalu_offset[j].second;
}
}
srs_freep(frames[i][n]);
}
if (video_header_change) {
srs_verbose("sps/pps change or init");
if (source == NULL) {
// TODO: FIXME: Should refactor it, directly use http server as handler.
ISrsSourceHandler* handler = _srs_hybrid->srs()->instance();
if ((err = _srs_sources->fetch_or_create(&request, handler, &source)) != srs_success) {
return srs_error_wrap(err, "create source");
}
source->on_publish();
}
uint8_t* video_header = new uint8_t[1500];
SrsBuffer *stream = new SrsBuffer((char*)video_header, 1500);
SrsAutoFree(SrsBuffer, stream);
stream->write_1bytes(0x17);
stream->write_1bytes(0x00);
stream->write_1bytes(0x00);
stream->write_1bytes(0x00);
stream->write_1bytes(0x00);
// NAL SIZE 61 76 63 43 01 42 C0 1E FF E1 SPS_LEN SPS 01 PPS_LEN PPS
stream->write_1bytes(0x01);
stream->write_1bytes(0x42);
stream->write_1bytes(0xC0);
stream->write_1bytes(0x1E);
stream->write_1bytes(0xFF);
stream->write_1bytes(0xE1);
stream->write_2bytes(sps.size());
stream->write_string(sps);
stream->write_1bytes(0x01);
stream->write_2bytes(pps.size());
stream->write_string(pps);
SrsMessageHeader header;
header.message_type = 9;
header.timestamp = timestamp / 90;
SrsCommonMessage* shared_video = new SrsCommonMessage();
SrsAutoFree(SrsCommonMessage, shared_video);
shared_video->create(&header, reinterpret_cast<char*>(video_header), stream->pos());
srs_error_t e = source->on_video(shared_video);
if (e != srs_success) {
srs_warn("on video header err=%s", srs_error_desc(e).c_str());
}
srs_verbose("rtp on video header");
}
if (! sps.empty() && ! pps.empty()) {
if (source == NULL) {
// TODO: FIXME: Should refactor it, directly use http server as handler.
ISrsSourceHandler* handler = _srs_hybrid->srs()->instance();
if ((err = _srs_sources->fetch_or_create(&request, handler, &source)) != srs_success) {
return srs_error_wrap(err, "create source");
}
source->on_publish();
}
if (idr) {
frame[0] = 0x17;
} else {
frame[0] = 0x27;
}
frame[1] = 0x01;
frame[2] = 0x00;
frame[3] = 0x00;
frame[4] = 0x00;
SrsMessageHeader header;
header.message_type = 9;
header.timestamp = timestamp / 90;
SrsCommonMessage* shared_video = new SrsCommonMessage();
SrsAutoFree(SrsCommonMessage, shared_video);
shared_video->create(&header, reinterpret_cast<char*>(frame), frame_len);
srs_error_t e = source->on_video(shared_video);
if (e != srs_success) {
srs_warn("on video err=%s", srs_error_desc(e).c_str());
}
srs_verbose("rtp on video");
}
}
return err;
}
SrsRtcSession::SrsRtcSession(SrsRtcServer* rtc_svr, const SrsRequest& req, const std::string& un, int context_id)
{
rtc_server = rtc_svr;
@ -1435,6 +1824,8 @@ SrsRtcSession::SrsRtcSession(SrsRtcServer* rtc_svr, const SrsRequest& req, const
// TODO: FIXME: Support reload.
sessionStunTimeout = _srs_config->get_rtc_stun_timeout(req.vhost);
rtc_publisher = new SrsRtcPublisher(this);
}
SrsRtcSession::~SrsRtcSession()
@ -1686,6 +2077,263 @@ srs_error_t SrsRtcSession::on_rtcp_ps_feedback(char* buf, int nb_buf, SrsUdpMuxS
return err;
}
srs_error_t SrsRtcSession::on_rtcp_xr(char* buf, int nb_buf, SrsUdpMuxSocket* skt)
{
srs_error_t err = srs_success;
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|reserved | PT=XR=207 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: report blocks :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
SrsBuffer stream(buf, nb_buf);
uint8_t first = stream.read_1bytes();
uint8_t pt = stream.read_1bytes();
uint16_t length = (stream.read_2bytes() + 1) * 4;
uint32_t ssrc = stream.read_4bytes();
if (length != nb_buf) {
return srs_error_new(ERROR_RTC_RTCP_CHECK, "invalid XR packet, length=%u, nb_buf=%d", length, nb_buf);
}
while (stream.pos() + 4 < length) {
uint8_t bt = stream.read_1bytes();
stream.skip(1);
uint16_t block_length = (stream.read_2bytes() + 1) * 4;
srs_verbose("XR, bt=%u", bt);
if (stream.pos() + block_length - 4 > nb_buf) {
return srs_error_new(ERROR_RTC_RTCP_CHECK, "invalid XR packet block, block_length=%u, nb_buf=%d", block_length, nb_buf);
}
if (bt == 5) {
for (int i = 4; i < block_length; i += 12) {
uint32_t ssrc = stream.read_4bytes();
uint32_t lrr = stream.read_4bytes();
uint32_t dlrr = stream.read_4bytes();
SrsNtp cur_ntp = SrsNtp::from_time_ms(srs_update_system_time()/1000);
uint32_t compact_ntp = (cur_ntp.ntp_second_ << 16) | (cur_ntp.ntp_fractions_ >> 16);
int rtt_ntp = compact_ntp - lrr - dlrr;
int rtt = ((rtt_ntp * 1000) >> 16) + ((rtt_ntp >> 16) * 1000);
/*
lsr = (srs_ntp.ntp_second_ << 16) | (srs_ntp.ntp_fractions_ >> 16);
uint32_t dlsr = (srs_update_system_time() - ssrc_lsr[ssrc_of_sender]) / 1000;
rr_dlsr = ((dlsr / 1000) << 16) | ((dlsr % 1000) * 65536 / 1000);
*/
srs_verbose("ssrc=%u, compact_ntp=%u, lrr=%u, dlrr=%u, rtt=%d",
ssrc, compact_ntp, lrr, dlrr, rtt);
if (ssrc == rtc_publisher->video_ssrc) {
rtc_publisher->rtp_video_queue->update_rtt(rtt);
} else if (ssrc == rtc_publisher->audio_ssrc) {
rtc_publisher->rtp_audio_queue->update_rtt(rtt);
}
}
}
}
return err;
}
srs_error_t SrsRtcSession::on_rtcp_sender_report(char* buf, int nb_buf, SrsUdpMuxSocket* skt)
{
srs_error_t err = srs_success;
if (nb_buf < 28) {
return srs_error_new(ERROR_RTC_RTCP_CHECK, "invalid rtp sender report packet, nb_buf=%d", nb_buf);
}
SrsBuffer* stream = new SrsBuffer(buf, nb_buf);
SrsAutoFree(SrsBuffer, stream);
srs_verbose("SS=%s", srs_string_dumps_hex(buf, nb_buf).c_str());
// @see: https://tools.ietf.org/html/rfc3550#section-6.4.1
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
header |V=2|P| RC | PT=SR=200 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC of sender |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
sender | NTP timestamp, most significant word |
info +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NTP timestamp, least significant word |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| RTP timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| sender's packet count |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| sender's octet count |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
report | SSRC_1 (SSRC of first source) |
block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1 | fraction lost | cumulative number of packets lost |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| extended highest sequence number received |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| interarrival jitter |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| last SR (LSR) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| delay since last SR (DLSR) |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
report | SSRC_2 (SSRC of second source) |
block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2 : ... :
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| profile-specific extensions |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
uint8_t first = stream->read_1bytes();
//uint8_t version = first & 0xC0;
//uint8_t padding = first & 0x20;
uint8_t rc = first & 0x1F;
/*uint8_t payload_type = */stream->read_1bytes();
uint16_t length = stream->read_2bytes();
if (((length + 1) * 4) != (rc * 24 + 28)) {
return srs_error_new(ERROR_RTC_RTCP_CHECK, "invalid rtcp sender report packet, length=%u, rc=%u", length, rc);
}
uint32_t ssrc_of_sender = stream->read_4bytes();
uint64_t ntp = stream->read_8bytes();
SrsNtp srs_ntp = SrsNtp::to_time_ms(ntp);
uint32_t rtp_time = stream->read_4bytes();
uint32_t sender_packet_count = stream->read_4bytes();
uint32_t sender_octec_count = stream->read_4bytes();
SrsNtp cur_ntp = SrsNtp::from_time_ms(srs_update_system_time()/1000);
srs_verbose("sender report, ssrc_of_sender=%u, ntp={%lu,%lu}, cur_ntp={%lu,%lu},rtp_time=%u, sender_packet_count=%u, sender_octec_count=%u",
ssrc_of_sender, srs_ntp.ntp_, srs_ntp.system_ms_, cur_ntp.ntp_, cur_ntp.system_ms_, rtp_time, sender_packet_count, sender_octec_count);
for (int i = 0; i < rc; ++i) {
uint32_t ssrc = stream->read_4bytes();
uint8_t fraction_lost = stream->read_1bytes();
uint32_t cumulative_number_of_packets_lost = stream->read_3bytes();
uint32_t highest_seq = stream->read_4bytes();
uint32_t jitter = stream->read_4bytes();
uint32_t lst = stream->read_4bytes();
uint32_t dlsr = stream->read_4bytes();
(void)ssrc; (void)fraction_lost; (void)cumulative_number_of_packets_lost; (void)highest_seq; (void)jitter; (void)lst; (void)dlsr;
srs_verbose("sender report, ssrc=%u, fraction_lost=%u, cumulative_number_of_packets_lost=%u, highest_seq=%u, jitter=%u, lst=%u, dlst=%u",
ssrc, fraction_lost, cumulative_number_of_packets_lost, highest_seq, jitter, lst, dlsr);
}
static map<uint32_t, uint64_t> ssrc_lsr;
// Response RR
{
char buf[1024];
SrsBuffer stream(buf, sizeof(buf));
stream.write_1bytes(0x81);
stream.write_1bytes(kRR);
stream.write_2bytes(7);
stream.write_4bytes(ssrc_of_sender);
SrsRtpQueue* rtp_queue = NULL;
string type = "unknown";
if (ssrc_of_sender == rtc_publisher->video_ssrc) {
rtp_queue = rtc_publisher->rtp_video_queue;
type = "video";
} else if (ssrc_of_sender == rtc_publisher->audio_ssrc) {
rtp_queue = rtc_publisher->rtp_audio_queue;
type = "audio";
}
uint8_t fraction_lost = rtp_queue->get_fraction_lost();
uint32_t cumulative_number_of_packets_lost = rtp_queue->get_cumulative_number_of_packets_lost() & 0x7FFFFF;
uint32_t extended_highest_sequence = rtp_queue->get_extended_highest_sequence();
uint32_t interarrival_jitter = rtp_queue->get_interarrival_jitter();
uint32_t lsr = 0;
uint32_t rr_dlsr = 0;
if (ssrc_lsr[ssrc_of_sender] > 0) {
lsr = (srs_ntp.ntp_second_ << 16) | (srs_ntp.ntp_fractions_ >> 16);
uint32_t dlsr = (srs_update_system_time() - ssrc_lsr[ssrc_of_sender]) / 1000;
rr_dlsr = ((dlsr / 1000) << 16) | ((dlsr % 1000) * 65536 / 1000);
}
stream.write_4bytes(ssrc_of_sender);
stream.write_1bytes(fraction_lost);
stream.write_3bytes(cumulative_number_of_packets_lost);
stream.write_4bytes(extended_highest_sequence);
stream.write_4bytes(interarrival_jitter);
stream.write_4bytes(lsr);
stream.write_4bytes(rr_dlsr);
srs_verbose("RR type=%s, ssrc=%u, fraction_lost=%u, cumulative_number_of_packets_lost=%u, extended_highest_sequence=%u, interarrival_jitter=%u",
type.c_str(), ssrc_of_sender, fraction_lost, cumulative_number_of_packets_lost, extended_highest_sequence, interarrival_jitter);
char protected_buf[kRtpPacketSize];
int nb_protected_buf = stream.pos();
if (dtls_session->protect_rtcp(protected_buf, stream.data(), nb_protected_buf) == srs_success) {
skt->sendto(protected_buf, nb_protected_buf, 0);
}
// XR
{
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|reserved | PT=XR=207 | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SSRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
: report blocks :
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| BT=4 | reserved | block length = 2 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NTP timestamp, most significant word |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NTP timestamp, least significant word |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
char buf[1024];
SrsBuffer stream(buf, sizeof(buf));
stream.write_1bytes(0x80);
stream.write_1bytes(kXR);
stream.write_2bytes(4);
stream.write_4bytes(ssrc_of_sender);
stream.write_1bytes(4);
stream.write_1bytes(0);
stream.write_2bytes(2);
stream.write_4bytes(cur_ntp.ntp_second_);
stream.write_4bytes(cur_ntp.ntp_fractions_);
ssrc_lxr[ssrc_of_sender] = srs_ntp.system_ms_;
//skt->sendto(stream.data(), stream.pos(), 0);
char protected_buf[kRtpPacketSize];
int nb_protected_buf = stream.pos();
if (dtls_session->protect_rtcp(protected_buf, stream.data(), nb_protected_buf) == srs_success) {
skt->sendto(protected_buf, nb_protected_buf, 0);
}
}
}
ssrc_lsr[ssrc_of_sender] = srs_update_system_time();
return err;
}
srs_error_t SrsRtcSession::on_rtcp_receiver_report(char* buf, int nb_buf, SrsUdpMuxSocket* skt)
{
srs_error_t err = srs_success;
@ -1757,6 +2405,31 @@ block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
srs_error_t SrsRtcSession::on_connection_established(SrsUdpMuxSocket* skt)
{
// FIXME:
if (true)
{
uint32_t video_ssrc = 0;
uint32_t audio_ssrc = 0;
uint16_t video_payload_type = 0;
uint16_t audio_payload_type = 0;
for (size_t i = 0; i < remote_sdp.media_descs_.size(); ++i) {
const SrsMediaDesc& media_desc = remote_sdp.media_descs_[i];
if (media_desc.is_audio()) {
if (! media_desc.ssrc_infos_.empty()) {
audio_ssrc = media_desc.ssrc_infos_[0].ssrc_;
audio_payload_type = media_desc.payload_types_[0].payload_type_;
}
} else if (media_desc.is_video()) {
if (! media_desc.ssrc_infos_.empty()) {
video_ssrc = media_desc.ssrc_infos_[0].ssrc_;
video_payload_type = media_desc.payload_types_[0].payload_type_;
}
}
}
rtc_publisher->initialize(video_ssrc, audio_ssrc, request);
}
srs_trace("rtc session=%s, to=%dms connection established", id().c_str(), srsu2msi(sessionStunTimeout));
return start_play(skt);
}
@ -1834,6 +2507,7 @@ srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* skt)
switch (payload_type) {
case kSR: {
err = on_rtcp_sender_report(ph, length, skt);
break;
}
case kRR: {
@ -1856,6 +2530,10 @@ srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* skt)
case kPsFb: {
err = on_rtcp_ps_feedback(ph, length, skt);
break;
}
case kXR: {
err = on_rtcp_xr(ph, length, skt);
break;
}
default:{
return srs_error_new(ERROR_RTC_RTCP_CHECK, "unknown rtcp type=%u", payload_type);
@ -1874,6 +2552,23 @@ srs_error_t SrsRtcSession::on_rtcp(SrsUdpMuxSocket* skt)
return err;
}
srs_error_t SrsRtcSession::on_rtp(SrsUdpMuxSocket* skt)
{
srs_error_t err = srs_success;
if (dtls_session == NULL) {
return srs_error_new(ERROR_RTC_RTCP, "recv unexpect rtp packet before dtls done");
}
char* unprotected_buf = new char[1460];
int nb_unprotected_buf = skt->size();
if ((err = dtls_session->unprotect_rtp(unprotected_buf, skt->data(), nb_unprotected_buf)) != srs_success) {
return srs_error_wrap(err, "rtp unprotect failed");
}
return rtc_publisher->on_rtp(skt, unprotected_buf, nb_unprotected_buf);
}
SrsUdpMuxSender::SrsUdpMuxSender(SrsRtcServer* s)
{
lfd = NULL;
@ -2256,7 +2951,11 @@ srs_error_t SrsRtcServer::listen_api()
// TODO: FIXME: Fetch api from hybrid manager.
SrsHttpServeMux* http_api_mux = _srs_hybrid->srs()->instance()->api_server();
if ((err = http_api_mux->handle("/rtc/v1/play/", new SrsGoApiRtcPlay(this))) != srs_success) {
return srs_error_wrap(err, "handle sdp");
return srs_error_wrap(err, "handle play");
}
if ((err = http_api_mux->handle("/rtc/v1/publish/", new SrsGoApiRtcPublish(this))) != srs_success) {
return srs_error_wrap(err, "handle publish");
}
return err;
@ -2369,9 +3068,7 @@ srs_error_t SrsRtcServer::on_rtp_or_rtcp(SrsUdpMuxSocket* skt)
if (is_rtcp(reinterpret_cast<const uint8_t*>(skt->data()), skt->size())) {
err = rtc_session->on_rtcp(skt);
} else {
// We disable it because no RTP for player.
// see https://github.com/ossrs/srs/blob/018577e685a07d9de7a47354e7a9c5f77f5f4202/trunk/src/app/srs_app_rtc_conn.cpp#L1081
// err = rtc_session->on_rtp(skt);
err = rtc_session->on_rtp(skt);
}
return err;