mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Merge branch 'feature/rtc' into develop
This commit is contained in:
commit
c62479b112
36 changed files with 1583 additions and 1091 deletions
|
@ -127,7 +127,7 @@ public:
|
|||
bool require(int required_size);
|
||||
public:
|
||||
// Skip some size.
|
||||
// @param size can be any value. positive to forward; nagetive to backward.
|
||||
// @param size can be any value. positive to forward; negative to backward.
|
||||
// @remark to skip(pos()) to reset buffer.
|
||||
// @remark assert initialized, the data() not NULL.
|
||||
void skip(int size);
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
|
||||
#include <srs_kernel_log.hpp>
|
||||
|
||||
#include <srs_kernel_error.hpp>
|
||||
|
||||
ISrsLog::ISrsLog()
|
||||
{
|
||||
}
|
||||
|
@ -33,56 +31,12 @@ ISrsLog::~ISrsLog()
|
|||
{
|
||||
}
|
||||
|
||||
srs_error_t ISrsLog::initialize()
|
||||
{
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
void ISrsLog::reopen()
|
||||
ISrsContext::ISrsContext()
|
||||
{
|
||||
}
|
||||
|
||||
void ISrsLog::verbose(const char* /*tag*/, const char* /*context_id*/, const char* /*fmt*/, ...)
|
||||
ISrsContext::~ISrsContext()
|
||||
{
|
||||
}
|
||||
|
||||
void ISrsLog::info(const char* /*tag*/, const char* /*context_id*/, const char* /*fmt*/, ...)
|
||||
{
|
||||
}
|
||||
|
||||
void ISrsLog::trace(const char* /*tag*/, const char* /*context_id*/, const char* /*fmt*/, ...)
|
||||
{
|
||||
}
|
||||
|
||||
void ISrsLog::warn(const char* /*tag*/, const char* /*context_id*/, const char* /*fmt*/, ...)
|
||||
{
|
||||
}
|
||||
|
||||
void ISrsLog::error(const char* /*tag*/, const char* /*context_id*/, const char* /*fmt*/, ...)
|
||||
{
|
||||
}
|
||||
|
||||
ISrsThreadContext::ISrsThreadContext()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsThreadContext::~ISrsThreadContext()
|
||||
{
|
||||
}
|
||||
|
||||
std::string ISrsThreadContext::generate_id()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string ISrsThreadContext::get_id()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string ISrsThreadContext::set_id(std::string /*v*/)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -60,49 +60,49 @@ public:
|
|||
virtual ~ISrsLog();
|
||||
public:
|
||||
// Initialize log utilities.
|
||||
virtual srs_error_t initialize();
|
||||
virtual srs_error_t initialize() = 0;
|
||||
// Reopen the log file for log rotate.
|
||||
virtual void reopen();
|
||||
virtual void reopen() = 0;
|
||||
public:
|
||||
// The log for verbose, very verbose information.
|
||||
virtual void verbose(const char* tag, const char* context_id, const char* fmt, ...);
|
||||
virtual void verbose(const char* tag, const char* context_id, const char* fmt, ...) = 0;
|
||||
// The log for debug, detail information.
|
||||
virtual void info(const char* tag, const char* context_id, const char* fmt, ...);
|
||||
virtual void info(const char* tag, const char* context_id, const char* fmt, ...) = 0;
|
||||
// The log for trace, important information.
|
||||
virtual void trace(const char* tag, const char* context_id, const char* fmt, ...);
|
||||
virtual void trace(const char* tag, const char* context_id, const char* fmt, ...) = 0;
|
||||
// The log for warn, warn is something should take attention, but not a error.
|
||||
virtual void warn(const char* tag, const char* context_id, const char* fmt, ...);
|
||||
virtual void warn(const char* tag, const char* context_id, const char* fmt, ...) = 0;
|
||||
// The log for error, something error occur, do something about the error, ie. close the connection,
|
||||
// but we will donot abort the program.
|
||||
virtual void error(const char* tag, const char* context_id, const char* fmt, ...);
|
||||
virtual void error(const char* tag, const char* context_id, const char* fmt, ...) = 0;
|
||||
};
|
||||
|
||||
// The context id manager to identify context, for instance, the green-thread.
|
||||
// Usage:
|
||||
// _srs_context->generate_id(); // when thread start.
|
||||
// _srs_context->get_id(); // get current generated id.
|
||||
// int old_id = _srs_context->set_id(1000); // set context id if need to merge thread context.
|
||||
// The context for multiple clients.
|
||||
class ISrsThreadContext
|
||||
// The logic context for a RTMP connection, or RTC Session.
|
||||
// We can grep the context id to identify the logic unit, for debugging.
|
||||
// For example:
|
||||
// _srs_context->generate_id(); // Generate a new context.
|
||||
// _srs_context->get_id(); // Get current context.
|
||||
// int old_id = _srs_context->set_id("1000"); // Change the context.
|
||||
class ISrsContext
|
||||
{
|
||||
public:
|
||||
ISrsThreadContext();
|
||||
virtual ~ISrsThreadContext();
|
||||
ISrsContext();
|
||||
virtual ~ISrsContext();
|
||||
public:
|
||||
// Generate the id for current context.
|
||||
virtual std::string generate_id();
|
||||
virtual std::string generate_id() = 0;
|
||||
// Get the generated id of current context.
|
||||
virtual std::string get_id();
|
||||
virtual std::string get_id() = 0;
|
||||
// Set the id of current context.
|
||||
// @return the previous id value; 0 if no context.
|
||||
virtual std::string set_id(std::string v);
|
||||
virtual std::string set_id(std::string v) = 0;
|
||||
};
|
||||
|
||||
// @global User must provides a log object
|
||||
extern ISrsLog* _srs_log;
|
||||
|
||||
// @global User must implements the LogContext and define a global instance.
|
||||
extern ISrsThreadContext* _srs_context;
|
||||
extern ISrsContext* _srs_context;
|
||||
|
||||
// Log style.
|
||||
// Use __FUNCTION__ to print c method
|
||||
|
|
|
@ -682,15 +682,15 @@ srs_error_t SrsRtcpTWCC::encode_chunk_two_bit(SrsRtcpTWCC::SrsRtcpTWCCChunk& chu
|
|||
pkt_len += sizeof(encoded_chunk);
|
||||
|
||||
if (shift) {
|
||||
chunk.size -= size;
|
||||
chunk.all_same = true;
|
||||
chunk.has_large_delta = false;
|
||||
for (i = size; i < chunk.size; ++i) {
|
||||
delta_size = chunk.delta_sizes[i];
|
||||
chunk.delta_sizes[i - size] = delta_size;
|
||||
for (i = 0; i < chunk.size; ++i) {
|
||||
delta_size = chunk.delta_sizes[i + size];
|
||||
chunk.delta_sizes[i] = delta_size;
|
||||
chunk.all_same = (chunk.all_same && delta_size == chunk.delta_sizes[0]);
|
||||
chunk.has_large_delta = chunk.has_large_delta || delta_size == kTwccFbLargeRecvDeltaBytes;
|
||||
}
|
||||
chunk.size -= size;
|
||||
}
|
||||
|
||||
return srs_success;
|
||||
|
@ -773,6 +773,17 @@ srs_error_t SrsRtcpTWCC::encode(SrsBuffer *buffer)
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
err = do_encode(buffer);
|
||||
|
||||
clear();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtcpTWCC::do_encode(SrsBuffer *buffer)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if(!buffer->require(nb_bytes())) {
|
||||
return srs_error_new(ERROR_RTC_RTCP, "requires %d bytes", nb_bytes());
|
||||
}
|
||||
|
@ -787,85 +798,79 @@ srs_error_t SrsRtcpTWCC::encode(SrsBuffer *buffer)
|
|||
uint16_t last_sn = base_sn_;
|
||||
packet_count_ = recv_packes_.size();
|
||||
|
||||
do {
|
||||
// encode chunk
|
||||
SrsRtcpTWCC::SrsRtcpTWCCChunk chunk;
|
||||
for(; it_sn != recv_sns_.end(); ++it_sn) {
|
||||
uint16_t current_sn = *it_sn;
|
||||
// calculate delta
|
||||
it_ts = recv_packes_.find(current_sn);
|
||||
srs_utime_t delta_us = calculate_delta_us(it_ts->second, last_ts);
|
||||
uint16_t delta = delta_us;
|
||||
if(delta != delta_us) {
|
||||
return srs_error_new(ERROR_RTC_RTCP, "twcc: delta:%lld, exceeds the 16-bit base receive delta", delta_us);
|
||||
}
|
||||
|
||||
if(current_sn > (last_sn + 1)) {
|
||||
// lost packet
|
||||
for(uint16_t lost_sn = last_sn + 1; lost_sn < current_sn; ++lost_sn) {
|
||||
process_pkt_chunk(chunk, 0);
|
||||
packet_count_++;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME 24-bit base receive delta not supported
|
||||
int recv_delta_size = (delta >= 0 && delta <= 0xff) ? 1 : 2;
|
||||
if ((err = process_pkt_chunk(chunk, recv_delta_size)) != srs_success) {
|
||||
return srs_error_new(ERROR_RTC_RTCP, "delta_size %d, failed to append_recv_delta", recv_delta_size);
|
||||
}
|
||||
|
||||
pkt_deltas_.push_back(delta);
|
||||
last_ts += delta * kTwccFbDeltaUnit;
|
||||
pkt_len += recv_delta_size;
|
||||
last_sn = current_sn;
|
||||
// encode chunk
|
||||
SrsRtcpTWCC::SrsRtcpTWCCChunk chunk;
|
||||
for(; it_sn != recv_sns_.end(); ++it_sn) {
|
||||
uint16_t current_sn = *it_sn;
|
||||
// calculate delta
|
||||
it_ts = recv_packes_.find(current_sn);
|
||||
srs_utime_t delta_us = calculate_delta_us(it_ts->second, last_ts);
|
||||
int16_t delta = delta_us;
|
||||
if(delta != delta_us) {
|
||||
return srs_error_new(ERROR_RTC_RTCP, "twcc: delta:%" PRId64 ", exceeds the 16bits", delta_us);
|
||||
}
|
||||
|
||||
if(0 < chunk.size) {
|
||||
if((err = encode_remaining_chunk(chunk)) != srs_success) {
|
||||
return srs_error_wrap(err, "encode chunk");
|
||||
if(current_sn > (last_sn + 1)) {
|
||||
// lost packet
|
||||
for(uint16_t lost_sn = last_sn + 1; lost_sn < current_sn; ++lost_sn) {
|
||||
process_pkt_chunk(chunk, 0);
|
||||
packet_count_++;
|
||||
}
|
||||
}
|
||||
|
||||
// encode rtcp twcc packet
|
||||
if((pkt_len % 4) == 0) {
|
||||
header_.length = pkt_len / 4;
|
||||
// FIXME 24-bit base receive delta not supported
|
||||
int recv_delta_size = (delta >= 0 && delta <= 0xff) ? 1 : 2;
|
||||
if ((err = process_pkt_chunk(chunk, recv_delta_size)) != srs_success) {
|
||||
return srs_error_new(ERROR_RTC_RTCP, "delta_size %d, failed to append_recv_delta", recv_delta_size);
|
||||
}
|
||||
|
||||
pkt_deltas_.push_back(delta);
|
||||
last_ts += delta * kTwccFbDeltaUnit;
|
||||
pkt_len += recv_delta_size;
|
||||
last_sn = current_sn;
|
||||
}
|
||||
|
||||
if(0 < chunk.size) {
|
||||
if((err = encode_remaining_chunk(chunk)) != srs_success) {
|
||||
return srs_error_wrap(err, "encode chunk");
|
||||
}
|
||||
}
|
||||
|
||||
// encode rtcp twcc packet
|
||||
if((pkt_len % 4) == 0) {
|
||||
header_.length = pkt_len / 4;
|
||||
} else {
|
||||
header_.length = (pkt_len + 4 - (pkt_len%4)) / 4;
|
||||
}
|
||||
header_.length -= 1;
|
||||
|
||||
if(srs_success != (err = encode_header(buffer))) {
|
||||
return srs_error_wrap(err, "encode header");
|
||||
}
|
||||
buffer->write_4bytes(sender_ssrc_);
|
||||
buffer->write_4bytes(media_ssrc_);
|
||||
buffer->write_2bytes(base_sn_);
|
||||
buffer->write_2bytes(packet_count_);
|
||||
buffer->write_3bytes(reference_time_);
|
||||
buffer->write_1bytes(fb_pkt_count_);
|
||||
|
||||
for(vector<uint16_t>::iterator it = encoded_chucks_.begin(); it != encoded_chucks_.end(); ++it) {
|
||||
buffer->write_2bytes(*it);
|
||||
}
|
||||
for(vector<uint16_t>::iterator it = pkt_deltas_.begin(); it != pkt_deltas_.end(); ++it) {
|
||||
if(0 <= *it && 0xFF >= *it) {
|
||||
// small delta
|
||||
uint8_t delta = *it;
|
||||
buffer->write_1bytes(delta);
|
||||
} else {
|
||||
header_.length = (pkt_len + 4 - (pkt_len%4)) / 4;
|
||||
}
|
||||
header_.length -= 1;
|
||||
|
||||
if(srs_success != (err = encode_header(buffer))) {
|
||||
err = srs_error_wrap(err, "encode header");
|
||||
break;
|
||||
}
|
||||
buffer->write_4bytes(sender_ssrc_);
|
||||
buffer->write_4bytes(media_ssrc_);
|
||||
buffer->write_2bytes(base_sn_);
|
||||
buffer->write_2bytes(packet_count_);
|
||||
buffer->write_3bytes(reference_time_);
|
||||
buffer->write_1bytes(fb_pkt_count_);
|
||||
|
||||
for(vector<uint16_t>::iterator it = encoded_chucks_.begin(); it != encoded_chucks_.end(); ++it) {
|
||||
// large or negative delta
|
||||
buffer->write_2bytes(*it);
|
||||
}
|
||||
for(vector<uint16_t>::iterator it = pkt_deltas_.begin(); it != pkt_deltas_.end(); ++it) {
|
||||
if(0 <= *it && 0xFF >= *it) {
|
||||
// small delta
|
||||
uint8_t delta = *it;
|
||||
buffer->write_1bytes(delta);
|
||||
} else {
|
||||
// large or negative delta
|
||||
buffer->write_2bytes(*it);
|
||||
}
|
||||
}
|
||||
while((pkt_len % 4) != 0) {
|
||||
buffer->write_1bytes(0);
|
||||
pkt_len++;
|
||||
}
|
||||
|
||||
} while(0);
|
||||
|
||||
clear();
|
||||
}
|
||||
while((pkt_len % 4) != 0) {
|
||||
buffer->write_1bytes(0);
|
||||
pkt_len++;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -293,7 +293,8 @@ public:
|
|||
virtual srs_error_t decode(SrsBuffer *buffer);
|
||||
virtual int nb_bytes();
|
||||
virtual srs_error_t encode(SrsBuffer *buffer);
|
||||
|
||||
private:
|
||||
srs_error_t do_encode(SrsBuffer *buffer);
|
||||
};
|
||||
|
||||
class SrsRtcpNack : public SrsRtcpCommon
|
||||
|
|
|
@ -53,15 +53,15 @@ int32_t srs_seq_distance(uint16_t value, uint16_t pre_value)
|
|||
return srs_rtp_seq_distance(pre_value, value);
|
||||
}
|
||||
|
||||
SrsRtpHeaderExtensionMap::SrsRtpHeaderExtensionMap()
|
||||
SrsRtpExtensionTypes::SrsRtpExtensionTypes()
|
||||
{
|
||||
}
|
||||
|
||||
SrsRtpHeaderExtensionMap::~SrsRtpHeaderExtensionMap()
|
||||
SrsRtpExtensionTypes::~SrsRtpExtensionTypes()
|
||||
{
|
||||
}
|
||||
|
||||
bool SrsRtpHeaderExtensionMap::register_by_uri(int id, std::string uri)
|
||||
bool SrsRtpExtensionTypes::register_by_uri(int id, std::string uri)
|
||||
{
|
||||
for (int i = 0; i < (int)sizeof(kExtensions); ++i) {
|
||||
if (kExtensions[i].uri == uri) {
|
||||
|
@ -71,7 +71,7 @@ bool SrsRtpHeaderExtensionMap::register_by_uri(int id, std::string uri)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool SrsRtpHeaderExtensionMap::register_id(int id, SrsRtpExtensionType type, std::string uri)
|
||||
bool SrsRtpExtensionTypes::register_id(int id, SrsRtpExtensionType type, std::string uri)
|
||||
{
|
||||
if (id < 1 || id > 255) {
|
||||
return false;
|
||||
|
@ -81,7 +81,7 @@ bool SrsRtpHeaderExtensionMap::register_id(int id, SrsRtpExtensionType type, std
|
|||
return true;
|
||||
}
|
||||
|
||||
SrsRtpExtensionType SrsRtpHeaderExtensionMap::get_type(int id) const
|
||||
SrsRtpExtensionType SrsRtpExtensionTypes::get_type(int id) const
|
||||
{
|
||||
for (int type = kRtpExtensionNone + 1; type < kRtpExtensionNumberOfExtensions; ++type) {
|
||||
if (ids_[type] == id) {
|
||||
|
@ -91,85 +91,241 @@ SrsRtpExtensionType SrsRtpHeaderExtensionMap::get_type(int id) const
|
|||
return kInvalidType;
|
||||
}
|
||||
|
||||
SrsRtpHeaderExtension::SrsRtpHeaderExtension()
|
||||
|
||||
|
||||
SrsRtpExtensionTwcc::SrsRtpExtensionTwcc(): has_twcc_(false), id_(0), sn_(0)
|
||||
{
|
||||
has_transport_sequence_number = false;
|
||||
transport_sequence_number = 0;
|
||||
transport_cc_ext_id = 0;
|
||||
}
|
||||
|
||||
SrsRtpHeaderExtension::~SrsRtpHeaderExtension()
|
||||
SrsRtpExtensionTwcc::~SrsRtpExtensionTwcc()
|
||||
{
|
||||
}
|
||||
|
||||
bool SrsRtpExtensionTwcc::has_twcc_ext()
|
||||
{
|
||||
return has_twcc_;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpExtensionTwcc::decode(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// 0 1 2
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | ID | L=1 |transport wide sequence number |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
if (!buf->require(1)) {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1);
|
||||
}
|
||||
uint8_t v = buf->read_1bytes();
|
||||
|
||||
id_ = (v & 0xF0) >> 4;
|
||||
uint8_t len = (v & 0x0F);
|
||||
if(!id_ || len != 1) {
|
||||
return srs_error_new(ERROR_RTC_RTP, "invalid twcc id=%d, len=%d", id_, len);
|
||||
}
|
||||
|
||||
if (!buf->require(3)) {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 3);
|
||||
}
|
||||
sn_ = buf->read_2bytes();
|
||||
buf->read_1bytes();
|
||||
|
||||
has_twcc_ = true;
|
||||
return err;
|
||||
}
|
||||
|
||||
int SrsRtpExtensionTwcc::nb_bytes()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpExtensionTwcc::encode(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
uint8_t id_len = (id_ & 0x0F)<< 4| 0x01;
|
||||
buf->write_1bytes(id_len);
|
||||
buf->write_2bytes(sn_);
|
||||
buf->write_1bytes(0x00);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
uint8_t SrsRtpExtensionTwcc::get_id()
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
|
||||
void SrsRtpExtensionTwcc::set_id(uint8_t id)
|
||||
{
|
||||
id_ = id;
|
||||
has_twcc_ = true;
|
||||
}
|
||||
|
||||
uint16_t SrsRtpExtensionTwcc::get_sn()
|
||||
{
|
||||
return sn_;
|
||||
}
|
||||
|
||||
void SrsRtpExtensionTwcc::set_sn(uint16_t sn)
|
||||
{
|
||||
sn_ = sn;
|
||||
has_twcc_ = true;
|
||||
}
|
||||
|
||||
SrsRtpExtensions::SrsRtpExtensions() : has_ext_(false)
|
||||
{
|
||||
}
|
||||
|
||||
SrsRtpExtensions::~SrsRtpExtensions()
|
||||
{
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpExtensions::decode(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
/* @see https://tools.ietf.org/html/rfc3550#section-5.3.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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| defined by profile | length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| header extension |
|
||||
| .... |
|
||||
*/
|
||||
if (!buf->require(4)) {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires 4 bytes");
|
||||
}
|
||||
uint16_t profile_id = buf->read_2bytes();
|
||||
uint16_t extension_length = buf->read_2bytes();
|
||||
|
||||
// @see: https://tools.ietf.org/html/rfc5285#section-4.2
|
||||
if (profile_id == 0xBEDE) {
|
||||
SrsBuffer xbuf(buf->head(), extension_length * 4);
|
||||
buf->skip(extension_length * 4);
|
||||
return decode_0xbede(&xbuf);
|
||||
} else if (profile_id == 0x1000) {
|
||||
buf->skip(extension_length * 4);
|
||||
} else {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "fail to parse extension");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpExtensions::decode_0xbede(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
while (!buf->empty()) {
|
||||
// The first byte maybe padding or id+len.
|
||||
if (!buf->require(1)) {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d bytes", 1);
|
||||
}
|
||||
uint8_t v = *((uint8_t*)buf->head());
|
||||
|
||||
// Padding, ignore
|
||||
if(v == 0) {
|
||||
buf->skip(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 0
|
||||
// 0 1 2 3 4 5 6 7
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
// | ID | len |
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
// Note that 'len' is the header extension element length, which is the
|
||||
// number of bytes - 1.
|
||||
uint8_t id = (v & 0xF0) >> 4;
|
||||
uint8_t len = (v & 0x0F);
|
||||
|
||||
SrsRtpExtensionType xtype = types_.get_type(id);
|
||||
if (xtype == kRtpExtensionTransportSequenceNumber) {
|
||||
if(srs_success != (err = twcc_.decode(buf))) {
|
||||
return srs_error_wrap(err, "decode twcc extension");
|
||||
}
|
||||
has_ext_ = true;
|
||||
} else {
|
||||
buf->skip(1 + (len + 1));
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int SrsRtpExtensions::nb_bytes()
|
||||
{
|
||||
return 4 + (twcc_.has_twcc_ext() ? twcc_.nb_bytes() : 0);
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpExtensions::encode(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
buf->write_2bytes(0xBEDE);
|
||||
int len = 0;
|
||||
//TODO: When add new rtp extension, it should add the extension length into len
|
||||
if(twcc_.has_twcc_ext()) {
|
||||
len += twcc_.nb_bytes();
|
||||
}
|
||||
buf->write_2bytes(len / 4);
|
||||
|
||||
if(twcc_.has_twcc_ext()) {
|
||||
if(srs_success != (err = twcc_.encode(buf))) {
|
||||
return srs_error_wrap(err, "encode twcc extension");
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
bool SrsRtpExtensions::exists()
|
||||
{
|
||||
return has_ext_;
|
||||
}
|
||||
|
||||
void SrsRtpExtensions::set_types_(const SrsRtpExtensionTypes* types)
|
||||
{
|
||||
if(types) {
|
||||
types_ = *types;
|
||||
}
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpExtensions::get_twcc_sequence_number(uint16_t& twcc_sn)
|
||||
{
|
||||
if(twcc_.has_twcc_ext()) {
|
||||
twcc_sn = twcc_.get_sn();
|
||||
return srs_success;
|
||||
}
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "not find twcc sequence number");
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpExtensions::set_twcc_sequence_number(uint8_t id, uint16_t sn)
|
||||
{
|
||||
has_ext_ = true;
|
||||
twcc_.set_id(id);
|
||||
twcc_.set_sn(sn);
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
SrsRtpHeader::SrsRtpHeader()
|
||||
{
|
||||
padding_length = 0;
|
||||
extension = false;
|
||||
cc = 0;
|
||||
marker = false;
|
||||
payload_type = 0;
|
||||
sequence = 0;
|
||||
timestamp = 0;
|
||||
ssrc = 0;
|
||||
extension_length = 0;
|
||||
ignore_padding_ = false;
|
||||
}
|
||||
|
||||
SrsRtpHeader::~SrsRtpHeader()
|
||||
{
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpHeader::parse_extension(SrsBuffer* buf) {
|
||||
srs_error_t err = srs_success;
|
||||
uint16_t profile_id = buf->read_2bytes();
|
||||
extension_length = buf->read_2bytes();
|
||||
|
||||
// @see: https://tools.ietf.org/html/rfc5285#section-4.2
|
||||
if (profile_id == 0xBEDE) {
|
||||
uint32_t xlen = extension_length * 4;
|
||||
while (xlen > 0) {
|
||||
// parse id and len
|
||||
uint8_t id_len = buf->read_1bytes();
|
||||
xlen--;
|
||||
if(id_len == 0) {
|
||||
// padding, ignore
|
||||
continue;
|
||||
}
|
||||
// 0
|
||||
// 0 1 2 3 4 5 6 7
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
// | ID | len |
|
||||
// +-+-+-+-+-+-+-+-+
|
||||
// Note that 'len' is the header extension element length, which is the
|
||||
// number of bytes - 1.
|
||||
uint8_t id = (id_len & 0xF0) >> 4;
|
||||
uint8_t len = (id_len & 0x0F);
|
||||
|
||||
SrsRtpExtensionType xtype = extension_map_.get_type(id);
|
||||
if (xtype == kRtpExtensionTransportSequenceNumber) {
|
||||
// 0 1 2
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | ID | L=1 |transport wide sequence number |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
header_extension.has_transport_sequence_number = true;
|
||||
header_extension.transport_sequence_number = buf->read_2bytes();
|
||||
header_extension.transport_cc_ext_id = id;
|
||||
xlen -= 2;
|
||||
} else {
|
||||
buf->skip(len + 1);
|
||||
xlen -= len + 1;
|
||||
}
|
||||
}
|
||||
} else if (profile_id == 0x1000) {
|
||||
buf->skip(extension_length * 4);
|
||||
} else {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "fail to parse extension");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpHeader::decode(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
@ -178,7 +334,7 @@ srs_error_t SrsRtpHeader::decode(SrsBuffer* buf)
|
|||
return srs_error_new(ERROR_RTC_RTP_MUXER, "requires %d+ bytes", kRtpHeaderFixedSize);
|
||||
}
|
||||
|
||||
/*
|
||||
/* @see https://tools.ietf.org/html/rfc1889#section-5.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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
@ -195,7 +351,7 @@ srs_error_t SrsRtpHeader::decode(SrsBuffer* buf)
|
|||
|
||||
uint8_t first = buf->read_1bytes();
|
||||
bool padding = (first & 0x20);
|
||||
extension = (first & 0x10);
|
||||
bool extension = (first & 0x10);
|
||||
cc = (first & 0x0F);
|
||||
|
||||
uint8_t second = buf->read_1bytes();
|
||||
|
@ -216,21 +372,12 @@ srs_error_t SrsRtpHeader::decode(SrsBuffer* buf)
|
|||
}
|
||||
|
||||
if (extension) {
|
||||
/* RTP header extension, RFC 3550.
|
||||
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
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| defined by profile | length |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| header extension |
|
||||
| .... |
|
||||
*/
|
||||
if ((err = parse_extension(buf)) != srs_success) {
|
||||
if ((err = parse_extensions(buf)) != srs_success) {
|
||||
return srs_error_wrap(err, "fail to parse extension");
|
||||
}
|
||||
}
|
||||
|
||||
if (padding && !buf->empty()) {
|
||||
if (padding && !ignore_padding_ && !buf->empty()) {
|
||||
padding_length = *(reinterpret_cast<uint8_t*>(buf->data() + buf->size() - 1));
|
||||
if (!buf->require(padding_length)) {
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "padding requires %d bytes", padding_length);
|
||||
|
@ -240,6 +387,16 @@ srs_error_t SrsRtpHeader::decode(SrsBuffer* buf)
|
|||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpHeader::parse_extensions(SrsBuffer* buf) {
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if(srs_success != (err = extensions_.decode(buf))) {
|
||||
return srs_error_wrap(err, "decode rtp extension");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpHeader::encode(SrsBuffer* buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
@ -251,7 +408,7 @@ srs_error_t SrsRtpHeader::encode(SrsBuffer* buf)
|
|||
if (padding_length > 0) {
|
||||
v |= 0x20;
|
||||
}
|
||||
if (extension) {
|
||||
if (extensions_.exists()) {
|
||||
v |= 0x10;
|
||||
}
|
||||
buf->write_1bytes(v);
|
||||
|
@ -277,40 +434,42 @@ srs_error_t SrsRtpHeader::encode(SrsBuffer* buf)
|
|||
buf->write_4bytes(csrc[i]);
|
||||
}
|
||||
|
||||
if (extension) {
|
||||
buf->write_2bytes(0xBEDE);
|
||||
// TODO: FIXME: extension_length should caculate by extension length
|
||||
buf->write_2bytes(extension_length);
|
||||
|
||||
if (header_extension.has_transport_sequence_number) {
|
||||
uint8_t id_len = (header_extension.transport_cc_ext_id & 0x0F)<< 4| 0x01;
|
||||
buf->write_1bytes(id_len);
|
||||
buf->write_2bytes(header_extension.transport_sequence_number);
|
||||
buf->write_1bytes(0x00);
|
||||
if (extensions_.exists()) {
|
||||
if(srs_success != (err = extensions_.encode(buf))) {
|
||||
return srs_error_wrap(err, "encode rtp extension");
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
void SrsRtpHeader::set_extensions(const SrsRtpHeaderExtensionMap* extmap)
|
||||
void SrsRtpHeader::set_extensions(const SrsRtpExtensionTypes* extmap)
|
||||
{
|
||||
if (extmap) {
|
||||
extension_map_ = *extmap;
|
||||
extensions_.set_types_(extmap);
|
||||
}
|
||||
}
|
||||
|
||||
void SrsRtpHeader::ignore_padding(bool v)
|
||||
{
|
||||
ignore_padding_ = v;
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpHeader::get_twcc_sequence_number(uint16_t& twcc_sn)
|
||||
{
|
||||
if (header_extension.has_transport_sequence_number == true) {
|
||||
twcc_sn = header_extension.transport_sequence_number;
|
||||
return srs_success;
|
||||
if (extensions_.exists()) {
|
||||
return extensions_.get_twcc_sequence_number(twcc_sn);
|
||||
}
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "not find twcc sequence number");
|
||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "no rtp extension");
|
||||
}
|
||||
|
||||
srs_error_t SrsRtpHeader::set_twcc_sequence_number(uint8_t id, uint16_t sn)
|
||||
{
|
||||
return extensions_.set_twcc_sequence_number(id, sn);
|
||||
}
|
||||
|
||||
int SrsRtpHeader::nb_bytes()
|
||||
{
|
||||
return kRtpHeaderFixedSize + cc * 4 + (extension ? (extension_length + 1) * 4 : 0);
|
||||
return kRtpHeaderFixedSize + cc * 4 + (extensions_.exists() ? extensions_.nb_bytes() : 0);
|
||||
}
|
||||
|
||||
void SrsRtpHeader::set_marker(bool v)
|
||||
|
@ -449,9 +608,9 @@ SrsRtpPacket2* SrsRtpPacket2::copy()
|
|||
return cp;
|
||||
}
|
||||
|
||||
void SrsRtpPacket2::set_rtp_header_extensions(const SrsRtpHeaderExtensionMap* extmap)
|
||||
void SrsRtpPacket2::set_extension_types(const SrsRtpExtensionTypes* v)
|
||||
{
|
||||
return header.set_extensions(extmap);
|
||||
return header.set_extensions(v);
|
||||
}
|
||||
|
||||
int SrsRtpPacket2::nb_bytes()
|
||||
|
|
|
@ -99,7 +99,7 @@ const SrsExtensionInfo kExtensions[] = {
|
|||
{kRtpExtensionTransportSequenceNumber, std::string("http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01")}
|
||||
};
|
||||
|
||||
class SrsRtpHeaderExtensionMap
|
||||
class SrsRtpExtensionTypes
|
||||
{
|
||||
public:
|
||||
static const SrsRtpExtensionType kInvalidType = kRtpExtensionNone;
|
||||
|
@ -108,30 +108,65 @@ public:
|
|||
bool register_by_uri(int id, std::string uri);
|
||||
SrsRtpExtensionType get_type(int id) const;
|
||||
public:
|
||||
SrsRtpHeaderExtensionMap();
|
||||
virtual ~SrsRtpHeaderExtensionMap();
|
||||
SrsRtpExtensionTypes();
|
||||
virtual ~SrsRtpExtensionTypes();
|
||||
private:
|
||||
bool register_id(int id, SrsRtpExtensionType type, std::string uri);
|
||||
private:
|
||||
uint8_t ids_[kRtpExtensionNumberOfExtensions];
|
||||
};
|
||||
|
||||
class SrsRtpHeaderExtension
|
||||
class SrsRtpExtensionTwcc : public ISrsCodec
|
||||
{
|
||||
bool has_twcc_;
|
||||
uint8_t id_;
|
||||
uint16_t sn_;
|
||||
public:
|
||||
bool has_transport_sequence_number;
|
||||
uint16_t transport_sequence_number;
|
||||
uint8_t transport_cc_ext_id;
|
||||
public:
|
||||
SrsRtpHeaderExtension();
|
||||
virtual ~SrsRtpHeaderExtension();
|
||||
SrsRtpExtensionTwcc();
|
||||
virtual ~SrsRtpExtensionTwcc();
|
||||
|
||||
bool has_twcc_ext();
|
||||
uint8_t get_id();
|
||||
void set_id(uint8_t id);
|
||||
uint16_t get_sn();
|
||||
void set_sn(uint16_t sn);
|
||||
|
||||
public:
|
||||
// ISrsCodec
|
||||
virtual srs_error_t decode(SrsBuffer* buf);
|
||||
virtual srs_error_t encode(SrsBuffer* buf);
|
||||
virtual int nb_bytes();
|
||||
};
|
||||
|
||||
class SrsRtpHeader
|
||||
class SrsRtpExtensions : public ISrsCodec
|
||||
{
|
||||
private:
|
||||
bool has_ext_;
|
||||
SrsRtpExtensionTypes types_;
|
||||
SrsRtpExtensionTwcc twcc_;
|
||||
public:
|
||||
SrsRtpExtensions();
|
||||
virtual ~SrsRtpExtensions();
|
||||
|
||||
bool exists();
|
||||
void set_types_(const SrsRtpExtensionTypes* types);
|
||||
srs_error_t get_twcc_sequence_number(uint16_t& twcc_sn);
|
||||
srs_error_t set_twcc_sequence_number(uint8_t id, uint16_t sn);
|
||||
|
||||
// ISrsCodec
|
||||
public:
|
||||
virtual srs_error_t decode(SrsBuffer* buf);
|
||||
private:
|
||||
srs_error_t decode_0xbede(SrsBuffer* buf);
|
||||
public:
|
||||
virtual srs_error_t encode(SrsBuffer* buf);
|
||||
virtual int nb_bytes();
|
||||
};
|
||||
|
||||
class SrsRtpHeader : public ISrsCodec
|
||||
{
|
||||
private:
|
||||
uint8_t padding_length;
|
||||
bool extension;
|
||||
uint8_t cc;
|
||||
bool marker;
|
||||
uint8_t payload_type;
|
||||
|
@ -139,16 +174,16 @@ private:
|
|||
uint32_t timestamp;
|
||||
uint32_t ssrc;
|
||||
uint32_t csrc[15];
|
||||
uint16_t extension_length;
|
||||
SrsRtpHeaderExtensionMap extension_map_;
|
||||
SrsRtpHeaderExtension header_extension;
|
||||
SrsRtpExtensions extensions_;
|
||||
bool ignore_padding_;
|
||||
public:
|
||||
SrsRtpHeader();
|
||||
virtual ~SrsRtpHeader();
|
||||
private:
|
||||
srs_error_t parse_extension(SrsBuffer* buf);
|
||||
public:
|
||||
virtual srs_error_t decode(SrsBuffer* buf);
|
||||
private:
|
||||
srs_error_t parse_extensions(SrsBuffer* buf);
|
||||
public:
|
||||
virtual srs_error_t encode(SrsBuffer* buf);
|
||||
virtual int nb_bytes();
|
||||
public:
|
||||
|
@ -164,8 +199,10 @@ public:
|
|||
uint32_t get_ssrc() const;
|
||||
void set_padding(uint8_t v);
|
||||
uint8_t get_padding() const;
|
||||
void set_extensions(const SrsRtpHeaderExtensionMap* extmap);
|
||||
void set_extensions(const SrsRtpExtensionTypes* extmap);
|
||||
void ignore_padding(bool v);
|
||||
srs_error_t get_twcc_sequence_number(uint16_t& twcc_sn);
|
||||
srs_error_t set_twcc_sequence_number(uint8_t id, uint16_t sn);
|
||||
};
|
||||
|
||||
class ISrsRtpPayloader : public ISrsCodec
|
||||
|
@ -222,7 +259,7 @@ public:
|
|||
// Copy the RTP packet.
|
||||
SrsRtpPacket2* copy();
|
||||
// Set RTP header extensions for encoding or decoding header extension
|
||||
void set_rtp_header_extensions(const SrsRtpHeaderExtensionMap* extmap);
|
||||
void set_extension_types(const SrsRtpExtensionTypes* v);
|
||||
// interface ISrsEncoder
|
||||
public:
|
||||
virtual int nb_bytes();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue