AI: Improve converage for app rtc module.
This commit is contained in:
parent
ea14caeee5
commit
c0fc8cb093
|
|
@ -402,6 +402,106 @@ testing:
|
||||||
- Verify edge cases like sequence number wrap-around, cache overflow, and null inputs
|
- Verify edge cases like sequence number wrap-around, cache overflow, and null inputs
|
||||||
- Use existing mock helper functions for consistency and maintainability
|
- Use existing mock helper functions for consistency and maintainability
|
||||||
|
|
||||||
|
test_object_declaration:
|
||||||
|
- pattern: "Use unique pointers for object instantiation"
|
||||||
|
description: "MANDATORY - Always use SrsUniquePtr for object declaration in unit tests instead of stack allocation"
|
||||||
|
usage: |
|
||||||
|
WRONG: Stack allocation for SRS classes
|
||||||
|
SrsRtcPublishStream publish_stream(&mock_exec, &mock_expire, &mock_receiver, cid);
|
||||||
|
SrsBuffer buffer(data, size);
|
||||||
|
SrsHttpUri uri;
|
||||||
|
|
||||||
|
CORRECT: Use SrsUniquePtr for SRS classes
|
||||||
|
SrsUniquePtr<SrsRtcPublishStream> publish_stream(new SrsRtcPublishStream(&mock_exec, &mock_expire, &mock_receiver, cid));
|
||||||
|
SrsUniquePtr<SrsBuffer> buffer(new SrsBuffer(data, size));
|
||||||
|
SrsUniquePtr<SrsHttpUri> uri(new SrsHttpUri());
|
||||||
|
|
||||||
|
// Access members using -> operator
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->initialize());
|
||||||
|
buffer->write_1bytes(0xff);
|
||||||
|
uri->parse("http://example.com");
|
||||||
|
|
||||||
|
EXCEPTION: Mock objects should be declared directly (stack allocation)
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
MockRtcAsyncCallRequest mock_request("test.vhost", "live", "stream1");
|
||||||
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
|
rationale: "Consistent with SRS memory management patterns, automatic cleanup, and prevents stack overflow issues with large objects. Mock objects are lightweight and designed for direct instantiation."
|
||||||
|
|
||||||
|
mock_class_organization:
|
||||||
|
- pattern: "Mock class structure"
|
||||||
|
description: "MANDATORY - Always create mock class declarations in .hpp files and implementations in .cpp files"
|
||||||
|
usage: |
|
||||||
|
WRONG: Inline mock class definition in .cpp test file
|
||||||
|
// In srs_utest_app.cpp
|
||||||
|
class MockRtcConnection {
|
||||||
|
public:
|
||||||
|
bool enabled() { return true; }
|
||||||
|
srs_error_t send_packet() { return srs_success; }
|
||||||
|
};
|
||||||
|
|
||||||
|
CORRECT: Mock class declaration in .hpp, implementation in .cpp
|
||||||
|
// In srs_utest_app.hpp
|
||||||
|
class MockRtcConnection {
|
||||||
|
public:
|
||||||
|
bool enabled();
|
||||||
|
srs_error_t send_packet();
|
||||||
|
};
|
||||||
|
|
||||||
|
// In srs_utest_app.cpp
|
||||||
|
bool MockRtcConnection::enabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
srs_error_t MockRtcConnection::send_packet() {
|
||||||
|
return srs_success;
|
||||||
|
}
|
||||||
|
rationale: "Proper separation of interface and implementation, better code organization, and easier maintenance"
|
||||||
|
|
||||||
|
- pattern: "Mock function organization"
|
||||||
|
description: "MANDATORY - Always declare mock functions in .hpp files and implement in .cpp files"
|
||||||
|
usage: |
|
||||||
|
WRONG: Inline mock function in .cpp test file
|
||||||
|
// In srs_utest_app.cpp
|
||||||
|
srs_error_t mock_read_function(char* buf, int size) {
|
||||||
|
return srs_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
CORRECT: Mock function declaration in .hpp, implementation in .cpp
|
||||||
|
// In srs_utest_app.hpp
|
||||||
|
srs_error_t mock_read_function(char* buf, int size);
|
||||||
|
|
||||||
|
// In srs_utest_app.cpp
|
||||||
|
srs_error_t mock_read_function(char* buf, int size) {
|
||||||
|
return srs_success;
|
||||||
|
}
|
||||||
|
rationale: "Consistent with SRS coding standards and better code organization"
|
||||||
|
|
||||||
|
- pattern: "Reuse existing mocks"
|
||||||
|
description: "MANDATORY - Always try to use existing mock classes by including the appropriate header file before creating new mocks"
|
||||||
|
usage: |
|
||||||
|
CORRECT: Check and reuse existing mocks
|
||||||
|
// First, include existing mock headers
|
||||||
|
#include "srs_utest_app.hpp" // For MockRtcConnection, MockHttpServer, etc.
|
||||||
|
|
||||||
|
// Use existing mock if available
|
||||||
|
MockRtcConnection* mock_conn = new MockRtcConnection();
|
||||||
|
|
||||||
|
// Only create new mock if none exists
|
||||||
|
class MockNewFeature {
|
||||||
|
public:
|
||||||
|
srs_error_t new_method();
|
||||||
|
};
|
||||||
|
rationale: "Reduces code duplication, maintains consistency, and leverages existing test infrastructure"
|
||||||
|
|
||||||
|
- pattern: "Mock creation guidelines"
|
||||||
|
description: "Guidelines for when and how to create new mock classes"
|
||||||
|
rules:
|
||||||
|
- "Only create new mock classes if no suitable existing mock is available"
|
||||||
|
- "Check all existing utest header files (srs_utest_app*.hpp) for reusable mocks"
|
||||||
|
- "Place new mock class declarations in the appropriate srs_utest_app*.hpp file"
|
||||||
|
- "Place new mock class implementations in the corresponding srs_utest_app*.cpp file"
|
||||||
|
- "Follow existing mock naming conventions (Mock prefix + class name)"
|
||||||
|
- "Keep mock implementations simple and focused on test requirements"
|
||||||
|
|
||||||
error_handling_macros:
|
error_handling_macros:
|
||||||
- Use HELPER_EXPECT_SUCCESS(x) when expecting a function to succeed (returns srs_success)
|
- Use HELPER_EXPECT_SUCCESS(x) when expecting a function to succeed (returns srs_success)
|
||||||
- Use HELPER_EXPECT_FAILED(x) when expecting a function to fail (returns non-srs_success error)
|
- Use HELPER_EXPECT_FAILED(x) when expecting a function to fail (returns non-srs_success error)
|
||||||
|
|
|
||||||
9
.codecov.yml
Normal file
9
.codecov.yml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
coverage:
|
||||||
|
status:
|
||||||
|
project:
|
||||||
|
default:
|
||||||
|
target: auto
|
||||||
|
threshold: 2%
|
||||||
|
patch:
|
||||||
|
default:
|
||||||
|
informational: true
|
||||||
2
trunk/configure
vendored
2
trunk/configure
vendored
|
|
@ -382,7 +382,7 @@ if [[ $SRS_UTEST == YES ]]; then
|
||||||
"srs_utest_st" "srs_utest_rtc2" "srs_utest_rtc3" "srs_utest_fmp4" "srs_utest_source_lock"
|
"srs_utest_st" "srs_utest_rtc2" "srs_utest_rtc3" "srs_utest_fmp4" "srs_utest_source_lock"
|
||||||
"srs_utest_stream_token" "srs_utest_rtc_recv_track" "srs_utest_st2" "srs_utest_hevc_structs"
|
"srs_utest_stream_token" "srs_utest_rtc_recv_track" "srs_utest_st2" "srs_utest_hevc_structs"
|
||||||
"srs_utest_coworkers" "srs_utest_pithy_print" "srs_utest_kernel3" "srs_utest_protocol4"
|
"srs_utest_coworkers" "srs_utest_pithy_print" "srs_utest_kernel3" "srs_utest_protocol4"
|
||||||
"srs_utest_protocol3" "srs_utest_app3" "srs_utest_app4")
|
"srs_utest_protocol3" "srs_utest_app3" "srs_utest_app4" "srs_utest_app5" "srs_utest_app6" "srs_utest_app7" "srs_utest_app_rtc2rtmp")
|
||||||
# Always include SRT utest
|
# Always include SRT utest
|
||||||
MODULE_FILES+=("srs_utest_srt")
|
MODULE_FILES+=("srs_utest_srt")
|
||||||
if [[ $SRS_GB28181 == YES ]]; then
|
if [[ $SRS_GB28181 == YES ]]; then
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ public:
|
||||||
virtual bool hybrid_dying_water_level() = 0;
|
virtual bool hybrid_dying_water_level() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsCircuitBreaker : public ISrsCircuitBreaker, public ISrsFastTimer
|
class SrsCircuitBreaker : public ISrsCircuitBreaker, public ISrsFastTimerHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
bool enabled_;
|
bool enabled_;
|
||||||
|
|
|
||||||
|
|
@ -1380,6 +1380,14 @@ srs_error_t SrsConfDirective::read_token(SrsConfigBuffer *buffer, vector<string>
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsAppConfig::ISrsAppConfig()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsAppConfig::~ISrsAppConfig()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsConfig::SrsConfig()
|
SrsConfig::SrsConfig()
|
||||||
{
|
{
|
||||||
env_only_ = false;
|
env_only_ = false;
|
||||||
|
|
|
||||||
|
|
@ -274,12 +274,34 @@ enum SrsReloadState {
|
||||||
SrsReloadStateFinished = 90,
|
SrsReloadStateFinished = 90,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The app level config interface.
|
||||||
|
class ISrsAppConfig : public ISrsConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsAppConfig();
|
||||||
|
virtual ~ISrsAppConfig();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool get_vhost_http_hooks_enabled(std::string vhost) = 0;
|
||||||
|
virtual SrsConfDirective *get_vhost_on_stop(std::string vhost) = 0;
|
||||||
|
virtual bool get_rtc_nack_enabled(std::string vhost) = 0;
|
||||||
|
virtual bool get_rtc_nack_no_copy(std::string vhost) = 0;
|
||||||
|
virtual bool get_realtime_enabled(std::string vhost, bool is_rtc) = 0;
|
||||||
|
virtual int get_mw_msgs(std::string vhost, bool is_realtime, bool is_rtc) = 0;
|
||||||
|
virtual SrsConfDirective *get_vhost_on_unpublish(std::string vhost) = 0;
|
||||||
|
virtual int get_rtc_drop_for_pt(std::string vhost) = 0;
|
||||||
|
virtual bool get_rtc_twcc_enabled(std::string vhost) = 0;
|
||||||
|
virtual bool get_srt_enabled() = 0;
|
||||||
|
virtual bool get_srt_enabled(std::string vhost) = 0;
|
||||||
|
virtual bool get_rtc_to_rtmp(std::string vhost) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// The config service provider.
|
// The config service provider.
|
||||||
// For the config supports reload, so never keep the reference cross st-thread,
|
// For the config supports reload, so never keep the reference cross st-thread,
|
||||||
// that is, never save the SrsConfDirective* get by any api of config,
|
// that is, never save the SrsConfDirective* get by any api of config,
|
||||||
// For it maybe free in the reload st-thread cycle.
|
// For it maybe free in the reload st-thread cycle.
|
||||||
// You could keep it before st-thread switch, or simply never keep it.
|
// You could keep it before st-thread switch, or simply never keep it.
|
||||||
class SrsConfig : public ISrsConfig
|
class SrsConfig : public ISrsAppConfig
|
||||||
{
|
{
|
||||||
friend class SrsConfDirective;
|
friend class SrsConfDirective;
|
||||||
// user command
|
// user command
|
||||||
|
|
@ -633,11 +655,11 @@ public:
|
||||||
// Get the mw_msgs, mw wait time in packets for vhost.
|
// Get the mw_msgs, mw wait time in packets for vhost.
|
||||||
// @param vhost, the vhost to get the mw sleep msgs.
|
// @param vhost, the vhost to get the mw sleep msgs.
|
||||||
// TODO: FIXME: add utest for mw config.
|
// TODO: FIXME: add utest for mw config.
|
||||||
virtual int get_mw_msgs(std::string vhost, bool is_realtime, bool is_rtc = false);
|
virtual int get_mw_msgs(std::string vhost, bool is_realtime, bool is_rtc);
|
||||||
// Whether min latency mode enabled.
|
// Whether min latency mode enabled.
|
||||||
// @param vhost, the vhost to get the min_latency.
|
// @param vhost, the vhost to get the min_latency.
|
||||||
// TODO: FIXME: add utest for min_latency.
|
// TODO: FIXME: add utest for min_latency.
|
||||||
virtual bool get_realtime_enabled(std::string vhost, bool is_rtc = false);
|
virtual bool get_realtime_enabled(std::string vhost, bool is_rtc);
|
||||||
// Whether enable tcp nodelay for all clients of vhost.
|
// Whether enable tcp nodelay for all clients of vhost.
|
||||||
virtual bool get_tcp_nodelay(std::string vhost);
|
virtual bool get_tcp_nodelay(std::string vhost);
|
||||||
// The minimal send interval in srs_utime_t.
|
// The minimal send interval in srs_utime_t.
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ srs_error_t SrsHttpHeartbeat::do_heartbeat()
|
||||||
obj->set("device_id", SrsJsonAny::str(device_id.c_str()));
|
obj->set("device_id", SrsJsonAny::str(device_id.c_str()));
|
||||||
obj->set("ip", SrsJsonAny::str(ip.c_str()));
|
obj->set("ip", SrsJsonAny::str(ip.c_str()));
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
obj->set("server", SrsJsonAny::str(stat->server_id().c_str()));
|
||||||
obj->set("service", SrsJsonAny::str(stat->service_id().c_str()));
|
obj->set("service", SrsJsonAny::str(stat->service_id().c_str()));
|
||||||
obj->set("pid", SrsJsonAny::str(stat->service_pid().c_str()));
|
obj->set("pid", SrsJsonAny::str(stat->service_pid().c_str()));
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ SrsGoApiRoot::~SrsGoApiRoot()
|
||||||
|
|
||||||
srs_error_t SrsGoApiRoot::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsGoApiRoot::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
|
|
@ -217,7 +217,7 @@ SrsGoApiApi::~SrsGoApiApi()
|
||||||
|
|
||||||
srs_error_t SrsGoApiApi::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsGoApiApi::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
|
|
@ -244,7 +244,7 @@ SrsGoApiV1::~SrsGoApiV1()
|
||||||
|
|
||||||
srs_error_t SrsGoApiV1::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsGoApiV1::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
|
|
@ -300,7 +300,7 @@ SrsGoApiVersion::~SrsGoApiVersion()
|
||||||
|
|
||||||
srs_error_t SrsGoApiVersion::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsGoApiVersion::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
|
|
@ -330,7 +330,7 @@ SrsGoApiSummaries::~SrsGoApiSummaries()
|
||||||
|
|
||||||
srs_error_t SrsGoApiSummaries::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsGoApiSummaries::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
|
|
@ -354,7 +354,7 @@ SrsGoApiRusages::~SrsGoApiRusages()
|
||||||
|
|
||||||
srs_error_t SrsGoApiRusages::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsGoApiRusages::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
|
|
@ -400,7 +400,7 @@ SrsGoApiSelfProcStats::~SrsGoApiSelfProcStats()
|
||||||
|
|
||||||
srs_error_t SrsGoApiSelfProcStats::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsGoApiSelfProcStats::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
|
|
@ -478,7 +478,7 @@ SrsGoApiSystemProcStats::~SrsGoApiSystemProcStats()
|
||||||
|
|
||||||
srs_error_t SrsGoApiSystemProcStats::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsGoApiSystemProcStats::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
|
|
@ -518,7 +518,7 @@ SrsGoApiMemInfos::~SrsGoApiMemInfos()
|
||||||
|
|
||||||
srs_error_t SrsGoApiMemInfos::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsGoApiMemInfos::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
|
|
@ -559,7 +559,7 @@ SrsGoApiAuthors::~SrsGoApiAuthors()
|
||||||
|
|
||||||
srs_error_t SrsGoApiAuthors::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsGoApiAuthors::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
|
|
@ -587,7 +587,7 @@ SrsGoApiFeatures::~SrsGoApiFeatures()
|
||||||
|
|
||||||
srs_error_t SrsGoApiFeatures::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsGoApiFeatures::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
|
|
@ -656,7 +656,7 @@ SrsGoApiRequests::~SrsGoApiRequests()
|
||||||
|
|
||||||
srs_error_t SrsGoApiRequests::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsGoApiRequests::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
|
|
@ -703,7 +703,7 @@ srs_error_t SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessag
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
// path: {pattern}{vhost_id}
|
// path: {pattern}{vhost_id}
|
||||||
// e.g. /api/v1/vhosts/100 pattern= /api/v1/vhosts/, vhost_id=100
|
// e.g. /api/v1/vhosts/100 pattern= /api/v1/vhosts/, vhost_id=100
|
||||||
|
|
@ -761,7 +761,7 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
// path: {pattern}{stream_id}
|
// path: {pattern}{stream_id}
|
||||||
// e.g. /api/v1/streams/100 pattern= /api/v1/streams/, stream_id=100
|
// e.g. /api/v1/streams/100 pattern= /api/v1/streams/, stream_id=100
|
||||||
|
|
@ -823,7 +823,7 @@ srs_error_t SrsGoApiClients::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
// path: {pattern}{client_id}
|
// path: {pattern}{client_id}
|
||||||
// e.g. /api/v1/clients/100 pattern= /api/v1/clients/, client_id=100
|
// e.g. /api/v1/clients/100 pattern= /api/v1/clients/, client_id=100
|
||||||
|
|
@ -1273,7 +1273,7 @@ srs_error_t SrsGoApiMetrics::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
|
||||||
* error counter
|
* error counter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
||||||
#if defined(__linux__) || defined(SRS_OSX)
|
#if defined(__linux__) || defined(SRS_OSX)
|
||||||
|
|
|
||||||
|
|
@ -416,8 +416,8 @@ srs_error_t SrsHttpxConn::on_conn_done(srs_error_t r0)
|
||||||
{
|
{
|
||||||
// Only stat the HTTP streaming clients, ignore all API clients.
|
// Only stat the HTTP streaming clients, ignore all API clients.
|
||||||
if (enable_stat_) {
|
if (enable_stat_) {
|
||||||
SrsStatistic::instance()->on_disconnect(get_id().c_str(), r0);
|
_srs_stat->on_disconnect(get_id().c_str(), r0);
|
||||||
SrsStatistic::instance()->kbps_add_delta(get_id().c_str(), conn_->delta());
|
_srs_stat->kbps_add_delta(get_id().c_str(), conn_->delta());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Because we use manager to manage this object,
|
// Because we use manager to manage this object,
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ srs_error_t SrsHttpHooks::on_connect(string url, ISrsRequest *req)
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
SrsContextId cid = _srs_context->get_id();
|
SrsContextId cid = _srs_context->get_id();
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
||||||
|
|
@ -93,7 +93,7 @@ void SrsHttpHooks::on_close(string url, ISrsRequest *req, int64_t send_bytes, in
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
SrsContextId cid = _srs_context->get_id();
|
SrsContextId cid = _srs_context->get_id();
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
||||||
|
|
@ -130,7 +130,7 @@ srs_error_t SrsHttpHooks::on_publish(string url, ISrsRequest *req)
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
SrsContextId cid = _srs_context->get_id();
|
SrsContextId cid = _srs_context->get_id();
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
||||||
|
|
@ -171,7 +171,7 @@ void SrsHttpHooks::on_unpublish(string url, ISrsRequest *req)
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
SrsContextId cid = _srs_context->get_id();
|
SrsContextId cid = _srs_context->get_id();
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
||||||
|
|
@ -215,7 +215,7 @@ srs_error_t SrsHttpHooks::on_play(string url, ISrsRequest *req)
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
SrsContextId cid = _srs_context->get_id();
|
SrsContextId cid = _srs_context->get_id();
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
||||||
|
|
@ -257,7 +257,7 @@ void SrsHttpHooks::on_stop(string url, ISrsRequest *req)
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
SrsContextId cid = _srs_context->get_id();
|
SrsContextId cid = _srs_context->get_id();
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
||||||
|
|
@ -303,7 +303,7 @@ srs_error_t SrsHttpHooks::on_dvr(SrsContextId c, string url, ISrsRequest *req, s
|
||||||
SrsContextId cid = c;
|
SrsContextId cid = c;
|
||||||
std::string cwd = _srs_config->cwd();
|
std::string cwd = _srs_config->cwd();
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
||||||
|
|
@ -354,7 +354,7 @@ srs_error_t SrsHttpHooks::on_hls(SrsContextId c, string url, ISrsRequest *req, s
|
||||||
ts_url = prefix + "/" + ts_url;
|
ts_url = prefix + "/" + ts_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
|
||||||
|
|
@ -407,7 +407,7 @@ srs_error_t SrsHttpHooks::on_hls_notify(SrsContextId c, std::string url, ISrsReq
|
||||||
url = ts_url;
|
url = ts_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
url = srs_strings_replace(url, "[server_id]", stat->server_id().c_str());
|
url = srs_strings_replace(url, "[server_id]", stat->server_id().c_str());
|
||||||
url = srs_strings_replace(url, "[service_id]", stat->service_id().c_str());
|
url = srs_strings_replace(url, "[service_id]", stat->service_id().c_str());
|
||||||
|
|
@ -526,7 +526,7 @@ srs_error_t SrsHttpHooks::on_forward_backend(string url, ISrsRequest *req, std::
|
||||||
|
|
||||||
SrsContextId cid = _srs_context->get_id();
|
SrsContextId cid = _srs_context->get_id();
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
|
||||||
|
|
||||||
obj->set("action", SrsJsonAny::str("on_forward"));
|
obj->set("action", SrsJsonAny::str("on_forward"));
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ void SrsHlsVirtualConn::expire()
|
||||||
interrupt_ = true;
|
interrupt_ = true;
|
||||||
|
|
||||||
// remove statistic quickly
|
// remove statistic quickly
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
stat->on_disconnect(ctx_, srs_success);
|
stat->on_disconnect(ctx_, srs_success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,7 +141,7 @@ void SrsHlsStream::on_serve_ts_ctx(ISrsHttpResponseWriter *w, ISrsHttpMessage *r
|
||||||
// Only update the delta, because SrsServer will sample it. Note that SrsServer also does the stat for all clients
|
// Only update the delta, because SrsServer will sample it. Note that SrsServer also does the stat for all clients
|
||||||
// including this one, but it should be ignored because the id is not matched, and instead we use the hls_ctx as
|
// including this one, but it should be ignored because the id is not matched, and instead we use the hls_ctx as
|
||||||
// session id to match the client.
|
// session id to match the client.
|
||||||
SrsStatistic::instance()->kbps_add_delta(ctx, delta);
|
_srs_stat->kbps_add_delta(ctx, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsHlsStream::serve_new_session(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, ISrsRequest *req, std::string &ctx)
|
srs_error_t SrsHlsStream::serve_new_session(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, ISrsRequest *req, std::string &ctx)
|
||||||
|
|
@ -162,7 +162,7 @@ srs_error_t SrsHlsStream::serve_new_session(ISrsHttpResponseWriter *w, ISrsHttpM
|
||||||
_srs_context->set_id(SrsContextId().set_value(ctx));
|
_srs_context->set_id(SrsContextId().set_value(ctx));
|
||||||
|
|
||||||
// We must do stat the client before hooks, because hooks depends on it.
|
// We must do stat the client before hooks, because hooks depends on it.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
if ((err = stat->on_client(ctx, req, NULL, SrsHlsPlay)) != srs_success) {
|
if ((err = stat->on_client(ctx, req, NULL, SrsHlsPlay)) != srs_success) {
|
||||||
return srs_error_wrap(err, "stat on client");
|
return srs_error_wrap(err, "stat on client");
|
||||||
}
|
}
|
||||||
|
|
@ -292,7 +292,7 @@ void SrsHlsStream::alive(std::string ctx, ISrsRequest *req)
|
||||||
map_ctx_info_.insert(make_pair(ctx, conn));
|
map_ctx_info_.insert(make_pair(ctx, conn));
|
||||||
|
|
||||||
// Update the conn of stat client, which is used for receiving the event of kickoff.
|
// Update the conn of stat client, which is used for receiving the event of kickoff.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
SrsStatisticClient *client = stat->find_client(ctx);
|
SrsStatisticClient *client = stat->find_client(ctx);
|
||||||
if (client) {
|
if (client) {
|
||||||
client->conn_ = conn;
|
client->conn_ = conn;
|
||||||
|
|
@ -387,7 +387,7 @@ srs_error_t SrsHlsStream::on_timer(srs_utime_t interval)
|
||||||
|
|
||||||
http_hooks_on_stop(info->req_);
|
http_hooks_on_stop(info->req_);
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
// TODO: FIXME: Should finger out the err.
|
// TODO: FIXME: Should finger out the err.
|
||||||
stat->on_disconnect(ctx, srs_success);
|
stat->on_disconnect(ctx, srs_success);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
// Server HLS streaming.
|
// Server HLS streaming.
|
||||||
class SrsHlsStream : public ISrsFastTimer
|
class SrsHlsStream : public ISrsFastTimerHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// The period of validity of the ctx
|
// The period of validity of the ctx
|
||||||
|
|
@ -53,7 +53,7 @@ private:
|
||||||
srs_error_t http_hooks_on_play(ISrsRequest *req);
|
srs_error_t http_hooks_on_play(ISrsRequest *req);
|
||||||
void http_hooks_on_stop(ISrsRequest *req);
|
void http_hooks_on_stop(ISrsRequest *req);
|
||||||
bool is_interrupt(std::string id);
|
bool is_interrupt(std::string id);
|
||||||
// interface ISrsFastTimer
|
// interface ISrsFastTimerHandler
|
||||||
private:
|
private:
|
||||||
srs_error_t on_timer(srs_utime_t interval);
|
srs_error_t on_timer(srs_utime_t interval);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -663,7 +663,7 @@ srs_error_t SrsLiveStream::serve_http_impl(ISrsHttpResponseWriter *w, ISrsHttpMe
|
||||||
req_->ip_ = hc->remote_ip();
|
req_->ip_ = hc->remote_ip();
|
||||||
|
|
||||||
// We must do stat the client before hooks, because hooks depends on it.
|
// We must do stat the client before hooks, because hooks depends on it.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
if ((err = stat->on_client(_srs_context->get_id().c_str(), req_, hc, SrsFlvPlay)) != srs_success) {
|
if ((err = stat->on_client(_srs_context->get_id().c_str(), req_, hc, SrsFlvPlay)) != srs_success) {
|
||||||
return srs_error_wrap(err, "stat on client");
|
return srs_error_wrap(err, "stat on client");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ srs_error_t SrsLatestVersion::start()
|
||||||
return srs_success;
|
return srs_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
server_id_ = SrsStatistic::instance()->server_id();
|
server_id_ = _srs_stat->server_id();
|
||||||
session_id_ = srs_generate_stat_vid();
|
session_id_ = srs_generate_stat_vid();
|
||||||
|
|
||||||
return trd_->start();
|
return trd_->start();
|
||||||
|
|
@ -243,7 +243,7 @@ srs_error_t SrsLatestVersion::query_latest_version(string &url)
|
||||||
<< "&ts=" << srs_time_now_cached()
|
<< "&ts=" << srs_time_now_cached()
|
||||||
<< "&alive=" << srsu2ms(srs_time_now_cached() - srs_time_since_startup()) / 1000;
|
<< "&alive=" << srsu2ms(srs_time_now_cached() - srs_time_since_startup()) / 1000;
|
||||||
srs_build_features(ss);
|
srs_build_features(ss);
|
||||||
SrsStatistic::instance()->dumps_hints_kv(ss);
|
_srs_stat->dumps_hints_kv(ss);
|
||||||
url = ss.str();
|
url = ss.str();
|
||||||
|
|
||||||
SrsHttpUri uri;
|
SrsHttpUri uri;
|
||||||
|
|
|
||||||
|
|
@ -279,7 +279,7 @@ SrsPublishRecvThread::SrsPublishRecvThread(SrsRtmpServer *rtmp_sdk, ISrsRequest
|
||||||
mr_ = _srs_config->get_mr_enabled(req_->vhost_);
|
mr_ = _srs_config->get_mr_enabled(req_->vhost_);
|
||||||
mr_sleep_ = _srs_config->get_mr_sleep(req_->vhost_);
|
mr_sleep_ = _srs_config->get_mr_sleep(req_->vhost_);
|
||||||
|
|
||||||
realtime_ = _srs_config->get_realtime_enabled(req_->vhost_);
|
realtime_ = _srs_config->get_realtime_enabled(req_->vhost_, false);
|
||||||
|
|
||||||
_srs_config->subscribe(this);
|
_srs_config->subscribe(this);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -178,9 +178,9 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
|
||||||
}
|
}
|
||||||
|
|
||||||
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||||
res->set("server", SrsJsonAny::str(SrsStatistic::instance()->server_id().c_str()));
|
res->set("server", SrsJsonAny::str(_srs_stat->server_id().c_str()));
|
||||||
res->set("service", SrsJsonAny::str(SrsStatistic::instance()->service_id().c_str()));
|
res->set("service", SrsJsonAny::str(_srs_stat->service_id().c_str()));
|
||||||
res->set("pid", SrsJsonAny::str(SrsStatistic::instance()->service_pid().c_str()));
|
res->set("pid", SrsJsonAny::str(_srs_stat->service_pid().c_str()));
|
||||||
|
|
||||||
// TODO: add candidates in response json?
|
// TODO: add candidates in response json?
|
||||||
res->set("sdp", SrsJsonAny::str(ruc.local_sdp_str_.c_str()));
|
res->set("sdp", SrsJsonAny::str(ruc.local_sdp_str_.c_str()));
|
||||||
|
|
@ -465,9 +465,9 @@ srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter *w, ISrsHtt
|
||||||
}
|
}
|
||||||
|
|
||||||
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||||
res->set("server", SrsJsonAny::str(SrsStatistic::instance()->server_id().c_str()));
|
res->set("server", SrsJsonAny::str(_srs_stat->server_id().c_str()));
|
||||||
res->set("service", SrsJsonAny::str(SrsStatistic::instance()->service_id().c_str()));
|
res->set("service", SrsJsonAny::str(_srs_stat->service_id().c_str()));
|
||||||
res->set("pid", SrsJsonAny::str(SrsStatistic::instance()->service_pid().c_str()));
|
res->set("pid", SrsJsonAny::str(_srs_stat->service_pid().c_str()));
|
||||||
|
|
||||||
// TODO: add candidates in response json?
|
// TODO: add candidates in response json?
|
||||||
res->set("sdp", SrsJsonAny::str(ruc.local_sdp_str_.c_str()));
|
res->set("sdp", SrsJsonAny::str(ruc.local_sdp_str_.c_str()));
|
||||||
|
|
|
||||||
|
|
@ -293,31 +293,31 @@ srs_error_t SrsPlaintextTransport::unprotect_rtcp(void *packet, int *nb_plaintex
|
||||||
return srs_success;
|
return srs_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
ISrsRtcPLIWorkerHandler::ISrsRtcPLIWorkerHandler()
|
ISrsRtcPliWorkerHandler::ISrsRtcPliWorkerHandler()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ISrsRtcPLIWorkerHandler::~ISrsRtcPLIWorkerHandler()
|
ISrsRtcPliWorkerHandler::~ISrsRtcPliWorkerHandler()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcPLIWorker::SrsRtcPLIWorker(ISrsRtcPLIWorkerHandler *h)
|
SrsRtcPliWorker::SrsRtcPliWorker(ISrsRtcPliWorkerHandler *h)
|
||||||
{
|
{
|
||||||
handler_ = h;
|
handler_ = h;
|
||||||
wait_ = srs_cond_new();
|
wait_ = new SrsCond();
|
||||||
trd_ = new SrsSTCoroutine("pli", this, _srs_context->get_id());
|
trd_ = new SrsSTCoroutine("pli", this, _srs_context->get_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcPLIWorker::~SrsRtcPLIWorker()
|
SrsRtcPliWorker::~SrsRtcPliWorker()
|
||||||
{
|
{
|
||||||
srs_cond_signal(wait_);
|
wait_->signal();
|
||||||
trd_->stop();
|
trd_->stop();
|
||||||
|
|
||||||
srs_freep(trd_);
|
srs_freep(trd_);
|
||||||
srs_cond_destroy(wait_);
|
srs_freep(wait_);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsRtcPLIWorker::start()
|
srs_error_t SrsRtcPliWorker::start()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
@ -328,13 +328,13 @@ srs_error_t SrsRtcPLIWorker::start()
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsRtcPLIWorker::request_keyframe(uint32_t ssrc, SrsContextId cid)
|
void SrsRtcPliWorker::request_keyframe(uint32_t ssrc, SrsContextId cid)
|
||||||
{
|
{
|
||||||
plis_.insert(make_pair(ssrc, cid));
|
plis_.insert(make_pair(ssrc, cid));
|
||||||
srs_cond_signal(wait_);
|
wait_->signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsRtcPLIWorker::cycle()
|
srs_error_t SrsRtcPliWorker::cycle()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
@ -359,7 +359,8 @@ srs_error_t SrsRtcPLIWorker::cycle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
srs_cond_wait(wait_);
|
|
||||||
|
wait_->wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -369,18 +370,25 @@ SrsRtcAsyncCallOnStop::SrsRtcAsyncCallOnStop(SrsContextId c, ISrsRequest *r)
|
||||||
{
|
{
|
||||||
cid_ = c;
|
cid_ = c;
|
||||||
req_ = r->copy();
|
req_ = r->copy();
|
||||||
|
hooks_ = _srs_hooks;
|
||||||
|
context_ = _srs_context;
|
||||||
|
config_ = _srs_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcAsyncCallOnStop::~SrsRtcAsyncCallOnStop()
|
SrsRtcAsyncCallOnStop::~SrsRtcAsyncCallOnStop()
|
||||||
{
|
{
|
||||||
srs_freep(req_);
|
srs_freep(req_);
|
||||||
|
|
||||||
|
hooks_ = NULL;
|
||||||
|
context_ = NULL;
|
||||||
|
config_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsRtcAsyncCallOnStop::call()
|
srs_error_t SrsRtcAsyncCallOnStop::call()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost_)) {
|
if (!config_->get_vhost_http_hooks_enabled(req_->vhost_)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -390,7 +398,7 @@ srs_error_t SrsRtcAsyncCallOnStop::call()
|
||||||
vector<string> hooks;
|
vector<string> hooks;
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsConfDirective *conf = _srs_config->get_vhost_on_stop(req_->vhost_);
|
SrsConfDirective *conf = config_->get_vhost_on_stop(req_->vhost_);
|
||||||
|
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -399,12 +407,12 @@ srs_error_t SrsRtcAsyncCallOnStop::call()
|
||||||
hooks = conf->args_;
|
hooks = conf->args_;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsContextRestore(_srs_context->get_id());
|
SrsContextRestore(context_->get_id());
|
||||||
_srs_context->set_id(cid_);
|
context_->set_id(cid_);
|
||||||
|
|
||||||
for (int i = 0; i < (int)hooks.size(); i++) {
|
for (int i = 0; i < (int)hooks.size(); i++) {
|
||||||
std::string url = hooks.at(i);
|
std::string url = hooks.at(i);
|
||||||
_srs_hooks->on_stop(url, req_);
|
hooks_->on_stop(url, req_);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -415,15 +423,18 @@ std::string SrsRtcAsyncCallOnStop::to_string()
|
||||||
return std::string("");
|
return std::string("");
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcPlayStream::SrsRtcPlayStream(SrsRtcConnection *s, const SrsContextId &cid) : source_(new SrsRtcSource())
|
SrsRtcPlayStream::SrsRtcPlayStream(ISrsExecRtcAsyncTask *exec, ISrsExpire *expire, ISrsRtcPacketSender *sender, const SrsContextId &cid) : source_(new SrsRtcSource())
|
||||||
{
|
{
|
||||||
|
exec_ = exec;
|
||||||
|
expire_ = expire;
|
||||||
|
sender_ = sender;
|
||||||
|
|
||||||
cid_ = cid;
|
cid_ = cid;
|
||||||
trd_ = NULL;
|
trd_ = NULL;
|
||||||
|
|
||||||
req_ = NULL;
|
req_ = NULL;
|
||||||
|
|
||||||
is_started_ = false;
|
is_started_ = false;
|
||||||
session_ = s;
|
|
||||||
|
|
||||||
mw_msgs_ = 0;
|
mw_msgs_ = 0;
|
||||||
realtime_ = true;
|
realtime_ = true;
|
||||||
|
|
@ -433,16 +444,20 @@ SrsRtcPlayStream::SrsRtcPlayStream(SrsRtcConnection *s, const SrsContextId &cid)
|
||||||
|
|
||||||
_srs_config->subscribe(this);
|
_srs_config->subscribe(this);
|
||||||
nack_epp_ = new SrsErrorPithyPrint();
|
nack_epp_ = new SrsErrorPithyPrint();
|
||||||
pli_worker_ = new SrsRtcPLIWorker(this);
|
pli_worker_ = new SrsRtcPliWorker(this);
|
||||||
|
|
||||||
cache_ssrc0_ = cache_ssrc1_ = cache_ssrc2_ = 0;
|
cache_ssrc0_ = cache_ssrc1_ = cache_ssrc2_ = 0;
|
||||||
cache_track0_ = cache_track1_ = cache_track2_ = NULL;
|
cache_track0_ = cache_track1_ = cache_track2_ = NULL;
|
||||||
|
|
||||||
|
config_ = _srs_config;
|
||||||
|
rtc_sources_ = _srs_rtc_sources;
|
||||||
|
stat_ = _srs_stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcPlayStream::~SrsRtcPlayStream()
|
SrsRtcPlayStream::~SrsRtcPlayStream()
|
||||||
{
|
{
|
||||||
if (req_) {
|
if (req_ && exec_) {
|
||||||
session_->exec_->exec_rtc_async_work(new SrsRtcAsyncCallOnStop(cid_, req_));
|
exec_->exec_rtc_async_work(new SrsRtcAsyncCallOnStop(cid_, req_));
|
||||||
}
|
}
|
||||||
|
|
||||||
_srs_config->unsubscribe(this);
|
_srs_config->unsubscribe(this);
|
||||||
|
|
@ -467,9 +482,12 @@ SrsRtcPlayStream::~SrsRtcPlayStream()
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the statistic when client coveried.
|
// update the statistic when client coveried.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
|
||||||
// TODO: FIXME: Should finger out the err.
|
// TODO: FIXME: Should finger out the err.
|
||||||
stat->on_disconnect(cid_.c_str(), srs_success);
|
stat_->on_disconnect(cid_.c_str(), srs_success);
|
||||||
|
|
||||||
|
config_ = NULL;
|
||||||
|
rtc_sources_ = NULL;
|
||||||
|
stat_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsRtcPlayStream::initialize(ISrsRequest *req, std::map<uint32_t, SrsRtcTrackDescription *> sub_relations)
|
srs_error_t SrsRtcPlayStream::initialize(ISrsRequest *req, std::map<uint32_t, SrsRtcTrackDescription *> sub_relations)
|
||||||
|
|
@ -479,12 +497,11 @@ srs_error_t SrsRtcPlayStream::initialize(ISrsRequest *req, std::map<uint32_t, Sr
|
||||||
req_ = req->copy();
|
req_ = req->copy();
|
||||||
|
|
||||||
// We must do stat the client before hooks, because hooks depends on it.
|
// We must do stat the client before hooks, because hooks depends on it.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
if ((err = stat_->on_client(cid_.c_str(), req_, expire_, SrsRtcConnPlay)) != srs_success) {
|
||||||
if ((err = stat->on_client(cid_.c_str(), req_, session_, SrsRtcConnPlay)) != srs_success) {
|
|
||||||
return srs_error_wrap(err, "rtc: stat client");
|
return srs_error_wrap(err, "rtc: stat client");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = _srs_rtc_sources->fetch_or_create(req_, source_)) != srs_success) {
|
if ((err = rtc_sources_->fetch_or_create(req_, source_)) != srs_success) {
|
||||||
return srs_error_wrap(err, "rtc fetch source failed");
|
return srs_error_wrap(err, "rtc fetch source failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -493,19 +510,19 @@ srs_error_t SrsRtcPlayStream::initialize(ISrsRequest *req, std::map<uint32_t, Sr
|
||||||
SrsRtcTrackDescription *desc = it->second;
|
SrsRtcTrackDescription *desc = it->second;
|
||||||
|
|
||||||
if (desc->type_ == "audio") {
|
if (desc->type_ == "audio") {
|
||||||
SrsRtcAudioSendTrack *track = new SrsRtcAudioSendTrack(session_, desc);
|
SrsRtcAudioSendTrack *track = new SrsRtcAudioSendTrack(sender_, desc);
|
||||||
audio_tracks_.insert(make_pair(ssrc, track));
|
audio_tracks_.insert(make_pair(ssrc, track));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desc->type_ == "video") {
|
if (desc->type_ == "video") {
|
||||||
SrsRtcVideoSendTrack *track = new SrsRtcVideoSendTrack(session_, desc);
|
SrsRtcVideoSendTrack *track = new SrsRtcVideoSendTrack(sender_, desc);
|
||||||
video_tracks_.insert(make_pair(ssrc, track));
|
video_tracks_.insert(make_pair(ssrc, track));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: FIXME: Support reload.
|
// TODO: FIXME: Support reload.
|
||||||
nack_enabled_ = _srs_config->get_rtc_nack_enabled(req->vhost_);
|
nack_enabled_ = config_->get_rtc_nack_enabled(req->vhost_);
|
||||||
nack_no_copy_ = _srs_config->get_rtc_nack_no_copy(req->vhost_);
|
nack_no_copy_ = config_->get_rtc_nack_no_copy(req->vhost_);
|
||||||
srs_trace("RTC player nack=%d, nnc=%d", nack_enabled_, nack_no_copy_);
|
srs_trace("RTC player nack=%d, nnc=%d", nack_enabled_, nack_no_copy_);
|
||||||
|
|
||||||
// Setup tracks.
|
// Setup tracks.
|
||||||
|
|
@ -641,8 +658,8 @@ srs_error_t SrsRtcPlayStream::cycle()
|
||||||
return srs_error_wrap(err, "dumps consumer, url=%s", req_->get_stream_url().c_str());
|
return srs_error_wrap(err, "dumps consumer, url=%s", req_->get_stream_url().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
realtime_ = _srs_config->get_realtime_enabled(req_->vhost_, true);
|
realtime_ = config_->get_realtime_enabled(req_->vhost_, true);
|
||||||
mw_msgs_ = _srs_config->get_mw_msgs(req_->vhost_, realtime_, true);
|
mw_msgs_ = config_->get_mw_msgs(req_->vhost_, realtime_, true);
|
||||||
|
|
||||||
// TODO: FIXME: Add cost in ms.
|
// TODO: FIXME: Add cost in ms.
|
||||||
SrsContextId cid = source->source_id();
|
SrsContextId cid = source->source_id();
|
||||||
|
|
@ -925,7 +942,15 @@ srs_error_t SrsRtcPlayStream::do_request_keyframe(uint32_t ssrc, SrsContextId ci
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcPublishRtcpTimer::SrsRtcPublishRtcpTimer(SrsRtcPublishStream *p) : p_(p)
|
ISrsRtcRtcpSender::ISrsRtcRtcpSender()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsRtcRtcpSender::~ISrsRtcRtcpSender()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsRtcPublishRtcpTimer::SrsRtcPublishRtcpTimer(ISrsRtcRtcpSender *sender) : sender_(sender)
|
||||||
{
|
{
|
||||||
lock_ = srs_mutex_new();
|
lock_ = srs_mutex_new();
|
||||||
_srs_shared_timer->timer1s()->subscribe(this);
|
_srs_shared_timer->timer1s()->subscribe(this);
|
||||||
|
|
@ -952,19 +977,19 @@ srs_error_t SrsRtcPublishRtcpTimer::on_timer(srs_utime_t interval)
|
||||||
|
|
||||||
++_srs_pps_pub->sugar_;
|
++_srs_pps_pub->sugar_;
|
||||||
|
|
||||||
if (!p_->is_started_) {
|
if (!sender_->is_sender_started()) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For RR and RRTR.
|
// For RR and RRTR.
|
||||||
++_srs_pps_rr->sugar_;
|
++_srs_pps_rr->sugar_;
|
||||||
|
|
||||||
if ((err = p_->send_rtcp_rr()) != srs_success) {
|
if ((err = sender_->send_rtcp_rr()) != srs_success) {
|
||||||
srs_warn("RR err %s", srs_error_desc(err).c_str());
|
srs_warn("RR err %s", srs_error_desc(err).c_str());
|
||||||
srs_freep(err);
|
srs_freep(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = p_->send_rtcp_xr_rrtr()) != srs_success) {
|
if ((err = sender_->send_rtcp_xr_rrtr()) != srs_success) {
|
||||||
srs_warn("XR err %s", srs_error_desc(err).c_str());
|
srs_warn("XR err %s", srs_error_desc(err).c_str());
|
||||||
srs_freep(err);
|
srs_freep(err);
|
||||||
}
|
}
|
||||||
|
|
@ -972,7 +997,7 @@ srs_error_t SrsRtcPublishRtcpTimer::on_timer(srs_utime_t interval)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcPublishTwccTimer::SrsRtcPublishTwccTimer(SrsRtcPublishStream *p) : p_(p)
|
SrsRtcPublishTwccTimer::SrsRtcPublishTwccTimer(ISrsRtcRtcpSender *sender) : sender_(sender)
|
||||||
{
|
{
|
||||||
lock_ = srs_mutex_new();
|
lock_ = srs_mutex_new();
|
||||||
_srs_shared_timer->timer100ms()->subscribe(this);
|
_srs_shared_timer->timer100ms()->subscribe(this);
|
||||||
|
|
@ -999,12 +1024,12 @@ srs_error_t SrsRtcPublishTwccTimer::on_timer(srs_utime_t interval)
|
||||||
|
|
||||||
++_srs_pps_pub->sugar_;
|
++_srs_pps_pub->sugar_;
|
||||||
|
|
||||||
if (!p_->is_started_) {
|
if (!sender_->is_sender_started()) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For TWCC feedback.
|
// For TWCC feedback.
|
||||||
if (!p_->twcc_enabled_) {
|
if (!sender_->is_sender_twcc_enabled()) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1018,7 +1043,7 @@ srs_error_t SrsRtcPublishTwccTimer::on_timer(srs_utime_t interval)
|
||||||
|
|
||||||
// We should not depends on the received packet,
|
// We should not depends on the received packet,
|
||||||
// instead we should send feedback every Nms.
|
// instead we should send feedback every Nms.
|
||||||
if ((err = p_->send_periodic_twcc()) != srs_success) {
|
if ((err = sender_->send_periodic_twcc()) != srs_success) {
|
||||||
srs_warn("TWCC err %s", srs_error_desc(err).c_str());
|
srs_warn("TWCC err %s", srs_error_desc(err).c_str());
|
||||||
srs_freep(err);
|
srs_freep(err);
|
||||||
}
|
}
|
||||||
|
|
@ -1030,18 +1055,24 @@ SrsRtcAsyncCallOnUnpublish::SrsRtcAsyncCallOnUnpublish(SrsContextId c, ISrsReque
|
||||||
{
|
{
|
||||||
cid_ = c;
|
cid_ = c;
|
||||||
req_ = r->copy();
|
req_ = r->copy();
|
||||||
|
|
||||||
|
hooks_ = _srs_hooks;
|
||||||
|
config_ = _srs_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcAsyncCallOnUnpublish::~SrsRtcAsyncCallOnUnpublish()
|
SrsRtcAsyncCallOnUnpublish::~SrsRtcAsyncCallOnUnpublish()
|
||||||
{
|
{
|
||||||
srs_freep(req_);
|
srs_freep(req_);
|
||||||
|
|
||||||
|
hooks_ = NULL;
|
||||||
|
config_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsRtcAsyncCallOnUnpublish::call()
|
srs_error_t SrsRtcAsyncCallOnUnpublish::call()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost_)) {
|
if (!config_->get_vhost_http_hooks_enabled(req_->vhost_)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1051,7 +1082,7 @@ srs_error_t SrsRtcAsyncCallOnUnpublish::call()
|
||||||
vector<string> hooks;
|
vector<string> hooks;
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsConfDirective *conf = _srs_config->get_vhost_on_unpublish(req_->vhost_);
|
SrsConfDirective *conf = config_->get_vhost_on_unpublish(req_->vhost_);
|
||||||
|
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -1065,7 +1096,7 @@ srs_error_t SrsRtcAsyncCallOnUnpublish::call()
|
||||||
|
|
||||||
for (int i = 0; i < (int)hooks.size(); i++) {
|
for (int i = 0; i < (int)hooks.size(); i++) {
|
||||||
std::string url = hooks.at(i);
|
std::string url = hooks.at(i);
|
||||||
_srs_hooks->on_unpublish(url, req_);
|
hooks_->on_unpublish(url, req_);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -1076,11 +1107,14 @@ std::string SrsRtcAsyncCallOnUnpublish::to_string()
|
||||||
return std::string("");
|
return std::string("");
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcPublishStream::SrsRtcPublishStream(SrsRtcConnection *session, const SrsContextId &cid) : source_(new SrsRtcSource())
|
SrsRtcPublishStream::SrsRtcPublishStream(ISrsExecRtcAsyncTask *exec, ISrsExpire *expire, ISrsRtcPacketReceiver *receiver, const SrsContextId &cid) : source_(new SrsRtcSource())
|
||||||
{
|
{
|
||||||
|
exec_ = exec;
|
||||||
|
expire_ = expire;
|
||||||
|
receiver_ = receiver;
|
||||||
|
|
||||||
cid_ = cid;
|
cid_ = cid;
|
||||||
is_started_ = false;
|
is_sender_started_ = false;
|
||||||
session_ = session;
|
|
||||||
request_keyframe_ = false;
|
request_keyframe_ = false;
|
||||||
pli_epp_ = new SrsErrorPithyPrint();
|
pli_epp_ = new SrsErrorPithyPrint();
|
||||||
twcc_epp_ = new SrsErrorPithyPrint(3.0);
|
twcc_epp_ = new SrsErrorPithyPrint(3.0);
|
||||||
|
|
@ -1096,17 +1130,24 @@ SrsRtcPublishStream::SrsRtcPublishStream(SrsRtcConnection *session, const SrsCon
|
||||||
twcc_id_ = 0;
|
twcc_id_ = 0;
|
||||||
twcc_fb_count_ = 0;
|
twcc_fb_count_ = 0;
|
||||||
|
|
||||||
pli_worker_ = new SrsRtcPLIWorker(this);
|
pli_worker_ = new SrsRtcPliWorker(this);
|
||||||
last_time_send_twcc_ = 0;
|
last_time_send_twcc_ = 0;
|
||||||
|
|
||||||
timer_rtcp_ = new SrsRtcPublishRtcpTimer(this);
|
timer_rtcp_ = new SrsRtcPublishRtcpTimer(this);
|
||||||
timer_twcc_ = new SrsRtcPublishTwccTimer(this);
|
timer_twcc_ = new SrsRtcPublishTwccTimer(this);
|
||||||
|
|
||||||
|
stat_ = _srs_stat;
|
||||||
|
config_ = _srs_config;
|
||||||
|
rtc_sources_ = _srs_rtc_sources;
|
||||||
|
live_sources_ = _srs_sources;
|
||||||
|
srt_sources_ = _srs_srt_sources;
|
||||||
|
circuit_breaker_ = _srs_circuit_breaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcPublishStream::~SrsRtcPublishStream()
|
SrsRtcPublishStream::~SrsRtcPublishStream()
|
||||||
{
|
{
|
||||||
if (req_) {
|
if (req_ && exec_) {
|
||||||
session_->exec_->exec_rtc_async_work(new SrsRtcAsyncCallOnUnpublish(cid_, req_));
|
exec_->exec_rtc_async_work(new SrsRtcAsyncCallOnUnpublish(cid_, req_));
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_freep(timer_rtcp_);
|
srs_freep(timer_rtcp_);
|
||||||
|
|
@ -1133,9 +1174,16 @@ SrsRtcPublishStream::~SrsRtcPublishStream()
|
||||||
srs_freep(req_);
|
srs_freep(req_);
|
||||||
|
|
||||||
// update the statistic when client coveried.
|
// update the statistic when client coveried.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
|
||||||
// TODO: FIXME: Should finger out the err.
|
// TODO: FIXME: Should finger out the err.
|
||||||
stat->on_disconnect(cid_.c_str(), srs_success);
|
stat_->on_disconnect(cid_.c_str(), srs_success);
|
||||||
|
|
||||||
|
// Optional but just to make it clear.
|
||||||
|
stat_ = NULL;
|
||||||
|
config_ = NULL;
|
||||||
|
rtc_sources_ = NULL;
|
||||||
|
live_sources_ = NULL;
|
||||||
|
srt_sources_ = NULL;
|
||||||
|
circuit_breaker_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsRtcPublishStream::initialize(ISrsRequest *r, SrsRtcSourceDescription *stream_desc)
|
srs_error_t SrsRtcPublishStream::initialize(ISrsRequest *r, SrsRtcSourceDescription *stream_desc)
|
||||||
|
|
@ -1145,18 +1193,17 @@ srs_error_t SrsRtcPublishStream::initialize(ISrsRequest *r, SrsRtcSourceDescript
|
||||||
req_ = r->copy();
|
req_ = r->copy();
|
||||||
|
|
||||||
// We must do stat the client before hooks, because hooks depends on it.
|
// We must do stat the client before hooks, because hooks depends on it.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
if ((err = stat_->on_client(cid_.c_str(), req_, expire_, SrsRtcConnPublish)) != srs_success) {
|
||||||
if ((err = stat->on_client(cid_.c_str(), req_, session_, SrsRtcConnPublish)) != srs_success) {
|
|
||||||
return srs_error_wrap(err, "rtc: stat client");
|
return srs_error_wrap(err, "rtc: stat client");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream_desc->audio_track_desc_) {
|
if (stream_desc->audio_track_desc_) {
|
||||||
audio_tracks_.push_back(new SrsRtcAudioRecvTrack(session_, stream_desc->audio_track_desc_));
|
audio_tracks_.push_back(new SrsRtcAudioRecvTrack(receiver_, stream_desc->audio_track_desc_));
|
||||||
}
|
}
|
||||||
|
|
||||||
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 *desc = stream_desc->video_track_descs_.at(i);
|
SrsRtcTrackDescription *desc = stream_desc->video_track_descs_.at(i);
|
||||||
video_tracks_.push_back(new SrsRtcVideoRecvTrack(session_, desc));
|
video_tracks_.push_back(new SrsRtcVideoRecvTrack(receiver_, desc));
|
||||||
}
|
}
|
||||||
|
|
||||||
int twcc_id = -1;
|
int twcc_id = -1;
|
||||||
|
|
@ -1175,10 +1222,10 @@ srs_error_t SrsRtcPublishStream::initialize(ISrsRequest *r, SrsRtcSourceDescript
|
||||||
rtcp_twcc_.set_media_ssrc(media_ssrc);
|
rtcp_twcc_.set_media_ssrc(media_ssrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
nack_enabled_ = _srs_config->get_rtc_nack_enabled(req_->vhost_);
|
nack_enabled_ = config_->get_rtc_nack_enabled(req_->vhost_);
|
||||||
nack_no_copy_ = _srs_config->get_rtc_nack_no_copy(req_->vhost_);
|
nack_no_copy_ = config_->get_rtc_nack_no_copy(req_->vhost_);
|
||||||
pt_to_drop_ = (uint16_t)_srs_config->get_rtc_drop_for_pt(req_->vhost_);
|
pt_to_drop_ = (uint16_t)config_->get_rtc_drop_for_pt(req_->vhost_);
|
||||||
twcc_enabled_ = _srs_config->get_rtc_twcc_enabled(req_->vhost_);
|
twcc_enabled_ = config_->get_rtc_twcc_enabled(req_->vhost_);
|
||||||
|
|
||||||
// No TWCC when negotiate, disable it.
|
// No TWCC when negotiate, disable it.
|
||||||
if (twcc_id <= 0) {
|
if (twcc_id <= 0) {
|
||||||
|
|
@ -1199,14 +1246,14 @@ srs_error_t SrsRtcPublishStream::initialize(ISrsRequest *r, SrsRtcSourceDescript
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the publish stream in source to enable PLI as such.
|
// Setup the publish stream in source to enable PLI as such.
|
||||||
if ((err = _srs_rtc_sources->fetch_or_create(req_, source_)) != srs_success) {
|
if ((err = rtc_sources_->fetch_or_create(req_, source_)) != srs_success) {
|
||||||
return srs_error_wrap(err, "create source");
|
return srs_error_wrap(err, "create source");
|
||||||
}
|
}
|
||||||
source_->set_publish_stream(this);
|
source_->set_publish_stream(this);
|
||||||
|
|
||||||
// TODO: FIMXE: Check it in SrsRtcConnection::add_publisher?
|
// TODO: FIMXE: Check it in SrsRtcConnection::add_publisher?
|
||||||
SrsSharedPtr<SrsLiveSource> live_source;
|
SrsSharedPtr<SrsLiveSource> live_source;
|
||||||
if ((err = _srs_sources->fetch_or_create(r, live_source)) != srs_success) {
|
if ((err = live_sources_->fetch_or_create(r, live_source)) != srs_success) {
|
||||||
return srs_error_wrap(err, "create live source");
|
return srs_error_wrap(err, "create live source");
|
||||||
}
|
}
|
||||||
if (!live_source->can_publish(false)) {
|
if (!live_source->can_publish(false)) {
|
||||||
|
|
@ -1214,11 +1261,11 @@ srs_error_t SrsRtcPublishStream::initialize(ISrsRequest *r, SrsRtcSourceDescript
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether SRT stream is busy.
|
// Check whether SRT stream is busy.
|
||||||
bool srt_server_enabled = _srs_config->get_srt_enabled();
|
bool srt_server_enabled = config_->get_srt_enabled();
|
||||||
bool srt_enabled = _srs_config->get_srt_enabled(r->vhost_);
|
bool srt_enabled = config_->get_srt_enabled(r->vhost_);
|
||||||
if (srt_server_enabled && srt_enabled) {
|
if (srt_server_enabled && srt_enabled) {
|
||||||
SrsSharedPtr<SrsSrtSource> srt;
|
SrsSharedPtr<SrsSrtSource> srt;
|
||||||
if ((err = _srs_srt_sources->fetch_or_create(r, srt)) != srs_success) {
|
if ((err = srt_sources_->fetch_or_create(r, srt)) != srs_success) {
|
||||||
return srs_error_wrap(err, "create source");
|
return srs_error_wrap(err, "create source");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1232,7 +1279,7 @@ srs_error_t SrsRtcPublishStream::initialize(ISrsRequest *r, SrsRtcSourceDescript
|
||||||
|
|
||||||
// Bridge to RTMP.
|
// Bridge to RTMP.
|
||||||
// TODO: Support bridge to RTSP.
|
// TODO: Support bridge to RTSP.
|
||||||
bool rtc_to_rtmp = _srs_config->get_rtc_to_rtmp(req_->vhost_);
|
bool rtc_to_rtmp = config_->get_rtc_to_rtmp(req_->vhost_);
|
||||||
if (rtc_to_rtmp) {
|
if (rtc_to_rtmp) {
|
||||||
// Disable GOP cache for RTC2RTMP bridge, to keep the streams in sync,
|
// Disable GOP cache for RTC2RTMP bridge, to keep the streams in sync,
|
||||||
// especially for stream merging.
|
// especially for stream merging.
|
||||||
|
|
@ -1263,7 +1310,7 @@ srs_error_t SrsRtcPublishStream::start()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if (is_started_) {
|
if (is_sender_started_) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1275,7 +1322,7 @@ srs_error_t SrsRtcPublishStream::start()
|
||||||
return srs_error_wrap(err, "start pli worker");
|
return srs_error_wrap(err, "start pli worker");
|
||||||
}
|
}
|
||||||
|
|
||||||
is_started_ = true;
|
is_sender_started_ = true;
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -1314,6 +1361,16 @@ const SrsContextId &SrsRtcPublishStream::context_id()
|
||||||
return cid_;
|
return cid_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SrsRtcPublishStream::is_sender_twcc_enabled()
|
||||||
|
{
|
||||||
|
return twcc_enabled_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SrsRtcPublishStream::is_sender_started()
|
||||||
|
{
|
||||||
|
return is_sender_started_;
|
||||||
|
}
|
||||||
|
|
||||||
srs_error_t SrsRtcPublishStream::send_rtcp_rr()
|
srs_error_t SrsRtcPublishStream::send_rtcp_rr()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
@ -1466,7 +1523,7 @@ srs_error_t SrsRtcPublishStream::do_on_rtp_plaintext(SrsRtpPacket *&pkt, SrsBuff
|
||||||
}
|
}
|
||||||
|
|
||||||
// If circuit-breaker is enabled, disable nack.
|
// If circuit-breaker is enabled, disable nack.
|
||||||
if (_srs_circuit_breaker->hybrid_critical_water_level()) {
|
if (circuit_breaker_->hybrid_critical_water_level()) {
|
||||||
++_srs_pps_snack4->sugar_;
|
++_srs_pps_snack4->sugar_;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -1563,7 +1620,7 @@ srs_error_t SrsRtcPublishStream::send_periodic_twcc()
|
||||||
return srs_error_wrap(err, "encode, count=%u", twcc_fb_count_);
|
return srs_error_wrap(err, "encode, count=%u", twcc_fb_count_);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = session_->send_rtcp(pkt, buffer->pos())) != srs_success) {
|
if ((err = receiver_->send_rtcp(pkt, buffer->pos())) != srs_success) {
|
||||||
return srs_error_wrap(err, "send twcc, count=%u", twcc_fb_count_);
|
return srs_error_wrap(err, "send twcc, count=%u", twcc_fb_count_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1678,7 +1735,7 @@ void SrsRtcPublishStream::request_keyframe(uint32_t ssrc, SrsContextId cid)
|
||||||
srs_error_t SrsRtcPublishStream::do_request_keyframe(uint32_t ssrc, SrsContextId sub_cid)
|
srs_error_t SrsRtcPublishStream::do_request_keyframe(uint32_t ssrc, SrsContextId sub_cid)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
if ((err = session_->send_rtcp_fb_pli(ssrc, sub_cid)) != srs_success) {
|
if ((err = receiver_->send_rtcp_fb_pli(ssrc, sub_cid)) != srs_success) {
|
||||||
srs_warn("PLI err %s", srs_error_desc(err).c_str());
|
srs_warn("PLI err %s", srs_error_desc(err).c_str());
|
||||||
srs_freep(err);
|
srs_freep(err);
|
||||||
}
|
}
|
||||||
|
|
@ -1753,16 +1810,27 @@ void SrsRtcPublishStream::update_send_report_time(uint32_t ssrc, const SrsNtp &n
|
||||||
SrsRtcConnectionNackTimer::SrsRtcConnectionNackTimer(SrsRtcConnection *p) : p_(p)
|
SrsRtcConnectionNackTimer::SrsRtcConnectionNackTimer(SrsRtcConnection *p) : p_(p)
|
||||||
{
|
{
|
||||||
lock_ = srs_mutex_new();
|
lock_ = srs_mutex_new();
|
||||||
_srs_shared_timer->timer20ms()->subscribe(this);
|
|
||||||
|
shared_timer_ = _srs_shared_timer;
|
||||||
|
circuit_breaker_ = _srs_circuit_breaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcConnectionNackTimer::~SrsRtcConnectionNackTimer()
|
SrsRtcConnectionNackTimer::~SrsRtcConnectionNackTimer()
|
||||||
{
|
{
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsLocker(&lock_);
|
SrsLocker(&lock_);
|
||||||
_srs_shared_timer->timer20ms()->unsubscribe(this);
|
shared_timer_->timer20ms()->unsubscribe(this);
|
||||||
}
|
}
|
||||||
srs_mutex_destroy(lock_);
|
srs_mutex_destroy(lock_);
|
||||||
|
|
||||||
|
shared_timer_ = NULL;
|
||||||
|
circuit_breaker_ = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsRtcConnectionNackTimer::initialize()
|
||||||
|
{
|
||||||
|
shared_timer_->timer20ms()->subscribe(this);
|
||||||
|
return srs_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsRtcConnectionNackTimer::on_timer(srs_utime_t interval)
|
srs_error_t SrsRtcConnectionNackTimer::on_timer(srs_utime_t interval)
|
||||||
|
|
@ -1782,7 +1850,7 @@ srs_error_t SrsRtcConnectionNackTimer::on_timer(srs_utime_t interval)
|
||||||
++_srs_pps_conn->sugar_;
|
++_srs_pps_conn->sugar_;
|
||||||
|
|
||||||
// If circuit-breaker is enabled, disable nack.
|
// If circuit-breaker is enabled, disable nack.
|
||||||
if (_srs_circuit_breaker->hybrid_critical_water_level()) {
|
if (circuit_breaker_->hybrid_critical_water_level()) {
|
||||||
++_srs_pps_snack4->sugar_;
|
++_srs_pps_snack4->sugar_;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -2072,6 +2140,10 @@ srs_error_t SrsRtcConnection::initialize(ISrsRequest *r, bool dtls, bool srtp, s
|
||||||
|
|
||||||
nack_enabled_ = _srs_config->get_rtc_nack_enabled(req_->vhost_);
|
nack_enabled_ = _srs_config->get_rtc_nack_enabled(req_->vhost_);
|
||||||
|
|
||||||
|
if ((err = timer_nack_->initialize()) != srs_success) {
|
||||||
|
return srs_error_wrap(err, "initialize timer nack");
|
||||||
|
}
|
||||||
|
|
||||||
srs_trace("RTC init session, user=%s, url=%s, encrypt=%u/%u, DTLS(role=%s, version=%s), timeout=%dms, nack=%d",
|
srs_trace("RTC init session, user=%s, url=%s, encrypt=%u/%u, DTLS(role=%s, version=%s), timeout=%dms, nack=%d",
|
||||||
username.c_str(), r->get_stream_url().c_str(), dtls, srtp, cfg->dtls_role_.c_str(), cfg->dtls_version_.c_str(),
|
username.c_str(), r->get_stream_url().c_str(), dtls, srtp, cfg->dtls_role_.c_str(), cfg->dtls_version_.c_str(),
|
||||||
srsu2msi(session_timeout_), nack_enabled_);
|
srsu2msi(session_timeout_), nack_enabled_);
|
||||||
|
|
@ -3530,7 +3602,7 @@ srs_error_t SrsRtcConnection::create_player(ISrsRequest *req, std::map<uint32_t,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcPlayStream *player = new SrsRtcPlayStream(this, _srs_context->get_id());
|
SrsRtcPlayStream *player = new SrsRtcPlayStream(exec_, this, this, _srs_context->get_id());
|
||||||
if ((err = player->initialize(req, sub_relations)) != srs_success) {
|
if ((err = player->initialize(req, sub_relations)) != srs_success) {
|
||||||
srs_freep(player);
|
srs_freep(player);
|
||||||
return srs_error_wrap(err, "SrsRtcPlayStream init");
|
return srs_error_wrap(err, "SrsRtcPlayStream init");
|
||||||
|
|
@ -3598,7 +3670,7 @@ srs_error_t SrsRtcConnection::create_publisher(ISrsRequest *req, SrsRtcSourceDes
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcPublishStream *publisher = new SrsRtcPublishStream(this, _srs_context->get_id());
|
SrsRtcPublishStream *publisher = new SrsRtcPublishStream(exec_, this, 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");
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,12 @@ class SrsRtcUdpNetwork;
|
||||||
class ISrsRtcNetwork;
|
class ISrsRtcNetwork;
|
||||||
class SrsRtcTcpNetwork;
|
class SrsRtcTcpNetwork;
|
||||||
class SrsStreamPublishToken;
|
class SrsStreamPublishToken;
|
||||||
|
class ISrsHttpHooks;
|
||||||
|
class ISrsAppConfig;
|
||||||
|
class ISrsStatistic;
|
||||||
|
class ISrsExecRtcAsyncTask;
|
||||||
|
class ISrsSrtSourceManager;
|
||||||
|
class ISrsLiveSourceManager;
|
||||||
|
|
||||||
const uint8_t kSR = 200;
|
const uint8_t kSR = 200;
|
||||||
const uint8_t kRR = 201;
|
const uint8_t kRR = 201;
|
||||||
|
|
@ -97,8 +103,8 @@ class SrsSecurityTransport : public ISrsRtcTransport
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ISrsRtcNetwork *network_;
|
ISrsRtcNetwork *network_;
|
||||||
SrsDtls *dtls_;
|
ISrsDtls *dtls_;
|
||||||
SrsSRTP *srtp_;
|
ISrsSRTP *srtp_;
|
||||||
bool handshake_done_;
|
bool handshake_done_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -171,31 +177,31 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
// The handler for PLI worker coroutine.
|
// The handler for PLI worker coroutine.
|
||||||
class ISrsRtcPLIWorkerHandler
|
class ISrsRtcPliWorkerHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ISrsRtcPLIWorkerHandler();
|
ISrsRtcPliWorkerHandler();
|
||||||
virtual ~ISrsRtcPLIWorkerHandler();
|
virtual ~ISrsRtcPliWorkerHandler();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t do_request_keyframe(uint32_t ssrc, SrsContextId cid) = 0;
|
virtual srs_error_t do_request_keyframe(uint32_t ssrc, SrsContextId cid) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A worker coroutine to request the PLI.
|
// A worker coroutine to request the PLI.
|
||||||
class SrsRtcPLIWorker : public ISrsCoroutineHandler
|
class SrsRtcPliWorker : public ISrsCoroutineHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ISrsCoroutine *trd_;
|
ISrsCoroutine *trd_;
|
||||||
srs_cond_t wait_;
|
ISrsCond *wait_;
|
||||||
ISrsRtcPLIWorkerHandler *handler_;
|
ISrsRtcPliWorkerHandler *handler_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Key is SSRC, value is the CID of subscriber which requests PLI.
|
// Key is SSRC, value is the CID of subscriber which requests PLI.
|
||||||
std::map<uint32_t, SrsContextId> plis_;
|
std::map<uint32_t, SrsContextId> plis_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsRtcPLIWorker(ISrsRtcPLIWorkerHandler *h);
|
SrsRtcPliWorker(ISrsRtcPliWorkerHandler *h);
|
||||||
virtual ~SrsRtcPLIWorker();
|
virtual ~SrsRtcPliWorker();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t start();
|
virtual srs_error_t start();
|
||||||
|
|
@ -211,6 +217,9 @@ class SrsRtcAsyncCallOnStop : public ISrsAsyncCallTask
|
||||||
private:
|
private:
|
||||||
SrsContextId cid_;
|
SrsContextId cid_;
|
||||||
ISrsRequest *req_;
|
ISrsRequest *req_;
|
||||||
|
ISrsHttpHooks *hooks_;
|
||||||
|
ISrsContext *context_;
|
||||||
|
ISrsAppConfig *config_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsRtcAsyncCallOnStop(SrsContextId c, ISrsRequest *r);
|
SrsRtcAsyncCallOnStop(SrsContextId c, ISrsRequest *r);
|
||||||
|
|
@ -222,13 +231,22 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
// A RTC play stream, client pull and play stream from SRS.
|
// A RTC play stream, client pull and play stream from SRS.
|
||||||
class SrsRtcPlayStream : public ISrsCoroutineHandler, public ISrsReloadHandler, public ISrsRtcPLIWorkerHandler, public ISrsRtcSourceChangeCallback
|
class SrsRtcPlayStream : public ISrsCoroutineHandler, public ISrsReloadHandler, public ISrsRtcPliWorkerHandler, public ISrsRtcSourceChangeCallback
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
ISrsExecRtcAsyncTask *exec_;
|
||||||
|
ISrsExpire *expire_;
|
||||||
|
ISrsRtcPacketSender *sender_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ISrsAppConfig *config_;
|
||||||
|
ISrsRtcSourceManager *rtc_sources_;
|
||||||
|
ISrsStatistic *stat_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SrsContextId cid_;
|
SrsContextId cid_;
|
||||||
SrsFastCoroutine *trd_;
|
SrsFastCoroutine *trd_;
|
||||||
SrsRtcConnection *session_;
|
SrsRtcPliWorker *pli_worker_;
|
||||||
SrsRtcPLIWorker *pli_worker_;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ISrsRequest *req_;
|
ISrsRequest *req_;
|
||||||
|
|
@ -261,7 +279,7 @@ private:
|
||||||
bool is_started_;
|
bool is_started_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsRtcPlayStream(SrsRtcConnection *s, const SrsContextId &cid);
|
SrsRtcPlayStream(ISrsExecRtcAsyncTask *exec, ISrsExpire *expire, ISrsRtcPacketSender *sender, const SrsContextId &cid);
|
||||||
virtual ~SrsRtcPlayStream();
|
virtual ~SrsRtcPlayStream();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -296,37 +314,54 @@ private:
|
||||||
srs_error_t on_rtcp_ps_feedback(SrsRtcpFbCommon *rtcp);
|
srs_error_t on_rtcp_ps_feedback(SrsRtcpFbCommon *rtcp);
|
||||||
srs_error_t on_rtcp_rr(SrsRtcpRR *rtcp);
|
srs_error_t on_rtcp_rr(SrsRtcpRR *rtcp);
|
||||||
uint32_t get_video_publish_ssrc(uint32_t play_ssrc);
|
uint32_t get_video_publish_ssrc(uint32_t play_ssrc);
|
||||||
// Interface ISrsRtcPLIWorkerHandler
|
// Interface ISrsRtcPliWorkerHandler
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t do_request_keyframe(uint32_t ssrc, SrsContextId cid);
|
virtual srs_error_t do_request_keyframe(uint32_t ssrc, SrsContextId cid);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The RTC RTCP sender interface.
|
||||||
|
class ISrsRtcRtcpSender
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsRtcRtcpSender();
|
||||||
|
virtual ~ISrsRtcRtcpSender();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool is_sender_started() = 0;
|
||||||
|
virtual srs_error_t send_rtcp_rr() = 0;
|
||||||
|
virtual srs_error_t send_rtcp_xr_rrtr() = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool is_sender_twcc_enabled() = 0;
|
||||||
|
virtual srs_error_t send_periodic_twcc() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// A fast timer for publish stream, for RTCP feedback.
|
// A fast timer for publish stream, for RTCP feedback.
|
||||||
class SrsRtcPublishRtcpTimer : public ISrsFastTimer
|
class SrsRtcPublishRtcpTimer : public ISrsFastTimerHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsRtcPublishStream *p_;
|
ISrsRtcRtcpSender *sender_;
|
||||||
srs_mutex_t lock_;
|
srs_mutex_t lock_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsRtcPublishRtcpTimer(SrsRtcPublishStream *p);
|
SrsRtcPublishRtcpTimer(ISrsRtcRtcpSender *sender);
|
||||||
virtual ~SrsRtcPublishRtcpTimer();
|
virtual ~SrsRtcPublishRtcpTimer();
|
||||||
// interface ISrsFastTimer
|
// interface ISrsFastTimerHandler
|
||||||
private:
|
private:
|
||||||
srs_error_t on_timer(srs_utime_t interval);
|
srs_error_t on_timer(srs_utime_t interval);
|
||||||
};
|
};
|
||||||
|
|
||||||
// A fast timer for publish stream, for TWCC feedback.
|
// A fast timer for publish stream, for TWCC feedback.
|
||||||
class SrsRtcPublishTwccTimer : public ISrsFastTimer
|
class SrsRtcPublishTwccTimer : public ISrsFastTimerHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsRtcPublishStream *p_;
|
ISrsRtcRtcpSender *sender_;
|
||||||
srs_mutex_t lock_;
|
srs_mutex_t lock_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsRtcPublishTwccTimer(SrsRtcPublishStream *p);
|
SrsRtcPublishTwccTimer(ISrsRtcRtcpSender *sender);
|
||||||
virtual ~SrsRtcPublishTwccTimer();
|
virtual ~SrsRtcPublishTwccTimer();
|
||||||
// interface ISrsFastTimer
|
// interface ISrsFastTimerHandler
|
||||||
private:
|
private:
|
||||||
srs_error_t on_timer(srs_utime_t interval);
|
srs_error_t on_timer(srs_utime_t interval);
|
||||||
};
|
};
|
||||||
|
|
@ -334,6 +369,10 @@ private:
|
||||||
// the rtc on_unpublish async call.
|
// the rtc on_unpublish async call.
|
||||||
class SrsRtcAsyncCallOnUnpublish : public ISrsAsyncCallTask
|
class SrsRtcAsyncCallOnUnpublish : public ISrsAsyncCallTask
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
ISrsHttpHooks *hooks_;
|
||||||
|
ISrsAppConfig *config_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SrsContextId cid_;
|
SrsContextId cid_;
|
||||||
ISrsRequest *req_;
|
ISrsRequest *req_;
|
||||||
|
|
@ -348,8 +387,21 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
// A RTC publish stream, client push and publish stream to SRS.
|
// A RTC publish stream, client push and publish stream to SRS.
|
||||||
class SrsRtcPublishStream : public ISrsRtpPacketDecodeHandler, public ISrsRtcPublishStream, public ISrsRtcPLIWorkerHandler
|
class SrsRtcPublishStream : public ISrsRtpPacketDecodeHandler, public ISrsRtcPublishStream, public ISrsRtcPliWorkerHandler, public ISrsRtcRtcpSender
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
ISrsExecRtcAsyncTask *exec_;
|
||||||
|
ISrsExpire *expire_;
|
||||||
|
ISrsRtcPacketReceiver *receiver_;
|
||||||
|
ISrsCircuitBreaker *circuit_breaker_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ISrsStatistic *stat_;
|
||||||
|
ISrsAppConfig *config_;
|
||||||
|
ISrsRtcSourceManager *rtc_sources_;
|
||||||
|
ISrsLiveSourceManager *live_sources_;
|
||||||
|
ISrsSrtSourceManager *srt_sources_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class SrsRtcPublishRtcpTimer;
|
friend class SrsRtcPublishRtcpTimer;
|
||||||
friend class SrsRtcPublishTwccTimer;
|
friend class SrsRtcPublishTwccTimer;
|
||||||
|
|
@ -359,11 +411,10 @@ private:
|
||||||
private:
|
private:
|
||||||
SrsContextId cid_;
|
SrsContextId cid_;
|
||||||
uint64_t nn_audio_frames_;
|
uint64_t nn_audio_frames_;
|
||||||
SrsRtcPLIWorker *pli_worker_;
|
SrsRtcPliWorker *pli_worker_;
|
||||||
SrsErrorPithyPrint *twcc_epp_;
|
SrsErrorPithyPrint *twcc_epp_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SrsRtcConnection *session_;
|
|
||||||
uint16_t pt_to_drop_;
|
uint16_t pt_to_drop_;
|
||||||
// Whether enabled nack.
|
// Whether enabled nack.
|
||||||
bool nack_enabled_;
|
bool nack_enabled_;
|
||||||
|
|
@ -390,11 +441,11 @@ private:
|
||||||
uint8_t twcc_fb_count_;
|
uint8_t twcc_fb_count_;
|
||||||
SrsRtcpTWCC rtcp_twcc_;
|
SrsRtcpTWCC rtcp_twcc_;
|
||||||
SrsRtpExtensionTypes extension_types_;
|
SrsRtpExtensionTypes extension_types_;
|
||||||
bool is_started_;
|
bool is_sender_started_;
|
||||||
srs_utime_t last_time_send_twcc_;
|
srs_utime_t last_time_send_twcc_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsRtcPublishStream(SrsRtcConnection *session, const SrsContextId &cid);
|
SrsRtcPublishStream(ISrsExecRtcAsyncTask *exec, ISrsExpire *expire, ISrsRtcPacketReceiver *receiver, const SrsContextId &cid);
|
||||||
virtual ~SrsRtcPublishStream();
|
virtual ~SrsRtcPublishStream();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -405,6 +456,8 @@ public:
|
||||||
virtual const SrsContextId &context_id();
|
virtual const SrsContextId &context_id();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool is_sender_started();
|
||||||
|
bool is_sender_twcc_enabled();
|
||||||
srs_error_t send_rtcp_rr();
|
srs_error_t send_rtcp_rr();
|
||||||
srs_error_t send_rtcp_xr_rrtr();
|
srs_error_t send_rtcp_xr_rrtr();
|
||||||
|
|
||||||
|
|
@ -450,8 +503,12 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// A fast timer for conntion, for NACK feedback.
|
// A fast timer for conntion, for NACK feedback.
|
||||||
class SrsRtcConnectionNackTimer : public ISrsFastTimer
|
class SrsRtcConnectionNackTimer : public ISrsFastTimerHandler
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
ISrsSharedTimer *shared_timer_;
|
||||||
|
ISrsCircuitBreaker *circuit_breaker_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SrsRtcConnection *p_;
|
SrsRtcConnection *p_;
|
||||||
srs_mutex_t lock_;
|
srs_mutex_t lock_;
|
||||||
|
|
@ -459,7 +516,11 @@ private:
|
||||||
public:
|
public:
|
||||||
SrsRtcConnectionNackTimer(SrsRtcConnection *p);
|
SrsRtcConnectionNackTimer(SrsRtcConnection *p);
|
||||||
virtual ~SrsRtcConnectionNackTimer();
|
virtual ~SrsRtcConnectionNackTimer();
|
||||||
// interface ISrsFastTimer
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize();
|
||||||
|
|
||||||
|
// interface ISrsFastTimerHandler
|
||||||
private:
|
private:
|
||||||
srs_error_t on_timer(srs_utime_t interval);
|
srs_error_t on_timer(srs_utime_t interval);
|
||||||
};
|
};
|
||||||
|
|
@ -479,11 +540,9 @@ public:
|
||||||
//
|
//
|
||||||
// For performance, we use non-public from resource,
|
// For performance, we use non-public from resource,
|
||||||
// see https://stackoverflow.com/questions/3747066/c-cannot-convert-from-base-a-to-derived-type-b-via-virtual-base-a
|
// see https://stackoverflow.com/questions/3747066/c-cannot-convert-from-base-a-to-derived-type-b-via-virtual-base-a
|
||||||
class SrsRtcConnection : public ISrsResource, public ISrsDisposingHandler, public ISrsExpire
|
class SrsRtcConnection : public ISrsResource, public ISrsDisposingHandler, public ISrsExpire, public ISrsRtcPacketSender, public ISrsRtcPacketReceiver
|
||||||
{
|
{
|
||||||
friend class SrsSecurityTransport;
|
friend class SrsSecurityTransport;
|
||||||
friend class SrsRtcPlayStream;
|
|
||||||
friend class SrsRtcPublishStream;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class SrsRtcConnectionNackTimer;
|
friend class SrsRtcConnectionNackTimer;
|
||||||
|
|
|
||||||
|
|
@ -912,6 +912,14 @@ srs_error_t SrsDtlsEmptyImpl::start_arq()
|
||||||
return srs_success;
|
return srs_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsDtls::ISrsDtls()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsDtls::~ISrsDtls()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsDtls::SrsDtls(ISrsDtlsCallback *callback)
|
SrsDtls::SrsDtls(ISrsDtlsCallback *callback)
|
||||||
{
|
{
|
||||||
callback_ = callback;
|
callback_ = callback;
|
||||||
|
|
@ -950,6 +958,14 @@ srs_error_t SrsDtls::get_srtp_key(std::string &recv_key, std::string &send_key)
|
||||||
return impl_->get_srtp_key(recv_key, send_key);
|
return impl_->get_srtp_key(recv_key, send_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsSRTP::ISrsSRTP()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsSRTP::~ISrsSRTP()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsSRTP::SrsSRTP()
|
SrsSRTP::SrsSRTP()
|
||||||
{
|
{
|
||||||
recv_ctx_ = NULL;
|
recv_ctx_ = NULL;
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,22 @@ protected:
|
||||||
virtual srs_error_t start_arq();
|
virtual srs_error_t start_arq();
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsDtls
|
// The interface for DTLS.
|
||||||
|
class ISrsDtls
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsDtls();
|
||||||
|
virtual ~ISrsDtls();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(std::string role, std::string version) = 0;
|
||||||
|
virtual srs_error_t start_active_handshake() = 0;
|
||||||
|
virtual srs_error_t on_dtls(char *data, int nb_data) = 0;
|
||||||
|
virtual srs_error_t get_srtp_key(std::string &recv_key, std::string &send_key) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The DTLS transport.
|
||||||
|
class SrsDtls : public ISrsDtls
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsDtlsImpl *impl_;
|
SrsDtlsImpl *impl_;
|
||||||
|
|
@ -225,7 +240,23 @@ 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);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsSRTP
|
// The interface for SRTP.
|
||||||
|
class ISrsSRTP
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsSRTP();
|
||||||
|
virtual ~ISrsSRTP();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(std::string recv_key, std::string send_key) = 0;
|
||||||
|
virtual srs_error_t protect_rtp(void *packet, int *nb_cipher) = 0;
|
||||||
|
virtual srs_error_t protect_rtcp(void *packet, int *nb_cipher) = 0;
|
||||||
|
virtual srs_error_t unprotect_rtp(void *packet, int *nb_plaintext) = 0;
|
||||||
|
virtual srs_error_t unprotect_rtcp(void *packet, int *nb_plaintext) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The SRTP transport.
|
||||||
|
class SrsSRTP : public ISrsSRTP
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
srtp_t recv_ctx_;
|
srtp_t recv_ctx_;
|
||||||
|
|
|
||||||
|
|
@ -789,8 +789,8 @@ srs_error_t SrsRtcTcpConn::cycle()
|
||||||
srs_error_t err = do_cycle();
|
srs_error_t err = do_cycle();
|
||||||
|
|
||||||
// Only stat the HTTP streaming clients, ignore all API clients.
|
// Only stat the HTTP streaming clients, ignore all API clients.
|
||||||
SrsStatistic::instance()->on_disconnect(get_id().c_str(), err);
|
_srs_stat->on_disconnect(get_id().c_str(), err);
|
||||||
SrsStatistic::instance()->kbps_add_delta(get_id().c_str(), delta_);
|
_srs_stat->kbps_add_delta(get_id().c_str(), delta_);
|
||||||
|
|
||||||
// Only remove session when network is established, because client might use other UDP network.
|
// Only remove session when network is established, because client might use other UDP network.
|
||||||
if (session_ && session_->tcp()->is_establelished()) {
|
if (session_ && session_->tcp()->is_establelished()) {
|
||||||
|
|
|
||||||
|
|
@ -253,6 +253,14 @@ void SrsRtcConsumer::on_stream_change(SrsRtcSourceDescription *desc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsRtcSourceManager::ISrsRtcSourceManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsRtcSourceManager::~ISrsRtcSourceManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsRtcSourceManager::SrsRtcSourceManager()
|
SrsRtcSourceManager::SrsRtcSourceManager()
|
||||||
{
|
{
|
||||||
lock_ = srs_mutex_new();
|
lock_ = srs_mutex_new();
|
||||||
|
|
@ -700,7 +708,7 @@ srs_error_t SrsRtcSource::on_publish()
|
||||||
_srs_shared_timer->timer100ms()->subscribe(this);
|
_srs_shared_timer->timer100ms()->subscribe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
stat->on_stream_publish(req_, _source_id.c_str());
|
stat->on_stream_publish(req_, _source_id.c_str());
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -734,7 +742,7 @@ void SrsRtcSource::on_unpublish()
|
||||||
srs_freep(rtc_bridge_);
|
srs_freep(rtc_bridge_);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
stat->on_stream_close(req_);
|
stat->on_stream_close(req_);
|
||||||
|
|
||||||
// Destroy and cleanup source when no publishers and consumers.
|
// Destroy and cleanup source when no publishers and consumers.
|
||||||
|
|
@ -1467,6 +1475,9 @@ SrsRtpPacket *SrsRtcFrameBuilderVideoPacketCache::take_packet(uint16_t sequence_
|
||||||
return pkt;
|
return pkt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Should improve the frame builder by jitter and NACK, consider if only RTC2RTMP without
|
||||||
|
// any RTC player, then if one RTP packet is lost, the frame builder will not request the lost
|
||||||
|
// packet. This makes the whole GOP not available.
|
||||||
int32_t SrsRtcFrameBuilderVideoPacketCache::find_next_lost_sn(uint16_t current_sn, uint16_t header_sn, uint16_t &end_sn)
|
int32_t SrsRtcFrameBuilderVideoPacketCache::find_next_lost_sn(uint16_t current_sn, uint16_t header_sn, uint16_t &end_sn)
|
||||||
{
|
{
|
||||||
uint32_t last_rtp_ts = get_rtp_timestamp(header_sn);
|
uint32_t last_rtp_ts = get_rtp_timestamp(header_sn);
|
||||||
|
|
@ -1548,7 +1559,8 @@ void SrsRtcFrameBuilderVideoFrameDetector::on_keyframe_start(SrsRtpPacket *pkt)
|
||||||
rtp_key_frame_ts_ = pkt->header_.get_timestamp();
|
rtp_key_frame_ts_ = pkt->header_.get_timestamp();
|
||||||
header_sn_ = pkt->header_.get_sequence();
|
header_sn_ = pkt->header_.get_sequence();
|
||||||
lost_sn_ = header_sn_ + 1;
|
lost_sn_ = header_sn_ + 1;
|
||||||
// Received key frame and clean cache of old p frame pkts
|
// Received key frame and clean cache of old p frame pkts.
|
||||||
|
// TODO: Should use jitter buffer to avoid clear previous P frame in case of reordering.
|
||||||
video_cache_->clear_all();
|
video_cache_->clear_all();
|
||||||
srs_trace("RTC2RTMP: keyframe set ts=%u, header=%hu, lost=%hu", (uint32_t)rtp_key_frame_ts_, header_sn_, lost_sn_);
|
srs_trace("RTC2RTMP: keyframe set ts=%u, header=%hu, lost=%hu", (uint32_t)rtp_key_frame_ts_, header_sn_, lost_sn_);
|
||||||
} else if (rtp_key_frame_ts_ != pkt->header_.get_timestamp()) {
|
} else if (rtp_key_frame_ts_ != pkt->header_.get_timestamp()) {
|
||||||
|
|
@ -1559,6 +1571,8 @@ void SrsRtcFrameBuilderVideoFrameDetector::on_keyframe_start(SrsRtpPacket *pkt)
|
||||||
rtp_key_frame_ts_ = pkt->header_.get_timestamp();
|
rtp_key_frame_ts_ = pkt->header_.get_timestamp();
|
||||||
header_sn_ = pkt->header_.get_sequence();
|
header_sn_ = pkt->header_.get_sequence();
|
||||||
lost_sn_ = header_sn_ + 1;
|
lost_sn_ = header_sn_ + 1;
|
||||||
|
// Received key frame and clean cache of old p frame pkts.
|
||||||
|
// TODO: Should use jitter buffer to avoid clear previous P frame in case of reordering.
|
||||||
video_cache_->clear_all();
|
video_cache_->clear_all();
|
||||||
srs_warn("RTC2RTMP: keyframe drop old ts=%u, header=%hu, lost=%hu, set new ts=%u, header=%hu, lost=%hu",
|
srs_warn("RTC2RTMP: keyframe drop old ts=%u, header=%hu, lost=%hu, set new ts=%u, header=%hu, lost=%hu",
|
||||||
(uint32_t)old_ts, old_header_sn, old_lost_sn, (uint32_t)rtp_key_frame_ts_, header_sn_, lost_sn_);
|
(uint32_t)old_ts, old_header_sn, old_lost_sn, (uint32_t)rtp_key_frame_ts_, header_sn_, lost_sn_);
|
||||||
|
|
@ -1683,6 +1697,9 @@ srs_error_t SrsRtcFrameBuilderAudioPacketCache::process_packet(SrsRtpPacket *src
|
||||||
(now - last_audio_process_time_) > timeout_;
|
(now - last_audio_process_time_) > timeout_;
|
||||||
uint16_t window_end = last_audio_seq_num_ + SLIDING_WINDOW_SIZE;
|
uint16_t window_end = last_audio_seq_num_ + SLIDING_WINDOW_SIZE;
|
||||||
|
|
||||||
|
// TODO: Should improve the audio cache by NACK, consider if only RTC2RTMP without
|
||||||
|
// any RTC player, then if one RTP packet is lost, the audio cache will not request the lost
|
||||||
|
// packet. This means some audio packets are lost.
|
||||||
while (!audio_buffer_.empty()) {
|
while (!audio_buffer_.empty()) {
|
||||||
std::map<uint16_t, SrsRtpPacket *>::iterator it = audio_buffer_.begin();
|
std::map<uint16_t, SrsRtpPacket *>::iterator it = audio_buffer_.begin();
|
||||||
uint16_t next_seq = it->first;
|
uint16_t next_seq = it->first;
|
||||||
|
|
@ -1861,7 +1878,7 @@ srs_error_t SrsRtcFrameBuilder::transcode_audio(SrsRtpPacket *pkt)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
// to common message.
|
// Generate a sequence header for the first audio packet
|
||||||
uint32_t ts = pkt->get_avsync_time();
|
uint32_t ts = pkt->get_avsync_time();
|
||||||
if (is_first_audio_) {
|
if (is_first_audio_) {
|
||||||
int header_len = 0;
|
int header_len = 0;
|
||||||
|
|
@ -1950,8 +1967,10 @@ srs_error_t SrsRtcFrameBuilder::packet_video(SrsRtpPacket *pkt)
|
||||||
if ((err = frame_detector_->detect_frame(current_sn, start, end, got_frame)) != srs_success) {
|
if ((err = frame_detector_->detect_frame(current_sn, start, end, got_frame)) != srs_success) {
|
||||||
return srs_error_wrap(err, "detect frame failed");
|
return srs_error_wrap(err, "detect frame failed");
|
||||||
}
|
}
|
||||||
if (got_frame && (err = packet_video_rtmp(start, end)) != srs_success) {
|
if (got_frame) {
|
||||||
err = srs_error_wrap(err, "fail to pack video frame, start=%u, end=%u", start, end);
|
if ((err = packet_video_rtmp(start, end)) != srs_success) {
|
||||||
|
err = srs_error_wrap(err, "fail to pack video frame, start=%u, end=%u", start, end);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1976,6 +1995,17 @@ srs_error_t SrsRtcFrameBuilder::packet_video_key_frame(SrsRtpPacket *pkt)
|
||||||
|
|
||||||
frame_detector_->on_keyframe_start(pkt);
|
frame_detector_->on_keyframe_start(pkt);
|
||||||
|
|
||||||
|
// If only contains SPS/PPS, no need to store in cache.
|
||||||
|
SrsRtpSTAPPayload *stap_payload = dynamic_cast<SrsRtpSTAPPayload *>(pkt->payload());
|
||||||
|
if (stap_payload && stap_payload->get_idr() == NULL) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
SrsRtpSTAPPayloadHevc *stap_payload_hevc = dynamic_cast<SrsRtpSTAPPayloadHevc *>(pkt->payload());
|
||||||
|
if (stap_payload_hevc && stap_payload_hevc->get_idr() == NULL) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache the keyframe packet, which contains IDR, as long as SPS/PPS/VPS sequence header.
|
||||||
video_cache_->store_packet(pkt->copy());
|
video_cache_->store_packet(pkt->copy());
|
||||||
|
|
||||||
uint16_t current_sn = pkt->header_.get_sequence();
|
uint16_t current_sn = pkt->header_.get_sequence();
|
||||||
|
|
@ -1985,8 +2015,10 @@ srs_error_t SrsRtcFrameBuilder::packet_video_key_frame(SrsRtpPacket *pkt)
|
||||||
if ((err = frame_detector_->detect_frame(current_sn, start, end, got_frame)) != srs_success) {
|
if ((err = frame_detector_->detect_frame(current_sn, start, end, got_frame)) != srs_success) {
|
||||||
return srs_error_wrap(err, "detect frame failed");
|
return srs_error_wrap(err, "detect frame failed");
|
||||||
}
|
}
|
||||||
if (got_frame && (err = packet_video_rtmp(start, end)) != srs_success) {
|
if (got_frame) {
|
||||||
err = srs_error_wrap(err, "fail to pack video frame, start=%u, end=%u", start, end);
|
if ((err = packet_video_rtmp(start, end)) != srs_success) {
|
||||||
|
err = srs_error_wrap(err, "fail to pack video frame, start=%u, end=%u", start, end);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2164,7 +2196,7 @@ srs_error_t SrsRtcFrameBuilder::do_packet_sequence_header_hevc(SrsRtpPacket *pkt
|
||||||
char *flv = NULL;
|
char *flv = NULL;
|
||||||
int nb_flv = 0;
|
int nb_flv = 0;
|
||||||
if ((err = hevc->mux_hevc2flv_enhanced(sh, SrsVideoAvcFrameTypeKeyFrame, SrsVideoHEVCFrameTraitPacketTypeSequenceStart, pkt->get_avsync_time(),
|
if ((err = hevc->mux_hevc2flv_enhanced(sh, SrsVideoAvcFrameTypeKeyFrame, SrsVideoHEVCFrameTraitPacketTypeSequenceStart, pkt->get_avsync_time(),
|
||||||
pkt->get_avsync_time(), &flv, &nb_flv)) != srs_success) {
|
pkt->get_avsync_time(), &flv, &nb_flv)) != srs_success) {
|
||||||
return srs_error_wrap(err, "mux sequence header");
|
return srs_error_wrap(err, "mux sequence header");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2193,8 +2225,11 @@ int SrsRtcFrameBuilder::calculate_packet_payload_size(SrsRtpPacket *pkt)
|
||||||
|
|
||||||
// H.264 FU-A payload
|
// H.264 FU-A payload
|
||||||
SrsRtpFUAPayload2 *fua_payload = dynamic_cast<SrsRtpFUAPayload2 *>(pkt->payload());
|
SrsRtpFUAPayload2 *fua_payload = dynamic_cast<SrsRtpFUAPayload2 *>(pkt->payload());
|
||||||
if (fua_payload && fua_payload->size_ > 0) {
|
if (fua_payload) {
|
||||||
int size = fua_payload->size_;
|
int size = fua_payload->size_;
|
||||||
|
if (size <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (fua_payload->start_) {
|
if (fua_payload->start_) {
|
||||||
size += 1 + 4; // NALU header + length prefix
|
size += 1 + 4; // NALU header + length prefix
|
||||||
}
|
}
|
||||||
|
|
@ -2216,8 +2251,11 @@ int SrsRtcFrameBuilder::calculate_packet_payload_size(SrsRtpPacket *pkt)
|
||||||
|
|
||||||
// H.265 FU-A payload
|
// H.265 FU-A payload
|
||||||
SrsRtpFUAPayloadHevc2 *fua_payload_hevc = dynamic_cast<SrsRtpFUAPayloadHevc2 *>(pkt->payload());
|
SrsRtpFUAPayloadHevc2 *fua_payload_hevc = dynamic_cast<SrsRtpFUAPayloadHevc2 *>(pkt->payload());
|
||||||
if (fua_payload_hevc && fua_payload_hevc->size_ > 0) {
|
if (fua_payload_hevc) {
|
||||||
int size = fua_payload_hevc->size_;
|
int size = fua_payload_hevc->size_;
|
||||||
|
if (size <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (fua_payload_hevc->start_) {
|
if (fua_payload_hevc->start_) {
|
||||||
size += 2 + 4; // HEVC NALU header + length prefix
|
size += 2 + 4; // HEVC NALU header + length prefix
|
||||||
}
|
}
|
||||||
|
|
@ -2239,7 +2277,10 @@ int SrsRtcFrameBuilder::calculate_packet_payload_size(SrsRtpPacket *pkt)
|
||||||
|
|
||||||
// Raw payload
|
// Raw payload
|
||||||
SrsRtpRawPayload *raw_payload = dynamic_cast<SrsRtpRawPayload *>(pkt->payload());
|
SrsRtpRawPayload *raw_payload = dynamic_cast<SrsRtpRawPayload *>(pkt->payload());
|
||||||
if (raw_payload && raw_payload->nn_payload_ > 0) {
|
if (raw_payload) {
|
||||||
|
if (raw_payload->nn_payload_ <= 1) {
|
||||||
|
return 0; // Ignore empty payload, which only has the NALU header.
|
||||||
|
}
|
||||||
return 4 + raw_payload->nn_payload_; // length prefix + payload
|
return 4 + raw_payload->nn_payload_; // length prefix + payload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2254,15 +2295,19 @@ void SrsRtcFrameBuilder::write_packet_payload_to_buffer(SrsRtpPacket *pkt, SrsBu
|
||||||
|
|
||||||
// H.264 FU-A payload
|
// H.264 FU-A payload
|
||||||
SrsRtpFUAPayload2 *fua_payload = dynamic_cast<SrsRtpFUAPayload2 *>(pkt->payload());
|
SrsRtpFUAPayload2 *fua_payload = dynamic_cast<SrsRtpFUAPayload2 *>(pkt->payload());
|
||||||
if (fua_payload && fua_payload->size_ > 0) {
|
if (fua_payload) {
|
||||||
|
int size = fua_payload->size_;
|
||||||
|
if (size <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (fua_payload->start_) {
|
if (fua_payload->start_) {
|
||||||
nalu_len = fua_payload->size_ + 1;
|
nalu_len = size + 1;
|
||||||
payload.skip(4); // Skip 4 bytes to write nalu_len later
|
payload.skip(4); // Skip 4 bytes to write nalu_len later
|
||||||
payload.write_1bytes(fua_payload->nri_ | fua_payload->nalu_type_);
|
payload.write_1bytes(fua_payload->nri_ | fua_payload->nalu_type_);
|
||||||
payload.write_bytes(fua_payload->payload_, fua_payload->size_);
|
payload.write_bytes(fua_payload->payload_, size);
|
||||||
} else {
|
} else {
|
||||||
nalu_len += fua_payload->size_;
|
nalu_len += size;
|
||||||
payload.write_bytes(fua_payload->payload_, fua_payload->size_);
|
payload.write_bytes(fua_payload->payload_, size);
|
||||||
if (fua_payload->end_) {
|
if (fua_payload->end_) {
|
||||||
// Write nalu_len back
|
// Write nalu_len back
|
||||||
payload.skip(-(4 + nalu_len));
|
payload.skip(-(4 + nalu_len));
|
||||||
|
|
@ -2288,16 +2333,20 @@ void SrsRtcFrameBuilder::write_packet_payload_to_buffer(SrsRtpPacket *pkt, SrsBu
|
||||||
|
|
||||||
// H.265 FU-A payload
|
// H.265 FU-A payload
|
||||||
SrsRtpFUAPayloadHevc2 *fua_payload_hevc = dynamic_cast<SrsRtpFUAPayloadHevc2 *>(pkt->payload());
|
SrsRtpFUAPayloadHevc2 *fua_payload_hevc = dynamic_cast<SrsRtpFUAPayloadHevc2 *>(pkt->payload());
|
||||||
if (fua_payload_hevc && fua_payload_hevc->size_ > 0) {
|
if (fua_payload_hevc) {
|
||||||
|
int size = fua_payload_hevc->size_;
|
||||||
|
if (size <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (fua_payload_hevc->start_) {
|
if (fua_payload_hevc->start_) {
|
||||||
nalu_len = fua_payload_hevc->size_ + 2;
|
nalu_len = size + 2;
|
||||||
payload.skip(4); // Skip 4 bytes to write nalu_len later
|
payload.skip(4); // Skip 4 bytes to write nalu_len later
|
||||||
payload.write_1bytes(fua_payload_hevc->nalu_type_ << 1);
|
payload.write_1bytes(fua_payload_hevc->nalu_type_ << 1);
|
||||||
payload.write_1bytes(0x01);
|
payload.write_1bytes(0x01);
|
||||||
payload.write_bytes(fua_payload_hevc->payload_, fua_payload_hevc->size_);
|
payload.write_bytes(fua_payload_hevc->payload_, size);
|
||||||
} else {
|
} else {
|
||||||
nalu_len += fua_payload_hevc->size_;
|
nalu_len += size;
|
||||||
payload.write_bytes(fua_payload_hevc->payload_, fua_payload_hevc->size_);
|
payload.write_bytes(fua_payload_hevc->payload_, size);
|
||||||
if (fua_payload_hevc->end_) {
|
if (fua_payload_hevc->end_) {
|
||||||
// Write nalu_len back
|
// Write nalu_len back
|
||||||
payload.skip(-(4 + nalu_len));
|
payload.skip(-(4 + nalu_len));
|
||||||
|
|
@ -2323,7 +2372,10 @@ void SrsRtcFrameBuilder::write_packet_payload_to_buffer(SrsRtpPacket *pkt, SrsBu
|
||||||
|
|
||||||
// Raw payload
|
// Raw payload
|
||||||
SrsRtpRawPayload *raw_payload = dynamic_cast<SrsRtpRawPayload *>(pkt->payload());
|
SrsRtpRawPayload *raw_payload = dynamic_cast<SrsRtpRawPayload *>(pkt->payload());
|
||||||
if (raw_payload && raw_payload->nn_payload_ > 0) {
|
if (raw_payload) {
|
||||||
|
if (raw_payload->nn_payload_ <= 1) {
|
||||||
|
return; // Ignore empty payload, which only has the NALU header.
|
||||||
|
}
|
||||||
payload.write_4bytes(raw_payload->nn_payload_);
|
payload.write_4bytes(raw_payload->nn_payload_);
|
||||||
payload.write_bytes(raw_payload->payload_, raw_payload->nn_payload_);
|
payload.write_bytes(raw_payload->payload_, raw_payload->nn_payload_);
|
||||||
return;
|
return;
|
||||||
|
|
@ -2359,7 +2411,7 @@ srs_error_t SrsRtcFrameBuilder::packet_video_rtmp(const uint16_t start, const ui
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 == nb_payload) {
|
if (0 == nb_payload) {
|
||||||
srs_warn("empty nalu");
|
srs_info("RTC2RTMP: empty rtp packet, start=%u, end=%u, cnt=%d", start, end, cnt);
|
||||||
|
|
||||||
// The chrome web browser send RTP packet with empty payload frequently,
|
// The chrome web browser send RTP packet with empty payload frequently,
|
||||||
// reset header_sn_, lost_sn_ and continue to found next frame in this case,
|
// reset header_sn_, lost_sn_ and continue to found next frame in this case,
|
||||||
|
|
@ -2369,8 +2421,10 @@ srs_error_t SrsRtcFrameBuilder::packet_video_rtmp(const uint16_t start, const ui
|
||||||
if ((err = frame_detector_->detect_next_frame(end + 1, next_start, next_end, got_frame)) != srs_success) {
|
if ((err = frame_detector_->detect_next_frame(end + 1, next_start, next_end, got_frame)) != srs_success) {
|
||||||
return srs_error_wrap(err, "update frame detector failed");
|
return srs_error_wrap(err, "update frame detector failed");
|
||||||
}
|
}
|
||||||
if (got_frame && (err = packet_video_rtmp(next_start, next_end)) != srs_success) {
|
if (got_frame) {
|
||||||
err = srs_error_wrap(err, "fail to pack video frame, start=%u, end=%u", next_start, next_end);
|
if ((err = packet_video_rtmp(next_start, next_end)) != srs_success) {
|
||||||
|
err = srs_error_wrap(err, "fail to pack video frame, start=%u, end=%u", next_start, next_end);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -2445,8 +2499,10 @@ srs_error_t SrsRtcFrameBuilder::packet_video_rtmp(const uint16_t start, const ui
|
||||||
if ((err = frame_detector_->detect_next_frame(end + 1, next_start, next_end, got_frame)) != srs_success) {
|
if ((err = frame_detector_->detect_next_frame(end + 1, next_start, next_end, got_frame)) != srs_success) {
|
||||||
return srs_error_wrap(err, "update frame detector failed");
|
return srs_error_wrap(err, "update frame detector failed");
|
||||||
}
|
}
|
||||||
if (got_frame && (err = packet_video_rtmp(next_start, next_end)) != srs_success) {
|
if (got_frame) {
|
||||||
err = srs_error_wrap(err, "fail to pack video frame, start=%u, end=%u", next_start, next_end);
|
if ((err = packet_video_rtmp(next_start, next_end)) != srs_success) {
|
||||||
|
err = srs_error_wrap(err, "fail to pack video frame, start=%u, end=%u", next_start, next_end);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -3030,9 +3086,17 @@ SrsRtcTrackDescription *SrsRtcSourceDescription::find_track_description_by_ssrc(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcRecvTrack::SrsRtcRecvTrack(SrsRtcConnection *session, SrsRtcTrackDescription *track_desc, bool is_audio)
|
ISrsRtcPacketReceiver::ISrsRtcPacketReceiver()
|
||||||
{
|
{
|
||||||
session_ = session;
|
}
|
||||||
|
|
||||||
|
ISrsRtcPacketReceiver::~ISrsRtcPacketReceiver()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsRtcRecvTrack::SrsRtcRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc, bool is_audio)
|
||||||
|
{
|
||||||
|
receiver_ = receiver;
|
||||||
track_desc_ = track_desc->copy();
|
track_desc_ = track_desc->copy();
|
||||||
nack_no_copy_ = false;
|
nack_no_copy_ = false;
|
||||||
|
|
||||||
|
|
@ -3130,7 +3194,7 @@ srs_error_t SrsRtcRecvTrack::send_rtcp_rr()
|
||||||
|
|
||||||
uint32_t ssrc = track_desc_->ssrc_;
|
uint32_t ssrc = track_desc_->ssrc_;
|
||||||
const uint64_t &last_time = last_sender_report_sys_time_;
|
const uint64_t &last_time = last_sender_report_sys_time_;
|
||||||
if ((err = session_->send_rtcp_rr(ssrc, rtp_queue_, last_time, last_sender_report_ntp_)) != srs_success) {
|
if ((err = receiver_->send_rtcp_rr(ssrc, rtp_queue_, last_time, last_sender_report_ntp_)) != srs_success) {
|
||||||
return srs_error_wrap(err, "ssrc=%u, last_time=%" PRId64, ssrc, last_time);
|
return srs_error_wrap(err, "ssrc=%u, last_time=%" PRId64, ssrc, last_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3141,7 +3205,7 @@ srs_error_t SrsRtcRecvTrack::send_rtcp_xr_rrtr()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if ((err = session_->send_rtcp_xr_rrtr(track_desc_->ssrc_)) != srs_success) {
|
if ((err = receiver_->send_rtcp_xr_rrtr(track_desc_->ssrc_)) != srs_success) {
|
||||||
return srs_error_wrap(err, "ssrc=%u", track_desc_->ssrc_);
|
return srs_error_wrap(err, "ssrc=%u", track_desc_->ssrc_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3218,13 +3282,13 @@ srs_error_t SrsRtcRecvTrack::do_check_send_nacks(uint32_t &timeout_nacks)
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
uint32_t sent_nacks = 0;
|
uint32_t sent_nacks = 0;
|
||||||
session_->check_send_nacks(nack_receiver_, track_desc_->ssrc_, sent_nacks, timeout_nacks);
|
receiver_->check_send_nacks(nack_receiver_, track_desc_->ssrc_, sent_nacks, timeout_nacks);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcAudioRecvTrack::SrsRtcAudioRecvTrack(SrsRtcConnection *session, SrsRtcTrackDescription *track_desc)
|
SrsRtcAudioRecvTrack::SrsRtcAudioRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc)
|
||||||
: SrsRtcRecvTrack(session, track_desc, true)
|
: SrsRtcRecvTrack(receiver, track_desc, true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3271,8 +3335,8 @@ srs_error_t SrsRtcAudioRecvTrack::check_send_nacks()
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcVideoRecvTrack::SrsRtcVideoRecvTrack(SrsRtcConnection *session, SrsRtcTrackDescription *track_desc)
|
SrsRtcVideoRecvTrack::SrsRtcVideoRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc)
|
||||||
: SrsRtcRecvTrack(session, track_desc, false)
|
: SrsRtcRecvTrack(receiver, track_desc, false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3389,9 +3453,17 @@ uint16_t SrsRtcSeqJitter::correct(uint16_t value)
|
||||||
return jitter_->correct(value);
|
return jitter_->correct(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcSendTrack::SrsRtcSendTrack(SrsRtcConnection *session, SrsRtcTrackDescription *track_desc, bool is_audio)
|
ISrsRtcPacketSender::ISrsRtcPacketSender()
|
||||||
{
|
{
|
||||||
session_ = session;
|
}
|
||||||
|
|
||||||
|
ISrsRtcPacketSender::~ISrsRtcPacketSender()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsRtcSendTrack::SrsRtcSendTrack(ISrsRtcPacketSender *sender, SrsRtcTrackDescription *track_desc, bool is_audio)
|
||||||
|
{
|
||||||
|
sender_ = sender;
|
||||||
track_desc_ = track_desc->copy();
|
track_desc_ = track_desc->copy();
|
||||||
nack_no_copy_ = false;
|
nack_no_copy_ = false;
|
||||||
|
|
||||||
|
|
@ -3517,7 +3589,7 @@ srs_error_t SrsRtcSendTrack::on_recv_nack(const vector<uint16_t> &lost_seqs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default, we send packets by sendmmsg.
|
// By default, we send packets by sendmmsg.
|
||||||
if ((err = session_->do_send_packet(pkt)) != srs_success) {
|
if ((err = sender_->do_send_packet(pkt)) != srs_success) {
|
||||||
return srs_error_wrap(err, "raw send");
|
return srs_error_wrap(err, "raw send");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3525,8 +3597,8 @@ srs_error_t SrsRtcSendTrack::on_recv_nack(const vector<uint16_t> &lost_seqs)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcAudioSendTrack::SrsRtcAudioSendTrack(SrsRtcConnection *session, SrsRtcTrackDescription *track_desc)
|
SrsRtcAudioSendTrack::SrsRtcAudioSendTrack(ISrsRtcPacketSender *sender, SrsRtcTrackDescription *track_desc)
|
||||||
: SrsRtcSendTrack(session, track_desc, true)
|
: SrsRtcSendTrack(sender, track_desc, true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3558,7 +3630,7 @@ srs_error_t SrsRtcAudioSendTrack::on_rtp(SrsRtpPacket *pkt)
|
||||||
// Rebuild the sequence number and timestamp of packet, see https://github.com/ossrs/srs/issues/3167
|
// Rebuild the sequence number and timestamp of packet, see https://github.com/ossrs/srs/issues/3167
|
||||||
rebuild_packet(pkt);
|
rebuild_packet(pkt);
|
||||||
|
|
||||||
if ((err = session_->do_send_packet(pkt)) != srs_success) {
|
if ((err = sender_->do_send_packet(pkt)) != srs_success) {
|
||||||
return srs_error_wrap(err, "raw send");
|
return srs_error_wrap(err, "raw send");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3575,8 +3647,8 @@ srs_error_t SrsRtcAudioSendTrack::on_rtcp(SrsRtpPacket *pkt)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtcVideoSendTrack::SrsRtcVideoSendTrack(SrsRtcConnection *session, SrsRtcTrackDescription *track_desc)
|
SrsRtcVideoSendTrack::SrsRtcVideoSendTrack(ISrsRtcPacketSender *sender, SrsRtcTrackDescription *track_desc)
|
||||||
: SrsRtcSendTrack(session, track_desc, false)
|
: SrsRtcSendTrack(sender, track_desc, false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3608,7 +3680,7 @@ srs_error_t SrsRtcVideoSendTrack::on_rtp(SrsRtpPacket *pkt)
|
||||||
// Rebuild the sequence number and timestamp of packet, see https://github.com/ossrs/srs/issues/3167
|
// Rebuild the sequence number and timestamp of packet, see https://github.com/ossrs/srs/issues/3167
|
||||||
rebuild_packet(pkt);
|
rebuild_packet(pkt);
|
||||||
|
|
||||||
if ((err = session_->do_send_packet(pkt)) != srs_success) {
|
if ((err = sender_->do_send_packet(pkt)) != srs_success) {
|
||||||
return srs_error_wrap(err, "raw send");
|
return srs_error_wrap(err, "raw send");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -156,8 +156,21 @@ public:
|
||||||
void on_stream_change(SrsRtcSourceDescription *desc);
|
void on_stream_change(SrsRtcSourceDescription *desc);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The RTC source manager interface.
|
||||||
|
class ISrsRtcSourceManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsRtcSourceManager();
|
||||||
|
virtual ~ISrsRtcSourceManager();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize() = 0;
|
||||||
|
virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr<SrsRtcSource> &pps) = 0;
|
||||||
|
virtual SrsSharedPtr<SrsRtcSource> fetch(ISrsRequest *r) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// The RTC source manager.
|
// The RTC source manager.
|
||||||
class SrsRtcSourceManager : public ISrsHourGlass
|
class SrsRtcSourceManager : public ISrsRtcSourceManager, public ISrsHourGlass
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
srs_mutex_t lock_;
|
srs_mutex_t lock_;
|
||||||
|
|
@ -218,7 +231,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
// A Source is a stream, to publish and to play with, binding to SrsRtcPublishStream and SrsRtcPlayStream.
|
// A Source is a stream, to publish and to play with, binding to SrsRtcPublishStream and SrsRtcPlayStream.
|
||||||
class SrsRtcSource : public ISrsRtpTarget, public ISrsFastTimer, public ISrsRtcSourceForConsumer
|
class SrsRtcSource : public ISrsRtpTarget, public ISrsFastTimerHandler, public ISrsRtcSourceForConsumer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// The RTP bridge, convert RTP packets to other protocols.
|
// The RTP bridge, convert RTP packets to other protocols.
|
||||||
|
|
@ -323,7 +336,7 @@ public:
|
||||||
virtual bool has_stream_desc();
|
virtual bool has_stream_desc();
|
||||||
virtual void set_stream_desc(SrsRtcSourceDescription *stream_desc);
|
virtual void set_stream_desc(SrsRtcSourceDescription *stream_desc);
|
||||||
virtual std::vector<SrsRtcTrackDescription *> get_track_desc(std::string type, std::string media_type);
|
virtual std::vector<SrsRtcTrackDescription *> get_track_desc(std::string type, std::string media_type);
|
||||||
// interface ISrsFastTimer
|
// interface ISrsFastTimerHandler
|
||||||
private:
|
private:
|
||||||
srs_error_t on_timer(srs_utime_t interval);
|
srs_error_t on_timer(srs_utime_t interval);
|
||||||
};
|
};
|
||||||
|
|
@ -746,13 +759,29 @@ public:
|
||||||
SrsRtcTrackDescription *find_track_description_by_ssrc(uint32_t ssrc);
|
SrsRtcTrackDescription *find_track_description_by_ssrc(uint32_t ssrc);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The RTC packet receiver interface.
|
||||||
|
class ISrsRtcPacketReceiver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsRtcPacketReceiver();
|
||||||
|
virtual ~ISrsRtcPacketReceiver();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer *rtp_queue, const uint64_t &last_send_systime, const SrsNtp &last_send_ntp) = 0;
|
||||||
|
virtual srs_error_t send_rtcp_xr_rrtr(uint32_t ssrc) = 0;
|
||||||
|
virtual void check_send_nacks(SrsRtpNackForReceiver *nack, uint32_t ssrc, uint32_t &sent_nacks, uint32_t &timeout_nacks) = 0;
|
||||||
|
virtual srs_error_t send_rtcp(char *data, int nb_data) = 0;
|
||||||
|
virtual srs_error_t send_rtcp_fb_pli(uint32_t ssrc, const SrsContextId &cid_of_subscriber) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The RTC receive track.
|
||||||
class SrsRtcRecvTrack
|
class SrsRtcRecvTrack
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
SrsRtcTrackDescription *track_desc_;
|
SrsRtcTrackDescription *track_desc_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SrsRtcConnection *session_;
|
ISrsRtcPacketReceiver *receiver_;
|
||||||
SrsRtpRingBuffer *rtp_queue_;
|
SrsRtpRingBuffer *rtp_queue_;
|
||||||
SrsRtpNackForReceiver *nack_receiver_;
|
SrsRtpNackForReceiver *nack_receiver_;
|
||||||
|
|
||||||
|
|
@ -773,7 +802,7 @@ protected:
|
||||||
uint64_t last_sender_report_sys_time_;
|
uint64_t last_sender_report_sys_time_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsRtcRecvTrack(SrsRtcConnection *session, SrsRtcTrackDescription *stream_descs, bool is_audio);
|
SrsRtcRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *stream_descs, bool is_audio);
|
||||||
virtual ~SrsRtcRecvTrack();
|
virtual ~SrsRtcRecvTrack();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -806,7 +835,7 @@ protected:
|
||||||
class SrsRtcAudioRecvTrack : public SrsRtcRecvTrack, public ISrsRtpPacketDecodeHandler
|
class SrsRtcAudioRecvTrack : public SrsRtcRecvTrack, public ISrsRtpPacketDecodeHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SrsRtcAudioRecvTrack(SrsRtcConnection *session, SrsRtcTrackDescription *track_desc);
|
SrsRtcAudioRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc);
|
||||||
virtual ~SrsRtcAudioRecvTrack();
|
virtual ~SrsRtcAudioRecvTrack();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -820,7 +849,7 @@ public:
|
||||||
class SrsRtcVideoRecvTrack : public SrsRtcRecvTrack, public ISrsRtpPacketDecodeHandler
|
class SrsRtcVideoRecvTrack : public SrsRtcRecvTrack, public ISrsRtpPacketDecodeHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SrsRtcVideoRecvTrack(SrsRtcConnection *session, SrsRtcTrackDescription *stream_descs);
|
SrsRtcVideoRecvTrack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *stream_descs);
|
||||||
virtual ~SrsRtcVideoRecvTrack();
|
virtual ~SrsRtcVideoRecvTrack();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -922,6 +951,17 @@ public:
|
||||||
uint16_t correct(uint16_t value);
|
uint16_t correct(uint16_t value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The RTC packet sender interface.
|
||||||
|
class ISrsRtcPacketSender
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsRtcPacketSender();
|
||||||
|
virtual ~ISrsRtcPacketSender();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t do_send_packet(SrsRtpPacket *pkt) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class SrsRtcSendTrack
|
class SrsRtcSendTrack
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -930,7 +970,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// The owner connection for this track.
|
// The owner connection for this track.
|
||||||
SrsRtcConnection *session_;
|
ISrsRtcPacketSender *sender_;
|
||||||
// NACK ARQ ring buffer.
|
// NACK ARQ ring buffer.
|
||||||
SrsRtpRingBuffer *rtp_queue_;
|
SrsRtpRingBuffer *rtp_queue_;
|
||||||
|
|
||||||
|
|
@ -946,7 +986,7 @@ private:
|
||||||
SrsErrorPithyPrint *nack_epp;
|
SrsErrorPithyPrint *nack_epp;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsRtcSendTrack(SrsRtcConnection *session, SrsRtcTrackDescription *track_desc, bool is_audio);
|
SrsRtcSendTrack(ISrsRtcPacketSender *sender, SrsRtcTrackDescription *track_desc, bool is_audio);
|
||||||
virtual ~SrsRtcSendTrack();
|
virtual ~SrsRtcSendTrack();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -975,7 +1015,7 @@ public:
|
||||||
class SrsRtcAudioSendTrack : public SrsRtcSendTrack
|
class SrsRtcAudioSendTrack : public SrsRtcSendTrack
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SrsRtcAudioSendTrack(SrsRtcConnection *session, SrsRtcTrackDescription *track_desc);
|
SrsRtcAudioSendTrack(ISrsRtcPacketSender *sender, SrsRtcTrackDescription *track_desc);
|
||||||
virtual ~SrsRtcAudioSendTrack();
|
virtual ~SrsRtcAudioSendTrack();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -986,7 +1026,7 @@ public:
|
||||||
class SrsRtcVideoSendTrack : public SrsRtcSendTrack
|
class SrsRtcVideoSendTrack : public SrsRtcSendTrack
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SrsRtcVideoSendTrack(SrsRtcConnection *session, SrsRtcTrackDescription *track_desc);
|
SrsRtcVideoSendTrack(ISrsRtcPacketSender *sender, SrsRtcTrackDescription *track_desc);
|
||||||
virtual ~SrsRtcVideoSendTrack();
|
virtual ~SrsRtcVideoSendTrack();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -541,7 +541,7 @@ srs_error_t SrsRtmpConn::stream_service_cycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
// We must do stat the client before hooks, because hooks depends on it.
|
// We must do stat the client before hooks, because hooks depends on it.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
if ((err = stat->on_client(_srs_context->get_id().c_str(), req, this, info_->type_)) != srs_success) {
|
if ((err = stat->on_client(_srs_context->get_id().c_str(), req, this, info_->type_)) != srs_success) {
|
||||||
return srs_error_wrap(err, "rtmp: stat client");
|
return srs_error_wrap(err, "rtmp: stat client");
|
||||||
}
|
}
|
||||||
|
|
@ -751,10 +751,10 @@ srs_error_t SrsRtmpConn::do_playing(SrsSharedPtr<SrsLiveSource> source, SrsLiveC
|
||||||
int64_t starttime = -1;
|
int64_t starttime = -1;
|
||||||
|
|
||||||
// setup the realtime.
|
// setup the realtime.
|
||||||
realtime_ = _srs_config->get_realtime_enabled(req->vhost_);
|
realtime_ = _srs_config->get_realtime_enabled(req->vhost_, false);
|
||||||
// setup the mw config.
|
// setup the mw config.
|
||||||
// when mw_sleep changed, resize the socket send buffer.
|
// when mw_sleep changed, resize the socket send buffer.
|
||||||
mw_msgs_ = _srs_config->get_mw_msgs(req->vhost_, realtime_);
|
mw_msgs_ = _srs_config->get_mw_msgs(req->vhost_, realtime_, false);
|
||||||
mw_sleep_ = _srs_config->get_mw_sleep(req->vhost_);
|
mw_sleep_ = _srs_config->get_mw_sleep(req->vhost_);
|
||||||
transport_->set_socket_buffer(mw_sleep_);
|
transport_->set_socket_buffer(mw_sleep_);
|
||||||
// initialize the send_min_interval
|
// initialize the send_min_interval
|
||||||
|
|
@ -877,7 +877,7 @@ srs_error_t SrsRtmpConn::publishing(SrsSharedPtr<SrsLiveSource> source)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We must do stat the client before hooks, because hooks depends on it.
|
// We must do stat the client before hooks, because hooks depends on it.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
if ((err = stat->on_client(_srs_context->get_id().c_str(), req, this, info_->type_)) != srs_success) {
|
if ((err = stat->on_client(_srs_context->get_id().c_str(), req, this, info_->type_)) != srs_success) {
|
||||||
return srs_error_wrap(err, "rtmp: stat client");
|
return srs_error_wrap(err, "rtmp: stat client");
|
||||||
}
|
}
|
||||||
|
|
@ -979,7 +979,7 @@ srs_error_t SrsRtmpConn::do_publishing(SrsSharedPtr<SrsLiveSource> source, SrsPu
|
||||||
|
|
||||||
// Update the stat for video fps.
|
// Update the stat for video fps.
|
||||||
// @remark https://github.com/ossrs/srs/issues/851
|
// @remark https://github.com/ossrs/srs/issues/851
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
if ((err = stat->on_video_frames(req, (int)(rtrd->nb_video_frames() - nb_frames))) != srs_success) {
|
if ((err = stat->on_video_frames(req, (int)(rtrd->nb_video_frames() - nb_frames))) != srs_success) {
|
||||||
return srs_error_wrap(err, "rtmp: stat video frames");
|
return srs_error_wrap(err, "rtmp: stat video frames");
|
||||||
}
|
}
|
||||||
|
|
@ -1557,7 +1557,7 @@ srs_error_t SrsRtmpConn::cycle()
|
||||||
err = do_cycle();
|
err = do_cycle();
|
||||||
|
|
||||||
// Update statistic when done.
|
// Update statistic when done.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
stat->kbps_add_delta(get_id().c_str(), delta_);
|
stat->kbps_add_delta(get_id().c_str(), delta_);
|
||||||
stat->on_disconnect(get_id().c_str(), err);
|
stat->on_disconnect(get_id().c_str(), err);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -958,7 +958,7 @@ srs_error_t SrsOriginHub::on_audio(SrsMediaPacket *shared_audio)
|
||||||
static int flv_sound_types[] = {1, 2, 0};
|
static int flv_sound_types[] = {1, 2, 0};
|
||||||
|
|
||||||
// when got audio stream info.
|
// when got audio stream info.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
if ((err = stat->on_audio_info(req_, format->acodec_->id_, c->sound_rate_, c->sound_type_, c->aac_object_)) != srs_success) {
|
if ((err = stat->on_audio_info(req_, format->acodec_->id_, c->sound_rate_, c->sound_type_, c->aac_object_)) != srs_success) {
|
||||||
return srs_error_wrap(err, "stat audio");
|
return srs_error_wrap(err, "stat audio");
|
||||||
}
|
}
|
||||||
|
|
@ -1042,7 +1042,7 @@ srs_error_t SrsOriginHub::on_video(SrsMediaPacket *shared_video, bool is_sequenc
|
||||||
srs_assert(c);
|
srs_assert(c);
|
||||||
|
|
||||||
// when got video stream info.
|
// when got video stream info.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
if (c->id_ == SrsVideoCodecIdAVC) {
|
if (c->id_ == SrsVideoCodecIdAVC) {
|
||||||
err = stat->on_video_info(req_, c->id_, c->avc_profile_, c->avc_level_, c->width_, c->height_);
|
err = stat->on_video_info(req_, c->id_, c->avc_profile_, c->avc_level_, c->width_, c->height_);
|
||||||
|
|
@ -1550,6 +1550,14 @@ srs_error_t SrsMetaCache::update_vsh(SrsMediaPacket *msg)
|
||||||
return vformat_->on_video(msg);
|
return vformat_->on_video(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsLiveSourceManager::ISrsLiveSourceManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsLiveSourceManager::~ISrsLiveSourceManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsLiveSourceManager *_srs_sources = NULL;
|
SrsLiveSourceManager *_srs_sources = NULL;
|
||||||
|
|
||||||
SrsLiveSourceManager::SrsLiveSourceManager()
|
SrsLiveSourceManager::SrsLiveSourceManager()
|
||||||
|
|
@ -2336,7 +2344,7 @@ srs_error_t SrsLiveSource::on_publish()
|
||||||
return srs_error_wrap(err, "bridge publish");
|
return srs_error_wrap(err, "bridge publish");
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
stat->on_stream_publish(req_, _source_id.c_str());
|
stat->on_stream_publish(req_, _source_id.c_str());
|
||||||
|
|
||||||
// When no players, the publisher is idle now.
|
// When no players, the publisher is idle now.
|
||||||
|
|
@ -2378,7 +2386,7 @@ void SrsLiveSource::on_unpublish()
|
||||||
ISrsLiveSourceHandler *handler = _srs_server;
|
ISrsLiveSourceHandler *handler = _srs_server;
|
||||||
srs_assert(handler);
|
srs_assert(handler);
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
stat->on_stream_close(req_);
|
stat->on_stream_close(req_);
|
||||||
|
|
||||||
handler->on_unpublish(req_);
|
handler->on_unpublish(req_);
|
||||||
|
|
|
||||||
|
|
@ -465,8 +465,25 @@ public:
|
||||||
virtual srs_error_t update_vsh(SrsMediaPacket *msg);
|
virtual srs_error_t update_vsh(SrsMediaPacket *msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The live source manager interface.
|
||||||
|
class ISrsLiveSourceManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsLiveSourceManager();
|
||||||
|
virtual ~ISrsLiveSourceManager();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// create source when fetch from cache failed.
|
||||||
|
// @param r the client request.
|
||||||
|
// @param h the event handler for source.
|
||||||
|
// @param pps the matched source, if success never be NULL.
|
||||||
|
virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr<SrsLiveSource> &pps) = 0;
|
||||||
|
// Get the exists source, NULL when not exists.
|
||||||
|
virtual SrsSharedPtr<SrsLiveSource> fetch(ISrsRequest *r) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// The source manager to create and refresh all stream sources.
|
// The source manager to create and refresh all stream sources.
|
||||||
class SrsLiveSourceManager : public ISrsHourGlass
|
class SrsLiveSourceManager : public ISrsHourGlass, public ISrsLiveSourceManager
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
srs_mutex_t lock_;
|
srs_mutex_t lock_;
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ SrsRtspPlayStream::~SrsRtspPlayStream()
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the statistic when client coveried.
|
// update the statistic when client coveried.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
// TODO: FIXME: Should finger out the err.
|
// TODO: FIXME: Should finger out the err.
|
||||||
stat->on_disconnect(cid_.c_str(), srs_success);
|
stat->on_disconnect(cid_.c_str(), srs_success);
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +87,7 @@ srs_error_t SrsRtspPlayStream::initialize(ISrsRequest *req, std::map<uint32_t, S
|
||||||
req_ = req->copy();
|
req_ = req->copy();
|
||||||
|
|
||||||
// We must do stat the client before hooks, because hooks depends on it.
|
// We must do stat the client before hooks, because hooks depends on it.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
if ((err = stat->on_client(cid_.c_str(), req_, session_, SrsRtcConnPlay)) != srs_success) {
|
if ((err = stat->on_client(cid_.c_str(), req_, session_, SrsRtcConnPlay)) != srs_success) {
|
||||||
return srs_error_wrap(err, "RTSP: stat client");
|
return srs_error_wrap(err, "RTSP: stat client");
|
||||||
}
|
}
|
||||||
|
|
@ -487,7 +487,7 @@ srs_error_t SrsRtspConnection::cycle()
|
||||||
err = do_cycle();
|
err = do_cycle();
|
||||||
|
|
||||||
// Update statistic when done.
|
// Update statistic when done.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
stat->kbps_add_delta(get_id().c_str(), delta());
|
stat->kbps_add_delta(get_id().c_str(), delta());
|
||||||
|
|
||||||
do_teardown();
|
do_teardown();
|
||||||
|
|
|
||||||
|
|
@ -429,7 +429,7 @@ srs_error_t SrsRtspSource::on_publish()
|
||||||
return srs_error_wrap(err, "source id change");
|
return srs_error_wrap(err, "source id change");
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
stat->on_stream_publish(req_, _source_id.c_str());
|
stat->on_stream_publish(req_, _source_id.c_str());
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -449,7 +449,7 @@ void SrsRtspSource::on_unpublish()
|
||||||
}
|
}
|
||||||
_source_id = SrsContextId();
|
_source_id = SrsContextId();
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
stat->on_stream_close(req_);
|
stat->on_stream_close(req_);
|
||||||
|
|
||||||
// Destroy and cleanup source when no publishers and consumers.
|
// Destroy and cleanup source when no publishers and consumers.
|
||||||
|
|
|
||||||
|
|
@ -178,6 +178,9 @@ SrsServer::SrsServer()
|
||||||
ingester_ = new SrsIngester();
|
ingester_ = new SrsIngester();
|
||||||
timer_ = NULL;
|
timer_ = NULL;
|
||||||
|
|
||||||
|
// Initialize global statistic instance.
|
||||||
|
_srs_stat = new SrsStatistic();
|
||||||
|
|
||||||
// Initialize WebRTC components
|
// Initialize WebRTC components
|
||||||
rtc_session_manager_ = new SrsRtcSessionManager();
|
rtc_session_manager_ = new SrsRtcSessionManager();
|
||||||
}
|
}
|
||||||
|
|
@ -230,6 +233,9 @@ SrsServer::~SrsServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_freep(rtc_session_manager_);
|
srs_freep(rtc_session_manager_);
|
||||||
|
|
||||||
|
// Cleanup global statistic instance.
|
||||||
|
srs_freep(_srs_stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsServer::dispose()
|
void SrsServer::dispose()
|
||||||
|
|
@ -1089,7 +1095,7 @@ srs_error_t SrsServer::notify(int event, srs_utime_t interval, srs_utime_t tick)
|
||||||
|
|
||||||
void SrsServer::resample_kbps()
|
void SrsServer::resample_kbps()
|
||||||
{
|
{
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
|
|
||||||
// collect delta from all clients.
|
// collect delta from all clients.
|
||||||
for (int i = 0; i < (int)_srs_conn_manager->size(); i++) {
|
for (int i = 0; i < (int)_srs_conn_manager->size(); i++) {
|
||||||
|
|
|
||||||
|
|
@ -230,7 +230,7 @@ srs_error_t SrsMpegtsSrtConn::cycle()
|
||||||
srs_error_t err = do_cycle();
|
srs_error_t err = do_cycle();
|
||||||
|
|
||||||
// Update statistic when done.
|
// Update statistic when done.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
stat->kbps_add_delta(get_id().c_str(), delta_);
|
stat->kbps_add_delta(get_id().c_str(), delta_);
|
||||||
stat->on_disconnect(get_id().c_str(), err);
|
stat->on_disconnect(get_id().c_str(), err);
|
||||||
|
|
||||||
|
|
@ -319,7 +319,7 @@ srs_error_t SrsMpegtsSrtConn::publishing()
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
// We must do stat the client before hooks, because hooks depends on it.
|
// We must do stat the client before hooks, because hooks depends on it.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
if ((err = stat->on_client(_srs_context->get_id().c_str(), req_, this, SrsSrtConnPublish)) != srs_success) {
|
if ((err = stat->on_client(_srs_context->get_id().c_str(), req_, this, SrsSrtConnPublish)) != srs_success) {
|
||||||
return srs_error_wrap(err, "srt: stat client");
|
return srs_error_wrap(err, "srt: stat client");
|
||||||
}
|
}
|
||||||
|
|
@ -348,7 +348,7 @@ srs_error_t SrsMpegtsSrtConn::playing()
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
// We must do stat the client before hooks, because hooks depends on it.
|
// We must do stat the client before hooks, because hooks depends on it.
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
if ((err = stat->on_client(_srs_context->get_id().c_str(), req_, this, SrsSrtConnPlay)) != srs_success) {
|
if ((err = stat->on_client(_srs_context->get_id().c_str(), req_, this, SrsSrtConnPlay)) != srs_success) {
|
||||||
return srs_error_wrap(err, "srt: stat client");
|
return srs_error_wrap(err, "srt: stat client");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,14 @@ int SrsSrtPacket::size()
|
||||||
return shared_buffer_->size();
|
return shared_buffer_->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsSrtSourceManager::ISrsSrtSourceManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsSrtSourceManager::~ISrsSrtSourceManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsSrtSourceManager::SrsSrtSourceManager()
|
SrsSrtSourceManager::SrsSrtSourceManager()
|
||||||
{
|
{
|
||||||
lock_ = srs_mutex_new();
|
lock_ = srs_mutex_new();
|
||||||
|
|
@ -684,12 +692,12 @@ srs_error_t SrsSrtFrameBuilder::check_vps_sps_pps_change(SrsTsMessage *msg)
|
||||||
char *flv = NULL;
|
char *flv = NULL;
|
||||||
int nb_flv = 0;
|
int nb_flv = 0;
|
||||||
if ((err = hevc->mux_hevc2flv_enhanced(sh,
|
if ((err = hevc->mux_hevc2flv_enhanced(sh,
|
||||||
SrsVideoAvcFrameTypeKeyFrame,
|
SrsVideoAvcFrameTypeKeyFrame,
|
||||||
SrsVideoHEVCFrameTraitPacketTypeSequenceStart,
|
SrsVideoHEVCFrameTraitPacketTypeSequenceStart,
|
||||||
dts,
|
dts,
|
||||||
pts,
|
pts,
|
||||||
&flv,
|
&flv,
|
||||||
&nb_flv)) != srs_success) {
|
&nb_flv)) != srs_success) {
|
||||||
return srs_error_wrap(err, "hevc sh to flv");
|
return srs_error_wrap(err, "hevc sh to flv");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1072,7 +1080,7 @@ srs_error_t SrsSrtSource::on_publish()
|
||||||
return srs_error_wrap(err, "bridge on publish");
|
return srs_error_wrap(err, "bridge on publish");
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
stat->on_stream_publish(req_, _source_id.c_str());
|
stat->on_stream_publish(req_, _source_id.c_str());
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -1085,7 +1093,7 @@ void SrsSrtSource::on_unpublish()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsStatistic *stat = SrsStatistic::instance();
|
SrsStatistic *stat = _srs_stat;
|
||||||
stat->on_stream_close(req_);
|
stat->on_stream_close(req_);
|
||||||
|
|
||||||
if (srt_bridge_) {
|
if (srt_bridge_) {
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,21 @@ private:
|
||||||
int actual_buffer_size_;
|
int actual_buffer_size_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsSrtSourceManager : public ISrsHourGlass
|
// The SRT source manager interface.
|
||||||
|
class ISrsSrtSourceManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsSrtSourceManager();
|
||||||
|
virtual ~ISrsSrtSourceManager();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize() = 0;
|
||||||
|
virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr<SrsSrtSource> &pps) = 0;
|
||||||
|
virtual SrsSharedPtr<SrsSrtSource> fetch(ISrsRequest *r) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The SRT source manager.
|
||||||
|
class SrsSrtSourceManager : public ISrsHourGlass, public ISrsSrtSourceManager
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
srs_mutex_t lock_;
|
srs_mutex_t lock_;
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,15 @@ srs_error_t SrsStatisticClient::dumps(SrsJsonObject *obj)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsStatistic *SrsStatistic::instance_ = NULL;
|
ISrsStatistic::ISrsStatistic()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsStatistic::~ISrsStatistic()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsStatistic *_srs_stat = NULL;
|
||||||
|
|
||||||
SrsStatistic::SrsStatistic()
|
SrsStatistic::SrsStatistic()
|
||||||
{
|
{
|
||||||
|
|
@ -287,14 +295,6 @@ SrsStatistic::~SrsStatistic()
|
||||||
rstreams_.clear();
|
rstreams_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsStatistic *SrsStatistic::instance()
|
|
||||||
{
|
|
||||||
if (instance_ == NULL) {
|
|
||||||
instance_ = new SrsStatistic();
|
|
||||||
}
|
|
||||||
return instance_;
|
|
||||||
}
|
|
||||||
|
|
||||||
SrsStatisticVhost *SrsStatistic::find_vhost_by_id(std::string vid)
|
SrsStatisticVhost *SrsStatistic::find_vhost_by_id(std::string vid)
|
||||||
{
|
{
|
||||||
std::map<string, SrsStatisticVhost *>::iterator it;
|
std::map<string, SrsStatisticVhost *>::iterator it;
|
||||||
|
|
|
||||||
|
|
@ -130,10 +130,22 @@ public:
|
||||||
virtual srs_error_t dumps(SrsJsonObject *obj);
|
virtual srs_error_t dumps(SrsJsonObject *obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SrsStatistic
|
// The interface for statistic.
|
||||||
|
class ISrsStatistic
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsStatistic();
|
||||||
|
virtual ~ISrsStatistic();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void on_disconnect(std::string id, srs_error_t err) = 0;
|
||||||
|
virtual srs_error_t on_client(std::string id, ISrsRequest *req, ISrsExpire *conn, SrsRtmpConnType type) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The global statistic instance.
|
||||||
|
class SrsStatistic : public ISrsStatistic
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
static SrsStatistic *instance_;
|
|
||||||
// The id to identify the sever.
|
// The id to identify the sever.
|
||||||
std::string server_id_;
|
std::string server_id_;
|
||||||
// The id to identify the service.
|
// The id to identify the service.
|
||||||
|
|
@ -167,13 +179,10 @@ private:
|
||||||
// The total of clients errors.
|
// The total of clients errors.
|
||||||
int64_t nb_errs_;
|
int64_t nb_errs_;
|
||||||
|
|
||||||
private:
|
public:
|
||||||
SrsStatistic();
|
SrsStatistic();
|
||||||
virtual ~SrsStatistic();
|
virtual ~SrsStatistic();
|
||||||
|
|
||||||
public:
|
|
||||||
static SrsStatistic *instance();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual SrsStatisticVhost *find_vhost_by_id(std::string vid);
|
virtual SrsStatisticVhost *find_vhost_by_id(std::string vid);
|
||||||
virtual SrsStatisticVhost *find_vhost_by_name(std::string name);
|
virtual SrsStatisticVhost *find_vhost_by_name(std::string name);
|
||||||
|
|
@ -259,4 +268,7 @@ public:
|
||||||
// Generate a random string id, with constant prefix.
|
// Generate a random string id, with constant prefix.
|
||||||
extern std::string srs_generate_stat_vid();
|
extern std::string srs_generate_stat_vid();
|
||||||
|
|
||||||
|
// Global statistic instance.
|
||||||
|
extern SrsStatistic *_srs_stat;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,14 @@ srs_error_t SrsHourGlass::cycle()
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsFastTimerHandler::ISrsFastTimerHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsFastTimerHandler::~ISrsFastTimerHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ISrsFastTimer::ISrsFastTimer()
|
ISrsFastTimer::ISrsFastTimer()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -160,16 +168,16 @@ srs_error_t SrsFastTimer::start()
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsFastTimer::subscribe(ISrsFastTimer *timer)
|
void SrsFastTimer::subscribe(ISrsFastTimerHandler *timer)
|
||||||
{
|
{
|
||||||
if (std::find(handlers_.begin(), handlers_.end(), timer) == handlers_.end()) {
|
if (std::find(handlers_.begin(), handlers_.end(), timer) == handlers_.end()) {
|
||||||
handlers_.push_back(timer);
|
handlers_.push_back(timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsFastTimer::unsubscribe(ISrsFastTimer *timer)
|
void SrsFastTimer::unsubscribe(ISrsFastTimerHandler *timer)
|
||||||
{
|
{
|
||||||
vector<ISrsFastTimer *>::iterator it = std::find(handlers_.begin(), handlers_.end(), timer);
|
vector<ISrsFastTimerHandler *>::iterator it = std::find(handlers_.begin(), handlers_.end(), timer);
|
||||||
if (it != handlers_.end()) {
|
if (it != handlers_.end()) {
|
||||||
handlers_.erase(it);
|
handlers_.erase(it);
|
||||||
}
|
}
|
||||||
|
|
@ -187,7 +195,7 @@ srs_error_t SrsFastTimer::cycle()
|
||||||
++_srs_pps_timer->sugar_;
|
++_srs_pps_timer->sugar_;
|
||||||
|
|
||||||
for (int i = 0; i < (int)handlers_.size(); i++) {
|
for (int i = 0; i < (int)handlers_.size(); i++) {
|
||||||
ISrsFastTimer *timer = handlers_.at(i);
|
ISrsFastTimerHandler *timer = handlers_.at(i);
|
||||||
|
|
||||||
if ((err = timer->on_timer(interval_)) != srs_success) {
|
if ((err = timer->on_timer(interval_)) != srs_success) {
|
||||||
srs_freep(err); // Ignore any error for shared timer.
|
srs_freep(err); // Ignore any error for shared timer.
|
||||||
|
|
@ -248,6 +256,14 @@ srs_error_t SrsClockWallMonitor::on_timer(srs_utime_t interval)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsSharedTimer::ISrsSharedTimer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsSharedTimer::~ISrsSharedTimer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsSharedTimer::SrsSharedTimer()
|
SrsSharedTimer::SrsSharedTimer()
|
||||||
{
|
{
|
||||||
timer20ms_ = NULL;
|
timer20ms_ = NULL;
|
||||||
|
|
@ -300,22 +316,22 @@ srs_error_t SrsSharedTimer::initialize()
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsFastTimer *SrsSharedTimer::timer20ms()
|
ISrsFastTimer *SrsSharedTimer::timer20ms()
|
||||||
{
|
{
|
||||||
return timer20ms_;
|
return timer20ms_;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsFastTimer *SrsSharedTimer::timer100ms()
|
ISrsFastTimer *SrsSharedTimer::timer100ms()
|
||||||
{
|
{
|
||||||
return timer100ms_;
|
return timer100ms_;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsFastTimer *SrsSharedTimer::timer1s()
|
ISrsFastTimer *SrsSharedTimer::timer1s()
|
||||||
{
|
{
|
||||||
return timer1s_;
|
return timer1s_;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsFastTimer *SrsSharedTimer::timer5s()
|
ISrsFastTimer *SrsSharedTimer::timer5s()
|
||||||
{
|
{
|
||||||
return timer5s_;
|
return timer5s_;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,18 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
// The handler for fast timer.
|
// The handler for fast timer.
|
||||||
|
class ISrsFastTimerHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsFastTimerHandler();
|
||||||
|
virtual ~ISrsFastTimerHandler();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Tick when timer is active.
|
||||||
|
virtual srs_error_t on_timer(srs_utime_t interval) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The interface for timer.
|
||||||
class ISrsFastTimer
|
class ISrsFastTimer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -103,19 +115,19 @@ public:
|
||||||
virtual ~ISrsFastTimer();
|
virtual ~ISrsFastTimer();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Tick when timer is active.
|
virtual void subscribe(ISrsFastTimerHandler *timer) = 0;
|
||||||
virtual srs_error_t on_timer(srs_utime_t interval) = 0;
|
virtual void unsubscribe(ISrsFastTimerHandler *timer) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The fast timer, shared by objects, for high performance.
|
// The fast timer, shared by objects, for high performance.
|
||||||
// For example, we should never start a timer for each connection or publisher or player,
|
// For example, we should never start a timer for each connection or publisher or player,
|
||||||
// instead, we should start only one fast timer in server.
|
// instead, we should start only one fast timer in server.
|
||||||
class SrsFastTimer : public ISrsCoroutineHandler
|
class SrsFastTimer : public ISrsCoroutineHandler, public ISrsFastTimer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ISrsCoroutine *trd_;
|
ISrsCoroutine *trd_;
|
||||||
srs_utime_t interval_;
|
srs_utime_t interval_;
|
||||||
std::vector<ISrsFastTimer *> handlers_;
|
std::vector<ISrsFastTimerHandler *> handlers_;
|
||||||
ISrsTime *time_;
|
ISrsTime *time_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -126,8 +138,8 @@ public:
|
||||||
srs_error_t start();
|
srs_error_t start();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void subscribe(ISrsFastTimer *timer);
|
void subscribe(ISrsFastTimerHandler *timer);
|
||||||
void unsubscribe(ISrsFastTimer *timer);
|
void unsubscribe(ISrsFastTimerHandler *timer);
|
||||||
// Interface ISrsCoroutineHandler
|
// Interface ISrsCoroutineHandler
|
||||||
private:
|
private:
|
||||||
// Cycle the hourglass, which will sleep resolution every time.
|
// Cycle the hourglass, which will sleep resolution every time.
|
||||||
|
|
@ -136,7 +148,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// To monitor the system wall clock timer deviation.
|
// To monitor the system wall clock timer deviation.
|
||||||
class SrsClockWallMonitor : public ISrsFastTimer
|
class SrsClockWallMonitor : public ISrsFastTimerHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ISrsTime *time_;
|
ISrsTime *time_;
|
||||||
|
|
@ -144,13 +156,27 @@ private:
|
||||||
public:
|
public:
|
||||||
SrsClockWallMonitor();
|
SrsClockWallMonitor();
|
||||||
virtual ~SrsClockWallMonitor();
|
virtual ~SrsClockWallMonitor();
|
||||||
// interface ISrsFastTimer
|
// interface ISrsFastTimerHandler
|
||||||
private:
|
private:
|
||||||
srs_error_t on_timer(srs_utime_t interval);
|
srs_error_t on_timer(srs_utime_t interval);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The interface for shared timer.
|
||||||
|
class ISrsSharedTimer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsSharedTimer();
|
||||||
|
virtual ~ISrsSharedTimer();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ISrsFastTimer *timer20ms() = 0;
|
||||||
|
virtual ISrsFastTimer *timer100ms() = 0;
|
||||||
|
virtual ISrsFastTimer *timer1s() = 0;
|
||||||
|
virtual ISrsFastTimer *timer5s() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// Global shared timer manager
|
// Global shared timer manager
|
||||||
class SrsSharedTimer
|
class SrsSharedTimer : public ISrsSharedTimer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsFastTimer *timer20ms_;
|
SrsFastTimer *timer20ms_;
|
||||||
|
|
@ -169,10 +195,10 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Access to global shared timers
|
// Access to global shared timers
|
||||||
SrsFastTimer *timer20ms();
|
ISrsFastTimer *timer20ms();
|
||||||
SrsFastTimer *timer100ms();
|
ISrsFastTimer *timer100ms();
|
||||||
SrsFastTimer *timer1s();
|
ISrsFastTimer *timer1s();
|
||||||
SrsFastTimer *timer5s();
|
ISrsFastTimer *timer5s();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Global shared timer instance
|
// Global shared timer instance
|
||||||
|
|
|
||||||
|
|
@ -1257,6 +1257,24 @@ SrsNaluSample *SrsRtpSTAPPayload::get_pps()
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SrsNaluSample *SrsRtpSTAPPayload::get_idr()
|
||||||
|
{
|
||||||
|
int nn_nalus = (int)nalus_.size();
|
||||||
|
for (int i = 0; i < nn_nalus; i++) {
|
||||||
|
SrsNaluSample *p = nalus_[i];
|
||||||
|
if (!p || !p->size_) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsAvcNaluType nalu_type = SrsAvcNaluTypeParse(p->bytes_[0]);
|
||||||
|
if (nalu_type == SrsAvcNaluTypeIDR) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t SrsRtpSTAPPayload::nb_bytes()
|
uint64_t SrsRtpSTAPPayload::nb_bytes()
|
||||||
{
|
{
|
||||||
int size = 1;
|
int size = 1;
|
||||||
|
|
@ -1630,6 +1648,24 @@ SrsNaluSample *SrsRtpSTAPPayloadHevc::get_pps()
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SrsNaluSample *SrsRtpSTAPPayloadHevc::get_idr()
|
||||||
|
{
|
||||||
|
int nn_nalus = (int)nalus_.size();
|
||||||
|
for (int i = 0; i < nn_nalus; i++) {
|
||||||
|
SrsNaluSample *p = nalus_[i];
|
||||||
|
if (!p || !p->size_) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHevcNaluType nalu_type = SrsHevcNaluTypeParse(p->bytes_[0]);
|
||||||
|
if (SrsIsIRAP(nalu_type)) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t SrsRtpSTAPPayloadHevc::nb_bytes()
|
uint64_t SrsRtpSTAPPayloadHevc::nb_bytes()
|
||||||
{
|
{
|
||||||
int size = 2;
|
int size = 2;
|
||||||
|
|
|
||||||
|
|
@ -470,6 +470,7 @@ public:
|
||||||
public:
|
public:
|
||||||
SrsNaluSample *get_sps();
|
SrsNaluSample *get_sps();
|
||||||
SrsNaluSample *get_pps();
|
SrsNaluSample *get_pps();
|
||||||
|
SrsNaluSample *get_idr();
|
||||||
// interface ISrsRtpPayloader
|
// interface ISrsRtpPayloader
|
||||||
public:
|
public:
|
||||||
virtual uint64_t nb_bytes();
|
virtual uint64_t nb_bytes();
|
||||||
|
|
@ -545,6 +546,7 @@ public:
|
||||||
SrsNaluSample *get_vps();
|
SrsNaluSample *get_vps();
|
||||||
SrsNaluSample *get_sps();
|
SrsNaluSample *get_sps();
|
||||||
SrsNaluSample *get_pps();
|
SrsNaluSample *get_pps();
|
||||||
|
SrsNaluSample *get_idr();
|
||||||
// interface ISrsRtpPayloader
|
// interface ISrsRtpPayloader
|
||||||
public:
|
public:
|
||||||
virtual uint64_t nb_bytes();
|
virtual uint64_t nb_bytes();
|
||||||
|
|
|
||||||
|
|
@ -44,15 +44,15 @@ VOID TEST(AppResourceManagerTest, FindByFastID)
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsResourceManager m("test");
|
SrsUniquePtr<SrsResourceManager> m(new SrsResourceManager("test"));
|
||||||
HELPER_EXPECT_SUCCESS(m.start());
|
HELPER_EXPECT_SUCCESS(m->start());
|
||||||
|
|
||||||
m.add_with_fast_id(101, new MockIDResource(1));
|
m->add_with_fast_id(101, new MockIDResource(1));
|
||||||
m.add_with_fast_id(102, new MockIDResource(2));
|
m->add_with_fast_id(102, new MockIDResource(2));
|
||||||
m.add_with_fast_id(103, new MockIDResource(3));
|
m->add_with_fast_id(103, new MockIDResource(3));
|
||||||
EXPECT_EQ(1, ((MockIDResource *)m.find_by_fast_id(101))->id);
|
EXPECT_EQ(1, ((MockIDResource *)m->find_by_fast_id(101))->id);
|
||||||
EXPECT_EQ(2, ((MockIDResource *)m.find_by_fast_id(102))->id);
|
EXPECT_EQ(2, ((MockIDResource *)m->find_by_fast_id(102))->id);
|
||||||
EXPECT_EQ(3, ((MockIDResource *)m.find_by_fast_id(103))->id);
|
EXPECT_EQ(3, ((MockIDResource *)m->find_by_fast_id(103))->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
|
|
@ -248,30 +248,30 @@ VOID TEST(AppCoroutineTest, SetCidOfCoroutine)
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
MockCoroutineHandler ch;
|
MockCoroutineHandler ch;
|
||||||
SrsSTCoroutine sc("test", &ch);
|
SrsUniquePtr<SrsSTCoroutine> sc(new SrsSTCoroutine("test", &ch));
|
||||||
ch.trd = ≻
|
ch.trd = sc.get();
|
||||||
EXPECT_TRUE(sc.cid().empty());
|
EXPECT_TRUE(sc->cid().empty());
|
||||||
|
|
||||||
// Start coroutine, which will create the cid.
|
// Start coroutine, which will create the cid.
|
||||||
HELPER_ASSERT_SUCCESS(sc.start());
|
HELPER_ASSERT_SUCCESS(sc->start());
|
||||||
HELPER_ASSERT_SUCCESS(sc.pull());
|
HELPER_ASSERT_SUCCESS(sc->pull());
|
||||||
|
|
||||||
srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS);
|
srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS);
|
||||||
EXPECT_TRUE(!sc.cid().empty());
|
EXPECT_TRUE(!sc->cid().empty());
|
||||||
EXPECT_TRUE(!ch.cid.empty());
|
EXPECT_TRUE(!ch.cid.empty());
|
||||||
|
|
||||||
// Should be a new cid.
|
// Should be a new cid.
|
||||||
SrsContextId cid = _srs_context->generate_id();
|
SrsContextId cid = _srs_context->generate_id();
|
||||||
EXPECT_TRUE(sc.cid().compare(cid) != 0);
|
EXPECT_TRUE(sc->cid().compare(cid) != 0);
|
||||||
EXPECT_TRUE(ch.cid.compare(cid) != 0);
|
EXPECT_TRUE(ch.cid.compare(cid) != 0);
|
||||||
|
|
||||||
// Set the cid and stop the coroutine.
|
// Set the cid and stop the coroutine.
|
||||||
sc.set_cid(cid);
|
sc->set_cid(cid);
|
||||||
sc.stop();
|
sc->stop();
|
||||||
|
|
||||||
// Now the cid should be the new one.
|
// Now the cid should be the new one.
|
||||||
srs_cond_timedwait(ch.exited, 100 * SRS_UTIME_MILLISECONDS);
|
srs_cond_timedwait(ch.exited, 100 * SRS_UTIME_MILLISECONDS);
|
||||||
EXPECT_TRUE(sc.cid().compare(cid) == 0);
|
EXPECT_TRUE(sc->cid().compare(cid) == 0);
|
||||||
EXPECT_TRUE(ch.cid.compare(cid) == 0);
|
EXPECT_TRUE(ch.cid.compare(cid) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
3182
trunk/src/utest/srs_utest_app5.cpp
Normal file
3182
trunk/src/utest/srs_utest_app5.cpp
Normal file
File diff suppressed because it is too large
Load Diff
33
trunk/src/utest/srs_utest_app5.hpp
Normal file
33
trunk/src/utest/srs_utest_app5.hpp
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013-2025 The SRS Authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SRS_UTEST_APP5_HPP
|
||||||
|
#define SRS_UTEST_APP5_HPP
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <srs_utest_app5.hpp>
|
||||||
|
*/
|
||||||
|
#include <srs_utest.hpp>
|
||||||
|
|
||||||
|
#include <srs_app_rtc_codec.hpp>
|
||||||
|
#include <srs_app_rtc_conn.hpp>
|
||||||
|
#include <srs_app_rtc_source.hpp>
|
||||||
|
#include <srs_kernel_rtc_rtp.hpp>
|
||||||
|
#include <srs_protocol_amf0.hpp>
|
||||||
|
#include <srs_protocol_format.hpp>
|
||||||
|
#include <srs_protocol_rtmp_stack.hpp>
|
||||||
|
#include <srs_utest_app4.hpp>
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class SrsMediaPacket;
|
||||||
|
class SrsRtpPacket;
|
||||||
|
|
||||||
|
// Helper functions for creating test objects
|
||||||
|
SrsRtpPacket *create_test_rtp_packet(uint16_t seq, uint32_t ts, uint32_t ssrc, bool marker = false);
|
||||||
|
SrsRtcTrackDescription *create_test_track_description(std::string type, uint32_t ssrc);
|
||||||
|
SrsCodecPayload *create_test_codec_payload(uint8_t pt, std::string name, int sample);
|
||||||
|
|
||||||
|
#endif
|
||||||
4279
trunk/src/utest/srs_utest_app6.cpp
Normal file
4279
trunk/src/utest/srs_utest_app6.cpp
Normal file
File diff suppressed because it is too large
Load Diff
614
trunk/src/utest/srs_utest_app6.hpp
Normal file
614
trunk/src/utest/srs_utest_app6.hpp
Normal file
|
|
@ -0,0 +1,614 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013-2025 The SRS Authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SRS_UTEST_APP6_HPP
|
||||||
|
#define SRS_UTEST_APP6_HPP
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <srs_utest_app6.hpp>
|
||||||
|
*/
|
||||||
|
#include <srs_utest.hpp>
|
||||||
|
|
||||||
|
#include <srs_app_config.hpp>
|
||||||
|
#include <srs_app_http_hooks.hpp>
|
||||||
|
#include <srs_app_rtc_conn.hpp>
|
||||||
|
#include <srs_app_rtc_dtls.hpp>
|
||||||
|
#include <srs_app_rtc_network.hpp>
|
||||||
|
#include <srs_app_rtc_source.hpp>
|
||||||
|
#include <srs_app_rtmp_source.hpp>
|
||||||
|
#include <srs_app_srt_source.hpp>
|
||||||
|
#include <srs_app_statistic.hpp>
|
||||||
|
#include <srs_protocol_sdp.hpp>
|
||||||
|
#include <srs_utest_app2.hpp>
|
||||||
|
#include <srs_utest_protocol3.hpp>
|
||||||
|
|
||||||
|
// Mock DTLS implementation for testing SrsSecurityTransport
|
||||||
|
class MockDtls : public ISrsDtls
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t initialize_error_;
|
||||||
|
srs_error_t start_active_handshake_error_;
|
||||||
|
srs_error_t on_dtls_error_;
|
||||||
|
srs_error_t get_srtp_key_error_;
|
||||||
|
std::string last_role_;
|
||||||
|
std::string last_version_;
|
||||||
|
std::string recv_key_;
|
||||||
|
std::string send_key_;
|
||||||
|
int initialize_count_;
|
||||||
|
int start_active_handshake_count_;
|
||||||
|
int on_dtls_count_;
|
||||||
|
int get_srtp_key_count_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockDtls();
|
||||||
|
virtual ~MockDtls();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(std::string role, std::string version);
|
||||||
|
virtual srs_error_t start_active_handshake();
|
||||||
|
virtual srs_error_t on_dtls(char *data, int nb_data);
|
||||||
|
virtual srs_error_t get_srtp_key(std::string &recv_key, std::string &send_key);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void reset();
|
||||||
|
void set_initialize_error(srs_error_t err);
|
||||||
|
void set_start_active_handshake_error(srs_error_t err);
|
||||||
|
void set_on_dtls_error(srs_error_t err);
|
||||||
|
void set_get_srtp_key_error(srs_error_t err);
|
||||||
|
void set_srtp_keys(const std::string &recv_key, const std::string &send_key);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock RTC Network for testing SrsSecurityTransport
|
||||||
|
class MockRtcNetwork : public ISrsRtcNetwork
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t on_dtls_handshake_done_error_;
|
||||||
|
srs_error_t on_dtls_alert_error_;
|
||||||
|
srs_error_t protect_rtp_error_;
|
||||||
|
srs_error_t protect_rtcp_error_;
|
||||||
|
srs_error_t write_error_;
|
||||||
|
std::string last_alert_type_;
|
||||||
|
std::string last_alert_desc_;
|
||||||
|
int on_dtls_handshake_done_count_;
|
||||||
|
int on_dtls_alert_count_;
|
||||||
|
int protect_rtp_count_;
|
||||||
|
int protect_rtcp_count_;
|
||||||
|
int write_count_;
|
||||||
|
bool is_established_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcNetwork();
|
||||||
|
virtual ~MockRtcNetwork();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t on_dtls_handshake_done();
|
||||||
|
virtual srs_error_t on_dtls_alert(std::string type, std::string desc);
|
||||||
|
virtual srs_error_t protect_rtp(void *packet, int *nb_cipher);
|
||||||
|
virtual srs_error_t protect_rtcp(void *packet, int *nb_cipher);
|
||||||
|
virtual bool is_establelished();
|
||||||
|
virtual srs_error_t write(void *buf, size_t size, ssize_t *nwrite);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void reset();
|
||||||
|
void set_on_dtls_handshake_done_error(srs_error_t err);
|
||||||
|
void set_on_dtls_alert_error(srs_error_t err);
|
||||||
|
void set_protect_rtp_error(srs_error_t err);
|
||||||
|
void set_protect_rtcp_error(srs_error_t err);
|
||||||
|
void set_write_error(srs_error_t err);
|
||||||
|
void set_established(bool established);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock SRTP implementation for testing SrsSecurityTransport
|
||||||
|
class MockSrtp : public ISrsSRTP
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t initialize_error_;
|
||||||
|
srs_error_t protect_rtp_error_;
|
||||||
|
srs_error_t protect_rtcp_error_;
|
||||||
|
srs_error_t unprotect_rtp_error_;
|
||||||
|
srs_error_t unprotect_rtcp_error_;
|
||||||
|
std::string last_recv_key_;
|
||||||
|
std::string last_send_key_;
|
||||||
|
int initialize_count_;
|
||||||
|
int protect_rtp_count_;
|
||||||
|
int protect_rtcp_count_;
|
||||||
|
int unprotect_rtp_count_;
|
||||||
|
int unprotect_rtcp_count_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockSrtp();
|
||||||
|
virtual ~MockSrtp();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(std::string recv_key, std::string send_key);
|
||||||
|
virtual srs_error_t protect_rtp(void *packet, int *nb_cipher);
|
||||||
|
virtual srs_error_t protect_rtcp(void *packet, int *nb_cipher);
|
||||||
|
virtual srs_error_t unprotect_rtp(void *packet, int *nb_plaintext);
|
||||||
|
virtual srs_error_t unprotect_rtcp(void *packet, int *nb_plaintext);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void reset();
|
||||||
|
void set_initialize_error(srs_error_t err);
|
||||||
|
void set_protect_rtp_error(srs_error_t err);
|
||||||
|
void set_protect_rtcp_error(srs_error_t err);
|
||||||
|
void set_unprotect_rtp_error(srs_error_t err);
|
||||||
|
void set_unprotect_rtcp_error(srs_error_t err);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock PLI Worker Handler for testing SrsRtcPliWorker
|
||||||
|
class MockRtcPliWorkerHandler : public ISrsRtcPliWorkerHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t do_request_keyframe_error_;
|
||||||
|
std::vector<std::pair<uint32_t, SrsContextId> > keyframe_requests_;
|
||||||
|
int do_request_keyframe_count_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcPliWorkerHandler();
|
||||||
|
virtual ~MockRtcPliWorkerHandler();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t do_request_keyframe(uint32_t ssrc, SrsContextId cid);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void reset();
|
||||||
|
void set_do_request_keyframe_error(srs_error_t err);
|
||||||
|
bool has_keyframe_request(uint32_t ssrc, const SrsContextId &cid);
|
||||||
|
int get_keyframe_request_count();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock PLI Worker for testing SrsRtcPlayStream::on_stream_change
|
||||||
|
class MockRtcPliWorker : public SrsRtcPliWorker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<std::pair<uint32_t, SrsContextId> > keyframe_requests_;
|
||||||
|
int request_keyframe_count_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcPliWorker(ISrsRtcPliWorkerHandler *h);
|
||||||
|
virtual ~MockRtcPliWorker();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void request_keyframe(uint32_t ssrc, SrsContextId cid);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void reset();
|
||||||
|
bool has_keyframe_request(uint32_t ssrc, const SrsContextId &cid);
|
||||||
|
int get_keyframe_request_count();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock HTTP hooks for testing SrsRtcAsyncCallOnStop
|
||||||
|
class MockHttpHooks : public ISrsHttpHooks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<std::pair<std::string, ISrsRequest *> > on_stop_calls_;
|
||||||
|
int on_stop_count_;
|
||||||
|
std::vector<std::pair<std::string, ISrsRequest *> > on_unpublish_calls_;
|
||||||
|
int on_unpublish_count_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockHttpHooks();
|
||||||
|
virtual ~MockHttpHooks();
|
||||||
|
virtual srs_error_t on_connect(std::string url, ISrsRequest *req);
|
||||||
|
virtual void on_close(std::string url, ISrsRequest *req, int64_t send_bytes, int64_t recv_bytes);
|
||||||
|
virtual srs_error_t on_publish(std::string url, ISrsRequest *req);
|
||||||
|
virtual void on_unpublish(std::string url, ISrsRequest *req);
|
||||||
|
virtual srs_error_t on_play(std::string url, ISrsRequest *req);
|
||||||
|
virtual void on_stop(std::string url, ISrsRequest *req);
|
||||||
|
virtual srs_error_t on_dvr(SrsContextId cid, std::string url, ISrsRequest *req, std::string file);
|
||||||
|
virtual srs_error_t on_hls(SrsContextId cid, std::string url, ISrsRequest *req, std::string file, std::string ts_url,
|
||||||
|
std::string m3u8, std::string m3u8_url, int sn, srs_utime_t duration);
|
||||||
|
virtual srs_error_t on_hls_notify(SrsContextId cid, std::string url, ISrsRequest *req, std::string ts_url, int nb_notify);
|
||||||
|
virtual srs_error_t discover_co_workers(std::string url, std::string &host, int &port);
|
||||||
|
virtual srs_error_t on_forward_backend(std::string url, ISrsRequest *req, std::vector<std::string> &rtmp_urls);
|
||||||
|
void clear_calls();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock context for testing SrsRtcAsyncCallOnStop
|
||||||
|
class MockContext : public ISrsContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SrsContextId current_id_;
|
||||||
|
SrsContextId get_id_result_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockContext();
|
||||||
|
virtual ~MockContext();
|
||||||
|
virtual SrsContextId generate_id();
|
||||||
|
virtual const SrsContextId &get_id();
|
||||||
|
virtual const SrsContextId &set_id(const SrsContextId &v);
|
||||||
|
void set_current_id(const SrsContextId &id);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock app config for testing SrsRtcAsyncCallOnStop
|
||||||
|
class MockAppConfig : public ISrsAppConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool http_hooks_enabled_;
|
||||||
|
SrsConfDirective *on_stop_directive_;
|
||||||
|
SrsConfDirective *on_unpublish_directive_;
|
||||||
|
bool rtc_nack_enabled_;
|
||||||
|
bool rtc_nack_no_copy_;
|
||||||
|
int rtc_drop_for_pt_;
|
||||||
|
bool rtc_twcc_enabled_;
|
||||||
|
bool srt_enabled_;
|
||||||
|
bool rtc_to_rtmp_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockAppConfig();
|
||||||
|
virtual ~MockAppConfig();
|
||||||
|
// ISrsConfig methods
|
||||||
|
virtual srs_utime_t get_pithy_print();
|
||||||
|
virtual std::string get_default_app_name();
|
||||||
|
// ISrsAppConfig methods
|
||||||
|
virtual bool get_vhost_http_hooks_enabled(std::string vhost);
|
||||||
|
virtual SrsConfDirective *get_vhost_on_stop(std::string vhost);
|
||||||
|
virtual SrsConfDirective *get_vhost_on_unpublish(std::string vhost);
|
||||||
|
virtual bool get_rtc_nack_enabled(std::string vhost);
|
||||||
|
virtual bool get_rtc_nack_no_copy(std::string vhost);
|
||||||
|
virtual bool get_realtime_enabled(std::string vhost, bool is_rtc);
|
||||||
|
virtual int get_mw_msgs(std::string vhost, bool is_realtime, bool is_rtc);
|
||||||
|
virtual int get_rtc_drop_for_pt(std::string vhost);
|
||||||
|
virtual bool get_rtc_twcc_enabled(std::string vhost);
|
||||||
|
virtual bool get_srt_enabled();
|
||||||
|
virtual bool get_srt_enabled(std::string vhost);
|
||||||
|
virtual bool get_rtc_to_rtmp(std::string vhost);
|
||||||
|
void set_http_hooks_enabled(bool enabled);
|
||||||
|
void set_on_stop_urls(const std::vector<std::string> &urls);
|
||||||
|
void clear_on_stop_directive();
|
||||||
|
void set_on_unpublish_urls(const std::vector<std::string> &urls);
|
||||||
|
void clear_on_unpublish_directive();
|
||||||
|
void set_rtc_nack_enabled(bool enabled);
|
||||||
|
void set_rtc_nack_no_copy(bool no_copy);
|
||||||
|
void set_rtc_drop_for_pt(int pt);
|
||||||
|
void set_rtc_twcc_enabled(bool enabled);
|
||||||
|
void set_srt_enabled(bool enabled);
|
||||||
|
void set_rtc_to_rtmp(bool enabled);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock request for testing SrsRtcAsyncCallOnStop
|
||||||
|
class MockRtcAsyncCallRequest : public ISrsRequest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string vhost_;
|
||||||
|
std::string app_;
|
||||||
|
std::string stream_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcAsyncCallRequest(std::string vhost = "__defaultVhost__", std::string app = "live", std::string stream = "test");
|
||||||
|
virtual ~MockRtcAsyncCallRequest();
|
||||||
|
virtual ISrsRequest *copy();
|
||||||
|
virtual std::string get_stream_url();
|
||||||
|
virtual void update_auth(ISrsRequest *req);
|
||||||
|
virtual void strip();
|
||||||
|
virtual ISrsRequest *as_http();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock RTC source manager for testing SrsRtcPlayStream
|
||||||
|
class MockRtcSourceManager : public ISrsRtcSourceManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t initialize_error_;
|
||||||
|
srs_error_t fetch_or_create_error_;
|
||||||
|
int initialize_count_;
|
||||||
|
int fetch_or_create_count_;
|
||||||
|
SrsSharedPtr<SrsRtcSource> mock_source_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcSourceManager();
|
||||||
|
virtual ~MockRtcSourceManager();
|
||||||
|
virtual srs_error_t initialize();
|
||||||
|
virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr<SrsRtcSource> &pps);
|
||||||
|
virtual SrsSharedPtr<SrsRtcSource> fetch(ISrsRequest *r);
|
||||||
|
void set_initialize_error(srs_error_t err);
|
||||||
|
void set_fetch_or_create_error(srs_error_t err);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock statistic for testing SrsRtcPlayStream
|
||||||
|
class MockRtcStatistic : public ISrsStatistic
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t on_client_error_;
|
||||||
|
int on_client_count_;
|
||||||
|
int on_disconnect_count_;
|
||||||
|
std::string last_client_id_;
|
||||||
|
ISrsRequest *last_client_req_;
|
||||||
|
ISrsExpire *last_client_conn_;
|
||||||
|
SrsRtmpConnType last_client_type_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcStatistic();
|
||||||
|
virtual ~MockRtcStatistic();
|
||||||
|
virtual void on_disconnect(std::string id, srs_error_t err);
|
||||||
|
virtual srs_error_t on_client(std::string id, ISrsRequest *req, ISrsExpire *conn, SrsRtmpConnType type);
|
||||||
|
void set_on_client_error(srs_error_t err);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock RTC async task executor for testing SrsRtcPlayStream::send_packet
|
||||||
|
class MockRtcAsyncTaskExecutor : public ISrsExecRtcAsyncTask
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t exec_error_;
|
||||||
|
int exec_count_;
|
||||||
|
ISrsAsyncCallTask *last_task_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcAsyncTaskExecutor();
|
||||||
|
virtual ~MockRtcAsyncTaskExecutor();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t exec_rtc_async_work(ISrsAsyncCallTask *t);
|
||||||
|
void set_exec_error(srs_error_t err);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock RTC packet sender for testing SrsRtcPlayStream::send_packet
|
||||||
|
class MockRtcPacketSender : public ISrsRtcPacketSender
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t send_packet_error_;
|
||||||
|
int send_packet_count_;
|
||||||
|
SrsRtpPacket *last_sent_packet_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcPacketSender();
|
||||||
|
virtual ~MockRtcPacketSender();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t do_send_packet(SrsRtpPacket *pkt);
|
||||||
|
void set_send_packet_error(srs_error_t err);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock RTC send track for testing SrsRtcPlayStream::send_packet
|
||||||
|
class MockRtcSendTrack : public SrsRtcSendTrack
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t on_rtp_error_;
|
||||||
|
srs_error_t on_nack_error_;
|
||||||
|
int on_rtp_count_;
|
||||||
|
int on_nack_count_;
|
||||||
|
SrsRtpPacket *last_rtp_packet_;
|
||||||
|
SrsRtpPacket **last_nack_packet_;
|
||||||
|
bool nack_set_to_null_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcSendTrack(ISrsRtcPacketSender *sender, SrsRtcTrackDescription *track_desc, bool is_audio);
|
||||||
|
virtual ~MockRtcSendTrack();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t on_rtp(SrsRtpPacket *pkt);
|
||||||
|
virtual srs_error_t on_rtcp(SrsRtpPacket *pkt);
|
||||||
|
virtual srs_error_t on_nack(SrsRtpPacket **ppkt);
|
||||||
|
void set_on_rtp_error(srs_error_t err);
|
||||||
|
void set_on_nack_error(srs_error_t err);
|
||||||
|
void set_nack_set_to_null(bool v);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock RTCP classes for testing SrsRtcPlayStream::on_rtcp
|
||||||
|
class MockRtcpCommon : public SrsRtcpCommon
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint8_t mock_type_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcpCommon(uint8_t type);
|
||||||
|
virtual ~MockRtcpCommon();
|
||||||
|
virtual uint8_t type() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockRtcpRR : public SrsRtcpRR
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MockRtcpRR(uint32_t sender_ssrc = 0);
|
||||||
|
virtual ~MockRtcpRR();
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockRtcpNack : public SrsRtcpNack
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MockRtcpNack(uint32_t sender_ssrc = 0);
|
||||||
|
virtual ~MockRtcpNack();
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockRtcpFbCommon : public SrsRtcpFbCommon
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint8_t mock_rc_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcpFbCommon(uint8_t rc = kPLI);
|
||||||
|
virtual ~MockRtcpFbCommon();
|
||||||
|
virtual uint8_t get_rc() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockRtcpXr : public SrsRtcpXr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MockRtcpXr(uint32_t ssrc = 0);
|
||||||
|
virtual ~MockRtcpXr();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock RTC send track with NACK response capability for testing on_rtcp_nack
|
||||||
|
class MockRtcSendTrackForNack : public SrsRtcSendTrack
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t on_recv_nack_error_;
|
||||||
|
int on_recv_nack_count_;
|
||||||
|
std::vector<uint16_t> last_lost_seqs_;
|
||||||
|
uint32_t test_ssrc_;
|
||||||
|
bool track_enabled_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcSendTrackForNack(ISrsRtcPacketSender *sender, SrsRtcTrackDescription *track_desc, bool is_audio, uint32_t ssrc);
|
||||||
|
virtual ~MockRtcSendTrackForNack();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t on_rtp(SrsRtpPacket *pkt);
|
||||||
|
virtual srs_error_t on_rtcp(SrsRtpPacket *pkt);
|
||||||
|
virtual srs_error_t on_recv_nack(const std::vector<uint16_t> &lost_seqs);
|
||||||
|
virtual bool has_ssrc(uint32_t ssrc);
|
||||||
|
virtual bool get_track_status();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_track_enabled(bool enabled);
|
||||||
|
void set_on_recv_nack_error(srs_error_t err);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock RTCP sender for testing SrsRtcPublishRtcpTimer
|
||||||
|
class MockRtcRtcpSender : public ISrsRtcRtcpSender
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool is_sender_started_;
|
||||||
|
bool is_sender_twcc_enabled_;
|
||||||
|
srs_error_t send_rtcp_rr_error_;
|
||||||
|
srs_error_t send_rtcp_xr_rrtr_error_;
|
||||||
|
srs_error_t send_periodic_twcc_error_;
|
||||||
|
int send_rtcp_rr_count_;
|
||||||
|
int send_rtcp_xr_rrtr_count_;
|
||||||
|
int send_periodic_twcc_count_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcRtcpSender();
|
||||||
|
virtual ~MockRtcRtcpSender();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool is_sender_started();
|
||||||
|
virtual srs_error_t send_rtcp_rr();
|
||||||
|
virtual srs_error_t send_rtcp_xr_rrtr();
|
||||||
|
virtual bool is_sender_twcc_enabled();
|
||||||
|
virtual srs_error_t send_periodic_twcc();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_sender_started(bool started);
|
||||||
|
void set_sender_twcc_enabled(bool enabled);
|
||||||
|
void set_send_rtcp_rr_error(srs_error_t err);
|
||||||
|
void set_send_rtcp_xr_rrtr_error(srs_error_t err);
|
||||||
|
void set_send_periodic_twcc_error(srs_error_t err);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock RTC packet receiver for testing SrsRtcPublishStream
|
||||||
|
class MockRtcPacketReceiver : public ISrsRtcPacketReceiver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t send_rtcp_rr_error_;
|
||||||
|
srs_error_t send_rtcp_xr_rrtr_error_;
|
||||||
|
srs_error_t send_rtcp_error_;
|
||||||
|
srs_error_t send_rtcp_fb_pli_error_;
|
||||||
|
int send_rtcp_rr_count_;
|
||||||
|
int send_rtcp_xr_rrtr_count_;
|
||||||
|
int send_rtcp_count_;
|
||||||
|
int send_rtcp_fb_pli_count_;
|
||||||
|
int check_send_nacks_count_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcPacketReceiver();
|
||||||
|
virtual ~MockRtcPacketReceiver();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t send_rtcp_rr(uint32_t ssrc, SrsRtpRingBuffer *rtp_queue, const uint64_t &last_send_systime, const SrsNtp &last_send_ntp);
|
||||||
|
virtual srs_error_t send_rtcp_xr_rrtr(uint32_t ssrc);
|
||||||
|
virtual void check_send_nacks(SrsRtpNackForReceiver *nack, uint32_t ssrc, uint32_t &sent_nacks, uint32_t &timeout_nacks);
|
||||||
|
virtual srs_error_t send_rtcp(char *data, int nb_data);
|
||||||
|
virtual srs_error_t send_rtcp_fb_pli(uint32_t ssrc, const SrsContextId &cid_of_subscriber);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_send_rtcp_rr_error(srs_error_t err);
|
||||||
|
void set_send_rtcp_xr_rrtr_error(srs_error_t err);
|
||||||
|
void set_send_rtcp_error(srs_error_t err);
|
||||||
|
void set_send_rtcp_fb_pli_error(srs_error_t err);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock expire for testing SrsRtcPublishStream
|
||||||
|
class MockRtcExpire : public ISrsExpire
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool expired_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcExpire();
|
||||||
|
virtual ~MockRtcExpire();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void expire();
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock live source manager for testing SrsRtcPublishStream
|
||||||
|
class MockLiveSourceManager : public ISrsLiveSourceManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t fetch_or_create_error_;
|
||||||
|
int fetch_or_create_count_;
|
||||||
|
SrsSharedPtr<SrsLiveSource> mock_source_;
|
||||||
|
bool can_publish_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockLiveSourceManager();
|
||||||
|
virtual ~MockLiveSourceManager();
|
||||||
|
virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr<SrsLiveSource> &pps);
|
||||||
|
virtual SrsSharedPtr<SrsLiveSource> fetch(ISrsRequest *r);
|
||||||
|
void set_fetch_or_create_error(srs_error_t err);
|
||||||
|
void set_can_publish(bool can_publish);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock live source for testing SrsRtcPublishStream
|
||||||
|
class MockLiveSource : public SrsLiveSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool can_publish_result_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockLiveSource();
|
||||||
|
virtual ~MockLiveSource();
|
||||||
|
virtual bool can_publish(bool is_edge);
|
||||||
|
void set_can_publish(bool can_publish);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock SRT source for testing SrsRtcPublishStream
|
||||||
|
class MockSrtSource : public SrsSrtSource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool can_publish_result_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockSrtSource();
|
||||||
|
virtual ~MockSrtSource();
|
||||||
|
virtual bool can_publish();
|
||||||
|
void set_can_publish(bool can_publish);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock SRT source manager for testing SrsRtcPublishStream
|
||||||
|
class MockSrtSourceManager : public ISrsSrtSourceManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t initialize_error_;
|
||||||
|
srs_error_t fetch_or_create_error_;
|
||||||
|
int initialize_count_;
|
||||||
|
int fetch_or_create_count_;
|
||||||
|
SrsSharedPtr<SrsSrtSource> mock_source_;
|
||||||
|
bool can_publish_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockSrtSourceManager();
|
||||||
|
virtual ~MockSrtSourceManager();
|
||||||
|
virtual srs_error_t initialize();
|
||||||
|
virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr<SrsSrtSource> &pps);
|
||||||
|
virtual SrsSharedPtr<SrsSrtSource> fetch(ISrsRequest *r);
|
||||||
|
void set_initialize_error(srs_error_t err);
|
||||||
|
void set_fetch_or_create_error(srs_error_t err);
|
||||||
|
void set_can_publish(bool can_publish);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
533
trunk/src/utest/srs_utest_app7.cpp
Normal file
533
trunk/src/utest/srs_utest_app7.cpp
Normal file
|
|
@ -0,0 +1,533 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013-2025 The SRS Authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
#include <srs_utest_app7.hpp>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#include <srs_app_rtc_conn.hpp>
|
||||||
|
#include <srs_kernel_error.hpp>
|
||||||
|
#include <srs_kernel_rtc_rtp.hpp>
|
||||||
|
#include <srs_utest_app5.hpp>
|
||||||
|
#include <srs_utest_app6.hpp>
|
||||||
|
|
||||||
|
// Mock video recv track implementation
|
||||||
|
MockRtcVideoRecvTrackForNack::MockRtcVideoRecvTrackForNack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc)
|
||||||
|
: SrsRtcVideoRecvTrack(receiver, track_desc)
|
||||||
|
{
|
||||||
|
check_send_nacks_error_ = srs_success;
|
||||||
|
check_send_nacks_count_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MockRtcVideoRecvTrackForNack::~MockRtcVideoRecvTrackForNack()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t MockRtcVideoRecvTrackForNack::check_send_nacks()
|
||||||
|
{
|
||||||
|
check_send_nacks_count_++;
|
||||||
|
return check_send_nacks_error_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MockRtcVideoRecvTrackForNack::set_check_send_nacks_error(srs_error_t err)
|
||||||
|
{
|
||||||
|
check_send_nacks_error_ = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MockRtcVideoRecvTrackForNack::reset()
|
||||||
|
{
|
||||||
|
check_send_nacks_error_ = srs_success;
|
||||||
|
check_send_nacks_count_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock audio recv track implementation
|
||||||
|
MockRtcAudioRecvTrackForNack::MockRtcAudioRecvTrackForNack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc)
|
||||||
|
: SrsRtcAudioRecvTrack(receiver, track_desc)
|
||||||
|
{
|
||||||
|
check_send_nacks_error_ = srs_success;
|
||||||
|
check_send_nacks_count_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MockRtcAudioRecvTrackForNack::~MockRtcAudioRecvTrackForNack()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t MockRtcAudioRecvTrackForNack::check_send_nacks()
|
||||||
|
{
|
||||||
|
check_send_nacks_count_++;
|
||||||
|
return check_send_nacks_error_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MockRtcAudioRecvTrackForNack::set_check_send_nacks_error(srs_error_t err)
|
||||||
|
{
|
||||||
|
check_send_nacks_error_ = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MockRtcAudioRecvTrackForNack::reset()
|
||||||
|
{
|
||||||
|
check_send_nacks_error_ = srs_success;
|
||||||
|
check_send_nacks_count_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TEST(SrsRtcPublishStreamTest, OnRtpCipherTypicalScenario)
|
||||||
|
{
|
||||||
|
srs_error_t err;
|
||||||
|
|
||||||
|
// Create mock objects
|
||||||
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
|
MockRtcExpire mock_expire;
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
SrsContextId cid;
|
||||||
|
cid.set_value("test-rtp-cipher-stream-id");
|
||||||
|
|
||||||
|
// Create SrsRtcPublishStream with mock dependencies
|
||||||
|
SrsUniquePtr<SrsRtcPublishStream> publish_stream(new SrsRtcPublishStream(&mock_exec, &mock_expire, &mock_receiver, cid));
|
||||||
|
|
||||||
|
// Test typical RTP packet processing scenario
|
||||||
|
// Create a simple RTP packet without extension (minimal valid packet)
|
||||||
|
unsigned char simple_rtp_data[] = {
|
||||||
|
// RTP header (12 bytes) - no extension
|
||||||
|
0x80, 0x60, 0x12, 0x34, // V=2, P=0, X=0, CC=0, M=0, PT=96, seq=0x1234
|
||||||
|
0x56, 0x78, 0x9A, 0xBC, // timestamp
|
||||||
|
0xDE, 0xF0, 0x12, 0x34 // SSRC
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test normal RTP packet processing (default state: no NACK simulation, no TWCC, no PT drop)
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->on_rtp_cipher((char *)simple_rtp_data, sizeof(simple_rtp_data)));
|
||||||
|
|
||||||
|
// Test with NACK simulation enabled
|
||||||
|
publish_stream->simulate_nack_drop(1); // Simulate dropping 1 packet
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->on_rtp_cipher((char *)simple_rtp_data, sizeof(simple_rtp_data)));
|
||||||
|
|
||||||
|
// Test with a different RTP packet after NACK simulation is consumed
|
||||||
|
unsigned char rtp_data2[] = {
|
||||||
|
// RTP header (12 bytes) - different sequence number
|
||||||
|
0x80, 0x60, 0x12, 0x35, // V=2, P=0, X=0, CC=0, M=0, PT=96, seq=0x1235
|
||||||
|
0x56, 0x78, 0x9A, 0xBD, // timestamp
|
||||||
|
0xDE, 0xF0, 0x12, 0x35 // SSRC
|
||||||
|
};
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->on_rtp_cipher((char *)rtp_data2, sizeof(rtp_data2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TEST(SrsRtcPublishStreamTest, OnRtpPlaintextTypicalScenario)
|
||||||
|
{
|
||||||
|
srs_error_t err;
|
||||||
|
|
||||||
|
// Create mock objects
|
||||||
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
|
MockRtcExpire mock_expire;
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
SrsContextId cid;
|
||||||
|
cid.set_value("test-rtp-plaintext-stream-id");
|
||||||
|
|
||||||
|
// Create SrsRtcPublishStream with mock dependencies
|
||||||
|
SrsUniquePtr<SrsRtcPublishStream> publish_stream(new SrsRtcPublishStream(&mock_exec, &mock_expire, &mock_receiver, cid));
|
||||||
|
|
||||||
|
// Create video track with matching SSRC for the RTP packet
|
||||||
|
SrsRtcTrackDescription video_desc;
|
||||||
|
video_desc.type_ = "video";
|
||||||
|
video_desc.id_ = "video_track_test";
|
||||||
|
video_desc.ssrc_ = 0xDEF01234; // SSRC from RTP packet (0xDE, 0xF0, 0x12, 0x34)
|
||||||
|
video_desc.is_active_ = true;
|
||||||
|
SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, &video_desc);
|
||||||
|
publish_stream->video_tracks_.push_back(video_track);
|
||||||
|
|
||||||
|
// Enable tracks for processing
|
||||||
|
publish_stream->set_all_tracks_status(true);
|
||||||
|
|
||||||
|
// Test typical RTP plaintext packet processing scenario
|
||||||
|
// Create a simple RTP packet without extension (minimal valid packet)
|
||||||
|
unsigned char simple_rtp_data[] = {
|
||||||
|
// RTP header (12 bytes) - no extension
|
||||||
|
0x80, 0x60, 0x12, 0x34, // V=2, P=0, X=0, CC=0, M=0, PT=96, seq=0x1234
|
||||||
|
0x56, 0x78, 0x9A, 0xBC, // timestamp
|
||||||
|
0xDE, 0xF0, 0x12, 0x34 // SSRC = 0xDEF01234
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test normal RTP plaintext packet processing
|
||||||
|
// This tests the complete flow: packet wrapping, buffer creation, do_on_rtp_plaintext call, and cleanup
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->on_rtp_plaintext((char *)simple_rtp_data, sizeof(simple_rtp_data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TEST(SrsRtcPublishStreamTest, CheckSendNacksTypicalScenario)
|
||||||
|
{
|
||||||
|
srs_error_t err;
|
||||||
|
|
||||||
|
// Create mock objects
|
||||||
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
|
MockRtcExpire mock_expire;
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
SrsContextId cid;
|
||||||
|
cid.set_value("test-check-send-nacks-stream-id");
|
||||||
|
|
||||||
|
// Create SrsRtcPublishStream with mock dependencies
|
||||||
|
SrsUniquePtr<SrsRtcPublishStream> publish_stream(new SrsRtcPublishStream(&mock_exec, &mock_expire, &mock_receiver, cid));
|
||||||
|
|
||||||
|
// Test scenario 1: NACK disabled - should return success immediately
|
||||||
|
publish_stream->nack_enabled_ = false;
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->check_send_nacks());
|
||||||
|
|
||||||
|
// Test scenario 2: NACK enabled with video and audio tracks
|
||||||
|
publish_stream->nack_enabled_ = true;
|
||||||
|
|
||||||
|
// Create mock video track
|
||||||
|
SrsRtcTrackDescription video_desc;
|
||||||
|
video_desc.type_ = "video";
|
||||||
|
video_desc.id_ = "video_track_nack_test";
|
||||||
|
video_desc.ssrc_ = 0x12345678;
|
||||||
|
video_desc.is_active_ = true;
|
||||||
|
MockRtcVideoRecvTrackForNack *video_track = new MockRtcVideoRecvTrackForNack(&mock_receiver, &video_desc);
|
||||||
|
publish_stream->video_tracks_.push_back(video_track);
|
||||||
|
|
||||||
|
// Create mock audio track
|
||||||
|
SrsRtcTrackDescription audio_desc;
|
||||||
|
audio_desc.type_ = "audio";
|
||||||
|
audio_desc.id_ = "audio_track_nack_test";
|
||||||
|
audio_desc.ssrc_ = 0x87654321;
|
||||||
|
audio_desc.is_active_ = true;
|
||||||
|
MockRtcAudioRecvTrackForNack *audio_track = new MockRtcAudioRecvTrackForNack(&mock_receiver, &audio_desc);
|
||||||
|
publish_stream->audio_tracks_.push_back(audio_track);
|
||||||
|
|
||||||
|
// Test successful NACK check for both tracks
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->check_send_nacks());
|
||||||
|
|
||||||
|
// Test video track error propagation
|
||||||
|
video_track->set_check_send_nacks_error(srs_error_new(ERROR_RTC_RTP_MUXER, "mock video track error"));
|
||||||
|
HELPER_EXPECT_FAILED(publish_stream->check_send_nacks());
|
||||||
|
video_track->reset(); // Reset to success
|
||||||
|
|
||||||
|
// Test audio track error propagation
|
||||||
|
audio_track->set_check_send_nacks_error(srs_error_new(ERROR_RTC_RTP_MUXER, "mock audio track error"));
|
||||||
|
HELPER_EXPECT_FAILED(publish_stream->check_send_nacks());
|
||||||
|
audio_track->reset(); // Reset to success
|
||||||
|
|
||||||
|
// Final test: both tracks successful again
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->check_send_nacks());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to create video track description with codec
|
||||||
|
SrsRtcTrackDescription *create_video_track_description_with_codec(std::string codec_name, uint32_t ssrc)
|
||||||
|
{
|
||||||
|
SrsRtcTrackDescription *desc = new SrsRtcTrackDescription();
|
||||||
|
desc->type_ = "video";
|
||||||
|
desc->ssrc_ = ssrc;
|
||||||
|
desc->id_ = "test-video-track";
|
||||||
|
desc->is_active_ = true;
|
||||||
|
desc->direction_ = "sendrecv";
|
||||||
|
desc->mid_ = "0";
|
||||||
|
|
||||||
|
// Create video payload with specified codec
|
||||||
|
SrsVideoPayload *video_payload = new SrsVideoPayload(96, codec_name, 90000);
|
||||||
|
desc->set_codec_payload(video_payload);
|
||||||
|
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TEST(SrsRtcPublishStreamTest, OnBeforeDecodePayloadTypicalScenario)
|
||||||
|
{
|
||||||
|
// Create mock objects
|
||||||
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
|
MockRtcExpire mock_expire;
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
SrsContextId cid;
|
||||||
|
cid.set_value("test-on-before-decode-payload-stream-id");
|
||||||
|
|
||||||
|
// Create SrsRtcPublishStream with mock dependencies
|
||||||
|
SrsUniquePtr<SrsRtcPublishStream> publish_stream(new SrsRtcPublishStream(&mock_exec, &mock_expire, &mock_receiver, cid));
|
||||||
|
|
||||||
|
// Create video track with proper codec payload
|
||||||
|
SrsUniquePtr<SrsRtcTrackDescription> video_desc(create_video_track_description_with_codec("H264", 0x12345678));
|
||||||
|
SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, video_desc.get());
|
||||||
|
publish_stream->video_tracks_.push_back(video_track);
|
||||||
|
|
||||||
|
// Create audio track with proper codec payload
|
||||||
|
SrsUniquePtr<SrsRtcTrackDescription> audio_desc(create_test_track_description("audio", 0x87654321));
|
||||||
|
SrsRtcAudioRecvTrack *audio_track = new SrsRtcAudioRecvTrack(&mock_receiver, audio_desc.get());
|
||||||
|
publish_stream->audio_tracks_.push_back(audio_track);
|
||||||
|
|
||||||
|
// Test scenario 1: Empty buffer - should return early without processing
|
||||||
|
SrsUniquePtr<SrsRtpPacket> pkt1(new SrsRtpPacket());
|
||||||
|
pkt1->header_.set_ssrc(0x12345678); // Video track SSRC
|
||||||
|
char empty_buffer_data[1024];
|
||||||
|
SrsBuffer empty_buffer(empty_buffer_data, 0); // Empty buffer
|
||||||
|
ISrsRtpPayloader *payload1 = NULL;
|
||||||
|
SrsRtpPacketPayloadType ppt1 = SrsRtpPacketPayloadTypeUnknown;
|
||||||
|
|
||||||
|
// Call on_before_decode_payload with empty buffer - should return without setting payload
|
||||||
|
publish_stream->on_before_decode_payload(pkt1.get(), &empty_buffer, &payload1, &ppt1);
|
||||||
|
EXPECT_TRUE(payload1 == NULL); // Should remain NULL for empty buffer
|
||||||
|
EXPECT_EQ(SrsRtpPacketPayloadTypeUnknown, ppt1); // Should remain unknown
|
||||||
|
|
||||||
|
// Test scenario 2: Video track processing with non-empty buffer
|
||||||
|
SrsUniquePtr<SrsRtpPacket> pkt2(new SrsRtpPacket());
|
||||||
|
pkt2->header_.set_ssrc(0x12345678); // Video track SSRC
|
||||||
|
char video_buffer_data[1024];
|
||||||
|
memset(video_buffer_data, 0x42, 100); // Fill with test data
|
||||||
|
SrsBuffer video_buffer(video_buffer_data, 100); // Non-empty buffer
|
||||||
|
ISrsRtpPayloader *payload2 = NULL;
|
||||||
|
SrsRtpPacketPayloadType ppt2 = SrsRtpPacketPayloadTypeUnknown;
|
||||||
|
|
||||||
|
// Call on_before_decode_payload for video track - should delegate to video track
|
||||||
|
publish_stream->on_before_decode_payload(pkt2.get(), &video_buffer, &payload2, &ppt2);
|
||||||
|
// Video track should have processed the payload (implementation details depend on video track logic)
|
||||||
|
|
||||||
|
// Test scenario 3: Audio track processing with non-empty buffer
|
||||||
|
SrsUniquePtr<SrsRtpPacket> pkt3(new SrsRtpPacket());
|
||||||
|
pkt3->header_.set_ssrc(0x87654321); // Audio track SSRC
|
||||||
|
char audio_buffer_data[1024];
|
||||||
|
memset(audio_buffer_data, 0x55, 80); // Fill with test data
|
||||||
|
SrsBuffer audio_buffer(audio_buffer_data, 80); // Non-empty buffer
|
||||||
|
ISrsRtpPayloader *payload3 = NULL;
|
||||||
|
SrsRtpPacketPayloadType ppt3 = SrsRtpPacketPayloadTypeUnknown;
|
||||||
|
|
||||||
|
// Call on_before_decode_payload for audio track - should delegate to audio track
|
||||||
|
publish_stream->on_before_decode_payload(pkt3.get(), &audio_buffer, &payload3, &ppt3);
|
||||||
|
// Audio track should have processed the payload and set it to raw payload
|
||||||
|
EXPECT_TRUE(payload3 != NULL); // Audio track should create raw payload
|
||||||
|
EXPECT_EQ(SrsRtpPacketPayloadTypeRaw, ppt3); // Audio track should set raw payload type
|
||||||
|
|
||||||
|
// Test scenario 4: Unknown SSRC - should not match any track
|
||||||
|
SrsUniquePtr<SrsRtpPacket> pkt4(new SrsRtpPacket());
|
||||||
|
pkt4->header_.set_ssrc(0x99999999); // Unknown SSRC
|
||||||
|
char unknown_buffer_data[1024];
|
||||||
|
memset(unknown_buffer_data, 0x77, 50); // Fill with test data
|
||||||
|
SrsBuffer unknown_buffer(unknown_buffer_data, 50); // Non-empty buffer
|
||||||
|
ISrsRtpPayloader *payload4 = NULL;
|
||||||
|
SrsRtpPacketPayloadType ppt4 = SrsRtpPacketPayloadTypeUnknown;
|
||||||
|
|
||||||
|
// Call on_before_decode_payload for unknown SSRC - should not process
|
||||||
|
publish_stream->on_before_decode_payload(pkt4.get(), &unknown_buffer, &payload4, &ppt4);
|
||||||
|
EXPECT_TRUE(payload4 == NULL); // Should remain NULL for unknown SSRC
|
||||||
|
EXPECT_EQ(SrsRtpPacketPayloadTypeUnknown, ppt4); // Should remain unknown
|
||||||
|
|
||||||
|
// Clean up payload created by audio track
|
||||||
|
if (payload3) {
|
||||||
|
srs_freep(payload3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TEST(SrsRtcPublishStreamTest, SendPeriodicTwccTypicalScenario)
|
||||||
|
{
|
||||||
|
srs_error_t err;
|
||||||
|
|
||||||
|
// Create mock objects
|
||||||
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
|
MockRtcExpire mock_expire;
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
SrsContextId cid;
|
||||||
|
cid.set_value("test-send-periodic-twcc-stream-id");
|
||||||
|
|
||||||
|
// Create SrsRtcPublishStream with mock dependencies
|
||||||
|
SrsUniquePtr<SrsRtcPublishStream> publish_stream(new SrsRtcPublishStream(&mock_exec, &mock_expire, &mock_receiver, cid));
|
||||||
|
|
||||||
|
// Test scenario 1: No TWCC feedback needed - should return success immediately
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->send_periodic_twcc());
|
||||||
|
|
||||||
|
// Test scenario 2: Add some TWCC packets to trigger feedback
|
||||||
|
// First, add some packets to the TWCC receiver to make need_feedback() return true
|
||||||
|
uint16_t test_sn1 = 1000;
|
||||||
|
uint16_t test_sn2 = 1001;
|
||||||
|
uint16_t test_sn3 = 1002;
|
||||||
|
|
||||||
|
// Add packets to TWCC - this will make need_feedback() return true
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->on_twcc(test_sn1));
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->on_twcc(test_sn2));
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->on_twcc(test_sn3));
|
||||||
|
|
||||||
|
// Now send_periodic_twcc should process the feedback and send RTCP packets
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->send_periodic_twcc());
|
||||||
|
|
||||||
|
// Verify that RTCP packets were sent through the mock receiver
|
||||||
|
EXPECT_TRUE(mock_receiver.send_rtcp_count_ > 0);
|
||||||
|
|
||||||
|
// Test scenario 3: Test with receiver send_rtcp error
|
||||||
|
mock_receiver.set_send_rtcp_error(srs_error_new(ERROR_RTC_RTP_MUXER, "mock send rtcp error"));
|
||||||
|
|
||||||
|
// Add more packets to trigger feedback again
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->on_twcc(1003));
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->on_twcc(1004));
|
||||||
|
|
||||||
|
// send_periodic_twcc should fail due to receiver error
|
||||||
|
HELPER_EXPECT_FAILED(publish_stream->send_periodic_twcc());
|
||||||
|
|
||||||
|
// Reset receiver error for cleanup
|
||||||
|
mock_receiver.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TEST(SrsRtcPublishStreamTest, OnRtcpTypicalScenario)
|
||||||
|
{
|
||||||
|
srs_error_t err;
|
||||||
|
|
||||||
|
// Create mock objects
|
||||||
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
|
MockRtcExpire mock_expire;
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
SrsContextId cid;
|
||||||
|
cid.set_value("test-on-rtcp-stream-id");
|
||||||
|
|
||||||
|
// Create SrsRtcPublishStream with mock dependencies
|
||||||
|
SrsUniquePtr<SrsRtcPublishStream> publish_stream(new SrsRtcPublishStream(&mock_exec, &mock_expire, &mock_receiver, cid));
|
||||||
|
|
||||||
|
// Test scenario 1: RTCP SR (Sender Report) - should call on_rtcp_sr
|
||||||
|
SrsUniquePtr<SrsRtcpSR> sr(new SrsRtcpSR());
|
||||||
|
sr->set_ssrc(0x12345678);
|
||||||
|
sr->set_ntp(0x123456789ABCDEF0ULL);
|
||||||
|
sr->set_rtp_ts(1000);
|
||||||
|
sr->set_rtp_send_packets(100);
|
||||||
|
sr->set_rtp_send_bytes(50000);
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->on_rtcp(sr.get()));
|
||||||
|
|
||||||
|
// Test scenario 2: RTCP SDES - should be ignored and return success
|
||||||
|
SrsUniquePtr<SrsRtcpCommon> sdes(new SrsRtcpCommon());
|
||||||
|
sdes->header_.type = SrsRtcpType_sdes;
|
||||||
|
sdes->set_ssrc(0xAABBCCDD);
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->on_rtcp(sdes.get()));
|
||||||
|
|
||||||
|
// Test scenario 3: RTCP BYE - should be ignored and return success
|
||||||
|
SrsUniquePtr<SrsRtcpCommon> bye(new SrsRtcpCommon());
|
||||||
|
bye->header_.type = SrsRtcpType_bye;
|
||||||
|
bye->set_ssrc(0xEEFF0011);
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->on_rtcp(bye.get()));
|
||||||
|
|
||||||
|
// Test scenario 4: Unknown RTCP type - should return error
|
||||||
|
SrsUniquePtr<SrsRtcpCommon> unknown(new SrsRtcpCommon());
|
||||||
|
unknown->header_.type = 255; // Invalid/unknown RTCP type
|
||||||
|
unknown->set_ssrc(0x99999999);
|
||||||
|
HELPER_EXPECT_FAILED(publish_stream->on_rtcp(unknown.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TEST(SrsRtcPublishStreamTest, OnRtcpXrTypicalScenario)
|
||||||
|
{
|
||||||
|
srs_error_t err;
|
||||||
|
|
||||||
|
// Create mock objects
|
||||||
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
|
MockRtcExpire mock_expire;
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
SrsContextId cid;
|
||||||
|
cid.set_value("test-on-rtcp-xr-stream-id");
|
||||||
|
|
||||||
|
// Create SrsRtcPublishStream with mock dependencies
|
||||||
|
SrsUniquePtr<SrsRtcPublishStream> publish_stream(new SrsRtcPublishStream(&mock_exec, &mock_expire, &mock_receiver, cid));
|
||||||
|
|
||||||
|
// Create video track to receive RTT updates
|
||||||
|
SrsRtcTrackDescription video_desc;
|
||||||
|
video_desc.type_ = "video";
|
||||||
|
video_desc.id_ = "video_track_xr_test";
|
||||||
|
video_desc.ssrc_ = 0x12345678;
|
||||||
|
video_desc.is_active_ = true;
|
||||||
|
SrsRtcVideoRecvTrack *video_track = new SrsRtcVideoRecvTrack(&mock_receiver, &video_desc);
|
||||||
|
publish_stream->video_tracks_.push_back(video_track);
|
||||||
|
|
||||||
|
// Create a valid RTCP XR packet with DLRR block (block type 5)
|
||||||
|
// RTCP XR packet structure:
|
||||||
|
// - RTCP header (8 bytes): V=2, P=0, RC=0, PT=207(XR), length, SSRC
|
||||||
|
// - Report block: BT=5, reserved, block_length, SSRC, LRR, DLRR
|
||||||
|
unsigned char xr_data[] = {
|
||||||
|
// RTCP header (8 bytes)
|
||||||
|
0x80, 0xCF, 0x00, 0x05, // V=2, P=0, RC=0, PT=207(XR), length=5 (24 bytes total)
|
||||||
|
0x87, 0x65, 0x43, 0x21, // SSRC of XR packet sender
|
||||||
|
// DLRR report block (16 bytes)
|
||||||
|
0x05, 0x00, 0x00, 0x03, // BT=5 (DLRR), reserved=0, block_length=3 (12 bytes)
|
||||||
|
0x12, 0x34, 0x56, 0x78, // SSRC of receiver (matches video track SSRC)
|
||||||
|
0x12, 0x34, 0x56, 0x78, // LRR (Last Receiver Report) - 32-bit compact NTP
|
||||||
|
0x00, 0x00, 0x10, 0x00 // DLRR (Delay since Last Receiver Report) - 32-bit value
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create SrsRtcpXr object and set its data
|
||||||
|
SrsUniquePtr<SrsRtcpXr> xr(new SrsRtcpXr());
|
||||||
|
xr->set_ssrc(0x87654321);
|
||||||
|
|
||||||
|
// Set the raw data for the XR packet (simulate what decode() would do)
|
||||||
|
xr->data_ = (char *)xr_data;
|
||||||
|
xr->nb_data_ = sizeof(xr_data);
|
||||||
|
|
||||||
|
// Test RTCP XR processing - should parse DLRR block and update RTT
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->on_rtcp_xr(xr.get()));
|
||||||
|
|
||||||
|
// The function should have processed the DLRR block and called update_rtt
|
||||||
|
// RTT calculation: compact_ntp - lrr - dlrr
|
||||||
|
// This is a typical scenario where RTT is calculated from timing information
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TEST(SrsRtcPublishStreamTest, RequestKeyframeTypicalScenario)
|
||||||
|
{
|
||||||
|
srs_error_t err;
|
||||||
|
|
||||||
|
// Create mock objects
|
||||||
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
|
MockRtcExpire mock_expire;
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
SrsContextId cid;
|
||||||
|
cid.set_value("test-request-keyframe-stream-id");
|
||||||
|
|
||||||
|
// Create SrsRtcPublishStream with mock dependencies
|
||||||
|
SrsUniquePtr<SrsRtcPublishStream> publish_stream(new SrsRtcPublishStream(&mock_exec, &mock_expire, &mock_receiver, cid));
|
||||||
|
|
||||||
|
// Test typical keyframe request scenario
|
||||||
|
uint32_t test_ssrc = 0x12345678;
|
||||||
|
SrsContextId subscriber_cid;
|
||||||
|
subscriber_cid.set_value("test-subscriber-cid");
|
||||||
|
|
||||||
|
// Test request_keyframe function - should delegate to pli_worker and log appropriately
|
||||||
|
publish_stream->request_keyframe(test_ssrc, subscriber_cid);
|
||||||
|
|
||||||
|
// Test do_request_keyframe function - should call receiver's send_rtcp_fb_pli
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->do_request_keyframe(test_ssrc, subscriber_cid));
|
||||||
|
|
||||||
|
// Verify that PLI packet was sent through the mock receiver
|
||||||
|
EXPECT_EQ(1, mock_receiver.send_rtcp_fb_pli_count_);
|
||||||
|
|
||||||
|
// Test error handling in do_request_keyframe
|
||||||
|
mock_receiver.set_send_rtcp_fb_pli_error(srs_error_new(ERROR_RTC_RTP_MUXER, "mock PLI send error"));
|
||||||
|
|
||||||
|
// Should still return success but log the error (error is freed internally)
|
||||||
|
HELPER_EXPECT_SUCCESS(publish_stream->do_request_keyframe(test_ssrc, subscriber_cid));
|
||||||
|
|
||||||
|
// Verify that PLI packet send was attempted again
|
||||||
|
EXPECT_EQ(2, mock_receiver.send_rtcp_fb_pli_count_);
|
||||||
|
|
||||||
|
// Reset receiver for cleanup
|
||||||
|
mock_receiver.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID TEST(SrsRtcPublishStreamTest, UpdateRttTypicalScenario)
|
||||||
|
{
|
||||||
|
// Create mock objects
|
||||||
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
|
MockRtcExpire mock_expire;
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
SrsContextId cid;
|
||||||
|
cid.set_value("test-update-rtt-stream-id");
|
||||||
|
|
||||||
|
// Create SrsRtcPublishStream with mock dependencies
|
||||||
|
SrsUniquePtr<SrsRtcPublishStream> publish_stream(new SrsRtcPublishStream(&mock_exec, &mock_expire, &mock_receiver, cid));
|
||||||
|
|
||||||
|
// Create audio track with specific SSRC
|
||||||
|
SrsRtcTrackDescription audio_desc;
|
||||||
|
audio_desc.type_ = "audio";
|
||||||
|
audio_desc.id_ = "audio_track_rtt_test";
|
||||||
|
audio_desc.ssrc_ = 0x87654321;
|
||||||
|
audio_desc.is_active_ = true;
|
||||||
|
SrsRtcAudioRecvTrack *audio_track = new SrsRtcAudioRecvTrack(&mock_receiver, &audio_desc);
|
||||||
|
publish_stream->audio_tracks_.push_back(audio_track);
|
||||||
|
|
||||||
|
// Test typical RTT update scenario for audio track
|
||||||
|
uint32_t test_ssrc = 0x87654321; // Matches audio track SSRC
|
||||||
|
int test_rtt = 50; // 50ms RTT
|
||||||
|
|
||||||
|
// Call update_rtt - should find audio track and update its RTT
|
||||||
|
publish_stream->update_rtt(test_ssrc, test_rtt);
|
||||||
|
|
||||||
|
// The function should have found the audio track and called update_rtt on it
|
||||||
|
// This delegates to the NACK receiver which updates its RTT and nack_interval
|
||||||
|
// No return value to check, but the function should complete without error
|
||||||
|
|
||||||
|
// Test with unknown SSRC - should not find any track and return silently
|
||||||
|
uint32_t unknown_ssrc = 0x99999999;
|
||||||
|
publish_stream->update_rtt(unknown_ssrc, test_rtt);
|
||||||
|
|
||||||
|
// Function should handle unknown SSRC gracefully without error
|
||||||
|
}
|
||||||
53
trunk/src/utest/srs_utest_app7.hpp
Normal file
53
trunk/src/utest/srs_utest_app7.hpp
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013-2025 The SRS Authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SRS_UTEST_APP7_HPP
|
||||||
|
#define SRS_UTEST_APP7_HPP
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <srs_utest_app7.hpp>
|
||||||
|
*/
|
||||||
|
#include <srs_utest.hpp>
|
||||||
|
|
||||||
|
#include <srs_app_rtc_conn.hpp>
|
||||||
|
#include <srs_app_rtc_source.hpp>
|
||||||
|
#include <srs_utest_app6.hpp>
|
||||||
|
|
||||||
|
// Mock video recv track for testing check_send_nacks
|
||||||
|
class MockRtcVideoRecvTrackForNack : public SrsRtcVideoRecvTrack
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t check_send_nacks_error_;
|
||||||
|
int check_send_nacks_count_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcVideoRecvTrackForNack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc);
|
||||||
|
virtual ~MockRtcVideoRecvTrackForNack();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t check_send_nacks();
|
||||||
|
void set_check_send_nacks_error(srs_error_t err);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock audio recv track for testing check_send_nacks
|
||||||
|
class MockRtcAudioRecvTrackForNack : public SrsRtcAudioRecvTrack
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t check_send_nacks_error_;
|
||||||
|
int check_send_nacks_count_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcAudioRecvTrackForNack(ISrsRtcPacketReceiver *receiver, SrsRtcTrackDescription *track_desc);
|
||||||
|
virtual ~MockRtcAudioRecvTrackForNack();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t check_send_nacks();
|
||||||
|
void set_check_send_nacks_error(srs_error_t err);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
1491
trunk/src/utest/srs_utest_app_rtc2rtmp.cpp
Normal file
1491
trunk/src/utest/srs_utest_app_rtc2rtmp.cpp
Normal file
File diff suppressed because it is too large
Load Diff
59
trunk/src/utest/srs_utest_app_rtc2rtmp.hpp
Normal file
59
trunk/src/utest/srs_utest_app_rtc2rtmp.hpp
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013-2025 The SRS Authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SRS_UTEST_APP_RTC2RTMP_HPP
|
||||||
|
#define SRS_UTEST_APP_RTC2RTMP_HPP
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <srs_utest_app_rtc2rtmp.hpp>
|
||||||
|
*/
|
||||||
|
#include <srs_utest.hpp>
|
||||||
|
|
||||||
|
#include <srs_app_stream_bridge.hpp>
|
||||||
|
#include <srs_protocol_rtmp_stack.hpp>
|
||||||
|
|
||||||
|
// Mock frame target for testing SrsRtcFrameBuilder
|
||||||
|
class MockRtc2RtmpFrameTarget : public ISrsFrameTarget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int on_frame_count_;
|
||||||
|
SrsMediaPacket *last_frame_;
|
||||||
|
srs_error_t frame_error_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtc2RtmpFrameTarget();
|
||||||
|
virtual ~MockRtc2RtmpFrameTarget();
|
||||||
|
virtual srs_error_t on_frame(SrsMediaPacket *frame);
|
||||||
|
void reset();
|
||||||
|
void set_frame_error(srs_error_t err);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock request class for testing
|
||||||
|
class MockRtc2RtmpRequest : public ISrsRequest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string vhost_;
|
||||||
|
std::string app_;
|
||||||
|
std::string stream_;
|
||||||
|
std::string host_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtc2RtmpRequest(std::string vhost = "__defaultVhost__", std::string app = "live", std::string stream = "test");
|
||||||
|
virtual ~MockRtc2RtmpRequest();
|
||||||
|
virtual ISrsRequest *copy();
|
||||||
|
virtual std::string get_stream_url();
|
||||||
|
virtual void update_auth(ISrsRequest *req);
|
||||||
|
virtual void strip();
|
||||||
|
virtual ISrsRequest *as_http();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SrsNaluSample *mock_create_nalu_sample(const uint8_t *data, int size);
|
||||||
|
extern SrsRtpPacket *mock_create_stap_packet_with_sps_pps(uint16_t seq, uint32_t ts);
|
||||||
|
extern SrsRtpPacket *mock_create_idr_packet(uint16_t seq, uint32_t ts, bool marker);
|
||||||
|
extern SrsRtpPacket *mock_create_p_frame_packet(uint16_t seq, uint32_t ts, bool marker);
|
||||||
|
extern SrsRtpPacket *mock_create_audio_packet(uint16_t seq, uint32_t ts, uint32_t avsync_time);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -3169,7 +3169,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig2)
|
||||||
EXPECT_FALSE(conf.get_mr_enabled("ossrs.net"));
|
EXPECT_FALSE(conf.get_mr_enabled("ossrs.net"));
|
||||||
EXPECT_EQ(350 * SRS_UTIME_MILLISECONDS, conf.get_mr_sleep("ossrs.net"));
|
EXPECT_EQ(350 * SRS_UTIME_MILLISECONDS, conf.get_mr_sleep("ossrs.net"));
|
||||||
EXPECT_EQ(350 * SRS_UTIME_MILLISECONDS, conf.get_mw_sleep("ossrs.net"));
|
EXPECT_EQ(350 * SRS_UTIME_MILLISECONDS, conf.get_mw_sleep("ossrs.net"));
|
||||||
EXPECT_FALSE(conf.get_realtime_enabled("ossrs.net"));
|
EXPECT_FALSE(conf.get_realtime_enabled("ossrs.net", false));
|
||||||
EXPECT_FALSE(conf.get_tcp_nodelay("ossrs.net"));
|
EXPECT_FALSE(conf.get_tcp_nodelay("ossrs.net"));
|
||||||
EXPECT_EQ(0, (int)conf.get_send_min_interval("ossrs.net"));
|
EXPECT_EQ(0, (int)conf.get_send_min_interval("ossrs.net"));
|
||||||
EXPECT_FALSE(conf.get_reduce_sequence_header("ossrs.net"));
|
EXPECT_FALSE(conf.get_reduce_sequence_header("ossrs.net"));
|
||||||
|
|
@ -3231,7 +3231,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig2)
|
||||||
if (true) {
|
if (true) {
|
||||||
MockSrsConfig conf;
|
MockSrsConfig conf;
|
||||||
HELPER_ASSERT_SUCCESS(conf.mock_parse(_MIN_OK_CONF "vhost ossrs.net{min_latency on;}"));
|
HELPER_ASSERT_SUCCESS(conf.mock_parse(_MIN_OK_CONF "vhost ossrs.net{min_latency on;}"));
|
||||||
EXPECT_TRUE(conf.get_realtime_enabled("ossrs.net"));
|
EXPECT_TRUE(conf.get_realtime_enabled("ossrs.net", false));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
|
|
|
||||||
|
|
@ -547,43 +547,43 @@ VOID TEST(KernelFastBufferTest, Grow)
|
||||||
srs_error_t err;
|
srs_error_t err;
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsFastStream b(5);
|
SrsUniquePtr<SrsFastStream> b(new SrsFastStream(5));
|
||||||
MockBufferReader r("Hello, world!");
|
MockBufferReader r("Hello, world!");
|
||||||
|
|
||||||
HELPER_ASSERT_SUCCESS(b.grow(&r, 5));
|
HELPER_ASSERT_SUCCESS(b->grow(&r, 5));
|
||||||
b.skip(2);
|
b->skip(2);
|
||||||
|
|
||||||
HELPER_ASSERT_FAILED(b.grow(&r, 6));
|
HELPER_ASSERT_FAILED(b->grow(&r, 6));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsFastStream b(5);
|
SrsUniquePtr<SrsFastStream> b(new SrsFastStream(5));
|
||||||
MockBufferReader r("Hello, world!");
|
MockBufferReader r("Hello, world!");
|
||||||
|
|
||||||
HELPER_ASSERT_SUCCESS(b.grow(&r, 5));
|
HELPER_ASSERT_SUCCESS(b->grow(&r, 5));
|
||||||
b.skip(5);
|
b->skip(5);
|
||||||
|
|
||||||
HELPER_ASSERT_FAILED(b.grow(&r, 6));
|
HELPER_ASSERT_FAILED(b->grow(&r, 6));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsFastStream b(6);
|
SrsUniquePtr<SrsFastStream> b(new SrsFastStream(6));
|
||||||
MockBufferReader r("Hello, world!");
|
MockBufferReader r("Hello, world!");
|
||||||
|
|
||||||
HELPER_ASSERT_SUCCESS(b.grow(&r, 5));
|
HELPER_ASSERT_SUCCESS(b->grow(&r, 5));
|
||||||
EXPECT_EQ('H', b.read_1byte());
|
EXPECT_EQ('H', b->read_1byte());
|
||||||
EXPECT_EQ('e', b.read_1byte());
|
EXPECT_EQ('e', b->read_1byte());
|
||||||
EXPECT_EQ('l', b.read_1byte());
|
EXPECT_EQ('l', b->read_1byte());
|
||||||
b.skip(2);
|
b->skip(2);
|
||||||
|
|
||||||
HELPER_ASSERT_SUCCESS(b.grow(&r, 2));
|
HELPER_ASSERT_SUCCESS(b->grow(&r, 2));
|
||||||
b.skip(2);
|
b->skip(2);
|
||||||
|
|
||||||
HELPER_ASSERT_SUCCESS(b.grow(&r, 5));
|
HELPER_ASSERT_SUCCESS(b->grow(&r, 5));
|
||||||
EXPECT_EQ('w', b.read_1byte());
|
EXPECT_EQ('w', b->read_1byte());
|
||||||
EXPECT_EQ('o', b.read_1byte());
|
EXPECT_EQ('o', b->read_1byte());
|
||||||
EXPECT_EQ('r', b.read_1byte());
|
EXPECT_EQ('r', b->read_1byte());
|
||||||
b.skip(2);
|
b->skip(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
|
|
@ -1696,11 +1696,11 @@ VOID TEST(KernelFLVTest, CoverFLVVodError)
|
||||||
VOID TEST(KernelStreamTest, StreamPos)
|
VOID TEST(KernelStreamTest, StreamPos)
|
||||||
{
|
{
|
||||||
char data[1024];
|
char data[1024];
|
||||||
SrsBuffer s(data, 1024);
|
SrsUniquePtr<SrsBuffer> s(new SrsBuffer(data, 1024));
|
||||||
EXPECT_TRUE(s.pos() == 0);
|
EXPECT_TRUE(s->pos() == 0);
|
||||||
|
|
||||||
s.read_bytes(data, 1024);
|
s->read_bytes(data, 1024);
|
||||||
EXPECT_TRUE(s.pos() == 1024);
|
EXPECT_TRUE(s->pos() == 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1709,11 +1709,11 @@ VOID TEST(KernelStreamTest, StreamPos)
|
||||||
VOID TEST(KernelStreamTest, StreamEmpty)
|
VOID TEST(KernelStreamTest, StreamEmpty)
|
||||||
{
|
{
|
||||||
char data[1024];
|
char data[1024];
|
||||||
SrsBuffer s(data, 1024);
|
SrsUniquePtr<SrsBuffer> s(new SrsBuffer(data, 1024));
|
||||||
EXPECT_FALSE(s.empty());
|
EXPECT_FALSE(s->empty());
|
||||||
|
|
||||||
s.read_bytes(data, 1024);
|
s->read_bytes(data, 1024);
|
||||||
EXPECT_TRUE(s.empty());
|
EXPECT_TRUE(s->empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1722,15 +1722,15 @@ VOID TEST(KernelStreamTest, StreamEmpty)
|
||||||
VOID TEST(KernelStreamTest, StreamRequire)
|
VOID TEST(KernelStreamTest, StreamRequire)
|
||||||
{
|
{
|
||||||
char data[1024];
|
char data[1024];
|
||||||
SrsBuffer s(data, 1024);
|
SrsUniquePtr<SrsBuffer> s(new SrsBuffer(data, 1024));
|
||||||
EXPECT_TRUE(s.require(1));
|
EXPECT_TRUE(s->require(1));
|
||||||
EXPECT_TRUE(s.require(1024));
|
EXPECT_TRUE(s->require(1024));
|
||||||
|
|
||||||
s.read_bytes(data, 1000);
|
s->read_bytes(data, 1000);
|
||||||
EXPECT_TRUE(s.require(1));
|
EXPECT_TRUE(s->require(1));
|
||||||
|
|
||||||
s.read_bytes(data, 24);
|
s->read_bytes(data, 24);
|
||||||
EXPECT_FALSE(s.require(1));
|
EXPECT_FALSE(s->require(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1739,14 +1739,14 @@ VOID TEST(KernelStreamTest, StreamRequire)
|
||||||
VOID TEST(KernelStreamTest, StreamSkip)
|
VOID TEST(KernelStreamTest, StreamSkip)
|
||||||
{
|
{
|
||||||
char data[1024];
|
char data[1024];
|
||||||
SrsBuffer s(data, 1024);
|
SrsUniquePtr<SrsBuffer> s(new SrsBuffer(data, 1024));
|
||||||
EXPECT_EQ(0, s.pos());
|
EXPECT_EQ(0, s->pos());
|
||||||
|
|
||||||
s.skip(1);
|
s->skip(1);
|
||||||
EXPECT_EQ(1, s.pos());
|
EXPECT_EQ(1, s->pos());
|
||||||
|
|
||||||
s.skip(-1);
|
s->skip(-1);
|
||||||
EXPECT_EQ(0, s.pos());
|
EXPECT_EQ(0, s->pos());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1755,17 +1755,17 @@ VOID TEST(KernelStreamTest, StreamSkip)
|
||||||
VOID TEST(KernelStreamTest, StreamRead1Bytes)
|
VOID TEST(KernelStreamTest, StreamRead1Bytes)
|
||||||
{
|
{
|
||||||
char data[1024];
|
char data[1024];
|
||||||
SrsBuffer s(data, 1024);
|
SrsUniquePtr<SrsBuffer> s(new SrsBuffer(data, 1024));
|
||||||
|
|
||||||
data[0] = 0x12;
|
data[0] = 0x12;
|
||||||
data[99] = 0x13;
|
data[99] = 0x13;
|
||||||
data[100] = 0x14;
|
data[100] = 0x14;
|
||||||
data[101] = 0x15;
|
data[101] = 0x15;
|
||||||
EXPECT_EQ(0x12, s.read_1bytes());
|
EXPECT_EQ(0x12, s->read_1bytes());
|
||||||
|
|
||||||
s.skip(-1 * s.pos());
|
s->skip(-1 * s->pos());
|
||||||
s.skip(100);
|
s->skip(100);
|
||||||
EXPECT_EQ(0x14, s.read_1bytes());
|
EXPECT_EQ(0x14, s->read_1bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1774,7 +1774,7 @@ VOID TEST(KernelStreamTest, StreamRead1Bytes)
|
||||||
VOID TEST(KernelStreamTest, StreamRead2Bytes)
|
VOID TEST(KernelStreamTest, StreamRead2Bytes)
|
||||||
{
|
{
|
||||||
char data[1024];
|
char data[1024];
|
||||||
SrsBuffer s(data, 1024);
|
SrsUniquePtr<SrsBuffer> s(new SrsBuffer(data, 1024));
|
||||||
|
|
||||||
data[0] = 0x01;
|
data[0] = 0x01;
|
||||||
data[1] = 0x02;
|
data[1] = 0x02;
|
||||||
|
|
@ -1787,12 +1787,12 @@ VOID TEST(KernelStreamTest, StreamRead2Bytes)
|
||||||
data[8] = 0x09;
|
data[8] = 0x09;
|
||||||
data[9] = 0x0a;
|
data[9] = 0x0a;
|
||||||
|
|
||||||
EXPECT_EQ(0x0102, s.read_2bytes());
|
EXPECT_EQ(0x0102, s->read_2bytes());
|
||||||
EXPECT_EQ(0x0304, s.read_2bytes());
|
EXPECT_EQ(0x0304, s->read_2bytes());
|
||||||
|
|
||||||
s.skip(-1 * s.pos());
|
s->skip(-1 * s->pos());
|
||||||
s.skip(3);
|
s->skip(3);
|
||||||
EXPECT_EQ(0x0405, s.read_2bytes());
|
EXPECT_EQ(0x0405, s->read_2bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ public:
|
||||||
void clear();
|
void clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
class MockSrsFastTimer : public ISrsFastTimer
|
class MockSrsFastTimer : public ISrsFastTimerHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::vector<srs_utime_t> timer_calls_;
|
std::vector<srs_utime_t> timer_calls_;
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@
|
||||||
#include <srs_kernel_rtc_rtp.hpp>
|
#include <srs_kernel_rtc_rtp.hpp>
|
||||||
#include <srs_protocol_conn.hpp>
|
#include <srs_protocol_conn.hpp>
|
||||||
|
|
||||||
|
#include <srs_utest_app6.hpp>
|
||||||
|
#include <srs_utest_protocol3.hpp>
|
||||||
#include <srs_utest_service.hpp>
|
#include <srs_utest_service.hpp>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -1328,11 +1330,15 @@ VOID TEST(KernelRTCTest, DumpsHexToString)
|
||||||
|
|
||||||
VOID TEST(KernelRTCTest, NACKFetchRTPPacket)
|
VOID TEST(KernelRTCTest, NACKFetchRTPPacket)
|
||||||
{
|
{
|
||||||
SrsRtcConnection s(NULL, SrsContextId());
|
// Create mock interfaces for SrsRtcPlayStream constructor
|
||||||
SrsRtcPlayStream play(&s, SrsContextId());
|
MockRtcAsyncTaskExecutor mock_executor;
|
||||||
|
MockExpire mock_expire;
|
||||||
|
MockRtcPacketSender mock_sender;
|
||||||
|
|
||||||
|
SrsUniquePtr<SrsRtcPlayStream> play(new SrsRtcPlayStream(&mock_executor, &mock_expire, &mock_sender, SrsContextId()));
|
||||||
|
|
||||||
SrsRtcTrackDescription ds;
|
SrsRtcTrackDescription ds;
|
||||||
SrsRtcVideoSendTrack *track = new SrsRtcVideoSendTrack(&s, &ds);
|
SrsRtcVideoSendTrack *track = new SrsRtcVideoSendTrack(&mock_sender, &ds);
|
||||||
SrsUniquePtr<SrsRtcVideoSendTrack> track_uptr(track);
|
SrsUniquePtr<SrsRtcVideoSendTrack> track_uptr(track);
|
||||||
|
|
||||||
// The RTP queue will free the packet.
|
// The RTP queue will free the packet.
|
||||||
|
|
@ -1556,8 +1562,12 @@ VOID TEST(KernelRTCTest, DefaultTrackStatus)
|
||||||
|
|
||||||
// Enable it by player.
|
// Enable it by player.
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsRtcConnection s(NULL, SrsContextId());
|
// Create mock interfaces for SrsRtcPlayStream constructor
|
||||||
SrsRtcPlayStream play(&s, SrsContextId());
|
MockRtcAsyncTaskExecutor mock_executor;
|
||||||
|
MockExpire mock_expire;
|
||||||
|
MockRtcPacketSender mock_sender;
|
||||||
|
|
||||||
|
SrsUniquePtr<SrsRtcPlayStream> play(new SrsRtcPlayStream(&mock_executor, &mock_expire, &mock_sender, SrsContextId()));
|
||||||
SrsRtcAudioSendTrack *audio;
|
SrsRtcAudioSendTrack *audio;
|
||||||
SrsRtcVideoSendTrack *video;
|
SrsRtcVideoSendTrack *video;
|
||||||
|
|
||||||
|
|
@ -1566,27 +1576,29 @@ VOID TEST(KernelRTCTest, DefaultTrackStatus)
|
||||||
ds.type_ = "audio";
|
ds.type_ = "audio";
|
||||||
ds.id_ = "NSNWOn19NDn12o8nNeji2";
|
ds.id_ = "NSNWOn19NDn12o8nNeji2";
|
||||||
ds.ssrc_ = 100;
|
ds.ssrc_ = 100;
|
||||||
play.audio_tracks_[ds.ssrc_] = audio = new SrsRtcAudioSendTrack(&s, &ds);
|
play->audio_tracks_[ds.ssrc_] = audio = new SrsRtcAudioSendTrack(&mock_sender, &ds);
|
||||||
}
|
}
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsRtcTrackDescription ds;
|
SrsRtcTrackDescription ds;
|
||||||
ds.type_ = "video";
|
ds.type_ = "video";
|
||||||
ds.id_ = "VMo22nfLDn122nfnDNL2";
|
ds.id_ = "VMo22nfLDn122nfnDNL2";
|
||||||
ds.ssrc_ = 200;
|
ds.ssrc_ = 200;
|
||||||
play.video_tracks_[ds.ssrc_] = video = new SrsRtcVideoSendTrack(&s, &ds);
|
play->video_tracks_[ds.ssrc_] = video = new SrsRtcVideoSendTrack(&mock_sender, &ds);
|
||||||
}
|
}
|
||||||
EXPECT_FALSE(audio->get_track_status());
|
EXPECT_FALSE(audio->get_track_status());
|
||||||
EXPECT_FALSE(video->get_track_status());
|
EXPECT_FALSE(video->get_track_status());
|
||||||
|
|
||||||
play.set_all_tracks_status(true);
|
play->set_all_tracks_status(true);
|
||||||
EXPECT_TRUE(audio->get_track_status());
|
EXPECT_TRUE(audio->get_track_status());
|
||||||
EXPECT_TRUE(video->get_track_status());
|
EXPECT_TRUE(video->get_track_status());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable it by publisher.
|
// Enable it by publisher.
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsRtcConnection s(NULL, SrsContextId());
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
SrsRtcPublishStream publish(&s, SrsContextId());
|
MockExpire mock_expire;
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
SrsUniquePtr<SrsRtcPublishStream> publish(new SrsRtcPublishStream(&mock_exec, &mock_expire, &mock_receiver, SrsContextId()));
|
||||||
SrsRtcAudioRecvTrack *audio;
|
SrsRtcAudioRecvTrack *audio;
|
||||||
SrsRtcVideoRecvTrack *video;
|
SrsRtcVideoRecvTrack *video;
|
||||||
|
|
||||||
|
|
@ -1595,21 +1607,21 @@ VOID TEST(KernelRTCTest, DefaultTrackStatus)
|
||||||
ds.type_ = "audio";
|
ds.type_ = "audio";
|
||||||
ds.id_ = "NSNWOn19NDn12o8nNeji2";
|
ds.id_ = "NSNWOn19NDn12o8nNeji2";
|
||||||
ds.ssrc_ = 100;
|
ds.ssrc_ = 100;
|
||||||
audio = new SrsRtcAudioRecvTrack(&s, &ds);
|
audio = new SrsRtcAudioRecvTrack(&mock_receiver, &ds);
|
||||||
publish.audio_tracks_.push_back(audio);
|
publish->audio_tracks_.push_back(audio);
|
||||||
}
|
}
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsRtcTrackDescription ds;
|
SrsRtcTrackDescription ds;
|
||||||
ds.type_ = "video";
|
ds.type_ = "video";
|
||||||
ds.id_ = "VMo22nfLDn122nfnDNL2";
|
ds.id_ = "VMo22nfLDn122nfnDNL2";
|
||||||
ds.ssrc_ = 200;
|
ds.ssrc_ = 200;
|
||||||
video = new SrsRtcVideoRecvTrack(&s, &ds);
|
video = new SrsRtcVideoRecvTrack(&mock_receiver, &ds);
|
||||||
publish.video_tracks_.push_back(video);
|
publish->video_tracks_.push_back(video);
|
||||||
}
|
}
|
||||||
EXPECT_FALSE(audio->get_track_status());
|
EXPECT_FALSE(audio->get_track_status());
|
||||||
EXPECT_FALSE(video->get_track_status());
|
EXPECT_FALSE(video->get_track_status());
|
||||||
|
|
||||||
publish.set_all_tracks_status(true);
|
publish->set_all_tracks_status(true);
|
||||||
EXPECT_TRUE(audio->get_track_status());
|
EXPECT_TRUE(audio->get_track_status());
|
||||||
EXPECT_TRUE(video->get_track_status());
|
EXPECT_TRUE(video->get_track_status());
|
||||||
}
|
}
|
||||||
|
|
@ -1646,15 +1658,17 @@ VOID TEST(KernelRTCTest, Ntp)
|
||||||
|
|
||||||
VOID TEST(KernelRTCTest, SyncTimestampBySenderReportNormal)
|
VOID TEST(KernelRTCTest, SyncTimestampBySenderReportNormal)
|
||||||
{
|
{
|
||||||
SrsRtcConnection s(NULL, SrsContextId());
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
SrsRtcPublishStream publish(&s, SrsContextId());
|
MockExpire mock_expire;
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
SrsRtcPublishStream publish(&mock_exec, &mock_expire, &mock_receiver, SrsContextId());
|
||||||
|
|
||||||
SrsRtcTrackDescription video_ds;
|
SrsRtcTrackDescription video_ds;
|
||||||
video_ds.type_ = "video";
|
video_ds.type_ = "video";
|
||||||
video_ds.id_ = "VMo22nfLDn122nfnDNL2";
|
video_ds.id_ = "VMo22nfLDn122nfnDNL2";
|
||||||
video_ds.ssrc_ = 200;
|
video_ds.ssrc_ = 200;
|
||||||
|
|
||||||
SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&s, &video_ds);
|
SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&mock_receiver, &video_ds);
|
||||||
publish.video_tracks_.push_back(video);
|
publish.video_tracks_.push_back(video);
|
||||||
|
|
||||||
publish.set_all_tracks_status(true);
|
publish.set_all_tracks_status(true);
|
||||||
|
|
@ -1712,15 +1726,17 @@ VOID TEST(KernelRTCTest, SyncTimestampBySenderReportNormal)
|
||||||
|
|
||||||
VOID TEST(KernelRTCTest, SyncTimestampBySenderReportOutOfOrder)
|
VOID TEST(KernelRTCTest, SyncTimestampBySenderReportOutOfOrder)
|
||||||
{
|
{
|
||||||
SrsRtcConnection s(NULL, SrsContextId());
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
SrsRtcPublishStream publish(&s, SrsContextId());
|
MockExpire mock_expire;
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
SrsRtcPublishStream publish(&mock_exec, &mock_expire, &mock_receiver, SrsContextId());
|
||||||
|
|
||||||
SrsRtcTrackDescription video_ds;
|
SrsRtcTrackDescription video_ds;
|
||||||
video_ds.type_ = "video";
|
video_ds.type_ = "video";
|
||||||
video_ds.id_ = "VMo22nfLDn122nfnDNL2";
|
video_ds.id_ = "VMo22nfLDn122nfnDNL2";
|
||||||
video_ds.ssrc_ = 200;
|
video_ds.ssrc_ = 200;
|
||||||
|
|
||||||
SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&s, &video_ds);
|
SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&mock_receiver, &video_ds);
|
||||||
publish.video_tracks_.push_back(video);
|
publish.video_tracks_.push_back(video);
|
||||||
|
|
||||||
publish.set_all_tracks_status(true);
|
publish.set_all_tracks_status(true);
|
||||||
|
|
@ -1783,15 +1799,17 @@ VOID TEST(KernelRTCTest, SyncTimestampBySenderReportOutOfOrder)
|
||||||
|
|
||||||
VOID TEST(KernelRTCTest, SyncTimestampBySenderReportConsecutive)
|
VOID TEST(KernelRTCTest, SyncTimestampBySenderReportConsecutive)
|
||||||
{
|
{
|
||||||
SrsRtcConnection s(NULL, SrsContextId());
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
SrsRtcPublishStream publish(&s, SrsContextId());
|
MockExpire mock_expire;
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
SrsRtcPublishStream publish(&mock_exec, &mock_expire, &mock_receiver, SrsContextId());
|
||||||
|
|
||||||
SrsRtcTrackDescription video_ds;
|
SrsRtcTrackDescription video_ds;
|
||||||
video_ds.type_ = "video";
|
video_ds.type_ = "video";
|
||||||
video_ds.id_ = "VMo22nfLDn122nfnDNL2";
|
video_ds.id_ = "VMo22nfLDn122nfnDNL2";
|
||||||
video_ds.ssrc_ = 200;
|
video_ds.ssrc_ = 200;
|
||||||
|
|
||||||
SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&s, &video_ds);
|
SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&mock_receiver, &video_ds);
|
||||||
publish.video_tracks_.push_back(video);
|
publish.video_tracks_.push_back(video);
|
||||||
|
|
||||||
publish.set_all_tracks_status(true);
|
publish.set_all_tracks_status(true);
|
||||||
|
|
@ -1887,15 +1905,17 @@ VOID TEST(KernelRTCTest, SrsRtcpNack)
|
||||||
|
|
||||||
VOID TEST(KernelRTCTest, SyncTimestampBySenderReportDuplicated)
|
VOID TEST(KernelRTCTest, SyncTimestampBySenderReportDuplicated)
|
||||||
{
|
{
|
||||||
SrsRtcConnection s(NULL, SrsContextId());
|
MockRtcAsyncTaskExecutor mock_exec;
|
||||||
SrsRtcPublishStream publish(&s, SrsContextId());
|
MockExpire mock_expire;
|
||||||
|
MockRtcPacketReceiver mock_receiver;
|
||||||
|
SrsRtcPublishStream publish(&mock_exec, &mock_expire, &mock_receiver, SrsContextId());
|
||||||
|
|
||||||
SrsRtcTrackDescription video_ds;
|
SrsRtcTrackDescription video_ds;
|
||||||
video_ds.type_ = "video";
|
video_ds.type_ = "video";
|
||||||
video_ds.id_ = "VMo22nfLDn122nfnDNL2";
|
video_ds.id_ = "VMo22nfLDn122nfnDNL2";
|
||||||
video_ds.ssrc_ = 200;
|
video_ds.ssrc_ = 200;
|
||||||
|
|
||||||
SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&s, &video_ds);
|
SrsRtcVideoRecvTrack *video = new SrsRtcVideoRecvTrack(&mock_receiver, &video_ds);
|
||||||
publish.video_tracks_.push_back(video);
|
publish.video_tracks_.push_back(video);
|
||||||
|
|
||||||
publish.set_all_tracks_status(true);
|
publish.set_all_tracks_status(true);
|
||||||
|
|
|
||||||
|
|
@ -37,18 +37,15 @@ VOID TEST(StTest, MutexPtrSugar)
|
||||||
VOID TEST(StTest, StUtimeInMicroseconds)
|
VOID TEST(StTest, StUtimeInMicroseconds)
|
||||||
{
|
{
|
||||||
st_utime_t st_time_1 = st_utime();
|
st_utime_t st_time_1 = st_utime();
|
||||||
// sleep 1 microsecond
|
usleep(1); // sleep 1 microsecond
|
||||||
#if !defined(SRS_CYGWIN64)
|
|
||||||
usleep(1);
|
|
||||||
#endif
|
|
||||||
st_utime_t st_time_2 = st_utime();
|
st_utime_t st_time_2 = st_utime();
|
||||||
|
|
||||||
EXPECT_GT(st_time_1, 0);
|
EXPECT_GT(st_time_1, 0);
|
||||||
EXPECT_GT(st_time_2, 0);
|
EXPECT_GT(st_time_2, 0);
|
||||||
EXPECT_GE(st_time_2, st_time_1);
|
EXPECT_GE(st_time_2, st_time_1);
|
||||||
// st_time_2 - st_time_1 should be in range of [1, 300] microseconds
|
// st_time_2 - st_time_1 should be in range of [1, 1000] microseconds
|
||||||
EXPECT_GE(st_time_2 - st_time_1, 0);
|
EXPECT_GE(st_time_2 - st_time_1, 0);
|
||||||
EXPECT_LE(st_time_2 - st_time_1, 300);
|
EXPECT_LE(st_time_2 - st_time_1, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline st_utime_t time_gettimeofday()
|
static inline st_utime_t time_gettimeofday()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user