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
8722bd2e0c
52 changed files with 1265 additions and 331 deletions
|
@ -159,6 +159,7 @@ For previous versions, please read:
|
||||||
|
|
||||||
## V4 changes
|
## V4 changes
|
||||||
|
|
||||||
|
* v4.0, 2020-08-18, RTC: DTLS support ARQ, covered with utest. 4.0.39
|
||||||
* v4.0, 2020-08-06, RTC: Refine error check. 4.0.37
|
* v4.0, 2020-08-06, RTC: Refine error check. 4.0.37
|
||||||
* v4.0, 2020-07-25, RTC: Support multiple address for client. 4.0.36
|
* v4.0, 2020-07-25, RTC: Support multiple address for client. 4.0.36
|
||||||
* v4.0, 2020-07-11, Refine log context with random string. 4.0.35
|
* v4.0, 2020-07-11, Refine log context with random string. 4.0.35
|
||||||
|
|
|
@ -178,7 +178,7 @@ Performance: @see https://blog.csdn.net/win_lin/article/details/5
|
||||||
|
|
||||||
--nasm=on|off Whether build FFMPEG for RTC with nasm support.
|
--nasm=on|off Whether build FFMPEG for RTC with nasm support.
|
||||||
--srtp-nasm=on|off Whether build SRTP with ASM(openssl-asm) support, requires RTC and openssl-1.0.*.
|
--srtp-nasm=on|off Whether build SRTP with ASM(openssl-asm) support, requires RTC and openssl-1.0.*.
|
||||||
--sendmmsg=on|off Whether enable UDP sendmmsg support. @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html
|
--sendmmsg=on|off Whether enable UDP sendmmsg support. Default: off. @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html
|
||||||
|
|
||||||
Toolchain options: @see https://github.com/ossrs/srs/issues/1547#issuecomment-576078411
|
Toolchain options: @see https://github.com/ossrs/srs/issues/1547#issuecomment-576078411
|
||||||
--static Whether add '-static' to link options.
|
--static Whether add '-static' to link options.
|
||||||
|
@ -204,9 +204,7 @@ Experts:
|
||||||
--use-shared-srt Use link shared libraries for SRT which uses MPL license.
|
--use-shared-srt Use link shared libraries for SRT which uses MPL license.
|
||||||
--build-tag=<TAG> Set the build object directory suffix.
|
--build-tag=<TAG> Set the build object directory suffix.
|
||||||
--clean=on|off Whether do 'make clean' when configure.
|
--clean=on|off Whether do 'make clean' when configure.
|
||||||
--detect-sendmmsg=on|off Whether detect the sendmmsg API.
|
--simulator=on|off Whether enable RTC network simulator. Default: off
|
||||||
--has-sendmmsg=on|off Whether OS supports sendmmsg API.
|
|
||||||
--simulator=on|off Whether enable RTC network simulator.
|
|
||||||
|
|
||||||
Workflow:
|
Workflow:
|
||||||
1. Apply "Presets". if not specified, use default preset.
|
1. Apply "Presets". if not specified, use default preset.
|
||||||
|
|
|
@ -151,7 +151,7 @@ srs_error_t SrsBandwidth::bandwidth_check(SrsRtmpServer* rtmp, ISrsProtocolStati
|
||||||
// reject the connection in the interval window.
|
// reject the connection in the interval window.
|
||||||
if (last_check_time > 0 && time_now - last_check_time < interval) {
|
if (last_check_time > 0 && time_now - last_check_time < interval) {
|
||||||
_rtmp->response_connect_reject(_req, "bandcheck rejected");
|
_rtmp->response_connect_reject(_req, "bandcheck rejected");
|
||||||
return srs_error_new(ERROR_SYSTEM_BANDWIDTH_DENIED, "reject, last_check=%" PRId64 ", now=%" PRId64 ", interval=%d", last_check_time, time_now, interval);
|
return srs_error_new(ERROR_SYSTEM_BANDWIDTH_DENIED, "reject, last_check=%" PRId64 ", now=%" PRId64 ", interval=%" PRId64 "", last_check_time, time_now, interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// accept and do bandwidth check.
|
// accept and do bandwidth check.
|
||||||
|
|
|
@ -130,7 +130,7 @@ namespace _srs_internal
|
||||||
// read total content from file.
|
// read total content from file.
|
||||||
ssize_t nread = 0;
|
ssize_t nread = 0;
|
||||||
if ((err = reader.read(start, filesize, &nread)) != srs_success) {
|
if ((err = reader.read(start, filesize, &nread)) != srs_success) {
|
||||||
return srs_error_wrap(err, "read %d only %d bytes", filesize, nread);
|
return srs_error_wrap(err, "read %d only %d bytes", filesize, (int)nread);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -620,6 +620,7 @@ srs_error_t srs_config_dumps_engine(SrsConfDirective* dir, SrsJsonObject* engine
|
||||||
|
|
||||||
SrsConfDirective::SrsConfDirective()
|
SrsConfDirective::SrsConfDirective()
|
||||||
{
|
{
|
||||||
|
conf_line = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsConfDirective::~SrsConfDirective()
|
SrsConfDirective::~SrsConfDirective()
|
||||||
|
@ -1140,6 +1141,7 @@ SrsConfig::SrsConfig()
|
||||||
show_help = false;
|
show_help = false;
|
||||||
show_version = false;
|
show_version = false;
|
||||||
test_conf = false;
|
test_conf = false;
|
||||||
|
show_signature = false;
|
||||||
|
|
||||||
root = new SrsConfDirective();
|
root = new SrsConfDirective();
|
||||||
root->conf_line = 0;
|
root->conf_line = 0;
|
||||||
|
@ -3661,7 +3663,7 @@ srs_error_t SrsConfig::check_normal_config()
|
||||||
for (int i = 0; i < (int)listens.size(); i++) {
|
for (int i = 0; i < (int)listens.size(); i++) {
|
||||||
string port = listens[i];
|
string port = listens[i];
|
||||||
if (port.empty() || ::atoi(port.c_str()) <= 0) {
|
if (port.empty() || ::atoi(port.c_str()) <= 0) {
|
||||||
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "listen.port=%d is invalid", port.c_str());
|
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "listen.port=%s is invalid", port.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -307,6 +307,7 @@ SrsDashController::SrsDashController()
|
||||||
vfragments = new SrsFragmentWindow();
|
vfragments = new SrsFragmentWindow();
|
||||||
afragments = new SrsFragmentWindow();
|
afragments = new SrsFragmentWindow();
|
||||||
audio_dts = video_dts = 0;
|
audio_dts = video_dts = 0;
|
||||||
|
fragment = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsDashController::~SrsDashController()
|
SrsDashController::~SrsDashController()
|
||||||
|
|
|
@ -48,6 +48,7 @@ SrsDvrSegmenter::SrsDvrSegmenter()
|
||||||
req = NULL;
|
req = NULL;
|
||||||
jitter = NULL;
|
jitter = NULL;
|
||||||
plan = NULL;
|
plan = NULL;
|
||||||
|
wait_keyframe = true;
|
||||||
|
|
||||||
fragment = new SrsFragment();
|
fragment = new SrsFragment();
|
||||||
fs = new SrsFileWriter();
|
fs = new SrsFileWriter();
|
||||||
|
@ -585,6 +586,7 @@ string SrsDvrAsyncCallOnDvr::to_string()
|
||||||
SrsDvrPlan::SrsDvrPlan()
|
SrsDvrPlan::SrsDvrPlan()
|
||||||
{
|
{
|
||||||
req = NULL;
|
req = NULL;
|
||||||
|
hub = NULL;
|
||||||
|
|
||||||
dvr_enabled = false;
|
dvr_enabled = false;
|
||||||
segment = NULL;
|
segment = NULL;
|
||||||
|
|
|
@ -65,6 +65,7 @@ SrsEdgeRtmpUpstream::SrsEdgeRtmpUpstream(string r)
|
||||||
{
|
{
|
||||||
redirect = r;
|
redirect = r;
|
||||||
sdk = NULL;
|
sdk = NULL;
|
||||||
|
selected_port = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsEdgeRtmpUpstream::~SrsEdgeRtmpUpstream()
|
SrsEdgeRtmpUpstream::~SrsEdgeRtmpUpstream()
|
||||||
|
@ -440,6 +441,7 @@ SrsEdgeForwarder::SrsEdgeForwarder()
|
||||||
edge = NULL;
|
edge = NULL;
|
||||||
req = NULL;
|
req = NULL;
|
||||||
send_error_code = ERROR_SUCCESS;
|
send_error_code = ERROR_SUCCESS;
|
||||||
|
source = NULL;
|
||||||
|
|
||||||
sdk = NULL;
|
sdk = NULL;
|
||||||
lb = new SrsLbRoundRobin();
|
lb = new SrsLbRoundRobin();
|
||||||
|
|
|
@ -200,6 +200,7 @@ SrsHlsMuxer::SrsHlsMuxer()
|
||||||
accept_floor_ts = 0;
|
accept_floor_ts = 0;
|
||||||
hls_ts_floor = false;
|
hls_ts_floor = false;
|
||||||
max_td = 0;
|
max_td = 0;
|
||||||
|
writer = NULL;
|
||||||
_sequence_no = 0;
|
_sequence_no = 0;
|
||||||
current = NULL;
|
current = NULL;
|
||||||
hls_keys = false;
|
hls_keys = false;
|
||||||
|
@ -214,6 +215,7 @@ SrsHlsMuxer::SrsHlsMuxer()
|
||||||
|
|
||||||
SrsHlsMuxer::~SrsHlsMuxer()
|
SrsHlsMuxer::~SrsHlsMuxer()
|
||||||
{
|
{
|
||||||
|
srs_freep(segments);
|
||||||
srs_freep(current);
|
srs_freep(current);
|
||||||
srs_freep(req);
|
srs_freep(req);
|
||||||
srs_freep(async);
|
srs_freep(async);
|
||||||
|
@ -757,6 +759,10 @@ srs_error_t SrsHlsMuxer::_refresh_m3u8(string m3u8_file)
|
||||||
|
|
||||||
// #EXT-X-MEDIA-SEQUENCE:4294967295\n
|
// #EXT-X-MEDIA-SEQUENCE:4294967295\n
|
||||||
SrsHlsSegment* first = dynamic_cast<SrsHlsSegment*>(segments->first());
|
SrsHlsSegment* first = dynamic_cast<SrsHlsSegment*>(segments->first());
|
||||||
|
if (first == NULL) {
|
||||||
|
return srs_error_new(ERROR_HLS_WRITE_FAILED, "segments cast");
|
||||||
|
}
|
||||||
|
|
||||||
ss << "#EXT-X-MEDIA-SEQUENCE:" << first->sequence_no << SRS_CONSTS_LF;
|
ss << "#EXT-X-MEDIA-SEQUENCE:" << first->sequence_no << SRS_CONSTS_LF;
|
||||||
|
|
||||||
// #EXT-X-TARGETDURATION:4294967295\n
|
// #EXT-X-TARGETDURATION:4294967295\n
|
||||||
|
|
|
@ -532,7 +532,7 @@ srs_error_t SrsHttpHooks::do_post(SrsHttpClient* hc, std::string url, std::strin
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((res_code->to_integer()) != ERROR_SUCCESS) {
|
if ((res_code->to_integer()) != ERROR_SUCCESS) {
|
||||||
return srs_error_new(ERROR_RESPONSE_CODE, "http: response object code %d %s", res_code->to_integer(), res.c_str());
|
return srs_error_new(ERROR_RESPONSE_CODE, "http: response object code %" PRId64 " %s", res_code->to_integer(), res.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -134,7 +134,7 @@ srs_error_t SrsVodStream::serve_flv_stream(ISrsHttpResponseWriter* w, ISrsHttpMe
|
||||||
|
|
||||||
// send data
|
// send data
|
||||||
if ((err = copy(w, fs, r, (int)left)) != srs_success) {
|
if ((err = copy(w, fs, r, (int)left)) != srs_success) {
|
||||||
return srs_error_wrap(err, "read flv=%s size=%d", fullpath.c_str(), left);
|
return srs_error_wrap(err, "read flv=%s size=%d", fullpath.c_str(), (int)left);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -184,7 +184,7 @@ srs_error_t SrsVodStream::serve_mp4_stream(ISrsHttpResponseWriter* w, ISrsHttpMe
|
||||||
|
|
||||||
// send data
|
// send data
|
||||||
if ((err = copy(w, fs, r, (int)left)) != srs_success) {
|
if ((err = copy(w, fs, r, (int)left)) != srs_success) {
|
||||||
return srs_error_wrap(err, "read mp4=%s size=%d", fullpath.c_str(), left);
|
return srs_error_wrap(err, "read mp4=%s size=%d", fullpath.c_str(), (int)left);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -38,6 +38,7 @@ using namespace std;
|
||||||
SrsIngesterFFMPEG::SrsIngesterFFMPEG()
|
SrsIngesterFFMPEG::SrsIngesterFFMPEG()
|
||||||
{
|
{
|
||||||
ffmpeg = NULL;
|
ffmpeg = NULL;
|
||||||
|
starttime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsIngesterFFMPEG::~SrsIngesterFFMPEG()
|
SrsIngesterFFMPEG::~SrsIngesterFFMPEG()
|
||||||
|
|
|
@ -125,6 +125,7 @@ void SrsUdpListener::set_socket_buffer()
|
||||||
int r0_sndbuf = 0;
|
int r0_sndbuf = 0;
|
||||||
if (true) {
|
if (true) {
|
||||||
socklen_t opt_len = sizeof(default_sndbuf);
|
socklen_t opt_len = sizeof(default_sndbuf);
|
||||||
|
// TODO: FIXME: check err
|
||||||
getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&default_sndbuf, &opt_len);
|
getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&default_sndbuf, &opt_len);
|
||||||
|
|
||||||
if ((r0_sndbuf = setsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&actual_sndbuf, sizeof(actual_sndbuf))) < 0) {
|
if ((r0_sndbuf = setsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&actual_sndbuf, sizeof(actual_sndbuf))) < 0) {
|
||||||
|
@ -132,6 +133,7 @@ void SrsUdpListener::set_socket_buffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
opt_len = sizeof(actual_sndbuf);
|
opt_len = sizeof(actual_sndbuf);
|
||||||
|
// TODO: FIXME: check err
|
||||||
getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&actual_sndbuf, &opt_len);
|
getsockopt(fd(), SOL_SOCKET, SO_SNDBUF, (void*)&actual_sndbuf, &opt_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,6 +144,7 @@ void SrsUdpListener::set_socket_buffer()
|
||||||
int r0_rcvbuf = 0;
|
int r0_rcvbuf = 0;
|
||||||
if (true) {
|
if (true) {
|
||||||
socklen_t opt_len = sizeof(default_rcvbuf);
|
socklen_t opt_len = sizeof(default_rcvbuf);
|
||||||
|
// TODO: FIXME: check err
|
||||||
getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&default_rcvbuf, &opt_len);
|
getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&default_rcvbuf, &opt_len);
|
||||||
|
|
||||||
if ((r0_rcvbuf = setsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&actual_rcvbuf, sizeof(actual_rcvbuf))) < 0) {
|
if ((r0_rcvbuf = setsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&actual_rcvbuf, sizeof(actual_rcvbuf))) < 0) {
|
||||||
|
@ -149,6 +152,7 @@ void SrsUdpListener::set_socket_buffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
opt_len = sizeof(actual_rcvbuf);
|
opt_len = sizeof(actual_rcvbuf);
|
||||||
|
// TODO: FIXME: check err
|
||||||
getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&actual_rcvbuf, &opt_len);
|
getsockopt(fd(), SOL_SOCKET, SO_RCVBUF, (void*)&actual_rcvbuf, &opt_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,6 +292,7 @@ SrsUdpMuxSocket::SrsUdpMuxSocket(srs_netfd_t fd)
|
||||||
lfd = fd;
|
lfd = fd;
|
||||||
|
|
||||||
fromlen = 0;
|
fromlen = 0;
|
||||||
|
peer_port = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsUdpMuxSocket::~SrsUdpMuxSocket()
|
SrsUdpMuxSocket::~SrsUdpMuxSocket()
|
||||||
|
|
|
@ -158,12 +158,14 @@ srs_error_t srs_redirect_output(string from_file, int to_fd)
|
||||||
if ((fd = ::open(from_file.c_str(), flags, mode)) < 0) {
|
if ((fd = ::open(from_file.c_str(), flags, mode)) < 0) {
|
||||||
return srs_error_new(ERROR_FORK_OPEN_LOG, "open process %d %s failed", to_fd, from_file.c_str());
|
return srs_error_new(ERROR_FORK_OPEN_LOG, "open process %d %s failed", to_fd, from_file.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dup2(fd, to_fd) < 0) {
|
int r0 = dup2(fd, to_fd);
|
||||||
return srs_error_new(ERROR_FORK_DUP2_LOG, "dup2 process %d failed", to_fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
::close(fd);
|
::close(fd);
|
||||||
|
|
||||||
|
if (r0 < 0) {
|
||||||
|
return srs_error_new(ERROR_FORK_DUP2_LOG, "dup2 fd=%d, to=%d, file=%s failed, r0=%d",
|
||||||
|
fd, to_fd, from_file.c_str(), r0);
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,7 +340,7 @@ srs_error_t SrsPublishRecvThread::error_code()
|
||||||
return srs_error_copy(recv_error);
|
return srs_error_copy(recv_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsPublishRecvThread::set_cid(std::string v)
|
void SrsPublishRecvThread::set_cid(SrsContextId v)
|
||||||
{
|
{
|
||||||
ncid = v;
|
ncid = v;
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,7 +180,7 @@ public:
|
||||||
virtual int64_t nb_msgs();
|
virtual int64_t nb_msgs();
|
||||||
virtual uint64_t nb_video_frames();
|
virtual uint64_t nb_video_frames();
|
||||||
virtual srs_error_t error_code();
|
virtual srs_error_t error_code();
|
||||||
virtual void set_cid(std::string v);
|
virtual void set_cid(SrsContextId v);
|
||||||
virtual SrsContextId get_cid();
|
virtual SrsContextId get_cid();
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t start();
|
virtual srs_error_t start();
|
||||||
|
|
|
@ -170,6 +170,7 @@ srs_error_t SrsAudioEncoder::initialize()
|
||||||
|
|
||||||
case 24000:
|
case 24000:
|
||||||
opus_encoder_ctl(opus_, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
|
opus_encoder_ctl(opus_, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
|
||||||
|
break;
|
||||||
|
|
||||||
case 16000:
|
case 16000:
|
||||||
opus_encoder_ctl(opus_, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
|
opus_encoder_ctl(opus_, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
|
||||||
|
@ -343,6 +344,10 @@ SrsAudioRecode::SrsAudioRecode(int channels, int samplerate)
|
||||||
{
|
{
|
||||||
size_ = 0;
|
size_ = 0;
|
||||||
data_ = new char[kPcmBufMax];
|
data_ = new char[kPcmBufMax];
|
||||||
|
|
||||||
|
dec_ = NULL;
|
||||||
|
enc_ = NULL;
|
||||||
|
resample_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsAudioRecode::~SrsAudioRecode()
|
SrsAudioRecode::~SrsAudioRecode()
|
||||||
|
@ -395,7 +400,7 @@ srs_error_t SrsAudioRecode::transcode(SrsSample *pkt, char **buf, int *buf_len,
|
||||||
int decode_len = kPacketBufMax;
|
int decode_len = kPacketBufMax;
|
||||||
static char decode_buffer[kPacketBufMax];
|
static char decode_buffer[kPacketBufMax];
|
||||||
if ((err = dec_->decode(pkt, decode_buffer, decode_len)) != srs_success) {
|
if ((err = dec_->decode(pkt, decode_buffer, decode_len)) != srs_success) {
|
||||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "decode error");
|
return srs_error_wrap(err, "decode error");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resample_) {
|
if (!resample_) {
|
||||||
|
@ -419,7 +424,7 @@ srs_error_t SrsAudioRecode::transcode(SrsSample *pkt, char **buf, int *buf_len,
|
||||||
int resample_len = kFrameBufMax;
|
int resample_len = kFrameBufMax;
|
||||||
static char resample_buffer[kFrameBufMax];
|
static char resample_buffer[kFrameBufMax];
|
||||||
if ((err = resample_->resample(&pcm, resample_buffer, resample_len)) != srs_success) {
|
if ((err = resample_->resample(&pcm, resample_buffer, resample_len)) != srs_success) {
|
||||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "resample error");
|
return srs_error_wrap(err, "resample error");
|
||||||
}
|
}
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
|
@ -446,7 +451,7 @@ srs_error_t SrsAudioRecode::transcode(SrsSample *pkt, char **buf, int *buf_len,
|
||||||
pcm.size = size_;
|
pcm.size = size_;
|
||||||
static char encode_buffer[kPacketBufMax];
|
static char encode_buffer[kPacketBufMax];
|
||||||
if ((err = enc_->encode(&pcm, encode_buffer, encode_len)) != srs_success) {
|
if ((err = enc_->encode(&pcm, encode_buffer, encode_len)) != srs_success) {
|
||||||
return srs_error_new(ERROR_RTC_RTP_MUXER, "encode error");
|
return srs_error_wrap(err, "encode error");
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(buf[n], encode_buffer, encode_len);
|
memcpy(buf[n], encode_buffer, encode_len);
|
||||||
|
|
|
@ -313,16 +313,17 @@ SrsRtcPlayStream::SrsRtcPlayStream(SrsRtcConnection* s, SrsContextId parent_cid)
|
||||||
|
|
||||||
_srs_config->subscribe(this);
|
_srs_config->subscribe(this);
|
||||||
timer_ = new SrsHourGlass(this, 1000 * SRS_UTIME_MILLISECONDS);
|
timer_ = new SrsHourGlass(this, 1000 * SRS_UTIME_MILLISECONDS);
|
||||||
|
|
||||||
|
nack_epp = new SrsErrorPithyPrint();
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcPlayStream::~SrsRtcPlayStream()
|
SrsRtcPlayStream::~SrsRtcPlayStream()
|
||||||
{
|
{
|
||||||
_srs_config->unsubscribe(this);
|
_srs_config->unsubscribe(this);
|
||||||
|
|
||||||
srs_freep(req_);
|
|
||||||
|
|
||||||
srs_freep(trd);
|
srs_freep(trd);
|
||||||
srs_freep(timer_);
|
srs_freep(timer_);
|
||||||
|
srs_freep(req_);
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
std::map<uint32_t, SrsRtcAudioSendTrack*>::iterator it;
|
std::map<uint32_t, SrsRtcAudioSendTrack*>::iterator it;
|
||||||
|
@ -337,6 +338,8 @@ SrsRtcPlayStream::~SrsRtcPlayStream()
|
||||||
srs_freep(it->second);
|
srs_freep(it->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
srs_freep(nack_epp);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsRtcPlayStream::initialize(SrsRequest* req, std::map<uint32_t, SrsRtcTrackDescription*> sub_relations)
|
srs_error_t SrsRtcPlayStream::initialize(SrsRequest* req, std::map<uint32_t, SrsRtcTrackDescription*> sub_relations)
|
||||||
|
@ -724,7 +727,7 @@ srs_error_t SrsRtcPlayStream::on_rtcp_nack(SrsRtcpNack* rtcp)
|
||||||
vector<SrsRtpPacket2*> resend_pkts;
|
vector<SrsRtpPacket2*> resend_pkts;
|
||||||
|
|
||||||
vector<uint16_t> sns = rtcp->get_lost_sns();
|
vector<uint16_t> sns = rtcp->get_lost_sns();
|
||||||
for(int i = 0; i < sns.size(); ++i) {
|
for(int i = 0; i < (int)sns.size(); ++i) {
|
||||||
uint16_t seq = sns.at(i);
|
uint16_t seq = sns.at(i);
|
||||||
nack_fetch(resend_pkts, rtcp->get_media_ssrc(), seq);
|
nack_fetch(resend_pkts, rtcp->get_media_ssrc(), seq);
|
||||||
}
|
}
|
||||||
|
@ -732,8 +735,12 @@ srs_error_t SrsRtcPlayStream::on_rtcp_nack(SrsRtcpNack* rtcp)
|
||||||
for (int i = 0; i < (int)resend_pkts.size(); ++i) {
|
for (int i = 0; i < (int)resend_pkts.size(); ++i) {
|
||||||
SrsRtpPacket2* pkt = resend_pkts[i];
|
SrsRtpPacket2* pkt = resend_pkts[i];
|
||||||
info.nn_bytes += pkt->nb_bytes();
|
info.nn_bytes += pkt->nb_bytes();
|
||||||
srs_trace("RTC NACK ARQ seq=%u, ssrc=%u, ts=%u, %d bytes", pkt->header.get_sequence(),
|
|
||||||
pkt->header.get_ssrc(), pkt->header.get_timestamp(), pkt->nb_bytes());
|
uint32_t nn = 0;
|
||||||
|
if (nack_epp->can_print(pkt->header.get_ssrc(), &nn)) {
|
||||||
|
srs_trace("RTC NACK ARQ seq=%u, ssrc=%u, ts=%u, count=%u/%u, %d bytes", pkt->header.get_sequence(),
|
||||||
|
pkt->header.get_ssrc(), pkt->header.get_timestamp(), nn, nack_epp->nn_count, pkt->nb_bytes());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default, we send packets by sendmmsg.
|
// By default, we send packets by sendmmsg.
|
||||||
|
@ -797,10 +804,11 @@ uint32_t SrsRtcPlayStream::get_video_publish_ssrc(uint32_t play_ssrc)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcPublishStream::SrsRtcPublishStream(SrsRtcConnection* session)
|
SrsRtcPublishStream::SrsRtcPublishStream(SrsRtcConnection* session, SrsContextId parent_cid)
|
||||||
{
|
{
|
||||||
timer_ = new SrsHourGlass(this, 200 * SRS_UTIME_MILLISECONDS);
|
timer_ = new SrsHourGlass(this, 200 * SRS_UTIME_MILLISECONDS);
|
||||||
|
|
||||||
|
parent_cid_ = parent_cid;
|
||||||
is_started = false;
|
is_started = false;
|
||||||
session_ = session;
|
session_ = session;
|
||||||
request_keyframe_ = false;
|
request_keyframe_ = false;
|
||||||
|
@ -869,6 +877,12 @@ srs_error_t SrsRtcPublishStream::initialize(SrsRequest* r, SrsRtcStreamDescripti
|
||||||
|
|
||||||
session_->stat_->nn_publishers++;
|
session_->stat_->nn_publishers++;
|
||||||
|
|
||||||
|
// Setup the publish stream in source to enable PLI as such.
|
||||||
|
if ((err = _srs_rtc_sources->fetch_or_create(req, &source)) != srs_success) {
|
||||||
|
return srs_error_wrap(err, "create source");
|
||||||
|
}
|
||||||
|
source->set_publish_stream(this);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -888,16 +902,10 @@ srs_error_t SrsRtcPublishStream::start()
|
||||||
return srs_error_wrap(err, "start timer");
|
return srs_error_wrap(err, "start timer");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = _srs_rtc_sources->fetch_or_create(req, &source)) != srs_success) {
|
|
||||||
return srs_error_wrap(err, "create source");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = source->on_publish()) != srs_success) {
|
if ((err = source->on_publish()) != srs_success) {
|
||||||
return srs_error_wrap(err, "on publish");
|
return srs_error_wrap(err, "on publish");
|
||||||
}
|
}
|
||||||
|
|
||||||
source->set_publish_stream(this);
|
|
||||||
|
|
||||||
if (_srs_rtc_hijacker) {
|
if (_srs_rtc_hijacker) {
|
||||||
if ((err = _srs_rtc_hijacker->on_start_publish(session_, this, req)) != srs_success) {
|
if ((err = _srs_rtc_hijacker->on_start_publish(session_, this, req)) != srs_success) {
|
||||||
return srs_error_wrap(err, "on start publish");
|
return srs_error_wrap(err, "on start publish");
|
||||||
|
@ -1003,7 +1011,8 @@ srs_error_t SrsRtcPublishStream::on_rtp(char* data, int nb_data)
|
||||||
|
|
||||||
// For NACK simulator, drop packet.
|
// For NACK simulator, drop packet.
|
||||||
if (nn_simulate_nack_drop) {
|
if (nn_simulate_nack_drop) {
|
||||||
SrsBuffer b(data, nb_data); SrsRtpHeader h; h.ignore_padding(true); h.decode(&b);
|
SrsBuffer b(data, nb_data); SrsRtpHeader h; h.ignore_padding(true);
|
||||||
|
err = h.decode(&b); srs_freep(err); // Ignore any error for simluate drop.
|
||||||
simulate_drop_packet(&h, nb_data);
|
simulate_drop_packet(&h, nb_data);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -1043,7 +1052,8 @@ srs_error_t SrsRtcPublishStream::on_rtp(char* data, int nb_data)
|
||||||
char* unprotected_buf = new char[kRtpPacketSize];
|
char* unprotected_buf = new char[kRtpPacketSize];
|
||||||
if ((err = session_->transport_->unprotect_rtp(data, unprotected_buf, nb_unprotected_buf)) != srs_success) {
|
if ((err = session_->transport_->unprotect_rtp(data, unprotected_buf, nb_unprotected_buf)) != srs_success) {
|
||||||
// We try to decode the RTP header for more detail error informations.
|
// We try to decode the RTP header for more detail error informations.
|
||||||
SrsBuffer b(data, nb_data); SrsRtpHeader h; h.ignore_padding(true); h.decode(&b);
|
SrsBuffer b(data, nb_data); SrsRtpHeader h; h.ignore_padding(true);
|
||||||
|
srs_error_t r0 = h.decode(&b); srs_freep(r0); // Ignore any error for header decoding.
|
||||||
err = srs_error_wrap(err, "marker=%u, pt=%u, seq=%u, ts=%u, ssrc=%u, pad=%u, payload=%uB", h.get_marker(), h.get_payload_type(),
|
err = srs_error_wrap(err, "marker=%u, pt=%u, seq=%u, ts=%u, ssrc=%u, pad=%u, payload=%uB", h.get_marker(), h.get_payload_type(),
|
||||||
h.get_sequence(), h.get_timestamp(), h.get_ssrc(), h.get_padding(), nb_data - b.pos());
|
h.get_sequence(), h.get_timestamp(), h.get_ssrc(), h.get_padding(), nb_data - b.pos());
|
||||||
|
|
||||||
|
@ -1449,19 +1459,7 @@ SrsRtcConnection::SrsRtcConnection(SrsRtcServer* s, SrsContextId context_id)
|
||||||
SrsRtcConnection::~SrsRtcConnection()
|
SrsRtcConnection::~SrsRtcConnection()
|
||||||
{
|
{
|
||||||
srs_freep(timer_);
|
srs_freep(timer_);
|
||||||
srs_freep(transport_);
|
|
||||||
srs_freep(req);
|
|
||||||
srs_freep(stat_);
|
|
||||||
srs_freep(pp_address_change);
|
|
||||||
|
|
||||||
// Note that we should never delete the sendonly_skt,
|
|
||||||
// it's just point to the object in peer_addresses_.
|
|
||||||
map<string, SrsUdpMuxSocket*>::iterator it;
|
|
||||||
for (it = peer_addresses_.begin(); it != peer_addresses_.end(); ++it) {
|
|
||||||
SrsUdpMuxSocket* addr = it->second;
|
|
||||||
srs_freep(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup publishers.
|
// Cleanup publishers.
|
||||||
for(map<string, SrsRtcPublishStream*>::iterator it = publishers_.begin(); it != publishers_.end(); ++it) {
|
for(map<string, SrsRtcPublishStream*>::iterator it = publishers_.begin(); it != publishers_.end(); ++it) {
|
||||||
SrsRtcPublishStream* publisher = it->second;
|
SrsRtcPublishStream* publisher = it->second;
|
||||||
|
@ -1477,6 +1475,19 @@ SrsRtcConnection::~SrsRtcConnection()
|
||||||
}
|
}
|
||||||
players_.clear();
|
players_.clear();
|
||||||
players_ssrc_map_.clear();
|
players_ssrc_map_.clear();
|
||||||
|
|
||||||
|
// Note that we should never delete the sendonly_skt,
|
||||||
|
// it's just point to the object in peer_addresses_.
|
||||||
|
map<string, SrsUdpMuxSocket*>::iterator it;
|
||||||
|
for (it = peer_addresses_.begin(); it != peer_addresses_.end(); ++it) {
|
||||||
|
SrsUdpMuxSocket* addr = it->second;
|
||||||
|
srs_freep(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_freep(transport_);
|
||||||
|
srs_freep(req);
|
||||||
|
srs_freep(stat_);
|
||||||
|
srs_freep(pp_address_change);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsSdp* SrsRtcConnection::get_local_sdp()
|
SrsSdp* SrsRtcConnection::get_local_sdp()
|
||||||
|
@ -1548,7 +1559,7 @@ srs_error_t SrsRtcConnection::add_publisher(SrsRequest* req, const SrsSdp& remot
|
||||||
return srs_error_wrap(err, "publish negotiate");
|
return srs_error_wrap(err, "publish negotiate");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = generate_publish_local_sdp(req, local_sdp, stream_desc)) != srs_success) {
|
if ((err = generate_publish_local_sdp(req, local_sdp, stream_desc, remote_sdp.is_unified())) != srs_success) {
|
||||||
return srs_error_wrap(err, "generate local sdp");
|
return srs_error_wrap(err, "generate local sdp");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1611,7 +1622,7 @@ srs_error_t SrsRtcConnection::add_player(SrsRequest* req, const SrsSdp& remote_s
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = generate_play_local_sdp(req, local_sdp, stream_desc)) != srs_success) {
|
if ((err = generate_play_local_sdp(req, local_sdp, stream_desc, remote_sdp.is_unified())) != srs_success) {
|
||||||
return srs_error_wrap(err, "generate local sdp");
|
return srs_error_wrap(err, "generate local sdp");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1622,7 +1633,7 @@ srs_error_t SrsRtcConnection::add_player(SrsRequest* req, const SrsSdp& remote_s
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsRtcConnection::add_player2(SrsRequest* req, SrsSdp& local_sdp)
|
srs_error_t SrsRtcConnection::add_player2(SrsRequest* req, bool unified_plan, SrsSdp& local_sdp)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
@ -1658,7 +1669,7 @@ srs_error_t SrsRtcConnection::add_player2(SrsRequest* req, SrsSdp& local_sdp)
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = generate_play_local_sdp(req, local_sdp, stream_desc)) != srs_success) {
|
if ((err = generate_play_local_sdp(req, local_sdp, stream_desc, unified_plan)) != srs_success) {
|
||||||
return srs_error_wrap(err, "generate local sdp");
|
return srs_error_wrap(err, "generate local sdp");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2091,7 +2102,7 @@ void SrsRtcConnection::check_send_nacks(SrsRtpNackForReceiver* nack, uint32_t ss
|
||||||
int nb_protected_buf = stream.pos();
|
int nb_protected_buf = stream.pos();
|
||||||
|
|
||||||
// FIXME: Merge nack rtcp into one packets.
|
// FIXME: Merge nack rtcp into one packets.
|
||||||
if (transport_->protect_rtcp(protected_buf, stream.data(), nb_protected_buf) == srs_success) {
|
if (transport_->protect_rtcp(stream.data(), protected_buf, nb_protected_buf) == srs_success) {
|
||||||
// TODO: FIXME: Check error.
|
// TODO: FIXME: Check error.
|
||||||
sendonly_skt->sendto(protected_buf, nb_protected_buf, 0);
|
sendonly_skt->sendto(protected_buf, nb_protected_buf, 0);
|
||||||
}
|
}
|
||||||
|
@ -2569,7 +2580,7 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRequest* req, cons
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsRtcConnection::generate_publish_local_sdp(SrsRequest* req, SrsSdp& local_sdp, SrsRtcStreamDescription* stream_desc)
|
srs_error_t SrsRtcConnection::generate_publish_local_sdp(SrsRequest* req, SrsSdp& local_sdp, SrsRtcStreamDescription* stream_desc, bool unified_plan)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
@ -2665,8 +2676,10 @@ srs_error_t SrsRtcConnection::generate_publish_local_sdp(SrsRequest* req, SrsSdp
|
||||||
local_media_desc.payload_types_.push_back(payload->generate_media_payload_type());
|
local_media_desc.payload_types_.push_back(payload->generate_media_payload_type());
|
||||||
}
|
}
|
||||||
|
|
||||||
// only need media desc info, not ssrc info;
|
if(!unified_plan) {
|
||||||
break;
|
// For PlanB, only need media desc info, not ssrc info;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -2789,9 +2802,9 @@ srs_error_t SrsRtcConnection::negotiate_play_capability(SrsRequest* req, SrsRtcS
|
||||||
//negotiate video media
|
//negotiate video media
|
||||||
std::vector<SrsRtcTrackDescription*> req_video_tracks = req_stream_desc->video_track_descs_;
|
std::vector<SrsRtcTrackDescription*> req_video_tracks = req_stream_desc->video_track_descs_;
|
||||||
src_track_descs = source->get_track_desc("video", "h264");
|
src_track_descs = source->get_track_desc("video", "h264");
|
||||||
for(int i = 0; i < req_video_tracks.size(); ++i) {
|
for(int i = 0; i < (int)req_video_tracks.size(); ++i) {
|
||||||
SrsRtcTrackDescription* req_video = req_video_tracks.at(i);
|
SrsRtcTrackDescription* req_video = req_video_tracks.at(i);
|
||||||
for(int j = 0; j < src_track_descs.size(); ++j) {
|
for(int j = 0; j < (int)src_track_descs.size(); ++j) {
|
||||||
SrsRtcTrackDescription* src_video = src_track_descs.at(j);
|
SrsRtcTrackDescription* src_video = src_track_descs.at(j);
|
||||||
if(req_video->id_ == src_video->id_) {
|
if(req_video->id_ == src_video->id_) {
|
||||||
// FIXME: use source sdp or subscribe sdp? native subscribe may have no sdp
|
// FIXME: use source sdp or subscribe sdp? native subscribe may have no sdp
|
||||||
|
@ -2859,7 +2872,42 @@ srs_error_t SrsRtcConnection::fetch_source_capability(SrsRequest* req, std::map<
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsRtcConnection::generate_play_local_sdp(SrsRequest* req, SrsSdp& local_sdp, SrsRtcStreamDescription* stream_desc)
|
void video_track_generate_play_offer(SrsRtcTrackDescription* track, SrsSdp& local_sdp)
|
||||||
|
{
|
||||||
|
local_sdp.media_descs_.push_back(SrsMediaDesc("video"));
|
||||||
|
SrsMediaDesc& local_media_desc = local_sdp.media_descs_.back();
|
||||||
|
|
||||||
|
local_media_desc.port_ = 9;
|
||||||
|
local_media_desc.protos_ = "UDP/TLS/RTP/SAVPF";
|
||||||
|
local_media_desc.rtcp_mux_ = true;
|
||||||
|
local_media_desc.rtcp_rsize_ = true;
|
||||||
|
|
||||||
|
local_media_desc.extmaps_ = track->extmaps_;
|
||||||
|
|
||||||
|
local_media_desc.mid_ = track->mid_;
|
||||||
|
local_sdp.groups_.push_back(local_media_desc.mid_);
|
||||||
|
|
||||||
|
if (track->direction_ == "recvonly") {
|
||||||
|
local_media_desc.recvonly_ = true;
|
||||||
|
} else if (track->direction_ == "sendonly") {
|
||||||
|
local_media_desc.sendonly_ = true;
|
||||||
|
} else if (track->direction_ == "sendrecv") {
|
||||||
|
local_media_desc.sendrecv_ = true;
|
||||||
|
} else if (track->direction_ == "inactive_") {
|
||||||
|
local_media_desc.inactive_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsVideoPayload* payload = (SrsVideoPayload*)track->media_;
|
||||||
|
|
||||||
|
local_media_desc.payload_types_.push_back(payload->generate_media_payload_type());
|
||||||
|
|
||||||
|
if (track->red_) {
|
||||||
|
SrsRedPayload* red_payload = (SrsRedPayload*)track->red_;
|
||||||
|
local_media_desc.payload_types_.push_back(red_payload->generate_media_payload_type());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsRtcConnection::generate_play_local_sdp(SrsRequest* req, SrsSdp& local_sdp, SrsRtcStreamDescription* stream_desc, bool unified_plan)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
@ -2948,39 +2996,14 @@ srs_error_t SrsRtcConnection::generate_play_local_sdp(SrsRequest* req, SrsSdp& l
|
||||||
for (int i = 0; i < (int)stream_desc->video_track_descs_.size(); ++i) {
|
for (int i = 0; i < (int)stream_desc->video_track_descs_.size(); ++i) {
|
||||||
SrsRtcTrackDescription* track = stream_desc->video_track_descs_[i];
|
SrsRtcTrackDescription* track = stream_desc->video_track_descs_[i];
|
||||||
|
|
||||||
// for plan b, we only add one m=
|
if (!unified_plan) {
|
||||||
if (i == 0) {
|
// for plan b, we only add one m= for video track.
|
||||||
local_sdp.media_descs_.push_back(SrsMediaDesc("video"));
|
if (i == 0) {
|
||||||
SrsMediaDesc& local_media_desc = local_sdp.media_descs_.back();
|
video_track_generate_play_offer(track, local_sdp);
|
||||||
|
|
||||||
local_media_desc.port_ = 9;
|
|
||||||
local_media_desc.protos_ = "UDP/TLS/RTP/SAVPF";
|
|
||||||
local_media_desc.rtcp_mux_ = true;
|
|
||||||
local_media_desc.rtcp_rsize_ = true;
|
|
||||||
|
|
||||||
local_media_desc.extmaps_ = track->extmaps_;
|
|
||||||
|
|
||||||
local_media_desc.mid_ = track->mid_;
|
|
||||||
local_sdp.groups_.push_back(local_media_desc.mid_);
|
|
||||||
|
|
||||||
if (track->direction_ == "recvonly") {
|
|
||||||
local_media_desc.recvonly_ = true;
|
|
||||||
} else if (track->direction_ == "sendonly") {
|
|
||||||
local_media_desc.sendonly_ = true;
|
|
||||||
} else if (track->direction_ == "sendrecv") {
|
|
||||||
local_media_desc.sendrecv_ = true;
|
|
||||||
} else if (track->direction_ == "inactive_") {
|
|
||||||
local_media_desc.inactive_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsVideoPayload* payload = (SrsVideoPayload*)track->media_;
|
|
||||||
|
|
||||||
local_media_desc.payload_types_.push_back(payload->generate_media_payload_type());
|
|
||||||
|
|
||||||
if (track->red_) {
|
|
||||||
SrsRedPayload* red_payload = (SrsRedPayload*)track->red_;
|
|
||||||
local_media_desc.payload_types_.push_back(red_payload->generate_media_payload_type());
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// unified plan SDP, generate a m= for each video track.
|
||||||
|
video_track_generate_play_offer(track, local_sdp);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsMediaDesc& local_media_desc = local_sdp.media_descs_.back();
|
SrsMediaDesc& local_media_desc = local_sdp.media_descs_.back();
|
||||||
|
@ -3089,7 +3112,7 @@ srs_error_t SrsRtcConnection::create_publisher(SrsRequest* req, SrsRtcStreamDesc
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcPublishStream* publisher = new SrsRtcPublishStream(this);
|
SrsRtcPublishStream* publisher = new SrsRtcPublishStream(this, _srs_context->get_id());
|
||||||
if ((err = publisher->initialize(req, stream_desc)) != srs_success) {
|
if ((err = publisher->initialize(req, stream_desc)) != srs_success) {
|
||||||
srs_freep(publisher);
|
srs_freep(publisher);
|
||||||
return srs_error_wrap(err, "rtc publisher init");
|
return srs_error_wrap(err, "rtc publisher init");
|
||||||
|
@ -3122,7 +3145,7 @@ srs_error_t SrsRtcConnection::create_publisher(SrsRequest* req, SrsRtcStreamDesc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < stream_desc->video_track_descs_.size(); ++i) {
|
for(int i = 0; i < (int)stream_desc->video_track_descs_.size(); ++i) {
|
||||||
SrsRtcTrackDescription* track_desc = stream_desc->video_track_descs_.at(i);
|
SrsRtcTrackDescription* track_desc = stream_desc->video_track_descs_.at(i);
|
||||||
if(publishers_ssrc_map_.end() != publishers_ssrc_map_.find(track_desc->ssrc_)) {
|
if(publishers_ssrc_map_.end() != publishers_ssrc_map_.find(track_desc->ssrc_)) {
|
||||||
return srs_error_new(ERROR_RTC_DUPLICATED_SSRC, " duplicate ssrc %d, track id: %s",
|
return srs_error_new(ERROR_RTC_DUPLICATED_SSRC, " duplicate ssrc %d, track id: %s",
|
||||||
|
|
|
@ -221,6 +221,8 @@ private:
|
||||||
// key: publish_ssrc, value: send track to process rtp/rtcp
|
// key: publish_ssrc, value: send track to process rtp/rtcp
|
||||||
std::map<uint32_t, SrsRtcAudioSendTrack*> audio_tracks_;
|
std::map<uint32_t, SrsRtcAudioSendTrack*> audio_tracks_;
|
||||||
std::map<uint32_t, SrsRtcVideoSendTrack*> video_tracks_;
|
std::map<uint32_t, SrsRtcVideoSendTrack*> video_tracks_;
|
||||||
|
// The pithy print for special stage.
|
||||||
|
SrsErrorPithyPrint* nack_epp;
|
||||||
private:
|
private:
|
||||||
// For merged-write messages.
|
// For merged-write messages.
|
||||||
int mw_msgs;
|
int mw_msgs;
|
||||||
|
@ -271,6 +273,7 @@ private:
|
||||||
class SrsRtcPublishStream : virtual public ISrsHourGlass, virtual public ISrsRtpPacketDecodeHandler, virtual public ISrsRtcPublishStream
|
class SrsRtcPublishStream : virtual public ISrsHourGlass, virtual public ISrsRtpPacketDecodeHandler, virtual public ISrsRtcPublishStream
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
SrsContextId parent_cid_;
|
||||||
SrsHourGlass* timer_;
|
SrsHourGlass* timer_;
|
||||||
uint64_t nn_audio_frames;
|
uint64_t nn_audio_frames;
|
||||||
private:
|
private:
|
||||||
|
@ -296,7 +299,7 @@ private:
|
||||||
SrsRtpExtensionTypes extension_types_;
|
SrsRtpExtensionTypes extension_types_;
|
||||||
bool is_started;
|
bool is_started;
|
||||||
public:
|
public:
|
||||||
SrsRtcPublishStream(SrsRtcConnection* session);
|
SrsRtcPublishStream(SrsRtcConnection* session, SrsContextId parent_cid);
|
||||||
virtual ~SrsRtcPublishStream();
|
virtual ~SrsRtcPublishStream();
|
||||||
public:
|
public:
|
||||||
srs_error_t initialize(SrsRequest* req, SrsRtcStreamDescription* stream_desc);
|
srs_error_t initialize(SrsRequest* req, SrsRtcStreamDescription* stream_desc);
|
||||||
|
@ -439,7 +442,7 @@ public:
|
||||||
srs_error_t add_publisher(SrsRequest* request, const SrsSdp& remote_sdp, SrsSdp& local_sdp);
|
srs_error_t add_publisher(SrsRequest* request, const SrsSdp& remote_sdp, SrsSdp& local_sdp);
|
||||||
srs_error_t add_player(SrsRequest* request, const SrsSdp& remote_sdp, SrsSdp& local_sdp);
|
srs_error_t add_player(SrsRequest* request, const SrsSdp& remote_sdp, SrsSdp& local_sdp);
|
||||||
// server send offer sdp to client, local sdp derivate from source stream desc.
|
// server send offer sdp to client, local sdp derivate from source stream desc.
|
||||||
srs_error_t add_player2(SrsRequest* request, SrsSdp& local_sdp);
|
srs_error_t add_player2(SrsRequest* request, bool unified_plan, SrsSdp& local_sdp);
|
||||||
public:
|
public:
|
||||||
// Before initialize, user must set the local SDP, which is used to inititlize DTLS.
|
// Before initialize, user must set the local SDP, which is used to inititlize DTLS.
|
||||||
srs_error_t initialize(SrsRequest* r, bool dtls, bool srtp, std::string username);
|
srs_error_t initialize(SrsRequest* r, bool dtls, bool srtp, std::string username);
|
||||||
|
@ -483,13 +486,13 @@ private:
|
||||||
srs_error_t on_binding_request(SrsStunPacket* r);
|
srs_error_t on_binding_request(SrsStunPacket* r);
|
||||||
// publish media capabilitiy negotiate
|
// publish media capabilitiy negotiate
|
||||||
srs_error_t negotiate_publish_capability(SrsRequest* req, const SrsSdp& remote_sdp, SrsRtcStreamDescription* stream_desc);
|
srs_error_t negotiate_publish_capability(SrsRequest* req, const SrsSdp& remote_sdp, SrsRtcStreamDescription* stream_desc);
|
||||||
srs_error_t generate_publish_local_sdp(SrsRequest* req, SrsSdp& local_sdp, SrsRtcStreamDescription* stream_desc);
|
srs_error_t generate_publish_local_sdp(SrsRequest* req, SrsSdp& local_sdp, SrsRtcStreamDescription* stream_desc, bool unified_plan);
|
||||||
// play media capabilitiy negotiate
|
// play media capabilitiy negotiate
|
||||||
//TODO: Use StreamDescription to negotiate and remove first negotiate_play_capability function
|
//TODO: Use StreamDescription to negotiate and remove first negotiate_play_capability function
|
||||||
srs_error_t negotiate_play_capability(SrsRequest* req, const SrsSdp& remote_sdp, std::map<uint32_t, SrsRtcTrackDescription*>& sub_relations);
|
srs_error_t negotiate_play_capability(SrsRequest* req, const SrsSdp& remote_sdp, std::map<uint32_t, SrsRtcTrackDescription*>& sub_relations);
|
||||||
srs_error_t negotiate_play_capability(SrsRequest* req, SrsRtcStreamDescription* req_stream_desc, std::map<uint32_t, SrsRtcTrackDescription*>& sub_relations);
|
srs_error_t negotiate_play_capability(SrsRequest* req, SrsRtcStreamDescription* req_stream_desc, std::map<uint32_t, SrsRtcTrackDescription*>& sub_relations);
|
||||||
srs_error_t fetch_source_capability(SrsRequest* req, std::map<uint32_t, SrsRtcTrackDescription*>& sub_relations);
|
srs_error_t fetch_source_capability(SrsRequest* req, std::map<uint32_t, SrsRtcTrackDescription*>& sub_relations);
|
||||||
srs_error_t generate_play_local_sdp(SrsRequest* req, SrsSdp& local_sdp, SrsRtcStreamDescription* stream_desc);
|
srs_error_t generate_play_local_sdp(SrsRequest* req, SrsSdp& local_sdp, SrsRtcStreamDescription* stream_desc, bool unified_plan);
|
||||||
srs_error_t create_player(SrsRequest* request, std::map<uint32_t, SrsRtcTrackDescription*> sub_relations);
|
srs_error_t create_player(SrsRequest* request, std::map<uint32_t, SrsRtcTrackDescription*> sub_relations);
|
||||||
srs_error_t create_publisher(SrsRequest* request, SrsRtcStreamDescription* stream_desc);
|
srs_error_t create_publisher(SrsRequest* request, SrsRtcStreamDescription* stream_desc);
|
||||||
};
|
};
|
||||||
|
|
|
@ -312,10 +312,12 @@ ISrsDtlsCallback::~ISrsDtlsCallback()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsDtls::SrsDtls(ISrsDtlsCallback* callback)
|
SrsDtlsImpl::SrsDtlsImpl(ISrsDtlsCallback* callback)
|
||||||
{
|
{
|
||||||
dtls_ctx = NULL;
|
dtls_ctx = NULL;
|
||||||
dtls = NULL;
|
dtls = NULL;
|
||||||
|
bio_in = NULL;
|
||||||
|
bio_out = NULL;
|
||||||
|
|
||||||
callback_ = callback;
|
callback_ = callback;
|
||||||
handshake_done_for_us = false;
|
handshake_done_for_us = false;
|
||||||
|
@ -323,17 +325,11 @@ SrsDtls::SrsDtls(ISrsDtlsCallback* callback)
|
||||||
last_outgoing_packet_cache = new uint8_t[kRtpPacketSize];
|
last_outgoing_packet_cache = new uint8_t[kRtpPacketSize];
|
||||||
nn_last_outgoing_packet = 0;
|
nn_last_outgoing_packet = 0;
|
||||||
|
|
||||||
role_ = SrsDtlsRoleServer;
|
|
||||||
version_ = SrsDtlsVersionAuto;
|
version_ = SrsDtlsVersionAuto;
|
||||||
|
|
||||||
trd = NULL;
|
|
||||||
state_ = SrsDtlsStateInit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsDtls::~SrsDtls()
|
SrsDtlsImpl::~SrsDtlsImpl()
|
||||||
{
|
{
|
||||||
srs_freep(trd);
|
|
||||||
|
|
||||||
if (dtls_ctx) {
|
if (dtls_ctx) {
|
||||||
SSL_CTX_free(dtls_ctx);
|
SSL_CTX_free(dtls_ctx);
|
||||||
dtls_ctx = NULL;
|
dtls_ctx = NULL;
|
||||||
|
@ -348,15 +344,10 @@ SrsDtls::~SrsDtls()
|
||||||
srs_freepa(last_outgoing_packet_cache);
|
srs_freepa(last_outgoing_packet_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsDtls::initialize(std::string role, std::string version)
|
srs_error_t SrsDtlsImpl::initialize(std::string version)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
role_ = SrsDtlsRoleServer;
|
|
||||||
if (role == "active") {
|
|
||||||
role_ = SrsDtlsRoleClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (version == "dtls1.0") {
|
if (version == "dtls1.0") {
|
||||||
version_ = SrsDtlsVersion1_0;
|
version_ = SrsDtlsVersion1_0;
|
||||||
} else if (version == "dtls1.2") {
|
} else if (version == "dtls1.2") {
|
||||||
|
@ -371,15 +362,6 @@ srs_error_t SrsDtls::initialize(std::string role, std::string version)
|
||||||
return srs_error_new(ERROR_OpenSslCreateSSL, "SSL_new dtls");
|
return srs_error_new(ERROR_OpenSslCreateSSL, "SSL_new dtls");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role_ == SrsDtlsRoleClient) {
|
|
||||||
// Dtls setup active, as client role.
|
|
||||||
SSL_set_connect_state(dtls);
|
|
||||||
SSL_set_max_send_fragment(dtls, kRtpPacketSize);
|
|
||||||
} else {
|
|
||||||
// Dtls setup passive, as server role.
|
|
||||||
SSL_set_accept_state(dtls);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((bio_in = BIO_new(BIO_s_mem())) == NULL) {
|
if ((bio_in = BIO_new(BIO_s_mem())) == NULL) {
|
||||||
return srs_error_new(ERROR_OpenSslBIONew, "BIO_new in");
|
return srs_error_new(ERROR_OpenSslBIONew, "BIO_new in");
|
||||||
}
|
}
|
||||||
|
@ -394,29 +376,10 @@ srs_error_t SrsDtls::initialize(std::string role, std::string version)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsDtls::start_active_handshake()
|
srs_error_t SrsDtlsImpl::on_dtls(char* data, int nb_data)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if (role_ == SrsDtlsRoleClient) {
|
|
||||||
return do_handshake();
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
srs_error_t SrsDtls::on_dtls(char* data, int nb_data)
|
|
||||||
{
|
|
||||||
srs_error_t err = srs_success;
|
|
||||||
|
|
||||||
// When got packet, stop the ARQ if server in the first ARQ state SrsDtlsStateServerHello.
|
|
||||||
// @note But for ARQ state, we should never stop the ARQ, for example, we are in the second ARQ sate
|
|
||||||
// SrsDtlsStateServerDone, but we got previous late wrong packet ServeHello, which is not the expect
|
|
||||||
// packet SessionNewTicket, we should never stop the ARQ thread.
|
|
||||||
if (role_ == SrsDtlsRoleClient && state_ == SrsDtlsStateServerHello) {
|
|
||||||
stop_arq();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = do_on_dtls(data, nb_data)) != srs_success) {
|
if ((err = do_on_dtls(data, nb_data)) != srs_success) {
|
||||||
return srs_error_wrap(err, "on_dtls size=%u, data=[%s]", nb_data,
|
return srs_error_wrap(err, "on_dtls size=%u, data=[%s]", nb_data,
|
||||||
srs_string_dumps_hex(data, nb_data, 32).c_str());
|
srs_string_dumps_hex(data, nb_data, 32).c_str());
|
||||||
|
@ -425,7 +388,7 @@ srs_error_t SrsDtls::on_dtls(char* data, int nb_data)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsDtls::do_on_dtls(char* data, int nb_data)
|
srs_error_t SrsDtlsImpl::do_on_dtls(char* data, int nb_data)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
@ -468,7 +431,7 @@ srs_error_t SrsDtls::do_on_dtls(char* data, int nb_data)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsDtls::do_handshake()
|
srs_error_t SrsDtlsImpl::do_handshake()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
@ -490,16 +453,9 @@ srs_error_t SrsDtls::do_handshake()
|
||||||
uint8_t* data = NULL;
|
uint8_t* data = NULL;
|
||||||
int size = BIO_get_mem_data(bio_out, &data);
|
int size = BIO_get_mem_data(bio_out, &data);
|
||||||
|
|
||||||
// If outgoing packet is empty, we use the last cache.
|
// Callback when got SSL original data.
|
||||||
// @remark Only for DTLS server, because DTLS client use ARQ thread to send cached packet.
|
|
||||||
bool cache = false;
|
bool cache = false;
|
||||||
if (role_ != SrsDtlsRoleClient && size <= 0 && nn_last_outgoing_packet) {
|
on_ssl_out_data(data, size, cache);
|
||||||
size = nn_last_outgoing_packet;
|
|
||||||
data = last_outgoing_packet_cache;
|
|
||||||
cache = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trace the detail of DTLS packet.
|
|
||||||
state_trace((uint8_t*)data, size, false, r0, r1, cache, false);
|
state_trace((uint8_t*)data, size, false, r0, r1, cache, false);
|
||||||
|
|
||||||
// Update the packet cache.
|
// Update the packet cache.
|
||||||
|
@ -508,29 +464,9 @@ srs_error_t SrsDtls::do_handshake()
|
||||||
nn_last_outgoing_packet = size;
|
nn_last_outgoing_packet = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Driven ARQ and state for DTLS client.
|
// Callback for the final output data, before send-out.
|
||||||
if (role_ == SrsDtlsRoleClient) {
|
if ((err = on_final_out_data(data, size)) != srs_success) {
|
||||||
// If we are sending client hello, change from init to new state.
|
return srs_error_wrap(err, "handle");
|
||||||
if (state_ == SrsDtlsStateInit && size > 14 && data[13] == 1) {
|
|
||||||
state_ = SrsDtlsStateClientHello;
|
|
||||||
}
|
|
||||||
// If we are sending certificate, change from SrsDtlsStateServerHello to new state.
|
|
||||||
if (state_ == SrsDtlsStateServerHello && size > 14 && data[13] == 11) {
|
|
||||||
state_ = SrsDtlsStateClientCertificate;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to start the ARQ for client.
|
|
||||||
if ((state_ == SrsDtlsStateClientHello || state_ == SrsDtlsStateClientCertificate)) {
|
|
||||||
if (state_ == SrsDtlsStateClientHello) {
|
|
||||||
state_ = SrsDtlsStateServerHello;
|
|
||||||
} else if (state_ == SrsDtlsStateClientCertificate) {
|
|
||||||
state_ = SrsDtlsStateServerDone;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = start_arq()) != srs_success) {
|
|
||||||
return srs_error_wrap(err, "start arq");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size > 0 && (err = callback_->write_dtls_data(data, size)) != srs_success) {
|
if (size > 0 && (err = callback_->write_dtls_data(data, size)) != srs_success) {
|
||||||
|
@ -539,30 +475,213 @@ srs_error_t SrsDtls::do_handshake()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handshake_done_for_us) {
|
if (handshake_done_for_us) {
|
||||||
// When handshake done, stop the ARQ.
|
if (((err = on_handshake_done()) != srs_success)) {
|
||||||
if (role_ == SrsDtlsRoleClient) {
|
return srs_error_wrap(err, "done");
|
||||||
state_ = SrsDtlsStateClientDone;
|
|
||||||
stop_arq();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify connection the DTLS is done.
|
|
||||||
if (((err = callback_->on_dtls_handshake_done()) != srs_success)) {
|
|
||||||
return srs_error_wrap(err, "dtls done");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsDtls::cycle()
|
void SrsDtlsImpl::state_trace(uint8_t* data, int length, bool incoming, int r0, int r1, bool cache, bool arq)
|
||||||
|
{
|
||||||
|
uint8_t content_type = 0;
|
||||||
|
if (length >= 1) {
|
||||||
|
content_type = (uint8_t)data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t size = 0;
|
||||||
|
if (length >= 13) {
|
||||||
|
size = uint16_t(data[11])<<8 | uint16_t(data[12]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t handshake_type = 0;
|
||||||
|
if (length >= 14) {
|
||||||
|
handshake_type = (uint8_t)data[13];
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_trace("DTLS: %s %s, done=%u, cache=%u, arq=%u, r0=%d, r1=%d, len=%u, cnt=%u, size=%u, hs=%u",
|
||||||
|
(is_dtls_client()? "Active":"Passive"), (incoming? "RECV":"SEND"), handshake_done_for_us, cache, arq,
|
||||||
|
r0, r1, length, content_type, size, handshake_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int SRTP_MASTER_KEY_KEY_LEN = 16;
|
||||||
|
const int SRTP_MASTER_KEY_SALT_LEN = 14;
|
||||||
|
srs_error_t SrsDtlsImpl::get_srtp_key(std::string& recv_key, std::string& send_key)
|
||||||
|
{
|
||||||
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
unsigned char material[SRTP_MASTER_KEY_LEN * 2] = {0}; // client(SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN) + server
|
||||||
|
static const string dtls_srtp_lable = "EXTRACTOR-dtls_srtp";
|
||||||
|
if (!SSL_export_keying_material(dtls, material, sizeof(material), dtls_srtp_lable.c_str(), dtls_srtp_lable.size(), NULL, 0, 0)) {
|
||||||
|
return srs_error_new(ERROR_RTC_SRTP_INIT, "SSL export key r0=%lu", ERR_get_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
std::string client_master_key(reinterpret_cast<char*>(material), SRTP_MASTER_KEY_KEY_LEN);
|
||||||
|
offset += SRTP_MASTER_KEY_KEY_LEN;
|
||||||
|
std::string server_master_key(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_KEY_LEN);
|
||||||
|
offset += SRTP_MASTER_KEY_KEY_LEN;
|
||||||
|
std::string client_master_salt(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_SALT_LEN);
|
||||||
|
offset += SRTP_MASTER_KEY_SALT_LEN;
|
||||||
|
std::string server_master_salt(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_SALT_LEN);
|
||||||
|
|
||||||
|
if (is_dtls_client()) {
|
||||||
|
recv_key = server_master_key + server_master_salt;
|
||||||
|
send_key = client_master_key + client_master_salt;
|
||||||
|
} else {
|
||||||
|
recv_key = client_master_key + client_master_salt;
|
||||||
|
send_key = server_master_key + server_master_salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsDtlsClientImpl::SrsDtlsClientImpl(ISrsDtlsCallback* callback) : SrsDtlsImpl(callback)
|
||||||
|
{
|
||||||
|
trd = NULL;
|
||||||
|
state_ = SrsDtlsStateInit;
|
||||||
|
arq_first = 50 * SRS_UTIME_MILLISECONDS;
|
||||||
|
arq_interval = 100 * SRS_UTIME_MILLISECONDS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsDtlsClientImpl::~SrsDtlsClientImpl()
|
||||||
|
{
|
||||||
|
srs_freep(trd);
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsDtlsClientImpl::initialize(std::string version)
|
||||||
|
{
|
||||||
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
if ((err = SrsDtlsImpl::initialize(version)) != srs_success) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dtls setup active, as client role.
|
||||||
|
SSL_set_connect_state(dtls);
|
||||||
|
SSL_set_max_send_fragment(dtls, kRtpPacketSize);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsDtlsClientImpl::start_active_handshake()
|
||||||
|
{
|
||||||
|
return do_handshake();
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsDtlsClientImpl::on_dtls(char* data, int nb_data)
|
||||||
|
{
|
||||||
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
// When got packet, stop the ARQ if server in the first ARQ state SrsDtlsStateServerHello.
|
||||||
|
// @note But for ARQ state, we should never stop the ARQ, for example, we are in the second ARQ sate
|
||||||
|
// SrsDtlsStateServerDone, but we got previous late wrong packet ServeHello, which is not the expect
|
||||||
|
// packet SessionNewTicket, we should never stop the ARQ thread.
|
||||||
|
if (state_ == SrsDtlsStateServerHello) {
|
||||||
|
stop_arq();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((err = SrsDtlsImpl::on_dtls(data, nb_data)) != srs_success) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsDtlsClientImpl::on_ssl_out_data(uint8_t*& data, int& size, bool& cached)
|
||||||
|
{
|
||||||
|
// DTLS client use ARQ thread to send cached packet.
|
||||||
|
cached = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsDtlsClientImpl::on_final_out_data(uint8_t* data, int size)
|
||||||
|
{
|
||||||
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
// Driven ARQ and state for DTLS client.
|
||||||
|
// If we are sending client hello, change from init to new state.
|
||||||
|
if (state_ == SrsDtlsStateInit && size > 14 && data[13] == 1) {
|
||||||
|
state_ = SrsDtlsStateClientHello;
|
||||||
|
}
|
||||||
|
// If we are sending certificate, change from SrsDtlsStateServerHello to new state.
|
||||||
|
if (state_ == SrsDtlsStateServerHello && size > 14 && data[13] == 11) {
|
||||||
|
state_ = SrsDtlsStateClientCertificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to start the ARQ for client.
|
||||||
|
if ((state_ == SrsDtlsStateClientHello || state_ == SrsDtlsStateClientCertificate)) {
|
||||||
|
if (state_ == SrsDtlsStateClientHello) {
|
||||||
|
state_ = SrsDtlsStateServerHello;
|
||||||
|
} else if (state_ == SrsDtlsStateClientCertificate) {
|
||||||
|
state_ = SrsDtlsStateServerDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((err = start_arq()) != srs_success) {
|
||||||
|
return srs_error_wrap(err, "start arq");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsDtlsClientImpl::on_handshake_done()
|
||||||
|
{
|
||||||
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
// When handshake done, stop the ARQ.
|
||||||
|
state_ = SrsDtlsStateClientDone;
|
||||||
|
stop_arq();
|
||||||
|
|
||||||
|
// Notify connection the DTLS is done.
|
||||||
|
if (((err = callback_->on_dtls_handshake_done()) != srs_success)) {
|
||||||
|
return srs_error_wrap(err, "dtls done");
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SrsDtlsClientImpl::is_dtls_client()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsDtlsClientImpl::start_arq()
|
||||||
|
{
|
||||||
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
srs_info("start arq, state=%u", state_);
|
||||||
|
|
||||||
|
// Dispose the previous ARQ thread.
|
||||||
|
srs_freep(trd);
|
||||||
|
trd = new SrsSTCoroutine("dtls", this, _srs_context->get_id());
|
||||||
|
|
||||||
|
// We should start the ARQ thread for DTLS client.
|
||||||
|
if ((err = trd->start()) != srs_success) {
|
||||||
|
return srs_error_wrap(err, "arq start");
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsDtlsClientImpl::stop_arq()
|
||||||
|
{
|
||||||
|
srs_info("stop arq, state=%u", state_);
|
||||||
|
srs_freep(trd);
|
||||||
|
srs_info("stop arq, done");
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsDtlsClientImpl::cycle()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
// The first ARQ delay.
|
// The first ARQ delay.
|
||||||
srs_usleep(50 * SRS_UTIME_MILLISECONDS);
|
srs_usleep(arq_first);
|
||||||
|
|
||||||
while (true) {
|
// Limit the max retry for ARQ.
|
||||||
srs_info("arq cycle, state=%u", state_);
|
for (int arq_retry_left = 7; arq_retry_left > 0; arq_retry_left--) {
|
||||||
|
srs_info("arq cycle, state=%u, retry=%d", state_, arq_retry_left);
|
||||||
|
|
||||||
// We ignore any error for ARQ thread.
|
// We ignore any error for ARQ thread.
|
||||||
if ((err = trd->pull()) != srs_success) {
|
if ((err = trd->pull()) != srs_success) {
|
||||||
|
@ -595,96 +714,110 @@ srs_error_t SrsDtls::cycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Use ARQ step timeouts.
|
// TODO: Use ARQ step timeouts.
|
||||||
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
|
srs_usleep(arq_interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsDtls::state_trace(uint8_t* data, int length, bool incoming, int r0, int r1, bool cache, bool arq)
|
SrsDtlsServerImpl::SrsDtlsServerImpl(ISrsDtlsCallback* callback) : SrsDtlsImpl(callback)
|
||||||
{
|
{
|
||||||
uint8_t content_type = 0;
|
|
||||||
if (length >= 1) {
|
|
||||||
content_type = (uint8_t)data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t size = 0;
|
|
||||||
if (length >= 13) {
|
|
||||||
size = uint16_t(data[11])<<8 | uint16_t(data[12]);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t handshake_type = 0;
|
|
||||||
if (length >= 14) {
|
|
||||||
handshake_type = (uint8_t)data[13];
|
|
||||||
}
|
|
||||||
|
|
||||||
srs_trace("DTLS: %s %s, done=%u, cache=%u, arq=%u, state=%u, r0=%d, r1=%d, len=%u, cnt=%u, size=%u, hs=%u",
|
|
||||||
(role_ == SrsDtlsRoleClient? "Active":"Passive"), (incoming? "RECV":"SEND"), handshake_done_for_us, cache, arq,
|
|
||||||
state_, r0, r1, length, content_type, size, handshake_type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsDtls::start_arq()
|
SrsDtlsServerImpl::~SrsDtlsServerImpl()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsDtlsServerImpl::initialize(std::string version)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if (role_ != SrsDtlsRoleClient) {
|
if ((err = SrsDtlsImpl::initialize(version)) != srs_success) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_info("start arq, state=%u", state_);
|
// Dtls setup passive, as server role.
|
||||||
|
SSL_set_accept_state(dtls);
|
||||||
// Dispose the previous ARQ thread.
|
|
||||||
srs_freep(trd);
|
|
||||||
trd = new SrsSTCoroutine("dtls", this, _srs_context->get_id());
|
|
||||||
|
|
||||||
// We should start the ARQ thread for DTLS client.
|
|
||||||
if ((err = trd->start()) != srs_success) {
|
|
||||||
return srs_error_wrap(err, "arq start");
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsDtls::stop_arq()
|
srs_error_t SrsDtlsServerImpl::start_active_handshake()
|
||||||
{
|
{
|
||||||
srs_info("stop arq, state=%u", state_);
|
return srs_success;
|
||||||
srs_freep(trd);
|
|
||||||
srs_info("stop arq, done");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const int SRTP_MASTER_KEY_KEY_LEN = 16;
|
void SrsDtlsServerImpl::on_ssl_out_data(uint8_t*& data, int& size, bool& cached)
|
||||||
const int SRTP_MASTER_KEY_SALT_LEN = 14;
|
{
|
||||||
srs_error_t SrsDtls::get_srtp_key(std::string& recv_key, std::string& send_key)
|
// If outgoing packet is empty, we use the last cache.
|
||||||
|
// @remark Only for DTLS server, because DTLS client use ARQ thread to send cached packet.
|
||||||
|
if (size <= 0 && nn_last_outgoing_packet) {
|
||||||
|
size = nn_last_outgoing_packet;
|
||||||
|
data = last_outgoing_packet_cache;
|
||||||
|
cached = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsDtlsServerImpl::on_final_out_data(uint8_t* data, int size)
|
||||||
|
{
|
||||||
|
return srs_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsDtlsServerImpl::on_handshake_done()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
unsigned char material[SRTP_MASTER_KEY_LEN * 2] = {0}; // client(SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN) + server
|
// Notify connection the DTLS is done.
|
||||||
static const string dtls_srtp_lable = "EXTRACTOR-dtls_srtp";
|
if (((err = callback_->on_dtls_handshake_done()) != srs_success)) {
|
||||||
if (!SSL_export_keying_material(dtls, material, sizeof(material), dtls_srtp_lable.c_str(), dtls_srtp_lable.size(), NULL, 0, 0)) {
|
return srs_error_wrap(err, "dtls done");
|
||||||
return srs_error_new(ERROR_RTC_SRTP_INIT, "SSL export key r0=%u", ERR_get_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t offset = 0;
|
|
||||||
|
|
||||||
std::string client_master_key(reinterpret_cast<char*>(material), SRTP_MASTER_KEY_KEY_LEN);
|
|
||||||
offset += SRTP_MASTER_KEY_KEY_LEN;
|
|
||||||
std::string server_master_key(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_KEY_LEN);
|
|
||||||
offset += SRTP_MASTER_KEY_KEY_LEN;
|
|
||||||
std::string client_master_salt(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_SALT_LEN);
|
|
||||||
offset += SRTP_MASTER_KEY_SALT_LEN;
|
|
||||||
std::string server_master_salt(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_SALT_LEN);
|
|
||||||
|
|
||||||
if (role_ == SrsDtlsRoleClient) {
|
|
||||||
recv_key = server_master_key + server_master_salt;
|
|
||||||
send_key = client_master_key + client_master_salt;
|
|
||||||
} else {
|
|
||||||
recv_key = client_master_key + client_master_salt;
|
|
||||||
send_key = server_master_key + server_master_salt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SrsDtlsServerImpl::is_dtls_client()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsDtls::SrsDtls(ISrsDtlsCallback* callback)
|
||||||
|
{
|
||||||
|
callback_ = callback;
|
||||||
|
impl = new SrsDtlsServerImpl(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsDtls::~SrsDtls()
|
||||||
|
{
|
||||||
|
srs_freep(impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsDtls::initialize(std::string role, std::string version)
|
||||||
|
{
|
||||||
|
srs_freep(impl);
|
||||||
|
if (role == "active") {
|
||||||
|
impl = new SrsDtlsClientImpl(callback_);
|
||||||
|
} else {
|
||||||
|
impl = new SrsDtlsServerImpl(callback_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return impl->initialize(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsDtls::start_active_handshake()
|
||||||
|
{
|
||||||
|
return impl->start_active_handshake();
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsDtls::on_dtls(char* data, int nb_data)
|
||||||
|
{
|
||||||
|
return impl->on_dtls(data, nb_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsDtls::get_srtp_key(std::string& recv_key, std::string& send_key)
|
||||||
|
{
|
||||||
|
return impl->get_srtp_key(recv_key, send_key);
|
||||||
|
}
|
||||||
|
|
||||||
SrsSRTP::SrsSRTP()
|
SrsSRTP::SrsSRTP()
|
||||||
{
|
{
|
||||||
recv_ctx_ = NULL;
|
recv_ctx_ = NULL;
|
||||||
|
|
|
@ -105,31 +105,93 @@ enum SrsDtlsState {
|
||||||
SrsDtlsStateClientDone, // Done.
|
SrsDtlsStateClientDone, // Done.
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsDtls : public ISrsCoroutineHandler
|
class SrsDtlsImpl
|
||||||
{
|
{
|
||||||
private:
|
protected:
|
||||||
SSL_CTX* dtls_ctx;
|
SSL_CTX* dtls_ctx;
|
||||||
SSL* dtls;
|
SSL* dtls;
|
||||||
BIO* bio_in;
|
BIO* bio_in;
|
||||||
BIO* bio_out;
|
BIO* bio_out;
|
||||||
ISrsDtlsCallback* callback_;
|
ISrsDtlsCallback* callback_;
|
||||||
private:
|
// @remark: dtls_version_ default value is SrsDtlsVersionAuto.
|
||||||
|
SrsDtlsVersion version_;
|
||||||
|
protected:
|
||||||
// Whether the handhshake is done, for us only.
|
// Whether the handhshake is done, for us only.
|
||||||
// @remark For us only, means peer maybe not done, we also need to handle the DTLS packet.
|
// @remark For us only, means peer maybe not done, we also need to handle the DTLS packet.
|
||||||
bool handshake_done_for_us;
|
bool handshake_done_for_us;
|
||||||
// DTLS packet cache, only last out-going packet.
|
// DTLS packet cache, only last out-going packet.
|
||||||
uint8_t* last_outgoing_packet_cache;
|
uint8_t* last_outgoing_packet_cache;
|
||||||
int nn_last_outgoing_packet;
|
int nn_last_outgoing_packet;
|
||||||
|
public:
|
||||||
|
SrsDtlsImpl(ISrsDtlsCallback* callback);
|
||||||
|
virtual ~SrsDtlsImpl();
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(std::string version);
|
||||||
|
virtual srs_error_t start_active_handshake() = 0;
|
||||||
|
virtual srs_error_t on_dtls(char* data, int nb_data);
|
||||||
|
protected:
|
||||||
|
srs_error_t do_on_dtls(char* data, int nb_data);
|
||||||
|
srs_error_t do_handshake();
|
||||||
|
void state_trace(uint8_t* data, int length, bool incoming, int r0, int r1, bool cache, bool arq);
|
||||||
|
public:
|
||||||
|
srs_error_t get_srtp_key(std::string& recv_key, std::string& send_key);
|
||||||
|
protected:
|
||||||
|
virtual void on_ssl_out_data(uint8_t*& data, int& size, bool& cached) = 0;
|
||||||
|
virtual srs_error_t on_final_out_data(uint8_t* data, int size) = 0;
|
||||||
|
virtual srs_error_t on_handshake_done() = 0;
|
||||||
|
virtual bool is_dtls_client() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SrsDtlsClientImpl : virtual public SrsDtlsImpl, virtual public ISrsCoroutineHandler
|
||||||
|
{
|
||||||
|
private:
|
||||||
// ARQ thread, for role active(DTLS client).
|
// ARQ thread, for role active(DTLS client).
|
||||||
// @note If passive(DTLS server), the ARQ is driven by DTLS client.
|
// @note If passive(DTLS server), the ARQ is driven by DTLS client.
|
||||||
SrsCoroutine* trd;
|
SrsCoroutine* trd;
|
||||||
// The DTLS-client state to drive the ARQ thread.
|
// The DTLS-client state to drive the ARQ thread.
|
||||||
SrsDtlsState state_;
|
SrsDtlsState state_;
|
||||||
|
// The timeout for ARQ.
|
||||||
|
srs_utime_t arq_first;
|
||||||
|
srs_utime_t arq_interval;
|
||||||
|
public:
|
||||||
|
SrsDtlsClientImpl(ISrsDtlsCallback* callback);
|
||||||
|
virtual ~SrsDtlsClientImpl();
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(std::string version);
|
||||||
|
virtual srs_error_t start_active_handshake();
|
||||||
|
virtual srs_error_t on_dtls(char* data, int nb_data);
|
||||||
|
protected:
|
||||||
|
virtual void on_ssl_out_data(uint8_t*& data, int& size, bool& cached);
|
||||||
|
virtual srs_error_t on_final_out_data(uint8_t* data, int size);
|
||||||
|
virtual srs_error_t on_handshake_done();
|
||||||
|
virtual bool is_dtls_client();
|
||||||
private:
|
private:
|
||||||
// @remark: dtls_role_ default value is DTLS_SERVER.
|
srs_error_t start_arq();
|
||||||
SrsDtlsRole role_;
|
void stop_arq();
|
||||||
// @remark: dtls_version_ default value is SrsDtlsVersionAuto.
|
public:
|
||||||
SrsDtlsVersion version_;
|
virtual srs_error_t cycle();
|
||||||
|
};
|
||||||
|
|
||||||
|
class SrsDtlsServerImpl : public SrsDtlsImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SrsDtlsServerImpl(ISrsDtlsCallback* callback);
|
||||||
|
virtual ~SrsDtlsServerImpl();
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(std::string version);
|
||||||
|
virtual srs_error_t start_active_handshake();
|
||||||
|
protected:
|
||||||
|
virtual void on_ssl_out_data(uint8_t*& data, int& size, bool& cached);
|
||||||
|
virtual srs_error_t on_final_out_data(uint8_t* data, int size);
|
||||||
|
virtual srs_error_t on_handshake_done();
|
||||||
|
virtual bool is_dtls_client();
|
||||||
|
};
|
||||||
|
|
||||||
|
class SrsDtls
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
SrsDtlsImpl* impl;
|
||||||
|
ISrsDtlsCallback* callback_;
|
||||||
public:
|
public:
|
||||||
SrsDtls(ISrsDtlsCallback* callback);
|
SrsDtls(ISrsDtlsCallback* callback);
|
||||||
virtual ~SrsDtls();
|
virtual ~SrsDtls();
|
||||||
|
@ -141,17 +203,6 @@ public:
|
||||||
// When got DTLS packet, may handshake packets or application data.
|
// When got DTLS packet, may handshake packets or application data.
|
||||||
// @remark When we are passive(DTLS server), we start handshake when got DTLS packet.
|
// @remark When we are passive(DTLS server), we start handshake when got DTLS packet.
|
||||||
srs_error_t on_dtls(char* data, int nb_data);
|
srs_error_t on_dtls(char* data, int nb_data);
|
||||||
private:
|
|
||||||
srs_error_t do_on_dtls(char* data, int nb_data);
|
|
||||||
srs_error_t do_handshake();
|
|
||||||
// interface ISrsCoroutineHandler
|
|
||||||
public:
|
|
||||||
virtual srs_error_t cycle();
|
|
||||||
private:
|
|
||||||
void state_trace(uint8_t* data, int length, bool incoming, int r0, int r1, bool cache, bool arq);
|
|
||||||
private:
|
|
||||||
srs_error_t start_arq();
|
|
||||||
void stop_arq();
|
|
||||||
public:
|
public:
|
||||||
srs_error_t get_srtp_key(std::string& recv_key, std::string& send_key);
|
srs_error_t get_srtp_key(std::string& recv_key, std::string& send_key);
|
||||||
};
|
};
|
||||||
|
|
|
@ -189,6 +189,7 @@ SrsRtpNackForReceiver::SrsRtpNackForReceiver(SrsRtpRingBuffer* rtp, size_t queue
|
||||||
rtp_ = rtp;
|
rtp_ = rtp;
|
||||||
pre_check_time_ = 0;
|
pre_check_time_ = 0;
|
||||||
last_remove_packet_time_ = -1;
|
last_remove_packet_time_ = -1;
|
||||||
|
rtt_ = 0;
|
||||||
|
|
||||||
srs_info("max_queue_size=%u, nack opt: max_count=%d, max_alive_time=%us, first_nack_interval=%" PRId64 ", nack_interval=%" PRId64,
|
srs_info("max_queue_size=%u, nack opt: max_count=%d, max_alive_time=%us, first_nack_interval=%" PRId64 ", nack_interval=%" PRId64,
|
||||||
max_queue_size_, opts_.max_count, opts_.max_alive_time, opts.first_nack_interval, opts_.nack_interval);
|
max_queue_size_, opts_.max_count, opts_.max_alive_time, opts.first_nack_interval, opts_.nack_interval);
|
||||||
|
|
|
@ -254,6 +254,7 @@ srs_error_t SrsSSRCGroup::encode(std::ostringstream& os)
|
||||||
SrsMediaPayloadType::SrsMediaPayloadType(int payload_type)
|
SrsMediaPayloadType::SrsMediaPayloadType(int payload_type)
|
||||||
{
|
{
|
||||||
payload_type_ = payload_type;
|
payload_type_ = payload_type;
|
||||||
|
clock_rate_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsMediaPayloadType::~SrsMediaPayloadType()
|
SrsMediaPayloadType::~SrsMediaPayloadType()
|
||||||
|
@ -288,7 +289,9 @@ SrsMediaDesc::SrsMediaDesc(const std::string& type)
|
||||||
{
|
{
|
||||||
type_ = type;
|
type_ = type;
|
||||||
|
|
||||||
|
port_ = 0;
|
||||||
rtcp_mux_ = false;
|
rtcp_mux_ = false;
|
||||||
|
rtcp_rsize_ = false;
|
||||||
|
|
||||||
sendrecv_ = false;
|
sendrecv_ = false;
|
||||||
recvonly_ = false;
|
recvonly_ = false;
|
||||||
|
@ -315,7 +318,7 @@ vector<SrsMediaPayloadType> SrsMediaDesc::find_media_with_encoding_name(const st
|
||||||
{
|
{
|
||||||
std::vector<SrsMediaPayloadType> payloads;
|
std::vector<SrsMediaPayloadType> payloads;
|
||||||
|
|
||||||
std::string lower_name, upper_name;
|
std::string lower_name(encoding_name), upper_name(encoding_name);
|
||||||
transform(encoding_name.begin(), encoding_name.end(), lower_name.begin(), ::tolower);
|
transform(encoding_name.begin(), encoding_name.end(), lower_name.begin(), ::tolower);
|
||||||
transform(encoding_name.begin(), encoding_name.end(), upper_name.begin(), ::toupper);
|
transform(encoding_name.begin(), encoding_name.end(), upper_name.begin(), ::toupper);
|
||||||
|
|
||||||
|
@ -1062,3 +1065,10 @@ srs_error_t SrsSdp::parse_media_description(const std::string& content)
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SrsSdp::is_unified() const
|
||||||
|
{
|
||||||
|
// TODO: FIXME: Maybe we should consider other situations.
|
||||||
|
return media_descs_.size() > 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -246,6 +246,8 @@ public:
|
||||||
|
|
||||||
// m-line, media sessions
|
// m-line, media sessions
|
||||||
std::vector<SrsMediaDesc> media_descs_;
|
std::vector<SrsMediaDesc> media_descs_;
|
||||||
|
|
||||||
|
bool is_unified() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -513,7 +513,7 @@ srs_error_t SrsRtcServer::do_create_session(
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsRtcServer::create_session2(SrsRequest* req, SrsSdp& local_sdp, const std::string& mock_eip, SrsRtcConnection** psession)
|
srs_error_t SrsRtcServer::create_session2(SrsRequest* req, SrsSdp& local_sdp, const std::string& mock_eip, bool unified_plan, SrsRtcConnection** psession)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
@ -525,7 +525,7 @@ srs_error_t SrsRtcServer::create_session2(SrsRequest* req, SrsSdp& local_sdp, co
|
||||||
|
|
||||||
SrsRtcConnection* session = new SrsRtcConnection(this, cid);
|
SrsRtcConnection* session = new SrsRtcConnection(this, cid);
|
||||||
// first add player for negotiate local sdp media info
|
// first add player for negotiate local sdp media info
|
||||||
if ((err = session->add_player2(req, local_sdp)) != srs_success) {
|
if ((err = session->add_player2(req, unified_plan, local_sdp)) != srs_success) {
|
||||||
srs_freep(session);
|
srs_freep(session);
|
||||||
return srs_error_wrap(err, "add player2");
|
return srs_error_wrap(err, "add player2");
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,7 @@ private:
|
||||||
);
|
);
|
||||||
public:
|
public:
|
||||||
// We start offering, create_session2 to generate offer, setup_session2 to handle answer.
|
// We start offering, create_session2 to generate offer, setup_session2 to handle answer.
|
||||||
srs_error_t create_session2(SrsRequest* req, SrsSdp& local_sdp, const std::string& mock_eip, SrsRtcConnection** psession);
|
srs_error_t create_session2(SrsRequest* req, SrsSdp& local_sdp, const std::string& mock_eip, bool unified_plan, SrsRtcConnection** psession);
|
||||||
srs_error_t setup_session2(SrsRtcConnection* session, SrsRequest* req, const SrsSdp& remote_sdp);
|
srs_error_t setup_session2(SrsRtcConnection* session, SrsRequest* req, const SrsSdp& remote_sdp);
|
||||||
// Destroy the session from server.
|
// Destroy the session from server.
|
||||||
void destroy(SrsRtcConnection* session);
|
void destroy(SrsRtcConnection* session);
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include <srs_app_rtc_conn.hpp>
|
#include <srs_app_rtc_conn.hpp>
|
||||||
#include <srs_protocol_utility.hpp>
|
#include <srs_protocol_utility.hpp>
|
||||||
#include <srs_protocol_json.hpp>
|
#include <srs_protocol_json.hpp>
|
||||||
|
#include <srs_app_pithy_print.hpp>
|
||||||
|
|
||||||
#ifdef SRS_FFMPEG_FIT
|
#ifdef SRS_FFMPEG_FIT
|
||||||
#include <srs_app_rtc_codec.hpp>
|
#include <srs_app_rtc_codec.hpp>
|
||||||
|
@ -539,6 +540,8 @@ SrsRtcFromRtmpBridger::SrsRtcFromRtmpBridger(SrsRtcStream* source)
|
||||||
// audio track description
|
// audio track description
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsRtcTrackDescription* audio_track_desc = new SrsRtcTrackDescription();
|
SrsRtcTrackDescription* audio_track_desc = new SrsRtcTrackDescription();
|
||||||
|
SrsAutoFree(SrsRtcTrackDescription, audio_track_desc);
|
||||||
|
|
||||||
audio_track_desc->type_ = "audio";
|
audio_track_desc->type_ = "audio";
|
||||||
audio_track_desc->id_ = "audio-" + srs_random_str(8);
|
audio_track_desc->id_ = "audio-" + srs_random_str(8);
|
||||||
|
|
||||||
|
@ -553,6 +556,8 @@ SrsRtcFromRtmpBridger::SrsRtcFromRtmpBridger(SrsRtcStream* source)
|
||||||
// video track description
|
// video track description
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsRtcTrackDescription* video_track_desc = new SrsRtcTrackDescription();
|
SrsRtcTrackDescription* video_track_desc = new SrsRtcTrackDescription();
|
||||||
|
SrsAutoFree(SrsRtcTrackDescription, video_track_desc);
|
||||||
|
|
||||||
video_track_desc->type_ = "video";
|
video_track_desc->type_ = "video";
|
||||||
video_track_desc->id_ = "video-" + srs_random_str(8);
|
video_track_desc->id_ = "video-" + srs_random_str(8);
|
||||||
|
|
||||||
|
@ -1117,6 +1122,8 @@ void SrsRtcDummyBridger::on_unpublish()
|
||||||
|
|
||||||
SrsCodecPayload::SrsCodecPayload()
|
SrsCodecPayload::SrsCodecPayload()
|
||||||
{
|
{
|
||||||
|
pt_ = 0;
|
||||||
|
sample_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsCodecPayload::SrsCodecPayload(uint8_t pt, std::string encode_name, int sample)
|
SrsCodecPayload::SrsCodecPayload(uint8_t pt, std::string encode_name, int sample)
|
||||||
|
@ -1249,7 +1256,7 @@ srs_error_t SrsVideoPayload::set_h264_param_desc(std::string fmtp)
|
||||||
|
|
||||||
SrsAudioPayload::SrsAudioPayload()
|
SrsAudioPayload::SrsAudioPayload()
|
||||||
{
|
{
|
||||||
type_ = "audio";
|
channel_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsAudioPayload::SrsAudioPayload(uint8_t pt, std::string encode_name, int sample, int channel)
|
SrsAudioPayload::SrsAudioPayload(uint8_t pt, std::string encode_name, int sample, int channel)
|
||||||
|
@ -1331,6 +1338,7 @@ srs_error_t SrsAudioPayload::set_opus_param_desc(std::string fmtp)
|
||||||
|
|
||||||
SrsRedPayload::SrsRedPayload()
|
SrsRedPayload::SrsRedPayload()
|
||||||
{
|
{
|
||||||
|
channel_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRedPayload::SrsRedPayload(uint8_t pt, std::string encode_name, int sample, int channel)
|
SrsRedPayload::SrsRedPayload(uint8_t pt, std::string encode_name, int sample, int channel)
|
||||||
|
@ -1604,6 +1612,8 @@ SrsRtcRecvTrack::SrsRtcRecvTrack(SrsRtcConnection* session, SrsRtcTrackDescripti
|
||||||
rtp_queue_ = new SrsRtpRingBuffer(1000);
|
rtp_queue_ = new SrsRtpRingBuffer(1000);
|
||||||
nack_receiver_ = new SrsRtpNackForReceiver(rtp_queue_, 1000 * 2 / 3);
|
nack_receiver_ = new SrsRtpNackForReceiver(rtp_queue_, 1000 * 2 / 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
last_sender_report_sys_time = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcRecvTrack::~SrsRtcRecvTrack()
|
SrsRtcRecvTrack::~SrsRtcRecvTrack()
|
||||||
|
@ -1804,6 +1814,8 @@ SrsRtcSendTrack::SrsRtcSendTrack(SrsRtcConnection* session, SrsRtcTrackDescripti
|
||||||
} else {
|
} else {
|
||||||
rtp_queue_ = new SrsRtpRingBuffer(1000);
|
rtp_queue_ = new SrsRtpRingBuffer(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nack_epp = new SrsErrorPithyPrint();
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcSendTrack::~SrsRtcSendTrack()
|
SrsRtcSendTrack::~SrsRtcSendTrack()
|
||||||
|
@ -1811,6 +1823,7 @@ SrsRtcSendTrack::~SrsRtcSendTrack()
|
||||||
srs_freep(rtp_queue_);
|
srs_freep(rtp_queue_);
|
||||||
srs_freep(track_desc_);
|
srs_freep(track_desc_);
|
||||||
srs_freep(statistic_);
|
srs_freep(statistic_);
|
||||||
|
srs_freep(nack_epp);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SrsRtcSendTrack::has_ssrc(uint32_t ssrc)
|
bool SrsRtcSendTrack::has_ssrc(uint32_t ssrc)
|
||||||
|
@ -1827,12 +1840,18 @@ SrsRtpPacket2* SrsRtcSendTrack::fetch_rtp_packet(uint16_t seq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// For NACK, it sequence must match exactly, or it cause SRTP fail.
|
// For NACK, it sequence must match exactly, or it cause SRTP fail.
|
||||||
if (pkt->header.get_sequence() != seq) {
|
// Return packet only when sequence is equal.
|
||||||
srs_trace("miss match seq=%u, pkt seq=%u", seq, pkt->header.get_sequence());
|
if (pkt->header.get_sequence() == seq) {
|
||||||
return NULL;
|
return pkt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pkt;
|
// Ignore if sequence not match.
|
||||||
|
uint32_t nn = 0;
|
||||||
|
if (nack_epp->can_print(pkt->header.get_ssrc(), &nn)) {
|
||||||
|
srs_trace("RTC NACK miss seq=%u, require_seq=%u, ssrc=%u, ts=%u, count=%u/%u, %d bytes", seq, pkt->header.get_sequence(),
|
||||||
|
pkt->header.get_ssrc(), pkt->header.get_timestamp(), nn, nack_epp->nn_count, pkt->nb_bytes());
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: FIXME: Should refine logs, set tracks in a time.
|
// TODO: FIXME: Should refine logs, set tracks in a time.
|
||||||
|
|
|
@ -55,6 +55,7 @@ class SrsRtpRingBuffer;
|
||||||
class SrsRtpNackForReceiver;
|
class SrsRtpNackForReceiver;
|
||||||
class SrsJsonObject;
|
class SrsJsonObject;
|
||||||
class SrsRtcPlayStreamStatistic;
|
class SrsRtcPlayStreamStatistic;
|
||||||
|
class SrsErrorPithyPrint;
|
||||||
|
|
||||||
class SrsNtp
|
class SrsNtp
|
||||||
{
|
{
|
||||||
|
@ -308,6 +309,12 @@ class SrsAudioPayload : public SrsCodecPayload
|
||||||
int minptime;
|
int minptime;
|
||||||
bool use_inband_fec;
|
bool use_inband_fec;
|
||||||
bool usedtx;
|
bool usedtx;
|
||||||
|
|
||||||
|
SrsOpusParameter() {
|
||||||
|
minptime = 0;
|
||||||
|
use_inband_fec = false;
|
||||||
|
usedtx = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -524,11 +531,14 @@ protected:
|
||||||
// send track description
|
// send track description
|
||||||
SrsRtcTrackDescription* track_desc_;
|
SrsRtcTrackDescription* track_desc_;
|
||||||
SrsRtcTrackStatistic* statistic_;
|
SrsRtcTrackStatistic* statistic_;
|
||||||
|
protected:
|
||||||
// The owner connection for this track.
|
// The owner connection for this track.
|
||||||
SrsRtcConnection* session_;
|
SrsRtcConnection* session_;
|
||||||
// NACK ARQ ring buffer.
|
// NACK ARQ ring buffer.
|
||||||
SrsRtpRingBuffer* rtp_queue_;
|
SrsRtpRingBuffer* rtp_queue_;
|
||||||
|
private:
|
||||||
|
// The pithy print for special stage.
|
||||||
|
SrsErrorPithyPrint* nack_epp;
|
||||||
public:
|
public:
|
||||||
SrsRtcSendTrack(SrsRtcConnection* session, SrsRtcTrackDescription* track_desc, bool is_audio);
|
SrsRtcSendTrack(SrsRtcConnection* session, SrsRtcTrackDescription* track_desc, bool is_audio);
|
||||||
virtual ~SrsRtcSendTrack();
|
virtual ~SrsRtcSendTrack();
|
||||||
|
|
|
@ -121,6 +121,9 @@ SrsRtmpConn::SrsRtmpConn(SrsServer* svr, srs_netfd_t c, string cip, int port) :
|
||||||
send_min_interval = 0;
|
send_min_interval = 0;
|
||||||
tcp_nodelay = false;
|
tcp_nodelay = false;
|
||||||
info = new SrsClientInfo();
|
info = new SrsClientInfo();
|
||||||
|
|
||||||
|
publish_1stpkt_timeout = 0;
|
||||||
|
publish_normal_timeout = 0;
|
||||||
|
|
||||||
_srs_config->subscribe(this);
|
_srs_config->subscribe(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,6 +193,11 @@ SrsRtspConn::SrsRtspConn(SrsRtspCaster* c, srs_netfd_t fd, std::string o)
|
||||||
skt = new SrsStSocket();
|
skt = new SrsStSocket();
|
||||||
rtsp = new SrsRtspStack(skt);
|
rtsp = new SrsRtspStack(skt);
|
||||||
trd = new SrsSTCoroutine("rtsp", this);
|
trd = new SrsSTCoroutine("rtsp", this);
|
||||||
|
|
||||||
|
audio_id = 0;
|
||||||
|
video_id = 0;
|
||||||
|
audio_sample_rate = 0;
|
||||||
|
audio_channel = 0;
|
||||||
|
|
||||||
req = NULL;
|
req = NULL;
|
||||||
sdk = NULL;
|
sdk = NULL;
|
||||||
|
@ -223,6 +228,9 @@ SrsRtspConn::~SrsRtspConn()
|
||||||
|
|
||||||
srs_freep(vjitter);
|
srs_freep(vjitter);
|
||||||
srs_freep(ajitter);
|
srs_freep(ajitter);
|
||||||
|
|
||||||
|
srs_freep(avc);
|
||||||
|
srs_freep(aac);
|
||||||
srs_freep(acodec);
|
srs_freep(acodec);
|
||||||
srs_freep(acache);
|
srs_freep(acache);
|
||||||
}
|
}
|
||||||
|
|
|
@ -380,7 +380,7 @@ SrsSignalManager::SrsSignalManager(SrsServer* s)
|
||||||
|
|
||||||
server = s;
|
server = s;
|
||||||
sig_pipe[0] = sig_pipe[1] = -1;
|
sig_pipe[0] = sig_pipe[1] = -1;
|
||||||
trd = new SrsSTCoroutine("signal", this);
|
trd = new SrsSTCoroutine("signal", this, _srs_context->get_id());
|
||||||
signal_read_stfd = NULL;
|
signal_read_stfd = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,7 +539,7 @@ srs_error_t SrsInotifyWorker::start()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((err = srs_fd_closeexec(fd))) != srs_success) {
|
if (((err = srs_fd_closeexec(fd))) != srs_success) {
|
||||||
return srs_error_new(ERROR_INOTIFY_OPENFD, "closeexec fd=%d", fd);
|
return srs_error_wrap(err, "closeexec fd=%d", fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// /* the following are legal, implemented events that user-space can watch for */
|
// /* the following are legal, implemented events that user-space can watch for */
|
||||||
|
@ -877,7 +877,7 @@ srs_error_t SrsServer::acquire_pid_file()
|
||||||
// write the pid
|
// write the pid
|
||||||
string pid = srs_int2str(getpid());
|
string pid = srs_int2str(getpid());
|
||||||
if (write(fd, pid.c_str(), pid.length()) != (int)pid.length()) {
|
if (write(fd, pid.c_str(), pid.length()) != (int)pid.length()) {
|
||||||
return srs_error_new(ERROR_SYSTEM_PID_WRITE_FILE, "write pid=%d to file=%s", pid.c_str(), pid_file.c_str());
|
return srs_error_new(ERROR_SYSTEM_PID_WRITE_FILE, "write pid=%s to file=%s", pid.c_str(), pid_file.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// auto close when fork child process.
|
// auto close when fork child process.
|
||||||
|
|
|
@ -940,6 +940,9 @@ SrsNetworkRtmpServer::SrsNetworkRtmpServer()
|
||||||
nb_conn_sys = nb_conn_srs = 0;
|
nb_conn_sys = nb_conn_srs = 0;
|
||||||
nb_conn_sys_et = nb_conn_sys_tw = 0;
|
nb_conn_sys_et = nb_conn_sys_tw = 0;
|
||||||
nb_conn_sys_udp = 0;
|
nb_conn_sys_udp = 0;
|
||||||
|
rkbps = skbps = 0;
|
||||||
|
rkbps_30s = skbps_30s = 0;
|
||||||
|
rkbps_5m = skbps_5m = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SrsNetworkRtmpServer _srs_network_rtmp_server;
|
static SrsNetworkRtmpServer _srs_network_rtmp_server;
|
||||||
|
@ -1298,24 +1301,25 @@ string srs_string_dumps_hex(const char* str, int length, int limit)
|
||||||
|
|
||||||
string srs_string_dumps_hex(const char* str, int length, int limit, char seperator, int line_limit, char newline)
|
string srs_string_dumps_hex(const char* str, int length, int limit, char seperator, int line_limit, char newline)
|
||||||
{
|
{
|
||||||
const int LIMIT = 1024*16;
|
// 1 byte trailing '\0'.
|
||||||
|
const int LIMIT = 1024*16 + 1;
|
||||||
static char buf[LIMIT];
|
static char buf[LIMIT];
|
||||||
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
for (int i = 0; i < length && i < limit && i < LIMIT; ++i) {
|
for (int i = 0; i < length && i < limit && len < LIMIT; ++i) {
|
||||||
int nb = snprintf(buf + len, LIMIT - len, "%02x", (uint8_t)str[i]);
|
int nb = snprintf(buf + len, LIMIT - len, "%02x", (uint8_t)str[i]);
|
||||||
if (nb < 0 || nb > LIMIT - len) {
|
if (nb < 0 || nb >= LIMIT - len) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
len += nb;
|
len += nb;
|
||||||
|
|
||||||
// Only append seperator and newline when not last byte.
|
// Only append seperator and newline when not last byte.
|
||||||
if (i < length - 1 && i < limit - 1 && i < LIMIT - 1) {
|
if (i < length - 1 && i < limit - 1 && len < LIMIT) {
|
||||||
if (seperator && len < LIMIT) {
|
if (seperator) {
|
||||||
buf[len++] = seperator;
|
buf[len++] = seperator;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newline && line_limit && i > 0 && ((i + 1) % line_limit) == 0 && len < LIMIT) {
|
if (newline && line_limit && i > 0 && ((i + 1) % line_limit) == 0) {
|
||||||
buf[len++] = newline;
|
buf[len++] = newline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1325,6 +1329,17 @@ string srs_string_dumps_hex(const char* str, int length, int limit, char seperat
|
||||||
if (len <= 0) {
|
if (len <= 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If overflow, cut the trailing newline.
|
||||||
|
if (newline && len >= LIMIT - 2 && buf[len - 1] == newline) {
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If overflow, cut the trailing seperator.
|
||||||
|
if (seperator && len >= LIMIT - 3 && buf[len - 1] == seperator) {
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
|
||||||
return string(buf, len);
|
return string(buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,6 @@ _SrsContextId::_SrsContextId()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
_SrsContextId::_SrsContextId(std::string v)
|
|
||||||
{
|
|
||||||
v_ = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
_SrsContextId::_SrsContextId(const _SrsContextId& cp)
|
_SrsContextId::_SrsContextId(const _SrsContextId& cp)
|
||||||
{
|
{
|
||||||
v_ = cp.v_;
|
v_ = cp.v_;
|
||||||
|
@ -62,3 +57,9 @@ int _SrsContextId::compare(const _SrsContextId& to) const
|
||||||
return v_.compare(to.v_);
|
return v_.compare(to.v_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_SrsContextId& _SrsContextId::set_value(const std::string& v)
|
||||||
|
{
|
||||||
|
v_ = v;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,6 @@ private:
|
||||||
std::string v_;
|
std::string v_;
|
||||||
public:
|
public:
|
||||||
_SrsContextId();
|
_SrsContextId();
|
||||||
_SrsContextId(std::string v);
|
|
||||||
_SrsContextId(const _SrsContextId& cp);
|
_SrsContextId(const _SrsContextId& cp);
|
||||||
_SrsContextId& operator=(const _SrsContextId& cp);
|
_SrsContextId& operator=(const _SrsContextId& cp);
|
||||||
virtual ~_SrsContextId();
|
virtual ~_SrsContextId();
|
||||||
|
@ -136,6 +135,8 @@ public:
|
||||||
// <0 Either the value of the first character that does not match is lower in the compared string, or all compared characters match but the compared string is shorter.
|
// <0 Either the value of the first character that does not match is lower in the compared string, or all compared characters match but the compared string is shorter.
|
||||||
// >0 Either the value of the first character that does not match is greater in the compared string, or all compared characters match but the compared string is longer.
|
// >0 Either the value of the first character that does not match is greater in the compared string, or all compared characters match but the compared string is longer.
|
||||||
int compare(const _SrsContextId& to) const;
|
int compare(const _SrsContextId& to) const;
|
||||||
|
// Set the value of context id.
|
||||||
|
_SrsContextId& set_value(const std::string& v);
|
||||||
};
|
};
|
||||||
typedef _SrsContextId SrsContextId;
|
typedef _SrsContextId SrsContextId;
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -24,6 +24,6 @@
|
||||||
#ifndef SRS_CORE_VERSION4_HPP
|
#ifndef SRS_CORE_VERSION4_HPP
|
||||||
#define SRS_CORE_VERSION4_HPP
|
#define SRS_CORE_VERSION4_HPP
|
||||||
|
|
||||||
#define SRS_VERSION4_REVISION 38
|
#define SRS_VERSION4_REVISION 39
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -46,6 +46,8 @@ SrsAacTransmuxer::SrsAacTransmuxer()
|
||||||
writer = NULL;
|
writer = NULL;
|
||||||
got_sequence_header = false;
|
got_sequence_header = false;
|
||||||
aac_object = SrsAacObjectTypeReserved;
|
aac_object = SrsAacObjectTypeReserved;
|
||||||
|
aac_sample_rate = 0;
|
||||||
|
aac_channels = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsAacTransmuxer::~SrsAacTransmuxer()
|
SrsAacTransmuxer::~SrsAacTransmuxer()
|
||||||
|
|
|
@ -3912,7 +3912,7 @@ srs_error_t SrsMp4DecodingTime2SampleBox::on_sample(uint32_t sample_index, SrsMp
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
if (index >= entries.size()) {
|
if (index >= entries.size()) {
|
||||||
return srs_error_new(ERROR_MP4_ILLEGAL_TIMESTAMP, "illegal ts, stts overflow, count=%d", entries.size());
|
return srs_error_new(ERROR_MP4_ILLEGAL_TIMESTAMP, "illegal ts, stts overflow, count=%zd", entries.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
count += entries[index].sample_count;
|
count += entries[index].sample_count;
|
||||||
|
@ -4038,7 +4038,7 @@ srs_error_t SrsMp4CompositionTime2SampleBox::on_sample(uint32_t sample_index, Sr
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
if (index >= entries.size()) {
|
if (index >= entries.size()) {
|
||||||
return srs_error_new(ERROR_MP4_ILLEGAL_TIMESTAMP, "illegal ts, ctts overflow, count=%d", entries.size());
|
return srs_error_new(ERROR_MP4_ILLEGAL_TIMESTAMP, "illegal ts, ctts overflow, count=%d", (int)entries.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
count += entries[index].sample_count;
|
count += entries[index].sample_count;
|
||||||
|
@ -4581,6 +4581,8 @@ SrsMp4SegmentIndexBox::SrsMp4SegmentIndexBox()
|
||||||
{
|
{
|
||||||
type = SrsMp4BoxTypeSIDX;
|
type = SrsMp4BoxTypeSIDX;
|
||||||
version = 0;
|
version = 0;
|
||||||
|
flags = reference_id = timescale = 0;
|
||||||
|
earliest_presentation_time = first_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsMp4SegmentIndexBox::~SrsMp4SegmentIndexBox()
|
SrsMp4SegmentIndexBox::~SrsMp4SegmentIndexBox()
|
||||||
|
@ -5215,7 +5217,7 @@ srs_error_t SrsMp4BoxReader::read(SrsSimpleStream* stream, SrsMp4Box** ppbox)
|
||||||
while (stream->length() < (int)required) {
|
while (stream->length() < (int)required) {
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
if ((err = rsio->read(buf, SRS_MP4_BUF_SIZE, &nread)) != srs_success) {
|
if ((err = rsio->read(buf, SRS_MP4_BUF_SIZE, &nread)) != srs_success) {
|
||||||
return srs_error_wrap(err, "load failed, nread=%d, required=%d", nread, required);
|
return srs_error_wrap(err, "load failed, nread=%d, required=%d", (int)nread, (int)required);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_assert(nread > 0);
|
srs_assert(nread > 0);
|
||||||
|
@ -6280,6 +6282,7 @@ SrsMp4M2tsSegmentEncoder::SrsMp4M2tsSegmentEncoder()
|
||||||
decode_basetime = 0;
|
decode_basetime = 0;
|
||||||
styp_bytes = 0;
|
styp_bytes = 0;
|
||||||
mdat_bytes = 0;
|
mdat_bytes = 0;
|
||||||
|
track_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsMp4M2tsSegmentEncoder::~SrsMp4M2tsSegmentEncoder()
|
SrsMp4M2tsSegmentEncoder::~SrsMp4M2tsSegmentEncoder()
|
||||||
|
|
|
@ -31,6 +31,7 @@ using namespace std;
|
||||||
|
|
||||||
SrsRtcpCommon::SrsRtcpCommon(): ssrc_(0), data_(NULL), nb_data_(0)
|
SrsRtcpCommon::SrsRtcpCommon(): ssrc_(0), data_(NULL), nb_data_(0)
|
||||||
{
|
{
|
||||||
|
payload_len_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcpCommon::~SrsRtcpCommon()
|
SrsRtcpCommon::~SrsRtcpCommon()
|
||||||
|
@ -165,7 +166,7 @@ uint8_t SrsRtcpApp::get_subtype() const
|
||||||
|
|
||||||
string SrsRtcpApp::get_name() const
|
string SrsRtcpApp::get_name() const
|
||||||
{
|
{
|
||||||
return string((char*)name_);
|
return string((char*)name_, strnlen((char*)name_, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsRtcpApp::get_payload(uint8_t*& payload, int& len)
|
srs_error_t SrsRtcpApp::get_payload(uint8_t*& payload, int& len)
|
||||||
|
@ -190,7 +191,7 @@ srs_error_t SrsRtcpApp::set_subtype(uint8_t type)
|
||||||
srs_error_t SrsRtcpApp::set_name(std::string name)
|
srs_error_t SrsRtcpApp::set_name(std::string name)
|
||||||
{
|
{
|
||||||
if(name.length() > 4) {
|
if(name.length() > 4) {
|
||||||
return srs_error_new(ERROR_RTC_RTCP, "invalid name length %d", name.length());
|
return srs_error_new(ERROR_RTC_RTCP, "invalid name length %zu", name.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(name_, 0, sizeof(name_));
|
memset(name_, 0, sizeof(name_));
|
||||||
|
@ -298,6 +299,13 @@ SrsRtcpSR::SrsRtcpSR()
|
||||||
header_.rc = 0;
|
header_.rc = 0;
|
||||||
header_.version = kRtcpVersion;
|
header_.version = kRtcpVersion;
|
||||||
header_.length = 6;
|
header_.length = 6;
|
||||||
|
|
||||||
|
ssrc_ = 0;
|
||||||
|
ntp_ = 0;
|
||||||
|
rtp_ts_ = 0;
|
||||||
|
send_rtp_packets_ = 0;
|
||||||
|
send_rtp_bytes_ = 0;
|
||||||
|
send_rtp_bytes_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcpSR::~SrsRtcpSR()
|
SrsRtcpSR::~SrsRtcpSR()
|
||||||
|
@ -706,6 +714,11 @@ SrsRtcpTWCC::SrsRtcpTWCC(uint32_t sender_ssrc) : pkt_len(0)
|
||||||
header_.rc = 15;
|
header_.rc = 15;
|
||||||
header_.version = kRtcpVersion;
|
header_.version = kRtcpVersion;
|
||||||
ssrc_ = sender_ssrc;
|
ssrc_ = sender_ssrc;
|
||||||
|
media_ssrc_ = 0;
|
||||||
|
base_sn_ = 0;
|
||||||
|
packet_count_ = 0;
|
||||||
|
reference_time_ = 0;
|
||||||
|
fb_pkt_count_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcpTWCC::~SrsRtcpTWCC()
|
SrsRtcpTWCC::~SrsRtcpTWCC()
|
||||||
|
@ -1032,7 +1045,7 @@ srs_error_t SrsRtcpTWCC::process_pkt_chunk(SrsRtcpTWCC::SrsRtcpTWCCChunk& chunk,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
if ((err = encode_chunk(chunk)) != srs_success) {
|
if ((err = encode_chunk(chunk)) != srs_success) {
|
||||||
return srs_error_new(ERROR_RTC_RTCP, "encode chunk, delta_size %u", delta_size);
|
return srs_error_wrap(err, "encode chunk, delta_size %u", delta_size);
|
||||||
}
|
}
|
||||||
add_to_chunk(chunk, delta_size);
|
add_to_chunk(chunk, delta_size);
|
||||||
return err;
|
return err;
|
||||||
|
@ -1118,7 +1131,7 @@ srs_error_t SrsRtcpTWCC::do_encode(SrsBuffer *buffer)
|
||||||
// FIXME 24-bit base receive delta not supported
|
// FIXME 24-bit base receive delta not supported
|
||||||
int recv_delta_size = (delta >= 0 && delta <= 0xff) ? 1 : 2;
|
int recv_delta_size = (delta >= 0 && delta <= 0xff) ? 1 : 2;
|
||||||
if ((err = process_pkt_chunk(chunk, recv_delta_size)) != srs_success) {
|
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);
|
return srs_error_wrap(err, "delta_size %d, failed to append_recv_delta", recv_delta_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
pkt_deltas_.push_back(delta);
|
pkt_deltas_.push_back(delta);
|
||||||
|
@ -1178,6 +1191,7 @@ SrsRtcpNack::SrsRtcpNack(uint32_t sender_ssrc)
|
||||||
header_.rc = 1;
|
header_.rc = 1;
|
||||||
header_.version = kRtcpVersion;
|
header_.version = kRtcpVersion;
|
||||||
ssrc_ = sender_ssrc;
|
ssrc_ = sender_ssrc;
|
||||||
|
media_ssrc_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcpNack::~SrsRtcpNack()
|
SrsRtcpNack::~SrsRtcpNack()
|
||||||
|
|
|
@ -66,6 +66,14 @@ struct SrsRtcpHeader
|
||||||
uint16_t type:8;
|
uint16_t type:8;
|
||||||
|
|
||||||
uint16_t length:16;
|
uint16_t length:16;
|
||||||
|
|
||||||
|
SrsRtcpHeader() {
|
||||||
|
rc = 0;
|
||||||
|
padding = 0;
|
||||||
|
version = 0;
|
||||||
|
type = 0;
|
||||||
|
length = 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsRtcpCommon: public ISrsCodec
|
class SrsRtcpCommon: public ISrsCodec
|
||||||
|
@ -134,6 +142,16 @@ struct SrsRtcpRB
|
||||||
uint32_t jitter;
|
uint32_t jitter;
|
||||||
uint32_t lsr;
|
uint32_t lsr;
|
||||||
uint32_t dlsr;
|
uint32_t dlsr;
|
||||||
|
|
||||||
|
SrsRtcpRB() {
|
||||||
|
ssrc = 0;
|
||||||
|
fraction_lost = 0;
|
||||||
|
lost_packets = 0;
|
||||||
|
highest_sn = 0;
|
||||||
|
jitter = 0;
|
||||||
|
lsr = 0;
|
||||||
|
dlsr = 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsRtcpSR : public SrsRtcpCommon
|
class SrsRtcpSR : public SrsRtcpCommon
|
||||||
|
|
|
@ -63,7 +63,7 @@ SrsRtpExtensionTypes::~SrsRtpExtensionTypes()
|
||||||
|
|
||||||
bool SrsRtpExtensionTypes::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) {
|
for (int i = 0; i < (int)(sizeof(kExtensions)/sizeof(kExtensions[0])); ++i) {
|
||||||
if (kExtensions[i].uri == uri) {
|
if (kExtensions[i].uri == uri) {
|
||||||
return register_id(id, kExtensions[i].type, kExtensions[i].uri);
|
return register_id(id, kExtensions[i].type, kExtensions[i].uri);
|
||||||
}
|
}
|
||||||
|
@ -247,7 +247,7 @@ srs_error_t SrsRtpExtensions::decode_0xbede(SrsBuffer* buf)
|
||||||
|
|
||||||
SrsRtpExtensionType xtype = types_.get_type(id);
|
SrsRtpExtensionType xtype = types_.get_type(id);
|
||||||
if (xtype == kRtpExtensionTransportSequenceNumber) {
|
if (xtype == kRtpExtensionTransportSequenceNumber) {
|
||||||
if (srs_success != (err = twcc_.decode(buf))) {
|
if ((err = twcc_.decode(buf)) != srs_success) {
|
||||||
return srs_error_wrap(err, "decode twcc extension");
|
return srs_error_wrap(err, "decode twcc extension");
|
||||||
}
|
}
|
||||||
has_ext_ = true;
|
has_ext_ = true;
|
||||||
|
@ -287,7 +287,7 @@ srs_error_t SrsRtpExtensions::encode(SrsBuffer* buf)
|
||||||
|
|
||||||
// Write extensions.
|
// Write extensions.
|
||||||
if (twcc_.has_twcc_ext()) {
|
if (twcc_.has_twcc_ext()) {
|
||||||
if (srs_success != (err = twcc_.encode(buf))) {
|
if ((err = twcc_.encode(buf)) != srs_success) {
|
||||||
return srs_error_wrap(err, "encode twcc extension");
|
return srs_error_wrap(err, "encode twcc extension");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1275,6 +1275,41 @@ SrsTsPayloadPES::SrsTsPayloadPES(SrsTsPacket* p) : SrsTsPayload(p)
|
||||||
nb_paddings = 0;
|
nb_paddings = 0;
|
||||||
const2bits = 0x02;
|
const2bits = 0x02;
|
||||||
const1_value0 = 0x07;
|
const1_value0 = 0x07;
|
||||||
|
|
||||||
|
packet_start_code_prefix = 0;
|
||||||
|
stream_id = 0;
|
||||||
|
PES_packet_length = 0;
|
||||||
|
PES_scrambling_control = 0;
|
||||||
|
PES_priority = 0;
|
||||||
|
data_alignment_indicator = 0;
|
||||||
|
copyright = 0;
|
||||||
|
original_or_copy = 0;
|
||||||
|
PTS_DTS_flags = 0;
|
||||||
|
ESCR_flag = 0;
|
||||||
|
ES_rate_flag = 0;
|
||||||
|
DSM_trick_mode_flag = 0;
|
||||||
|
additional_copy_info_flag = 0;
|
||||||
|
PES_CRC_flag = 0;
|
||||||
|
PES_extension_flag = 0;
|
||||||
|
PES_header_data_length = 0;
|
||||||
|
pts = dts = 0;
|
||||||
|
ESCR_base = 0;
|
||||||
|
ESCR_extension = 0;
|
||||||
|
ES_rate = 0;
|
||||||
|
trick_mode_control = 0;
|
||||||
|
trick_mode_value = 0;
|
||||||
|
additional_copy_info = 0;
|
||||||
|
previous_PES_packet_CRC = 0;
|
||||||
|
PES_private_data_flag = 0;
|
||||||
|
pack_header_field_flag = 0;
|
||||||
|
program_packet_sequence_counter_flag = 0;
|
||||||
|
P_STD_buffer_flag = 0;
|
||||||
|
PES_extension_flag_2 = 0;
|
||||||
|
program_packet_sequence_counter = 0;
|
||||||
|
MPEG1_MPEG2_identifier = 0;
|
||||||
|
original_stuff_length = 0;
|
||||||
|
P_STD_buffer_scale = 0;
|
||||||
|
P_STD_buffer_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTsPayloadPES::~SrsTsPayloadPES()
|
SrsTsPayloadPES::~SrsTsPayloadPES()
|
||||||
|
@ -1977,6 +2012,9 @@ SrsTsPayloadPSI::SrsTsPayloadPSI(SrsTsPacket* p) : SrsTsPayload(p)
|
||||||
const0_value = 0;
|
const0_value = 0;
|
||||||
const1_value = 3;
|
const1_value = 3;
|
||||||
CRC_32 = 0;
|
CRC_32 = 0;
|
||||||
|
section_length = 0;
|
||||||
|
section_syntax_indicator = 0;
|
||||||
|
table_id = SrsTsPsiIdPas;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTsPayloadPSI::~SrsTsPayloadPSI()
|
SrsTsPayloadPSI::~SrsTsPayloadPSI()
|
||||||
|
@ -2188,7 +2226,12 @@ srs_error_t SrsTsPayloadPATProgram::encode(SrsBuffer* stream)
|
||||||
|
|
||||||
SrsTsPayloadPAT::SrsTsPayloadPAT(SrsTsPacket* p) : SrsTsPayloadPSI(p)
|
SrsTsPayloadPAT::SrsTsPayloadPAT(SrsTsPacket* p) : SrsTsPayloadPSI(p)
|
||||||
{
|
{
|
||||||
|
transport_stream_id = 0;
|
||||||
const3_value = 3;
|
const3_value = 3;
|
||||||
|
version_number = 0;
|
||||||
|
current_next_indicator = 0;
|
||||||
|
section_number = 0;
|
||||||
|
last_section_number = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTsPayloadPAT::~SrsTsPayloadPAT()
|
SrsTsPayloadPAT::~SrsTsPayloadPAT()
|
||||||
|
@ -2387,6 +2430,12 @@ SrsTsPayloadPMT::SrsTsPayloadPMT(SrsTsPacket* p) : SrsTsPayloadPSI(p)
|
||||||
const1_value0 = 3;
|
const1_value0 = 3;
|
||||||
const1_value1 = 7;
|
const1_value1 = 7;
|
||||||
const1_value2 = 0x0f;
|
const1_value2 = 0x0f;
|
||||||
|
PCR_PID = 0;
|
||||||
|
last_section_number = 0;
|
||||||
|
program_number = 0;
|
||||||
|
version_number = 0;
|
||||||
|
current_next_indicator = 0;
|
||||||
|
section_number = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTsPayloadPMT::~SrsTsPayloadPMT()
|
SrsTsPayloadPMT::~SrsTsPayloadPMT()
|
||||||
|
|
|
@ -147,6 +147,7 @@ private:
|
||||||
skip = false;
|
skip = false;
|
||||||
sent = false;
|
sent = false;
|
||||||
dirty = false;
|
dirty = false;
|
||||||
|
duration = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fetch(std::string m3u8);
|
int fetch(std::string m3u8);
|
||||||
|
|
|
@ -457,7 +457,7 @@ srs_error_t SrsHttpFileServer::serve_file(ISrsHttpResponseWriter* w, ISrsHttpMes
|
||||||
// write body.
|
// write body.
|
||||||
int64_t left = length;
|
int64_t left = length;
|
||||||
if ((err = copy(w, fs, r, (int)left)) != srs_success) {
|
if ((err = copy(w, fs, r, (int)left)) != srs_success) {
|
||||||
return srs_error_wrap(err, "copy file=%s size=%d", fullpath.c_str(), left);
|
return srs_error_wrap(err, "copy file=%s size=%d", fullpath.c_str(), (int)left);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = w->final_request()) != srs_success) {
|
if ((err = w->final_request()) != srs_success) {
|
||||||
|
@ -557,7 +557,7 @@ srs_error_t SrsHttpFileServer::copy(ISrsHttpResponseWriter* w, SrsFileReader* fs
|
||||||
|
|
||||||
left -= nread;
|
left -= nread;
|
||||||
if ((err = w->write(buf, (int)nread)) != srs_success) {
|
if ((err = w->write(buf, (int)nread)) != srs_success) {
|
||||||
return srs_error_wrap(err, "write limit=%d, bytes=%d, left=%d", max_read, nread, left);
|
return srs_error_wrap(err, "write limit=%d, bytes=%d, left=%d", max_read, (int)nread, left);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1761,7 +1761,7 @@ namespace _srs_internal
|
||||||
|
|
||||||
// data
|
// data
|
||||||
if (!stream->require((int)value.length())) {
|
if (!stream->require((int)value.length())) {
|
||||||
return srs_error_new(ERROR_RTMP_AMF0_ENCODE, "requires %d only %d bytes", value.length(), stream->left());
|
return srs_error_new(ERROR_RTMP_AMF0_ENCODE, "requires %" PRIu64 " only %d bytes", value.length(), stream->left());
|
||||||
}
|
}
|
||||||
stream->write_string(value);
|
stream->write_string(value);
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,8 @@ SrsStunPacket::SrsStunPacket()
|
||||||
use_candidate = false;
|
use_candidate = false;
|
||||||
ice_controlled = false;
|
ice_controlled = false;
|
||||||
ice_controlling = false;
|
ice_controlling = false;
|
||||||
|
mapped_port = 0;
|
||||||
|
mapped_address = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsStunPacket::~SrsStunPacket()
|
SrsStunPacket::~SrsStunPacket()
|
||||||
|
|
|
@ -865,6 +865,8 @@ namespace _srs_internal
|
||||||
c1s1::c1s1()
|
c1s1::c1s1()
|
||||||
{
|
{
|
||||||
payload = NULL;
|
payload = NULL;
|
||||||
|
version = 0;
|
||||||
|
time = 0;
|
||||||
}
|
}
|
||||||
c1s1::~c1s1()
|
c1s1::~c1s1()
|
||||||
{
|
{
|
||||||
|
@ -978,7 +980,7 @@ namespace _srs_internal
|
||||||
srs_random_generate(random, 1504);
|
srs_random_generate(random, 1504);
|
||||||
|
|
||||||
int size = snprintf(random, 1504, "%s", RTMP_SIG_SRS_HANDSHAKE);
|
int size = snprintf(random, 1504, "%s", RTMP_SIG_SRS_HANDSHAKE);
|
||||||
srs_assert(++size < 1504);
|
srs_assert(size < 1504);
|
||||||
snprintf(random + 1504 - size, size, "%s", RTMP_SIG_SRS_HANDSHAKE);
|
snprintf(random + 1504 - size, size, "%s", RTMP_SIG_SRS_HANDSHAKE);
|
||||||
|
|
||||||
srs_random_generate(digest, 32);
|
srs_random_generate(digest, 32);
|
||||||
|
@ -1225,6 +1227,7 @@ srs_error_t SrsComplexHandshake::handshake_with_client(SrsHandshakeBytes* hs_byt
|
||||||
}
|
}
|
||||||
// verify s2
|
// verify s2
|
||||||
if ((err = s2.s2_validate(&c1, is_valid)) != srs_success || !is_valid) {
|
if ((err = s2.s2_validate(&c1, is_valid)) != srs_success || !is_valid) {
|
||||||
|
srs_freep(err);
|
||||||
return srs_error_new(ERROR_RTMP_TRY_SIMPLE_HS, "verify s2 failed, try simple handshake");
|
return srs_error_new(ERROR_RTMP_TRY_SIMPLE_HS, "verify s2 failed, try simple handshake");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3977,7 +3977,7 @@ srs_error_t SrsPlayPacket::decode(SrsBuffer* stream)
|
||||||
|
|
||||||
SrsAmf0Any* reset_value = NULL;
|
SrsAmf0Any* reset_value = NULL;
|
||||||
if ((err = srs_amf0_read_any(stream, &reset_value)) != srs_success) {
|
if ((err = srs_amf0_read_any(stream, &reset_value)) != srs_success) {
|
||||||
return srs_error_new(ERROR_RTMP_AMF0_DECODE, "reset");
|
return srs_error_wrap(err, "reset");
|
||||||
}
|
}
|
||||||
SrsAutoFree(SrsAmf0Any, reset_value);
|
SrsAutoFree(SrsAmf0Any, reset_value);
|
||||||
|
|
||||||
|
|
|
@ -792,6 +792,9 @@ SrsRtspSetupResponse::SrsRtspSetupResponse(int seq) : SrsRtspResponse(seq)
|
||||||
{
|
{
|
||||||
local_port_min = 0;
|
local_port_min = 0;
|
||||||
local_port_max = 0;
|
local_port_max = 0;
|
||||||
|
|
||||||
|
client_port_min = 0;
|
||||||
|
client_port_max = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtspSetupResponse::~SrsRtspSetupResponse()
|
SrsRtspSetupResponse::~SrsRtspSetupResponse()
|
||||||
|
|
|
@ -139,7 +139,7 @@ srs_error_t SrsHttpParser::parse_message_imp(ISrsReader* reader)
|
||||||
enum http_errno code;
|
enum http_errno code;
|
||||||
if ((code = HTTP_PARSER_ERRNO(&parser)) != HPE_OK) {
|
if ((code = HTTP_PARSER_ERRNO(&parser)) != HPE_OK) {
|
||||||
return srs_error_new(ERROR_HTTP_PARSE_HEADER, "parse %dB, nparsed=%d, err=%d/%s %s",
|
return srs_error_new(ERROR_HTTP_PARSE_HEADER, "parse %dB, nparsed=%d, err=%d/%s %s",
|
||||||
buffer->size(), consumed, code, http_errno_name(code), http_errno_description(code));
|
buffer->size(), (int)consumed, code, http_errno_name(code), http_errno_description(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
// When buffer consumed these bytes, it's dropped so the new ptr is actually the HTTP body. But http-parser
|
// When buffer consumed these bytes, it's dropped so the new ptr is actually the HTTP body. But http-parser
|
||||||
|
@ -319,6 +319,7 @@ SrsHttpMessage::SrsHttpMessage(ISrsReader* reader, SrsFastStream* buffer) : ISrs
|
||||||
_content_length = -1;
|
_content_length = -1;
|
||||||
// From HTTP/1.1, default to keep alive.
|
// From HTTP/1.1, default to keep alive.
|
||||||
_keep_alive = true;
|
_keep_alive = true;
|
||||||
|
type_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpMessage::~SrsHttpMessage()
|
SrsHttpMessage::~SrsHttpMessage()
|
||||||
|
@ -778,7 +779,7 @@ srs_error_t SrsHttpResponseWriter::write(char* data, int size)
|
||||||
iovs[3].iov_base = (char*)SRS_HTTP_CRLF;
|
iovs[3].iov_base = (char*)SRS_HTTP_CRLF;
|
||||||
iovs[3].iov_len = 2;
|
iovs[3].iov_len = 2;
|
||||||
|
|
||||||
ssize_t nwrite;
|
ssize_t nwrite = 0;
|
||||||
if ((err = skt->writev(iovs, 4, &nwrite)) != srs_success) {
|
if ((err = skt->writev(iovs, 4, &nwrite)) != srs_success) {
|
||||||
return srs_error_wrap(err, "write chunk");
|
return srs_error_wrap(err, "write chunk");
|
||||||
}
|
}
|
||||||
|
@ -854,7 +855,7 @@ srs_error_t SrsHttpResponseWriter::writev(const iovec* iov, int iovcnt, ssize_t*
|
||||||
iovss[2+iovcnt].iov_len = 2;
|
iovss[2+iovcnt].iov_len = 2;
|
||||||
|
|
||||||
// sendout all ioves.
|
// sendout all ioves.
|
||||||
ssize_t nwrite;
|
ssize_t nwrite = 0;
|
||||||
if ((err = srs_write_large_iovs(skt, iovss, nb_iovss, &nwrite)) != srs_success) {
|
if ((err = srs_write_large_iovs(skt, iovss, nb_iovss, &nwrite)) != srs_success) {
|
||||||
return srs_error_wrap(err, "writev large iovs");
|
return srs_error_wrap(err, "writev large iovs");
|
||||||
}
|
}
|
||||||
|
@ -940,6 +941,7 @@ SrsHttpResponseReader::SrsHttpResponseReader(SrsHttpMessage* msg, ISrsReader* re
|
||||||
nb_total_read = 0;
|
nb_total_read = 0;
|
||||||
nb_left_chunk = 0;
|
nb_left_chunk = 0;
|
||||||
buffer = body;
|
buffer = body;
|
||||||
|
nb_chunk = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpResponseReader::~SrsHttpResponseReader()
|
SrsHttpResponseReader::~SrsHttpResponseReader()
|
||||||
|
|
|
@ -45,8 +45,8 @@ SrsThreadContext::~SrsThreadContext()
|
||||||
|
|
||||||
SrsContextId SrsThreadContext::generate_id()
|
SrsContextId SrsThreadContext::generate_id()
|
||||||
{
|
{
|
||||||
SrsContextId cid = SrsContextId(srs_random_str(8));
|
SrsContextId cid = SrsContextId();
|
||||||
return cid;
|
return cid.set_value(srs_random_str(8));
|
||||||
}
|
}
|
||||||
|
|
||||||
const SrsContextId& SrsThreadContext::get_id()
|
const SrsContextId& SrsThreadContext::get_id()
|
||||||
|
|
|
@ -92,7 +92,8 @@ public:
|
||||||
// Quit without error.
|
// Quit without error.
|
||||||
bool quit;
|
bool quit;
|
||||||
public:
|
public:
|
||||||
MockCoroutineHandler() : trd(NULL), err(srs_success), cid("0"), quit(false) {
|
MockCoroutineHandler() : trd(NULL), err(srs_success), quit(false) {
|
||||||
|
cid.set_value("0");
|
||||||
running = srs_cond_new();
|
running = srs_cond_new();
|
||||||
exited = srs_cond_new();
|
exited = srs_cond_new();
|
||||||
}
|
}
|
||||||
|
@ -220,16 +221,17 @@ VOID TEST(AppCoroutineTest, Cycle)
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
MockCoroutineHandler ch;
|
MockCoroutineHandler ch;
|
||||||
SrsSTCoroutine sc("test", &ch, SrsContextId("250"));
|
SrsContextId cid;
|
||||||
|
SrsSTCoroutine sc("test", &ch, cid.set_value("250"));
|
||||||
ch.trd = ≻
|
ch.trd = ≻
|
||||||
EXPECT_TRUE(!sc.cid().compare(SrsContextId("250")));
|
EXPECT_TRUE(!sc.cid().compare(cid));
|
||||||
|
|
||||||
EXPECT_TRUE(srs_success == sc.start());
|
EXPECT_TRUE(srs_success == sc.start());
|
||||||
EXPECT_TRUE(srs_success == sc.pull());
|
EXPECT_TRUE(srs_success == sc.pull());
|
||||||
|
|
||||||
// After running, the cid in cycle should equal to the thread.
|
// After running, the cid in cycle should equal to the thread.
|
||||||
srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS);
|
srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS);
|
||||||
EXPECT_TRUE(!ch.cid.compare(SrsContextId("250")));
|
EXPECT_TRUE(!ch.cid.compare(cid));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
|
|
|
@ -34,6 +34,72 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#include <vector>
|
#include <vector>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
VOID TEST(KernelRTCTest, StringDumpHexTest)
|
||||||
|
{
|
||||||
|
// Typical normal case.
|
||||||
|
if (false) {
|
||||||
|
char data[8];
|
||||||
|
data[0] = (char)0x3c; data[sizeof(data) - 2] = (char)0x67; data[sizeof(data) - 1] = (char)0xc3;
|
||||||
|
string r = srs_string_dumps_hex(data, sizeof(data), INT_MAX, 0, 0, 0);
|
||||||
|
EXPECT_EQ(16, (int)r.length());
|
||||||
|
EXPECT_EQ('3', r.at(0)); EXPECT_EQ('c', r.at(1));
|
||||||
|
EXPECT_EQ('c', r.at(r.length() - 2)); EXPECT_EQ('3', r.at(r.length() - 1));
|
||||||
|
EXPECT_EQ('6', r.at(r.length() - 4)); EXPECT_EQ('7', r.at(r.length() - 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill all buffer.
|
||||||
|
if (false) {
|
||||||
|
char data[8 * 1024];
|
||||||
|
data[0] = (char)0x3c; data[sizeof(data) - 2] = (char)0x67; data[sizeof(data) - 1] = (char)0xc3;
|
||||||
|
string r = srs_string_dumps_hex(data, sizeof(data), INT_MAX, 0, 0, 0);
|
||||||
|
EXPECT_EQ(16 * 1024, (int)r.length());
|
||||||
|
EXPECT_EQ('3', r.at(0)); EXPECT_EQ('c', r.at(1));
|
||||||
|
EXPECT_EQ('c', r.at(r.length() - 2)); EXPECT_EQ('3', r.at(r.length() - 1));
|
||||||
|
EXPECT_EQ('6', r.at(r.length() - 4)); EXPECT_EQ('7', r.at(r.length() - 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overflow 1 byte.
|
||||||
|
if (true) {
|
||||||
|
char data[8 * 1024 + 1];
|
||||||
|
data[0] = (char)0x3c; data[sizeof(data) - 2] = (char)0x67; data[sizeof(data) - 1] = (char)0xc3;
|
||||||
|
string r = srs_string_dumps_hex(data, sizeof(data), INT_MAX, 0, 0, 0);
|
||||||
|
EXPECT_EQ(16 * 1024, (int)r.length());
|
||||||
|
EXPECT_EQ('3', r.at(0)); EXPECT_EQ('c', r.at(1));
|
||||||
|
EXPECT_EQ('6', r.at(r.length() - 2)); EXPECT_EQ('7', r.at(r.length() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill all buffer, with seperator.
|
||||||
|
if (true) {
|
||||||
|
char data[5461];
|
||||||
|
data[0] = (char)0x3c; data[sizeof(data) - 2] = (char)0x67; data[sizeof(data) - 1] = (char)0xc3;
|
||||||
|
string r = srs_string_dumps_hex(data, sizeof(data), INT_MAX, ',', 0, 0);
|
||||||
|
EXPECT_EQ(16383 - 1, (int)r.length());
|
||||||
|
EXPECT_EQ('3', r.at(0)); EXPECT_EQ('c', r.at(1));
|
||||||
|
EXPECT_EQ('c', r.at(r.length() - 2)); EXPECT_EQ('3', r.at(r.length() - 1));
|
||||||
|
EXPECT_EQ('6', r.at(r.length() - 5)); EXPECT_EQ('7', r.at(r.length() - 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overflow 1 byte, with seperator.
|
||||||
|
if (true) {
|
||||||
|
char data[5461 + 1];
|
||||||
|
data[0] = (char)0x3c; data[sizeof(data) - 2] = (char)0x67; data[sizeof(data) - 1] = (char)0xc3;
|
||||||
|
string r = srs_string_dumps_hex(data, sizeof(data), INT_MAX, ',', 0, 0);
|
||||||
|
EXPECT_EQ(16383 - 1, (int)r.length());
|
||||||
|
EXPECT_EQ('3', r.at(0)); EXPECT_EQ('c', r.at(1));
|
||||||
|
EXPECT_EQ('6', r.at(r.length() - 2)); EXPECT_EQ('7', r.at(r.length() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overflow 1 byte, with seperator and newline.
|
||||||
|
if (true) {
|
||||||
|
char data[5461 + 1];
|
||||||
|
data[0] = (char)0x3c; data[sizeof(data) - 2] = (char)0x67; data[sizeof(data) - 1] = (char)0xc3;
|
||||||
|
string r = srs_string_dumps_hex(data, sizeof(data), INT_MAX, ',', 5461, '\n');
|
||||||
|
EXPECT_EQ(16383 - 1, (int)r.length());
|
||||||
|
EXPECT_EQ('3', r.at(0)); EXPECT_EQ('c', r.at(1));
|
||||||
|
EXPECT_EQ('6', r.at(r.length() - 2)); EXPECT_EQ('7', r.at(r.length() - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern SSL_CTX* srs_build_dtls_ctx(SrsDtlsVersion version);
|
extern SSL_CTX* srs_build_dtls_ctx(SrsDtlsVersion version);
|
||||||
|
|
||||||
class MockDtls
|
class MockDtls
|
||||||
|
@ -188,6 +254,23 @@ public:
|
||||||
srs_error_t r0;
|
srs_error_t r0;
|
||||||
bool done;
|
bool done;
|
||||||
std::vector<SrsSample> samples;
|
std::vector<SrsSample> samples;
|
||||||
|
public:
|
||||||
|
int nn_client_hello_lost;
|
||||||
|
int nn_server_hello_lost;
|
||||||
|
int nn_certificate_lost;
|
||||||
|
int nn_new_session_lost;
|
||||||
|
int nn_change_cipher_lost;
|
||||||
|
public:
|
||||||
|
// client -> server
|
||||||
|
int nn_client_hello;
|
||||||
|
// server -> client
|
||||||
|
int nn_server_hello;
|
||||||
|
// client -> server
|
||||||
|
int nn_certificate;
|
||||||
|
// server -> client
|
||||||
|
int nn_new_session;
|
||||||
|
int nn_change_cipher;
|
||||||
|
public:
|
||||||
MockDtlsCallback();
|
MockDtlsCallback();
|
||||||
virtual ~MockDtlsCallback();
|
virtual ~MockDtlsCallback();
|
||||||
virtual srs_error_t on_dtls_handshake_done();
|
virtual srs_error_t on_dtls_handshake_done();
|
||||||
|
@ -204,6 +287,18 @@ MockDtlsCallback::MockDtlsCallback()
|
||||||
done = false;
|
done = false;
|
||||||
trd = new SrsSTCoroutine("mock", this);
|
trd = new SrsSTCoroutine("mock", this);
|
||||||
srs_assert(trd->start() == srs_success);
|
srs_assert(trd->start() == srs_success);
|
||||||
|
|
||||||
|
nn_client_hello_lost = 0;
|
||||||
|
nn_server_hello_lost = 0;
|
||||||
|
nn_certificate_lost = 0;
|
||||||
|
nn_new_session_lost = 0;
|
||||||
|
nn_change_cipher_lost = 0;
|
||||||
|
|
||||||
|
nn_client_hello = 0;
|
||||||
|
nn_server_hello = 0;
|
||||||
|
nn_certificate = 0;
|
||||||
|
nn_new_session = 0;
|
||||||
|
nn_change_cipher = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
MockDtlsCallback::~MockDtlsCallback()
|
MockDtlsCallback::~MockDtlsCallback()
|
||||||
|
@ -228,10 +323,49 @@ srs_error_t MockDtlsCallback::on_dtls_application_data(const char* data, const i
|
||||||
|
|
||||||
srs_error_t MockDtlsCallback::write_dtls_data(void* data, int size)
|
srs_error_t MockDtlsCallback::write_dtls_data(void* data, int size)
|
||||||
{
|
{
|
||||||
|
int nn_lost = 0;
|
||||||
|
if (true) {
|
||||||
|
uint8_t content_type = 0;
|
||||||
|
if (size >= 1) {
|
||||||
|
content_type = (uint8_t)((uint8_t*)data)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t handshake_type = 0;
|
||||||
|
if (size >= 14) {
|
||||||
|
handshake_type = (uint8_t)((uint8_t*)data)[13];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content_type == 22) {
|
||||||
|
if (handshake_type == 1) {
|
||||||
|
nn_lost = nn_client_hello_lost--;
|
||||||
|
nn_client_hello++;
|
||||||
|
} else if (handshake_type == 2) {
|
||||||
|
nn_lost = nn_server_hello_lost--;
|
||||||
|
nn_server_hello++;
|
||||||
|
} else if (handshake_type == 11) {
|
||||||
|
nn_lost = nn_certificate_lost--;
|
||||||
|
nn_certificate++;
|
||||||
|
} else if (handshake_type == 4) {
|
||||||
|
nn_lost = nn_new_session_lost--;
|
||||||
|
nn_new_session++;
|
||||||
|
}
|
||||||
|
} else if (content_type == 20) {
|
||||||
|
nn_lost = nn_change_cipher_lost--;
|
||||||
|
nn_change_cipher++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate to drop packet.
|
||||||
|
if (nn_lost > 0) {
|
||||||
|
return srs_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send out it.
|
||||||
char* cp = new char[size];
|
char* cp = new char[size];
|
||||||
memcpy(cp, data, size);
|
memcpy(cp, data, size);
|
||||||
|
|
||||||
samples.push_back(SrsSample((char*)cp, size));
|
samples.push_back(SrsSample((char*)cp, size));
|
||||||
|
|
||||||
return srs_success;
|
return srs_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,10 +383,12 @@ srs_error_t MockDtlsCallback::cycle()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsSample p = *samples.erase(samples.begin());
|
SrsSample p = samples.at(0);
|
||||||
|
samples.erase(samples.begin());
|
||||||
|
|
||||||
if (peer) {
|
if (peer) {
|
||||||
err = peer->on_dtls((char*)p.bytes, p.size);
|
err = peer->on_dtls((char*)p.bytes, p.size);
|
||||||
} else {
|
} else if (peer2) {
|
||||||
err = peer2->on_dtls((char*)p.bytes, p.size);
|
err = peer2->on_dtls((char*)p.bytes, p.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,10 +402,29 @@ srs_error_t MockDtlsCallback::cycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for mock io to done, try to switch to coroutine many times.
|
// Wait for mock io to done, try to switch to coroutine many times.
|
||||||
#define mock_wait_dtls_io_done(cio, sio) \
|
void mock_wait_dtls_io_done(int count = 100, int interval = 0)
|
||||||
for (int i = 0; i < 100 && (!cio.samples.empty() || !sio.samples.empty()); i++) { \
|
{
|
||||||
srs_usleep(0 * SRS_UTIME_MILLISECONDS); \
|
for (int i = 0; i < count; i++) {
|
||||||
|
srs_usleep(interval * SRS_UTIME_MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To avoid the crash when peer or peer2 is freed before io.
|
||||||
|
class MockBridgeDtlsIO
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
MockDtlsCallback* io_;
|
||||||
|
public:
|
||||||
|
MockBridgeDtlsIO(MockDtlsCallback* io, SrsDtls* peer, MockDtls* peer2) {
|
||||||
|
io_ = io;
|
||||||
|
io->peer = peer;
|
||||||
|
io->peer2 = peer2;
|
||||||
|
}
|
||||||
|
virtual ~MockBridgeDtlsIO() {
|
||||||
|
io_->peer = NULL;
|
||||||
|
io_->peer2 = NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct DTLSServerFlowCase
|
struct DTLSServerFlowCase
|
||||||
{
|
{
|
||||||
|
@ -293,6 +448,366 @@ std::ostream& operator<< (std::ostream& stream, const DTLSServerFlowCase& c)
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID TEST(KernelRTCTest, DTLSARQLimitTest)
|
||||||
|
{
|
||||||
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
// ClientHello lost, client retransmit the ClientHello.
|
||||||
|
if (true) {
|
||||||
|
MockDtlsCallback cio; SrsDtls client(&cio);
|
||||||
|
MockDtlsCallback sio; SrsDtls server(&sio);
|
||||||
|
MockBridgeDtlsIO b0(&cio, &server, NULL); MockBridgeDtlsIO b1(&sio, &client, NULL);
|
||||||
|
HELPER_EXPECT_SUCCESS(client.initialize("active", "dtls1.0"));
|
||||||
|
HELPER_EXPECT_SUCCESS(server.initialize("passive", "dtls1.0"));
|
||||||
|
|
||||||
|
// Use very short interval for utest.
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_first = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_interval = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
|
||||||
|
// Lost 10 packets, total packets should be 8(max to 8).
|
||||||
|
// Note that only one server hello.
|
||||||
|
cio.nn_client_hello_lost = 10;
|
||||||
|
|
||||||
|
HELPER_EXPECT_SUCCESS(client.start_active_handshake());
|
||||||
|
mock_wait_dtls_io_done(10, 3);
|
||||||
|
|
||||||
|
EXPECT_TRUE(sio.r0 == srs_success);
|
||||||
|
EXPECT_TRUE(cio.r0 == srs_success);
|
||||||
|
|
||||||
|
EXPECT_FALSE(cio.done);
|
||||||
|
EXPECT_FALSE(sio.done);
|
||||||
|
|
||||||
|
EXPECT_EQ(8, cio.nn_client_hello);
|
||||||
|
EXPECT_EQ(0, sio.nn_server_hello);
|
||||||
|
EXPECT_EQ(0, cio.nn_certificate);
|
||||||
|
EXPECT_EQ(0, sio.nn_new_session);
|
||||||
|
EXPECT_EQ(0, sio.nn_change_cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Certificate lost, client retransmit the Certificate.
|
||||||
|
if (true) {
|
||||||
|
MockDtlsCallback cio; SrsDtls client(&cio);
|
||||||
|
MockDtlsCallback sio; SrsDtls server(&sio);
|
||||||
|
MockBridgeDtlsIO b0(&cio, &server, NULL); MockBridgeDtlsIO b1(&sio, &client, NULL);
|
||||||
|
HELPER_EXPECT_SUCCESS(client.initialize("active", "dtls1.0"));
|
||||||
|
HELPER_EXPECT_SUCCESS(server.initialize("passive", "dtls1.0"));
|
||||||
|
|
||||||
|
// Use very short interval for utest.
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_first = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_interval = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
|
||||||
|
// Lost 10 packets, total packets should be 8(max to 8).
|
||||||
|
// Note that only one server NewSessionTicket.
|
||||||
|
cio.nn_certificate_lost = 10;
|
||||||
|
|
||||||
|
HELPER_EXPECT_SUCCESS(client.start_active_handshake());
|
||||||
|
mock_wait_dtls_io_done(10, 3);
|
||||||
|
|
||||||
|
EXPECT_TRUE(sio.r0 == srs_success);
|
||||||
|
EXPECT_TRUE(cio.r0 == srs_success);
|
||||||
|
|
||||||
|
EXPECT_FALSE(cio.done);
|
||||||
|
EXPECT_FALSE(sio.done);
|
||||||
|
|
||||||
|
EXPECT_EQ(1, cio.nn_client_hello);
|
||||||
|
EXPECT_EQ(1, sio.nn_server_hello);
|
||||||
|
EXPECT_EQ(8, cio.nn_certificate);
|
||||||
|
EXPECT_EQ(0, sio.nn_new_session);
|
||||||
|
EXPECT_EQ(0, sio.nn_change_cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerHello lost, client retransmit the ClientHello.
|
||||||
|
if (true) {
|
||||||
|
MockDtlsCallback cio; SrsDtls client(&cio);
|
||||||
|
MockDtlsCallback sio; SrsDtls server(&sio);
|
||||||
|
MockBridgeDtlsIO b0(&cio, &server, NULL); MockBridgeDtlsIO b1(&sio, &client, NULL);
|
||||||
|
HELPER_EXPECT_SUCCESS(client.initialize("active", "dtls1.0"));
|
||||||
|
HELPER_EXPECT_SUCCESS(server.initialize("passive", "dtls1.0"));
|
||||||
|
|
||||||
|
// Use very short interval for utest.
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_first = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_interval = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
|
||||||
|
// Lost 10 packets, total packets should be 8(max to 8).
|
||||||
|
sio.nn_server_hello_lost = 10;
|
||||||
|
|
||||||
|
HELPER_EXPECT_SUCCESS(client.start_active_handshake());
|
||||||
|
mock_wait_dtls_io_done(10, 3);
|
||||||
|
|
||||||
|
EXPECT_TRUE(sio.r0 == srs_success);
|
||||||
|
EXPECT_TRUE(cio.r0 == srs_success);
|
||||||
|
|
||||||
|
EXPECT_FALSE(cio.done);
|
||||||
|
EXPECT_FALSE(sio.done);
|
||||||
|
|
||||||
|
EXPECT_EQ(8, cio.nn_client_hello);
|
||||||
|
EXPECT_EQ(8, sio.nn_server_hello);
|
||||||
|
EXPECT_EQ(0, cio.nn_certificate);
|
||||||
|
EXPECT_EQ(0, sio.nn_new_session);
|
||||||
|
EXPECT_EQ(0, sio.nn_change_cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSessionTicket lost, client retransmit the Certificate.
|
||||||
|
if (true) {
|
||||||
|
MockDtlsCallback cio; SrsDtls client(&cio);
|
||||||
|
MockDtlsCallback sio; SrsDtls server(&sio);
|
||||||
|
MockBridgeDtlsIO b0(&cio, &server, NULL); MockBridgeDtlsIO b1(&sio, &client, NULL);
|
||||||
|
HELPER_EXPECT_SUCCESS(client.initialize("active", "dtls1.0"));
|
||||||
|
HELPER_EXPECT_SUCCESS(server.initialize("passive", "dtls1.0"));
|
||||||
|
|
||||||
|
// Use very short interval for utest.
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_first = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_interval = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
|
||||||
|
// Lost 10 packets, total packets should be 8(max to 8).
|
||||||
|
sio.nn_new_session_lost = 10;
|
||||||
|
|
||||||
|
HELPER_EXPECT_SUCCESS(client.start_active_handshake());
|
||||||
|
mock_wait_dtls_io_done(10, 3);
|
||||||
|
|
||||||
|
EXPECT_TRUE(sio.r0 == srs_success);
|
||||||
|
EXPECT_TRUE(cio.r0 == srs_success);
|
||||||
|
|
||||||
|
// Although the packet is lost, but it's done for server, and not done for client.
|
||||||
|
EXPECT_FALSE(cio.done);
|
||||||
|
EXPECT_TRUE(sio.done);
|
||||||
|
|
||||||
|
EXPECT_EQ(1, cio.nn_client_hello);
|
||||||
|
EXPECT_EQ(1, sio.nn_server_hello);
|
||||||
|
EXPECT_EQ(8, cio.nn_certificate);
|
||||||
|
EXPECT_EQ(8, sio.nn_new_session);
|
||||||
|
EXPECT_EQ(0, sio.nn_change_cipher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TEST(KernelRTCTest, DTLSClientARQTest)
|
||||||
|
{
|
||||||
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
// No ARQ, check the number of packets.
|
||||||
|
if (true) {
|
||||||
|
MockDtlsCallback cio; SrsDtls client(&cio);
|
||||||
|
MockDtlsCallback sio; SrsDtls server(&sio);
|
||||||
|
cio.peer = &server; sio.peer = &client;
|
||||||
|
HELPER_EXPECT_SUCCESS(client.initialize("active", "dtls1.0"));
|
||||||
|
HELPER_EXPECT_SUCCESS(server.initialize("passive", "dtls1.0"));
|
||||||
|
|
||||||
|
HELPER_EXPECT_SUCCESS(client.start_active_handshake());
|
||||||
|
mock_wait_dtls_io_done(30, 1);
|
||||||
|
|
||||||
|
EXPECT_TRUE(sio.r0 == srs_success);
|
||||||
|
EXPECT_TRUE(cio.r0 == srs_success);
|
||||||
|
|
||||||
|
EXPECT_TRUE(cio.done);
|
||||||
|
EXPECT_TRUE(sio.done);
|
||||||
|
|
||||||
|
EXPECT_EQ(1, cio.nn_client_hello);
|
||||||
|
EXPECT_EQ(1, sio.nn_server_hello);
|
||||||
|
EXPECT_EQ(1, cio.nn_certificate);
|
||||||
|
EXPECT_EQ(1, sio.nn_new_session);
|
||||||
|
EXPECT_EQ(0, sio.nn_change_cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientHello lost, client retransmit the ClientHello.
|
||||||
|
if (true) {
|
||||||
|
MockDtlsCallback cio; SrsDtls client(&cio);
|
||||||
|
MockDtlsCallback sio; SrsDtls server(&sio);
|
||||||
|
MockBridgeDtlsIO b0(&cio, &server, NULL); MockBridgeDtlsIO b1(&sio, &client, NULL);
|
||||||
|
HELPER_EXPECT_SUCCESS(client.initialize("active", "dtls1.0"));
|
||||||
|
HELPER_EXPECT_SUCCESS(server.initialize("passive", "dtls1.0"));
|
||||||
|
|
||||||
|
// Use very short interval for utest.
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_first = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_interval = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
|
||||||
|
// Lost 2 packets, total packets should be 3.
|
||||||
|
// Note that only one server hello.
|
||||||
|
cio.nn_client_hello_lost = 2;
|
||||||
|
|
||||||
|
HELPER_EXPECT_SUCCESS(client.start_active_handshake());
|
||||||
|
mock_wait_dtls_io_done(10, 3);
|
||||||
|
|
||||||
|
EXPECT_TRUE(sio.r0 == srs_success);
|
||||||
|
EXPECT_TRUE(cio.r0 == srs_success);
|
||||||
|
|
||||||
|
EXPECT_TRUE(cio.done);
|
||||||
|
EXPECT_TRUE(sio.done);
|
||||||
|
|
||||||
|
EXPECT_EQ(3, cio.nn_client_hello);
|
||||||
|
EXPECT_EQ(1, sio.nn_server_hello);
|
||||||
|
EXPECT_EQ(1, cio.nn_certificate);
|
||||||
|
EXPECT_EQ(1, sio.nn_new_session);
|
||||||
|
EXPECT_EQ(0, sio.nn_change_cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Certificate lost, client retransmit the Certificate.
|
||||||
|
if (true) {
|
||||||
|
MockDtlsCallback cio; SrsDtls client(&cio);
|
||||||
|
MockDtlsCallback sio; SrsDtls server(&sio);
|
||||||
|
MockBridgeDtlsIO b0(&cio, &server, NULL); MockBridgeDtlsIO b1(&sio, &client, NULL);
|
||||||
|
HELPER_EXPECT_SUCCESS(client.initialize("active", "dtls1.0"));
|
||||||
|
HELPER_EXPECT_SUCCESS(server.initialize("passive", "dtls1.0"));
|
||||||
|
|
||||||
|
// Use very short interval for utest.
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_first = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_interval = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
|
||||||
|
// Lost 2 packets, total packets should be 3.
|
||||||
|
// Note that only one server NewSessionTicket.
|
||||||
|
cio.nn_certificate_lost = 2;
|
||||||
|
|
||||||
|
HELPER_EXPECT_SUCCESS(client.start_active_handshake());
|
||||||
|
mock_wait_dtls_io_done(10, 3);
|
||||||
|
|
||||||
|
EXPECT_TRUE(sio.r0 == srs_success);
|
||||||
|
EXPECT_TRUE(cio.r0 == srs_success);
|
||||||
|
|
||||||
|
EXPECT_TRUE(cio.done);
|
||||||
|
EXPECT_TRUE(sio.done);
|
||||||
|
|
||||||
|
EXPECT_EQ(1, cio.nn_client_hello);
|
||||||
|
EXPECT_EQ(1, sio.nn_server_hello);
|
||||||
|
EXPECT_EQ(3, cio.nn_certificate);
|
||||||
|
EXPECT_EQ(1, sio.nn_new_session);
|
||||||
|
EXPECT_EQ(0, sio.nn_change_cipher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TEST(KernelRTCTest, DTLSServerARQTest)
|
||||||
|
{
|
||||||
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
// No ARQ, check the number of packets.
|
||||||
|
if (true) {
|
||||||
|
MockDtlsCallback cio; SrsDtls client(&cio);
|
||||||
|
MockDtlsCallback sio; SrsDtls server(&sio);
|
||||||
|
cio.peer = &server; sio.peer = &client;
|
||||||
|
HELPER_EXPECT_SUCCESS(client.initialize("active", "dtls1.0"));
|
||||||
|
HELPER_EXPECT_SUCCESS(server.initialize("passive", "dtls1.0"));
|
||||||
|
|
||||||
|
HELPER_EXPECT_SUCCESS(client.start_active_handshake());
|
||||||
|
mock_wait_dtls_io_done(30, 1);
|
||||||
|
|
||||||
|
EXPECT_TRUE(sio.r0 == srs_success);
|
||||||
|
EXPECT_TRUE(cio.r0 == srs_success);
|
||||||
|
|
||||||
|
EXPECT_TRUE(cio.done);
|
||||||
|
EXPECT_TRUE(sio.done);
|
||||||
|
|
||||||
|
EXPECT_EQ(1, cio.nn_client_hello);
|
||||||
|
EXPECT_EQ(1, sio.nn_server_hello);
|
||||||
|
EXPECT_EQ(1, cio.nn_certificate);
|
||||||
|
EXPECT_EQ(1, sio.nn_new_session);
|
||||||
|
EXPECT_EQ(0, sio.nn_change_cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerHello lost, client retransmit the ClientHello.
|
||||||
|
if (true) {
|
||||||
|
MockDtlsCallback cio; SrsDtls client(&cio);
|
||||||
|
MockDtlsCallback sio; SrsDtls server(&sio);
|
||||||
|
MockBridgeDtlsIO b0(&cio, &server, NULL); MockBridgeDtlsIO b1(&sio, &client, NULL);
|
||||||
|
HELPER_EXPECT_SUCCESS(client.initialize("active", "dtls1.0"));
|
||||||
|
HELPER_EXPECT_SUCCESS(server.initialize("passive", "dtls1.0"));
|
||||||
|
|
||||||
|
// Use very short interval for utest.
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_first = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_interval = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
|
||||||
|
// Lost 2 packets, total packets should be 3.
|
||||||
|
sio.nn_server_hello_lost = 2;
|
||||||
|
|
||||||
|
HELPER_EXPECT_SUCCESS(client.start_active_handshake());
|
||||||
|
mock_wait_dtls_io_done(10, 3);
|
||||||
|
|
||||||
|
EXPECT_TRUE(sio.r0 == srs_success);
|
||||||
|
EXPECT_TRUE(cio.r0 == srs_success);
|
||||||
|
|
||||||
|
EXPECT_TRUE(cio.done);
|
||||||
|
EXPECT_TRUE(sio.done);
|
||||||
|
|
||||||
|
EXPECT_EQ(3, cio.nn_client_hello);
|
||||||
|
EXPECT_EQ(3, sio.nn_server_hello);
|
||||||
|
EXPECT_EQ(1, cio.nn_certificate);
|
||||||
|
EXPECT_EQ(1, sio.nn_new_session);
|
||||||
|
EXPECT_EQ(0, sio.nn_change_cipher);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSessionTicket lost, client retransmit the Certificate.
|
||||||
|
if (true) {
|
||||||
|
MockDtlsCallback cio; SrsDtls client(&cio);
|
||||||
|
MockDtlsCallback sio; SrsDtls server(&sio);
|
||||||
|
MockBridgeDtlsIO b0(&cio, &server, NULL); MockBridgeDtlsIO b1(&sio, &client, NULL);
|
||||||
|
HELPER_EXPECT_SUCCESS(client.initialize("active", "dtls1.0"));
|
||||||
|
HELPER_EXPECT_SUCCESS(server.initialize("passive", "dtls1.0"));
|
||||||
|
|
||||||
|
// Use very short interval for utest.
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_first = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
dynamic_cast<SrsDtlsClientImpl*>(client.impl)->arq_interval = 1 * SRS_UTIME_MILLISECONDS;
|
||||||
|
|
||||||
|
// Lost 2 packets, total packets should be 3.
|
||||||
|
sio.nn_new_session_lost = 2;
|
||||||
|
|
||||||
|
HELPER_EXPECT_SUCCESS(client.start_active_handshake());
|
||||||
|
mock_wait_dtls_io_done(10, 3);
|
||||||
|
|
||||||
|
EXPECT_TRUE(sio.r0 == srs_success);
|
||||||
|
EXPECT_TRUE(cio.r0 == srs_success);
|
||||||
|
|
||||||
|
EXPECT_TRUE(cio.done);
|
||||||
|
EXPECT_TRUE(sio.done);
|
||||||
|
|
||||||
|
EXPECT_EQ(1, cio.nn_client_hello);
|
||||||
|
EXPECT_EQ(1, sio.nn_server_hello);
|
||||||
|
EXPECT_EQ(3, cio.nn_certificate);
|
||||||
|
EXPECT_EQ(3, sio.nn_new_session);
|
||||||
|
EXPECT_EQ(0, sio.nn_change_cipher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TEST(KernelRTCTest, DTLSClientFlowTest)
|
||||||
|
{
|
||||||
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
DTLSServerFlowCase cases[] = {
|
||||||
|
// OK, Client, Server: DTLS v1.0
|
||||||
|
{0, "dtls1.0", "dtls1.0", true, true, false, false},
|
||||||
|
// OK, Client, Server: DTLS v1.2
|
||||||
|
{1, "dtls1.2", "dtls1.2", true, true, false, false},
|
||||||
|
// OK, Client: DTLS v1.0, Server: DTLS auto(v1.0 or v1.2).
|
||||||
|
{2, "dtls1.0", "auto", true, true, false, false},
|
||||||
|
// OK, Client: DTLS v1.2, Server: DTLS auto(v1.0 or v1.2).
|
||||||
|
{3, "dtls1.2", "auto", true, true, false, false},
|
||||||
|
// OK, Client: DTLS auto(v1.0 or v1.2), Server: DTLS v1.0
|
||||||
|
{4, "auto", "dtls1.0", true, true, false, false},
|
||||||
|
// OK, Client: DTLS auto(v1.0 or v1.2), Server: DTLS v1.0
|
||||||
|
{5, "auto", "dtls1.2", true, true, false, false},
|
||||||
|
// Fail, Client: DTLS v1.0, Server: DTLS v1.2
|
||||||
|
{6, "dtls1.0", "dtls1.2", false, false, false, true},
|
||||||
|
// Fail, Client: DTLS v1.2, Server: DTLS v1.0
|
||||||
|
{7, "dtls1.2", "dtls1.0", false, false, true, false},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)(sizeof(cases) / sizeof(DTLSServerFlowCase)); i++) {
|
||||||
|
DTLSServerFlowCase c = cases[i];
|
||||||
|
|
||||||
|
MockDtlsCallback cio; SrsDtls client(&cio);
|
||||||
|
MockDtlsCallback sio; MockDtls server(&sio);
|
||||||
|
MockBridgeDtlsIO b0(&cio, NULL, &server); MockBridgeDtlsIO b1(&sio, &client, NULL);
|
||||||
|
HELPER_EXPECT_SUCCESS(client.initialize("active", c.ClientVersion)) << c;
|
||||||
|
HELPER_EXPECT_SUCCESS(server.initialize("passive", c.ServerVersion)) << c;
|
||||||
|
|
||||||
|
HELPER_EXPECT_SUCCESS(client.start_active_handshake()) << c;
|
||||||
|
mock_wait_dtls_io_done();
|
||||||
|
|
||||||
|
// Note that the cio error is generated from server, vice versa.
|
||||||
|
EXPECT_EQ(c.ClientError, sio.r0 != srs_success) << c;
|
||||||
|
EXPECT_EQ(c.ServerError, cio.r0 != srs_success) << c;
|
||||||
|
|
||||||
|
EXPECT_EQ(c.ClientDone, cio.done) << c;
|
||||||
|
EXPECT_EQ(c.ServerDone, sio.done) << c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VOID TEST(KernelRTCTest, DTLSServerFlowTest)
|
VOID TEST(KernelRTCTest, DTLSServerFlowTest)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
@ -321,12 +836,12 @@ VOID TEST(KernelRTCTest, DTLSServerFlowTest)
|
||||||
|
|
||||||
MockDtlsCallback cio; MockDtls client(&cio);
|
MockDtlsCallback cio; MockDtls client(&cio);
|
||||||
MockDtlsCallback sio; SrsDtls server(&sio);
|
MockDtlsCallback sio; SrsDtls server(&sio);
|
||||||
cio.peer = &server; sio.peer2 = &client;
|
MockBridgeDtlsIO b0(&cio, &server, NULL); MockBridgeDtlsIO b1(&sio, NULL, &client);
|
||||||
HELPER_EXPECT_SUCCESS(client.initialize("active", c.ClientVersion)) << c;
|
HELPER_EXPECT_SUCCESS(client.initialize("active", c.ClientVersion)) << c;
|
||||||
HELPER_EXPECT_SUCCESS(server.initialize("passive", c.ServerVersion)) << c;
|
HELPER_EXPECT_SUCCESS(server.initialize("passive", c.ServerVersion)) << c;
|
||||||
|
|
||||||
HELPER_EXPECT_SUCCESS(client.start_active_handshake()) << c;
|
HELPER_EXPECT_SUCCESS(client.start_active_handshake()) << c;
|
||||||
mock_wait_dtls_io_done(cio, sio);
|
mock_wait_dtls_io_done();
|
||||||
|
|
||||||
// Note that the cio error is generated from server, vice versa.
|
// Note that the cio error is generated from server, vice versa.
|
||||||
EXPECT_EQ(c.ClientError, sio.r0 != srs_success) << c;
|
EXPECT_EQ(c.ClientError, sio.r0 != srs_success) << c;
|
||||||
|
@ -668,7 +1183,7 @@ VOID TEST(KernelRTCTest, DefaultTrackStatus)
|
||||||
|
|
||||||
// Enable it by publisher.
|
// Enable it by publisher.
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsRtcConnection s(NULL, SrsContextId()); SrsRtcPublishStream publish(&s);
|
SrsRtcConnection s(NULL, SrsContextId()); SrsRtcPublishStream publish(&s, SrsContextId());
|
||||||
SrsRtcAudioRecvTrack* audio; SrsRtcVideoRecvTrack *video;
|
SrsRtcAudioRecvTrack* audio; SrsRtcVideoRecvTrack *video;
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
|
|
|
@ -1382,19 +1382,34 @@ VOID TEST(TCPServerTest, ContextUtility)
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsThreadContext ctx;
|
SrsThreadContext ctx;
|
||||||
|
|
||||||
EXPECT_TRUE(!ctx.set_id(SrsContextId("100")).compare(SrsContextId("100")));
|
if (true) {
|
||||||
EXPECT_TRUE(!ctx.set_id(SrsContextId("1000")).compare(SrsContextId("1000")));
|
SrsContextId cid;
|
||||||
EXPECT_TRUE(!ctx.get_id().compare(SrsContextId("1000")));
|
EXPECT_TRUE(!ctx.set_id(cid.set_value("100")).compare(cid));
|
||||||
|
}
|
||||||
|
if (true) {
|
||||||
|
SrsContextId cid;
|
||||||
|
EXPECT_TRUE(!ctx.set_id(cid.set_value("1000")).compare(cid));
|
||||||
|
}
|
||||||
|
if (true) {
|
||||||
|
SrsContextId cid;
|
||||||
|
EXPECT_TRUE(!ctx.get_id().compare(cid.set_value("1000")));
|
||||||
|
}
|
||||||
|
|
||||||
ctx.clear_cid();
|
ctx.clear_cid();
|
||||||
EXPECT_TRUE(!ctx.set_id(SrsContextId("100")).compare(SrsContextId("100")));
|
if (true) {
|
||||||
|
SrsContextId cid;
|
||||||
|
EXPECT_TRUE(!ctx.set_id(cid.set_value("100")).compare(cid));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SrsContextId cid;
|
||||||
|
cid.set_value("100");
|
||||||
|
|
||||||
int base_size = 0;
|
int base_size = 0;
|
||||||
if (true) {
|
if (true) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
int size = 0; char buf[1024]; HELPER_ARRAY_INIT(buf, 1024, 0);
|
int size = 0; char buf[1024]; HELPER_ARRAY_INIT(buf, 1024, 0);
|
||||||
ASSERT_TRUE(srs_log_header(buf, 1024, true, true, "SRS", SrsContextId("100"), "Trace", &size));
|
ASSERT_TRUE(srs_log_header(buf, 1024, true, true, "SRS", cid, "Trace", &size));
|
||||||
base_size = size;
|
base_size = size;
|
||||||
EXPECT_TRUE(base_size > 0);
|
EXPECT_TRUE(base_size > 0);
|
||||||
}
|
}
|
||||||
|
@ -1402,21 +1417,21 @@ VOID TEST(TCPServerTest, ContextUtility)
|
||||||
if (true) {
|
if (true) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
int size = 0; char buf[1024]; HELPER_ARRAY_INIT(buf, 1024, 0);
|
int size = 0; char buf[1024]; HELPER_ARRAY_INIT(buf, 1024, 0);
|
||||||
ASSERT_TRUE(srs_log_header(buf, 1024, false, true, "SRS", SrsContextId("100"), "Trace", &size));
|
ASSERT_TRUE(srs_log_header(buf, 1024, false, true, "SRS", cid, "Trace", &size));
|
||||||
EXPECT_EQ(base_size, size);
|
EXPECT_EQ(base_size, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
int size = 0; char buf[1024]; HELPER_ARRAY_INIT(buf, 1024, 0);
|
int size = 0; char buf[1024]; HELPER_ARRAY_INIT(buf, 1024, 0);
|
||||||
ASSERT_TRUE(srs_log_header(buf, 1024, false, true, NULL, SrsContextId("100"), "Trace", &size));
|
ASSERT_TRUE(srs_log_header(buf, 1024, false, true, NULL, cid, "Trace", &size));
|
||||||
EXPECT_EQ(base_size - 5, size);
|
EXPECT_EQ(base_size - 5, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
int size = 0; char buf[1024]; HELPER_ARRAY_INIT(buf, 1024, 0);
|
int size = 0; char buf[1024]; HELPER_ARRAY_INIT(buf, 1024, 0);
|
||||||
ASSERT_TRUE(srs_log_header(buf, 1024, false, false, NULL, SrsContextId("100"), "Trace", &size));
|
ASSERT_TRUE(srs_log_header(buf, 1024, false, false, NULL, cid, "Trace", &size));
|
||||||
EXPECT_EQ(base_size - 8, size);
|
EXPECT_EQ(base_size - 8, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue