Merge branch 'develop' into pr-fix_bridge

This commit is contained in:
winlin 2025-10-15 10:15:10 -04:00
commit 5466d99c9c
210 changed files with 39436 additions and 2382 deletions

View File

@ -301,6 +301,58 @@ code_patterns:
exceptions: "Only applies to SRS-defined classes/structs - do NOT change 3rd party code like llhttp"
rationale: "Consistent naming convention across SRS codebase for better code readability and maintenance - underscore distinguishes member variables from local variables and parameters"
access_specifiers_for_testing:
- pattern: "SRS_DECLARE_PRIVATE and SRS_DECLARE_PROTECTED macros"
description: "MANDATORY - Always use SRS_DECLARE_PRIVATE instead of 'private' and SRS_DECLARE_PROTECTED instead of 'protected' in class definitions"
purpose: "Enables unit tests to access private and protected members for dependency injection and mocking"
macro_definition: |
#ifdef SRS_FORCE_PUBLIC4UTEST
#define SRS_DECLARE_PRIVATE public
#define SRS_DECLARE_PROTECTED public
#else
#define SRS_DECLARE_PRIVATE private
#define SRS_DECLARE_PROTECTED protected
#endif
usage: |
WRONG: Using standard C++ access specifiers
class SrsBufferCache {
private:
ISrsAppConfig *config_;
ISrsRequest *req_;
protected:
virtual srs_error_t do_start();
public:
srs_error_t start();
};
CORRECT: Using SRS access specifier macros
class SrsBufferCache {
SRS_DECLARE_PRIVATE:
ISrsAppConfig *config_;
ISrsRequest *req_;
SRS_DECLARE_PROTECTED:
virtual srs_error_t do_start();
public:
srs_error_t start();
};
rules:
- "ALWAYS use SRS_DECLARE_PRIVATE instead of 'private' keyword"
- "ALWAYS use SRS_DECLARE_PROTECTED instead of 'protected' keyword"
- "Use standard 'public' keyword for public members (no macro needed)"
- "This applies to ALL production code classes in trunk/src/"
- "When SRS_FORCE_PUBLIC4UTEST is defined, all private/protected members become public for testing"
benefits:
- "Enables unit tests to inject mock dependencies into private member fields"
- "Allows tests to access and verify internal state"
- "Makes classes fully testable without breaking encapsulation in production"
- "Provides clean separation between production and test builds"
rationale: "This pattern allows unit tests to access private/protected members for dependency injection and mocking, while maintaining proper encapsulation in production builds. It's essential for writing comprehensive unit tests that can mock all dependencies."
commenting_style:
- pattern: "C++ style comments"
description: "MANDATORY - Use C++ style comments (//) instead of C style comments (/* */)"
@ -570,6 +622,82 @@ build_and_development:
description: "Run the unit tests for SRS"
working_directory: "trunk"
run_blackbox_tests:
description: "Blackbox tests are integration tests that test SRS as a complete system using FFmpeg as client"
location: "trunk/3rdparty/srs-bench/blackbox/"
prerequisites:
- "SRS server binary must be built first (make -j in trunk/)"
- "FFmpeg and FFprobe must be available in PATH"
- "Test media files (avatar.flv, etc.) must be present in srs-bench directory"
build_blackbox_tests:
command: "cd trunk/3rdparty/srs-bench && make"
description: "Build the blackbox test binary"
output: "./objs/srs_blackbox_test"
run_all_tests:
command: "./objs/srs_blackbox_test -test.v -srs-log -srs-stdout"
description: "Run all blackbox tests with verbose output and detailed SRS logs"
working_directory: "trunk/3rdparty/srs-bench"
run_specific_test:
command: "./objs/srs_blackbox_test -test.v -srs-log -srs-stdout -test.run TestName"
description: "Run a specific test by name (e.g., TestFast_RtmpPublish_DvrFlv_Basic)"
examples:
- "./objs/srs_blackbox_test -test.v -srs-log -srs-stdout -test.run TestFast_RtmpPublish_DvrFlv_Basic"
- "./objs/srs_blackbox_test -test.v -srs-log -srs-stdout -test.run TestFast_RtmpPublish_RtmpPlay_Basic"
- "./objs/srs_blackbox_test -test.v -srs-log -srs-stdout -test.run 'TestFast_RtmpPublish_Dvr.*'"
test_options:
- flag: "-test.v"
description: "Verbose output showing test progress (recommended)"
- flag: "-test.run <pattern>"
description: "Run only tests matching the pattern (Go regex)"
- flag: "-srs-log"
description: "Enable detailed SRS log output (recommended for debugging)"
- flag: "-srs-stdout"
description: "Show SRS stdout logs (recommended for debugging)"
- flag: "-srs-ffmpeg-stderr"
description: "Show FFmpeg stderr logs"
- flag: "-srs-ffprobe-stdout"
description: "Show FFprobe stdout logs"
- flag: "-srs-binary <path>"
description: "Specify custom SRS binary path (default: ../../objs/srs)"
- flag: "-srs-timeout <ms>"
description: "Timeout for each test case in milliseconds (default: 64000)"
how_it_works:
- "Each blackbox test automatically starts a fresh SRS server instance"
- "SRS is configured via environment variables (e.g., SRS_VHOST_DVR_ENABLED=on)"
- "Tests use FFmpeg to publish streams and FFprobe to verify output"
- "SRS server is automatically stopped when test completes"
- "Each test runs in isolation with its own SRS instance and random ports"
- "No need to manually start or stop SRS server"
test_categories:
rtmp: "TestFast_RtmpPublish_RtmpPlay_*, TestFast_RtmpPublish_HttpFlvPlay_*"
dvr: "TestFast_RtmpPublish_DvrFlv_*, TestFast_RtmpPublish_DvrMp4_*"
hls: "TestFast_RtmpPublish_HlsPlay_*"
hevc: "TestSlow_RtmpPublish_*_HEVC_*, TestSlow_SrtPublish_*_HEVC_*"
srt: "TestFast_SrtPublish_SrtPlay_*"
rtsp: "TestFast_RtmpPublish_RtspPlay_*"
http_api: "TestFast_Http_Api_*"
mp3: "TestFast_RtmpPublish_*_CodecMP3_*"
common_workflows:
quick_test:
description: "Run a single fast test to verify basic functionality"
command: "./objs/srs_blackbox_test -test.v -srs-log -srs-stdout -test.run TestFast_RtmpPublish_RtmpPlay_Basic"
dvr_tests:
description: "Run all DVR-related tests"
command: "./objs/srs_blackbox_test -test.v -srs-log -srs-stdout -test.run 'TestFast_RtmpPublish_Dvr.*'"
debug_test:
description: "Run test with full logging including FFmpeg stderr for debugging"
command: "./objs/srs_blackbox_test -test.v -srs-log -srs-stdout -srs-ffmpeg-stderr -test.run TestName"
testing:
test_patterns:
- Note that private and protected members are accessible in utests, as there is a macro to convert them to public
@ -579,6 +707,66 @@ testing:
- Verify edge cases like sequence number wrap-around, cache overflow, and null inputs
- Use existing mock helper functions for consistency and maintainability
mock_interface_fields:
principle: "MANDATORY - Always mock all private/protected interface member fields (ISrs* types) in the class under test"
description: |
When writing unit tests, ALWAYS identify and mock ALL interface member fields in the class under test.
Interface fields are those with ISrs* prefix (e.g., ISrsAppConfig*, ISrsBasicRtmpClient*, ISrsRequest*).
This enables proper dependency injection and isolation of the unit under test.
process:
- "Step 1: View the class header file to identify all private/protected member fields"
- "Step 2: Identify which fields are interfaces (start with ISrs prefix)"
- "Step 3: Create or reuse mock classes for each interface type"
- "Step 4: In the test, inject mock instances into the class under test by setting the private fields directly"
- "Step 5: After test completes, set injected fields to NULL before object destruction to avoid double-free"
example: |
// Class under test has these private fields:
class SrsEdgeRtmpUpstream {
private:
ISrsAppConfig *config_; // Interface - MUST mock
ISrsBasicRtmpClient *sdk_; // Interface - MUST mock
std::string redirect_; // Not interface - no need to mock
int selected_port_; // Not interface - no need to mock
};
// In unit test:
VOID TEST(EdgeRtmpUpstreamTest, ConnectToOrigin) {
// Create mocks for ALL interface fields
SrsUniquePtr<MockEdgeConfig> mock_config(new MockEdgeConfig());
MockEdgeRtmpClient *mock_sdk = new MockEdgeRtmpClient();
// Create object under test
SrsUniquePtr<SrsEdgeRtmpUpstream> upstream(new SrsEdgeRtmpUpstream(""));
// Inject mocks into private interface fields
upstream->config_ = mock_config.get();
upstream->sdk_ = mock_sdk;
// Run test
err = upstream->connect(req.get(), lb.get());
HELPER_EXPECT_SUCCESS(err);
// Verify mock interactions
EXPECT_TRUE(mock_sdk->connect_called_);
// Clean up - set to NULL to avoid double-free
upstream->sdk_ = NULL;
srs_freep(mock_sdk);
}
rules:
- "ALWAYS view the class header file first to identify all member fields"
- "ALWAYS mock ALL interface fields (ISrs* prefix) - no exceptions"
- "Create mock classes that implement the interface if they don't exist"
- "Reuse existing mock classes from srs_utest_app*.hpp when available"
- "Inject mocks by directly setting private member fields (accessible in utests)"
- "Set injected fields to NULL before object destruction to prevent double-free"
- "Non-interface fields (std::string, int, etc.) do not need mocking"
rationale: "Mocking all interface dependencies ensures tests are isolated, fast, and don't require real network/file/database resources. It also makes tests deterministic and easier to debug."
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"

View File

@ -29,6 +29,7 @@
**/3rdparty/patches/**
**/3rdparty/signaling/**
**/3rdparty/srt-1-fit/**
**/3rdparty/srs-bench/vendor/**
# Research files.
**/tools/**

View File

@ -5,6 +5,7 @@
# ColumnLimit: 0
# IndentWidth: 4
# TabWidth: 4
# Macros: SRS_DECLARE_PRIVATE=private, SRS_DECLARE_PROTECTED=protected (treat as access specifiers)
# refer to https://clang.llvm.org/docs/ClangFormatStyleOptions.html for more details.
---
Language: Cpp
@ -198,6 +199,9 @@ LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ''
MacroBlockEnd: ''
Macros:
- 'SRS_DECLARE_PRIVATE=private:'
- 'SRS_DECLARE_PROTECTED=protected:'
MainIncludeChar: Quote
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None

View File

@ -208,8 +208,10 @@ jobs:
echo "Release ossrs/srs:$SRS_TAG"
docker buildx build --platform linux/arm/v7,linux/arm64/v8,linux/amd64 \
--output "type=image,push=true" \
-t ossrs/srs:$SRS_TAG --build-arg SRS_AUTO_PACKAGER=$PACKAGER \
--build-arg CONFARGS='--sanitizer=off --gb28181=on' \
-t ossrs/srs:$SRS_TAG \
--build-arg SRS_AUTO_PACKAGER=$PACKAGER \
--build-arg IMAGE=ossrs/srs:ubuntu20 \
--build-arg CONFARGS='--sanitizer=off --gb28181=on --rtsp=on' \
-f Dockerfile .
# Docker alias images
# TODO: FIXME: If stable, please set the latest from 5.0 to 6.0

View File

@ -180,6 +180,7 @@ jobs:
--output "type=image,push=false" \
--build-arg IMAGE=ossrs/srs:ubuntu20-cache \
--build-arg INSTALLDEPENDS="NO" \
--build-arg CONFARGS="--sanitizer=on" \
-f Dockerfile .
runs-on: ubuntu-22.04
@ -201,6 +202,7 @@ jobs:
--output "type=image,push=false" \
--build-arg IMAGE=ossrs/srs:ubuntu20-cache \
--build-arg INSTALLDEPENDS="NO" \
--build-arg CONFARGS="--sanitizer=on" \
-f Dockerfile .
runs-on: ubuntu-22.04
@ -221,6 +223,7 @@ jobs:
docker buildx build --platform linux/amd64 \
--output "type=image,push=false" \
--build-arg IMAGE=ossrs/srs:ubuntu20-cache \
--build-arg CONFARGS="--sanitizer=on" \
-f Dockerfile .
runs-on: ubuntu-22.04

View File

@ -51,8 +51,7 @@ COPY --from=build /usr/local/srs /usr/local/srs
# Test the version of binaries.
RUN ldd /usr/local/srs/objs/ffmpeg/bin/ffmpeg && \
/usr/local/srs/objs/ffmpeg/bin/ffmpeg -version && \
ldd /usr/local/srs/objs/srs && \
/usr/local/srs/objs/srs -v
ldd /usr/local/srs/objs/srs
# Default workdir and command.
WORKDIR /usr/local/srs

View File

@ -113,7 +113,7 @@ func TestFast_RtmpPublish_RtspPlay_Basic(t *testing.T) {
if ts := 80; m.Format.ProbeScore < ts {
r4 = errors.Errorf("low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
}
if dv := m.Duration(); dv < duration {
if dv := m.Duration(); dv < duration/2 {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
}
@ -215,7 +215,7 @@ func TestFast_RtmpPublish_RtspPlay_MultipleClients(t *testing.T) {
if ts := 80; m.Format.ProbeScore < ts {
r5 = errors.Errorf("client1: low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
}
if dv := m.Duration(); dv < duration {
if dv := m.Duration(); dv < duration/2 {
r6 = errors.Errorf("client1: short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
}
@ -319,7 +319,7 @@ func TestFast_RtmpPublish_RtspPlay_CustomPort(t *testing.T) {
if ts := 80; m.Format.ProbeScore < ts {
r4 = errors.Errorf("low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
}
if dv := m.Duration(); dv < duration {
if dv := m.Duration(); dv < duration/2 {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
}
@ -406,8 +406,8 @@ func TestFast_RtmpPublish_RtspPlay_AudioOnly(t *testing.T) {
r4 = errors.Errorf("expected audio stream, got %v, %v, %v", m.Streams[0].CodecType, m.String(), str)
}
if dv := m.Duration(); dv < duration {
if dv := m.Duration(); dv < duration/2 {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
}
}
}

View File

@ -1,65 +1,65 @@
########################################################
FROM ossrs/srs:dev-cache AS centos7-baseline
COPY . /srs
RUN cd /srs/trunk && ./configure --srt=off --gb28181=off && make
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off && make
FROM ossrs/srs:dev-cache AS centos7-no-webrtc
COPY . /srs
RUN cd /srs/trunk && ./configure --srt=off --gb28181=off --rtc=off && make
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off --rtc=off && make
FROM ossrs/srs:dev-cache AS centos7-no-asm
COPY . /srs
RUN cd /srs/trunk && ./configure --srt=off --gb28181=off --nasm=off --srtp-nasm=off && make
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off --nasm=off --srtp-nasm=off && make
FROM ossrs/srs:dev-cache AS centos7-all
COPY . /srs
RUN cd /srs/trunk && ./configure --srt=on --gb28181=on --apm=on --h265=on && make
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=on --gb28181=on --apm=on --h265=on && make
FROM ossrs/srs:dev-cache AS centos7-ansi-no-ffmpeg
COPY . /srs
RUN cd /srs/trunk && ./configure --srt=off --gb28181=off --cxx11=off --cxx14=off --ffmpeg-fit=off && make
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off --cxx11=off --cxx14=off --ffmpeg-fit=off && make
########################################################
FROM ossrs/srs:ubuntu16-cache AS ubuntu16-baseline
COPY . /srs
RUN cd /srs/trunk && ./configure --srt=off --gb28181=off && make
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off && make
FROM ossrs/srs:ubuntu16-cache AS ubuntu16-all
COPY . /srs
RUN cd /srs/trunk && ./configure --srt=on --gb28181=on && make
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=on --gb28181=on && make
########################################################
FROM ossrs/srs:ubuntu18-cache AS ubuntu18-baseline
COPY . /srs
RUN cd /srs/trunk && ./configure --srt=off --gb28181=off && make
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off && make
FROM ossrs/srs:ubuntu18-cache AS ubuntu18-all
COPY . /srs
RUN cd /srs/trunk && ./configure --srt=on --gb28181=on && make
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=on --gb28181=on && make
########################################################
FROM ossrs/srs:ubuntu20-cache AS ubuntu20-baseline
COPY . /srs
RUN cd /srs/trunk && ./configure --srt=off --gb28181=off && make
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=off --gb28181=off && make
FROM ossrs/srs:ubuntu20-cache AS ubuntu20-all
COPY . /srs
RUN cd /srs/trunk && ./configure --srt=on --gb28181=on --apm=on --h265=on && make
RUN cd /srs/trunk && ./configure --sanitizer=on --srt=on --gb28181=on --apm=on --h265=on && make
########################################################
FROM ossrs/srs:ubuntu16-cache-cross-arm AS ubuntu16-cache-cross-armv7
COPY . /srs
RUN cd /srs/trunk && ./configure --cross-build --cross-prefix=arm-linux-gnueabihf- && make
RUN cd /srs/trunk && ./configure --sanitizer=on --cross-build --cross-prefix=arm-linux-gnueabihf- && make
FROM ossrs/srs:ubuntu16-cache-cross-aarch64 AS ubuntu16-cache-cross-aarch64
COPY . /srs
RUN cd /srs/trunk && ./configure --cross-build --cross-prefix=aarch64-linux-gnu- && make
RUN cd /srs/trunk && ./configure --sanitizer=on --cross-build --cross-prefix=aarch64-linux-gnu- && make
########################################################
FROM ossrs/srs:ubuntu20-cache-cross-arm AS ubuntu20-cache-cross-armv7
COPY . /srs
RUN cd /srs/trunk && ./configure --cross-build --cross-prefix=arm-linux-gnueabihf- && make
RUN cd /srs/trunk && ./configure --sanitizer=on --cross-build --cross-prefix=arm-linux-gnueabihf- && make
FROM ossrs/srs:ubuntu20-cache-cross-aarch64 AS ubuntu20-cache-cross-aarch64
COPY . /srs
RUN cd /srs/trunk && ./configure --cross-build --cross-prefix=aarch64-linux-gnu- && make
RUN cd /srs/trunk && ./configure --sanitizer=on --cross-build --cross-prefix=aarch64-linux-gnu- && make

View File

@ -16,6 +16,7 @@ COPY . /srs
WORKDIR /srs/trunk
# Note that we must enable the gcc7 or link failed.
# Enable sanitizer explicitly for coverage testing to catch memory issues.
RUN ./configure --rtsp=on --srt=on --gb28181=on --apm=on --h265=on --utest=on --gcov=on --sanitizer=on
RUN make utest ${MAKEARGS}

View File

@ -18,7 +18,8 @@ WORKDIR /srs/trunk
# Note that we must enable the gcc7 or link failed.
# Please note that we must disable the ffmpeg-opus, as it negatively impacts performance. We may consider
# enabling it in the future when support for multi-threading transcoding is available.
RUN ./configure --srt=on --gb28181=on --srt=on --rtsp=on --apm=on --utest=on --ffmpeg-opus=off --build-cache=on
# Enable sanitizer explicitly for CI/CD testing to catch memory issues.
RUN ./configure --srt=on --gb28181=on --srt=on --rtsp=on --apm=on --utest=on --sanitizer=on --ffmpeg-opus=off --build-cache=on
RUN make utest ${MAKEARGS}
# Build benchmark tool.

View File

@ -119,6 +119,12 @@ else
srs_undefine_macro "SRS_UTEST" $SRS_AUTO_HEADERS_H
fi
if [[ $SRS_FORCE_PUBLIC4UTEST == YES ]]; then
srs_define_macro "SRS_FORCE_PUBLIC4UTEST" $SRS_AUTO_HEADERS_H
else
srs_undefine_macro "SRS_FORCE_PUBLIC4UTEST" $SRS_AUTO_HEADERS_H
fi
# whatever the FFMPEG tools, if transcode and ingest specified,
# srs always compile the FFMPEG tool stub which used to start the FFMPEG process.
if [[ $SRS_FFMPEG_STUB == YES ]]; then

View File

@ -15,6 +15,7 @@ SRS_CXX14=NO
SRS_BACKTRACE=YES
SRS_NGINX=NO
SRS_UTEST=NO
SRS_FORCE_PUBLIC4UTEST=NO
# Always enable the bellow features.
SRS_STREAM_CASTER=YES
SRS_INGEST=YES
@ -551,10 +552,11 @@ function apply_auto_options() {
SRS_SHARED_SRTP=YES
fi
# Enable asan, but disable for Centos
# Disable sanitizer by default to avoid issues with daemon mode.
# Enable sanitizer only for utest and when explicitly requested.
# @see https://github.com/ossrs/srs/issues/3347
if [[ $SRS_SANITIZER == RESERVED && $OS_IS_CENTOS != YES ]]; then
echo "Enable asan by auto options."
if [[ $SRS_SANITIZER == RESERVED && $SRS_UTEST == YES ]]; then
echo "Enable asan for utest."
SRS_SANITIZER=YES
fi
@ -598,6 +600,13 @@ function apply_auto_options() {
SRS_CXX11=NO
fi
# When utest is enabled, automatically enable SRS_FORCE_PUBLIC4UTEST to make private members public
# This ensures consistent class layout between production code and utest code with AddressSanitizer
if [[ $SRS_UTEST == YES ]]; then
echo "Enable SRS_FORCE_PUBLIC4UTEST for utest to make private members public."
SRS_FORCE_PUBLIC4UTEST=YES
fi
# Force disable C++14 always - C++98 compatibility is required
if [[ $SRS_CXX14 != NO ]]; then
echo "Warning: C++14 support has been disabled. Forcing C++98 compatibility mode."

View File

@ -138,14 +138,23 @@ echo "" >> ${FILE}; echo "" >> ${FILE}
# Depends, the depends objects
echo "# Depends, the depends objects" >> ${FILE}
#
# current module header files
echo -n "SRS_UTEST_DEPS = " >> ${FILE}
# current SRS object files
echo -n "SRS_SOURCE_OBJS = " >> ${FILE}
for item in ${MODULE_OBJS[*]}; do
FILE_NAME=${item%.*}
echo -n "${SRS_TRUNK_PREFIX}/${SRS_OBJS}/${FILE_NAME}.o " >> ${FILE}
done
echo "" >> ${FILE}; echo "" >> ${FILE}
#
# current SRS header files
echo -n "SRS_SOURCE_HEADERS = " >> ${FILE}
for item in ${MODULE_OBJS[*]}; do
FILE_NAME=${item%.*}
echo -n "${SRS_TRUNK_PREFIX}/${FILE_NAME}.hpp " >> ${FILE}
done
echo "" >> ${FILE}; echo "" >> ${FILE}
#
# current utest header files
echo "# Depends, utest header files" >> ${FILE}
DEPS_NAME="UTEST_DEPS"
echo -n "${DEPS_NAME} = " >> ${FILE}
@ -163,7 +172,7 @@ MODULE_OBJS=()
for item in ${MODULE_FILES[*]}; do
MODULE_OBJS="${MODULE_OBJS[@]} ${item}.o"
cat << END >> ${FILE}
${item}.o : \$(${DEPS_NAME}) ${SRS_TRUNK_PREFIX}/${MODULE_DIR}/${item}.cpp \$(SRS_UTEST_DEPS)
${item}.o : \$(${DEPS_NAME}) ${SRS_TRUNK_PREFIX}/${MODULE_DIR}/${item}.cpp \$(SRS_SOURCE_HEADERS)
\$(CXX) \$(CPPFLAGS) \$(CXXFLAGS) \$(SRS_UTEST_INC) -c ${SRS_TRUNK_PREFIX}/${MODULE_DIR}/${item}.cpp -o \$@
END
done
@ -186,7 +195,7 @@ echo "" >> ${FILE}; echo "" >> ${FILE}
#
echo "# generate the utest binary" >> ${FILE}
cat << END >> ${FILE}
${SRS_TRUNK_PREFIX}/${SRS_OBJS}/${APP_NAME} : \$(SRS_UTEST_DEPS) ${MODULE_OBJS} gtest.a
${SRS_TRUNK_PREFIX}/${SRS_OBJS}/${APP_NAME} : \$(SRS_SOURCE_OBJS) ${MODULE_OBJS} gtest.a
\$(CXX) -o \$@ \$(CPPFLAGS) \$(CXXFLAGS) \$^ \$(DEPS_LIBRARIES_FILES) ${LINK_OPTIONS}
END

8
trunk/configure vendored
View File

@ -384,11 +384,15 @@ if [[ $SRS_UTEST == YES ]]; then
"srs_utest_coworkers" "srs_utest_pithy_print" "srs_utest_kernel3" "srs_utest_protocol4"
"srs_utest_protocol3" "srs_utest_app" "srs_utest_app2" "srs_utest_app3" "srs_utest_app4"
"srs_utest_app5" "srs_utest_app6" "srs_utest_app7" "srs_utest_app8" "srs_utest_app9"
"srs_utest_app10" "srs_utest_app11")
"srs_utest_app10" "srs_utest_app11" "srs_utest_app15" "srs_utest_app16"
"srs_utest_app17")
# Always include SRT utest
MODULE_FILES+=("srs_utest_srt")
if [[ $SRS_GB28181 == YES ]]; then
MODULE_FILES+=("srs_utest_gb28181")
MODULE_FILES+=("srs_utest_gb28181" "srs_utest_app14")
fi
if [[ $SRS_RTSP == YES ]]; then
MODULE_FILES+=("srs_utest_app12" "srs_utest_app13")
fi
ModuleLibIncs=(${SRS_OBJS} ${LibSTRoot} ${LibSSLRoot} ${LibSrtpRoot})
if [[ $SRS_FFMPEG_FIT == YES ]]; then

View File

@ -7,6 +7,7 @@ The changelog for SRS.
<a name="v7-changes"></a>
## SRS 7.0 Changelog
* v7.0, 2025-10-14, Disable sanitizer by default to fix memory leak. (#4364) v7.0.96
* v7.0, 2025-10-01, SRT: Support configurable default_streamid option. v7.0.95 (#4515)
* v7.0, 2025-09-27, Merge [#4513](https://github.com/ossrs/srs/pull/4513): For Edge, only support RTMP or HTTP-FLV. v7.0.94 (#4513)
* v7.0, 2025-09-21, Merge [#4505](https://github.com/ossrs/srs/pull/4505): improve blackbox test for rtsp. v7.0.93 (#4505)
@ -109,6 +110,7 @@ The changelog for SRS.
<a name="v6-changes"></a>
## SRS 6.0 Changelog
* v6.0, 2025-10-14, Disable sanitizer by default to fix memory leak. (#4364) v6.0.181
* v6.0, 2025-10-01, SRT: Support configurable default_streamid option. v6.0.180 (#4515)
* v6.0, 2025-09-27, For Edge, only support RTMP or HTTP-FLV. v6.0.179 (#4512)
* v6.0, 2025-09-21, Fix WHIP with transcoding bug. v6.0.178 (#4495)

View File

@ -24,4 +24,5 @@ fi
echo "Formatting source files in trunk directory..."
# Exclude the 3rdparty directory and format all .cpp, and .hpp
# Use -i to edit files in place
find trunk/src -name "*.*pp" | xargs clang-format -style=file -i
# Use xargs -P N to run N clang-format processes in parallel
find trunk/src -name "*.*pp" | xargs -P 16 -n 1 clang-format -style=file -i

View File

@ -53,10 +53,12 @@ public:
// That is, the task is execute/call in async mode.
class SrsAsyncCallWorker : public ISrsCoroutineHandler, public ISrsAsyncCallWorker
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsCoroutine *trd_;
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
std::vector<ISrsAsyncCallTask *> tasks_;
srs_cond_t wait_;
srs_mutex_t lock_;
@ -76,7 +78,8 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual void flush_tasks();
};

View File

@ -10,6 +10,7 @@
using namespace std;
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_http_conn.hpp>
#include <srs_app_rtmp_conn.hpp>
#include <srs_app_st.hpp>
@ -26,28 +27,41 @@ using namespace std;
#define SRS_HTTP_FLV_STREAM_BUFFER 4096
ISrsHttpFlvListener::ISrsHttpFlvListener()
{
}
ISrsHttpFlvListener::~ISrsHttpFlvListener()
{
}
SrsHttpFlvListener::SrsHttpFlvListener()
{
listener_ = new SrsTcpListener(this);
caster_ = new SrsAppCasterFlv();
config_ = _srs_config;
}
SrsHttpFlvListener::~SrsHttpFlvListener()
{
srs_freep(caster_);
srs_freep(listener_);
config_ = NULL;
}
srs_error_t SrsHttpFlvListener::initialize(SrsConfDirective *c)
{
srs_error_t err = srs_success;
int port = _srs_config->get_stream_caster_listen(c);
int port = config_->get_stream_caster_listen(c);
if (port <= 0) {
return srs_error_new(ERROR_STREAM_CASTER_PORT, "invalid port=%d", port);
}
listener_->set_endpoint(srs_net_address_any(), port)->set_label("PUSH-FLV");
listener_->set_endpoint(srs_net_address_any(), port);
listener_->set_label("PUSH-FLV");
if ((err = caster_->initialize(c)) != srs_success) {
return srs_error_wrap(err, "init caster port=%d", port);
@ -83,10 +97,20 @@ srs_error_t SrsHttpFlvListener::on_tcp_client(ISrsListener *listener, srs_netfd_
return err;
}
ISrsAppCasterFlv::ISrsAppCasterFlv()
{
}
ISrsAppCasterFlv::~ISrsAppCasterFlv()
{
}
SrsAppCasterFlv::SrsAppCasterFlv()
{
http_mux_ = new SrsHttpServeMux();
manager_ = new SrsResourceManager("CFLV");
config_ = _srs_config;
}
SrsAppCasterFlv::~SrsAppCasterFlv()
@ -99,13 +123,15 @@ SrsAppCasterFlv::~SrsAppCasterFlv()
ISrsConnection *conn = *it;
srs_freep(conn);
}
config_ = NULL;
}
srs_error_t SrsAppCasterFlv::initialize(SrsConfDirective *c)
{
srs_error_t err = srs_success;
output_ = _srs_config->get_stream_caster_output(c);
output_ = config_->get_stream_caster_output(c);
if ((err = http_mux_->handle("/", this)) != srs_success) {
return srs_error_wrap(err, "handle root");
@ -126,11 +152,11 @@ srs_error_t SrsAppCasterFlv::on_tcp_client(ISrsListener *listener, srs_netfd_t s
string ip = srs_get_peer_ip(fd);
int port = srs_get_peer_port(fd);
if (ip.empty() && !_srs_config->empty_ip_ok()) {
if (ip.empty() && !config_->empty_ip_ok()) {
srs_warn("empty ip for fd=%d", srs_netfd_fileno(stfd));
}
SrsDynamicHttpConn *conn = new SrsDynamicHttpConn(this, stfd, http_mux_, ip, port);
ISrsDynamicHttpConn *conn = new SrsDynamicHttpConn(this, stfd, http_mux_, ip, port);
conns_.push_back(conn);
if ((err = conn->start()) != srs_success) {
@ -160,11 +186,41 @@ void SrsAppCasterFlv::add(ISrsResource *conn, bool *exists)
manager_->add(conn, exists);
}
void SrsAppCasterFlv::add_with_id(const std::string &id, ISrsResource *conn)
{
manager_->add_with_id(id, conn);
}
void SrsAppCasterFlv::add_with_fast_id(uint64_t id, ISrsResource *conn)
{
manager_->add_with_fast_id(id, conn);
}
void SrsAppCasterFlv::add_with_name(const std::string &name, ISrsResource *conn)
{
manager_->add_with_name(name, conn);
}
ISrsResource *SrsAppCasterFlv::at(int index)
{
return manager_->at(index);
}
ISrsResource *SrsAppCasterFlv::find_by_id(std::string id)
{
return manager_->find_by_id(id);
}
ISrsResource *SrsAppCasterFlv::find_by_fast_id(uint64_t id)
{
return manager_->find_by_fast_id(id);
}
ISrsResource *SrsAppCasterFlv::find_by_name(std::string name)
{
return manager_->find_by_name(name);
}
void SrsAppCasterFlv::remove(ISrsResource *c)
{
ISrsConnection *conn = dynamic_cast<ISrsConnection *>(c);
@ -223,6 +279,14 @@ srs_error_t SrsAppCasterFlv::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
return err;
}
ISrsDynamicHttpConn::ISrsDynamicHttpConn()
{
}
ISrsDynamicHttpConn::~ISrsDynamicHttpConn()
{
}
SrsDynamicHttpConn::SrsDynamicHttpConn(ISrsResourceManager *cm, srs_netfd_t fd, SrsHttpServeMux *m, string cip, int cport)
{
// Create a identify for this client.
@ -236,17 +300,19 @@ SrsDynamicHttpConn::SrsDynamicHttpConn(ISrsResourceManager *cm, srs_netfd_t fd,
ip_ = cip;
port_ = cport;
_srs_config->subscribe(this);
config_ = _srs_config;
app_factory_ = _srs_app_factory;
}
SrsDynamicHttpConn::~SrsDynamicHttpConn()
{
_srs_config->unsubscribe(this);
srs_freep(conn_);
srs_freep(skt_);
srs_freep(sdk_);
srs_freep(pprint_);
config_ = NULL;
app_factory_ = NULL;
}
srs_error_t SrsDynamicHttpConn::proxy(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, std::string o)
@ -288,7 +354,7 @@ srs_error_t SrsDynamicHttpConn::do_proxy(ISrsHttpResponseReader *rr, SrsFlvDecod
srs_utime_t cto = SRS_CONSTS_RTMP_TIMEOUT;
srs_utime_t sto = SRS_CONSTS_RTMP_PULSE;
sdk_ = new SrsSimpleRtmpClient(output_, cto, sto);
sdk_ = app_factory_->create_rtmp_client(output_, cto, sto);
if ((err = sdk_->connect()) != srs_success) {
return srs_error_wrap(err, "connect %s failed, cto=%dms, sto=%dms.", output_.c_str(), srsu2msi(cto), srsu2msi(sto));
@ -346,12 +412,12 @@ srs_error_t SrsDynamicHttpConn::on_start()
return srs_success;
}
srs_error_t SrsDynamicHttpConn::on_http_message(ISrsHttpMessage *r, SrsHttpResponseWriter *w)
srs_error_t SrsDynamicHttpConn::on_http_message(ISrsHttpMessage *r, ISrsHttpResponseWriter *w)
{
return srs_success;
}
srs_error_t SrsDynamicHttpConn::on_message_done(ISrsHttpMessage *r, SrsHttpResponseWriter *w)
srs_error_t SrsDynamicHttpConn::on_message_done(ISrsHttpMessage *r, ISrsHttpResponseWriter *w)
{
return srs_success;
}
@ -384,7 +450,7 @@ srs_error_t SrsDynamicHttpConn::start()
{
srs_error_t err = srs_success;
bool v = _srs_config->get_http_stream_crossdomain();
bool v = config_->get_http_stream_crossdomain();
if ((err = conn_->set_crossdomain_enabled(v)) != srs_success) {
return srs_error_wrap(err, "set cors=%d", v);
}
@ -392,13 +458,23 @@ srs_error_t SrsDynamicHttpConn::start()
return conn_->start();
}
ISrsHttpFileReader::ISrsHttpFileReader()
{
}
ISrsHttpFileReader::~ISrsHttpFileReader()
{
}
SrsHttpFileReader::SrsHttpFileReader(ISrsHttpResponseReader *h)
{
http_ = h;
file_reader_ = new SrsFileReader();
}
SrsHttpFileReader::~SrsHttpFileReader()
{
srs_freep(file_reader_);
}
srs_error_t SrsHttpFileReader::open(std::string /*file*/)

View File

@ -23,6 +23,12 @@ class SrsFlvDecoder;
class SrsTcpClient;
class SrsSimpleRtmpClient;
class SrsAppCasterFlv;
class ISrsAppCasterFlv;
class ISrsAppConfig;
class ISrsAppFactory;
class ISrsBasicRtmpClient;
class ISrsProtocolReadWriter;
class ISrsHttpConn;
#include <srs_app_http_conn.hpp>
#include <srs_app_listener.hpp>
@ -30,12 +36,27 @@ class SrsAppCasterFlv;
#include <srs_kernel_file.hpp>
#include <srs_protocol_conn.hpp>
// A TCP listener, for flv stream server.
class SrsHttpFlvListener : public ISrsTcpHandler, public ISrsListener
// The http flv listener.
class ISrsHttpFlvListener : public ISrsTcpHandler, public ISrsListener
{
private:
public:
ISrsHttpFlvListener();
virtual ~ISrsHttpFlvListener();
public:
};
// A TCP listener, for flv stream server.
class SrsHttpFlvListener : public ISrsHttpFlvListener
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsTcpListener *listener_;
SrsAppCasterFlv *caster_;
ISrsAppCasterFlv *caster_;
public:
SrsHttpFlvListener();
@ -50,10 +71,26 @@ public:
virtual srs_error_t on_tcp_client(ISrsListener *listener, srs_netfd_t stfd);
};
// The stream caster for flv stream over HTTP POST.
class SrsAppCasterFlv : public ISrsTcpHandler, public ISrsResourceManager, public ISrsHttpHandler
// The http flv caster interface.
class ISrsAppCasterFlv : public ISrsTcpHandler, public ISrsResourceManager, public ISrsHttpHandler
{
private:
public:
ISrsAppCasterFlv();
virtual ~ISrsAppCasterFlv();
public:
virtual srs_error_t initialize(SrsConfDirective *c) = 0;
};
// The stream caster for flv stream over HTTP POST.
class SrsAppCasterFlv : public ISrsAppCasterFlv
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string output_;
SrsHttpServeMux *http_mux_;
std::vector<ISrsConnection *> conns_;
@ -74,7 +111,13 @@ public:
virtual bool empty();
virtual size_t size();
virtual void add(ISrsResource *conn, bool *exists = NULL);
virtual void add_with_id(const std::string &id, ISrsResource *conn);
virtual void add_with_fast_id(uint64_t id, ISrsResource *conn);
virtual void add_with_name(const std::string &name, ISrsResource *conn);
virtual ISrsResource *at(int index);
virtual ISrsResource *find_by_id(std::string id);
virtual ISrsResource *find_by_fast_id(uint64_t id);
virtual ISrsResource *find_by_name(std::string name);
virtual void remove(ISrsResource *c);
virtual void subscribe(ISrsDisposingHandler *h);
virtual void unsubscribe(ISrsDisposingHandler *h);
@ -84,18 +127,35 @@ public:
};
// The dynamic http connection, never drop the body.
class SrsDynamicHttpConn : public ISrsConnection, public ISrsStartable, public ISrsHttpConnOwner, public ISrsReloadHandler
class ISrsDynamicHttpConn : public ISrsConnection, public ISrsStartable, public ISrsHttpConnOwner
{
private:
public:
ISrsDynamicHttpConn();
virtual ~ISrsDynamicHttpConn();
public:
};
// The dynamic http connection, never drop the body.
class SrsDynamicHttpConn : public ISrsDynamicHttpConn
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The manager object to manage the connection.
ISrsResourceManager *manager_;
std::string output_;
SrsPithyPrint *pprint_;
SrsSimpleRtmpClient *sdk_;
SrsTcpConnection *skt_;
SrsHttpConn *conn_;
ISrsBasicRtmpClient *sdk_;
ISrsProtocolReadWriter *skt_;
ISrsHttpConn *conn_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The ip and port of client.
std::string ip_;
int port_;
@ -107,14 +167,15 @@ public:
public:
virtual srs_error_t proxy(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, std::string o);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_proxy(ISrsHttpResponseReader *rr, SrsFlvDecoder *dec);
// Extract APIs from SrsTcpConnection.
// Interface ISrsHttpConnOwner.
public:
virtual srs_error_t on_start();
virtual srs_error_t on_http_message(ISrsHttpMessage *r, SrsHttpResponseWriter *w);
virtual srs_error_t on_message_done(ISrsHttpMessage *r, SrsHttpResponseWriter *w);
virtual srs_error_t on_http_message(ISrsHttpMessage *r, ISrsHttpResponseWriter *w);
virtual srs_error_t on_message_done(ISrsHttpMessage *r, ISrsHttpResponseWriter *w);
virtual srs_error_t on_conn_done(srs_error_t r0);
// Interface ISrsResource.
public:
@ -129,10 +190,22 @@ public:
};
// The http wrapper for file reader, to read http post stream like a file.
class SrsHttpFileReader : public SrsFileReader
class ISrsHttpFileReader : public ISrsFileReader
{
private:
public:
ISrsHttpFileReader();
virtual ~ISrsHttpFileReader();
public:
};
// The http wrapper for file reader, to read http post stream like a file.
class SrsHttpFileReader : public ISrsHttpFileReader
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsHttpResponseReader *http_;
SrsFileReader *file_reader_;
public:
SrsHttpFileReader(ISrsHttpResponseReader *h);

View File

@ -43,27 +43,35 @@ SrsCircuitBreaker::SrsCircuitBreaker()
hybrid_high_water_level_ = 0;
hybrid_critical_water_level_ = 0;
hybrid_dying_water_level_ = 0;
host_ = new SrsHost();
config_ = _srs_config;
shared_timer_ = _srs_shared_timer;
}
SrsCircuitBreaker::~SrsCircuitBreaker()
{
srs_freep(host_);
config_ = NULL;
}
srs_error_t SrsCircuitBreaker::initialize()
{
srs_error_t err = srs_success;
enabled_ = _srs_config->get_circuit_breaker();
high_threshold_ = _srs_config->get_high_threshold();
high_pulse_ = _srs_config->get_high_pulse();
critical_threshold_ = _srs_config->get_critical_threshold();
critical_pulse_ = _srs_config->get_critical_pulse();
dying_threshold_ = _srs_config->get_dying_threshold();
dying_pulse_ = _srs_config->get_dying_pulse();
enabled_ = config_->get_circuit_breaker();
high_threshold_ = config_->get_high_threshold();
high_pulse_ = config_->get_high_pulse();
critical_threshold_ = config_->get_critical_threshold();
critical_pulse_ = config_->get_critical_pulse();
dying_threshold_ = config_->get_dying_threshold();
dying_pulse_ = config_->get_dying_pulse();
// Update the water level for circuit breaker.
// @see SrsCircuitBreaker::on_timer()
_srs_shared_timer->timer1s()->subscribe(this);
shared_timer_->timer1s()->subscribe(this);
srs_trace("CircuitBreaker: enabled=%d, high=%dx%d, critical=%dx%d, dying=%dx%d", enabled_,
high_pulse_, high_threshold_, critical_pulse_, critical_threshold_,
@ -93,7 +101,7 @@ srs_error_t SrsCircuitBreaker::on_timer(srs_utime_t interval)
// Update the CPU usage.
srs_update_proc_stat();
SrsProcSelfStat *stat = srs_get_self_proc_stat();
SrsProcSelfStat *stat = host_->self_proc_stat();
// Reset the high water-level when CPU is low for N times.
if (stat->percent_ * 100 > high_threshold_) {
@ -117,7 +125,7 @@ srs_error_t SrsCircuitBreaker::on_timer(srs_utime_t interval)
}
// Show statistics for RTC server.
SrsProcSelfStat *u = srs_get_self_proc_stat();
SrsProcSelfStat *u = host_->self_proc_stat();
// Resident Set Size: number of pages the process has in real memory.
int memory = (int)(u->rss_ * 4 / 1024);

View File

@ -11,6 +11,10 @@
#include <srs_kernel_hourglass.hpp>
class ISrsAppConfig;
class ISrsSharedTimer;
class ISrsHost;
// Interface for circuit breaker functionality to protect server in high load conditions.
// The circuit breaker monitors CPU usage and enables different levels of protection:
// - High water level: Disables some unnecessary features to reduce CPU load
@ -48,7 +52,14 @@ public:
class SrsCircuitBreaker : public ISrsCircuitBreaker, public ISrsFastTimerHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsSharedTimer *shared_timer_;
ISrsHost *host_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool enabled_;
int high_threshold_;
int high_pulse_;
@ -57,7 +68,8 @@ private:
int dying_threshold_;
int dying_pulse_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
int hybrid_high_water_level_;
int hybrid_critical_water_level_;
int hybrid_dying_water_level_;
@ -74,7 +86,8 @@ public:
bool hybrid_critical_water_level();
bool hybrid_dying_water_level();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t on_timer(srs_utime_t interval);
};

View File

@ -1878,13 +1878,6 @@ srs_error_t SrsConfig::check_normal_config()
srs_trace("srs checking config...");
////////////////////////////////////////////////////////////////////////
// check empty
////////////////////////////////////////////////////////////////////////
if (!env_only_ && root_->directives_.size() == 0) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "conf is empty");
}
////////////////////////////////////////////////////////////////////////
// check root directives.
////////////////////////////////////////////////////////////////////////
@ -2010,9 +2003,6 @@ srs_error_t SrsConfig::check_normal_config()
////////////////////////////////////////////////////////////////////////
if (true) {
vector<string> listens = get_listens();
if (!env_only_ && listens.size() <= 0) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "listen requires params");
}
for (int i = 0; i < (int)listens.size(); i++) {
if (!srs_net_is_valid_endpoint(listens[i])) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "rtmp.listen=%s is invalid", listens[i].c_str());

View File

@ -65,7 +65,8 @@ namespace srs_internal
// The buffer of config content.
class SrsConfigBuffer
{
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
// The last available position.
char *last_;
// The end of buffer.
@ -228,7 +229,8 @@ public:
virtual SrsJsonAny *dumps_arg0_to_number();
virtual SrsJsonAny *dumps_arg0_to_boolean();
// private parse.
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The directive parsing context.
enum SrsDirectiveContext {
// The root directives, parsing file.
@ -288,6 +290,8 @@ public:
virtual srs_error_t persistence() = 0;
virtual std::string config() = 0;
virtual SrsConfDirective *get_root() = 0;
// Get the current work directory.
virtual std::string cwd() = 0;
public:
// Global server config
@ -315,6 +319,22 @@ public:
virtual std::vector<std::string> get_https_api_listens() = 0;
virtual std::string get_https_api_ssl_key() = 0;
virtual std::string get_https_api_ssl_cert() = 0;
// Whether enable the HTTP RAW API.
virtual bool get_raw_api() = 0;
// Whether allow rpc reload.
virtual bool get_raw_api_allow_reload() = 0;
// Whether allow rpc query.
virtual bool get_raw_api_allow_query() = 0;
// Whether allow rpc update.
virtual bool get_raw_api_allow_update() = 0;
// Whether http api auth enabled.
virtual bool get_http_api_auth_enabled() = 0;
// Get the http api auth username.
virtual std::string get_http_api_auth_username() = 0;
// Get the http api auth password.
virtual std::string get_http_api_auth_password() = 0;
// Dumps the http_api sections to json for raw api info.
virtual srs_error_t raw_to_json(SrsJsonObject *obj) = 0;
public:
// HTTP Server config
@ -325,6 +345,7 @@ public:
virtual std::string get_https_stream_ssl_key() = 0;
virtual std::string get_https_stream_ssl_cert() = 0;
virtual std::string get_http_stream_dir() = 0;
virtual bool get_http_stream_crossdomain() = 0;
public:
// WebRTC config
@ -334,6 +355,13 @@ public:
virtual std::string get_rtc_server_protocol() = 0;
virtual std::vector<std::string> get_rtc_server_listens() = 0;
virtual int get_rtc_server_reuseport() = 0;
virtual bool get_rtc_server_encrypt() = 0;
virtual bool get_api_as_candidates() = 0;
virtual bool get_resolve_api_domain() = 0;
virtual bool get_keep_api_domain() = 0;
virtual std::string get_rtc_server_candidates() = 0;
virtual bool get_use_auto_detect_network_ip() = 0;
virtual std::string get_rtc_server_ip_family() = 0;
public:
// RTSP config
@ -349,11 +377,15 @@ public:
virtual std::vector<SrsConfDirective *> get_stream_casters() = 0;
virtual bool get_stream_caster_enabled(SrsConfDirective *conf) = 0;
virtual std::string get_stream_caster_engine(SrsConfDirective *conf) = 0;
virtual std::string get_stream_caster_output(SrsConfDirective *conf) = 0;
virtual int get_stream_caster_listen(SrsConfDirective *conf) = 0;
public:
// Exporter config
virtual bool get_exporter_enabled() = 0;
virtual std::string get_exporter_listen() = 0;
virtual std::string get_exporter_label() = 0;
virtual std::string get_exporter_tag() = 0;
public:
// Stats config
@ -364,6 +396,20 @@ public:
// Heartbeat config
virtual bool get_heartbeat_enabled() = 0;
virtual srs_utime_t get_heartbeat_interval() = 0;
virtual std::string get_heartbeat_url() = 0;
virtual std::string get_heartbeat_device_id() = 0;
virtual bool get_heartbeat_summaries() = 0;
virtual bool get_heartbeat_ports() = 0;
public:
// Circuit breaker config
virtual bool get_circuit_breaker() = 0;
virtual int get_high_threshold() = 0;
virtual int get_high_pulse() = 0;
virtual int get_critical_threshold() = 0;
virtual int get_critical_pulse() = 0;
virtual int get_dying_threshold() = 0;
virtual int get_dying_pulse() = 0;
public:
// RTMPS config
@ -372,6 +418,7 @@ public:
public:
// Vhost config
virtual void get_vhosts(std::vector<SrsConfDirective *> &vhosts) = 0;
virtual SrsConfDirective *get_vhost(std::string vhost, bool try_default_vhost = true) = 0;
virtual bool get_vhost_enabled(std::string vhost) = 0;
virtual bool get_vhost_enabled(SrsConfDirective *conf) = 0;
@ -436,9 +483,13 @@ public:
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 std::string get_srt_default_streamid() = 0;
virtual bool get_srt_to_rtmp(std::string vhost) = 0;
virtual bool get_rtc_to_rtmp(std::string vhost) = 0;
virtual srs_utime_t get_rtc_stun_timeout(std::string vhost) = 0;
virtual bool get_rtc_stun_strict_check(std::string vhost) = 0;
virtual std::string get_rtc_dtls_role(std::string vhost) = 0;
virtual std::string get_rtc_dtls_version(std::string vhost) = 0;
virtual SrsConfDirective *get_vhost_on_hls(std::string vhost) = 0;
virtual SrsConfDirective *get_vhost_on_hls_notify(std::string vhost) = 0;
virtual bool get_hls_enabled(std::string vhost) = 0;
@ -469,6 +520,16 @@ public:
virtual bool get_hls_ctx_enabled(std::string vhost) = 0;
virtual bool get_hls_ts_ctx_enabled(std::string vhost) = 0;
virtual bool get_hls_recover(std::string vhost) = 0;
virtual bool get_dash_enabled(std::string vhost) = 0;
virtual bool get_dash_enabled(SrsConfDirective *vhost) = 0;
virtual srs_utime_t get_dash_fragment(std::string vhost) = 0;
virtual srs_utime_t get_dash_update_period(std::string vhost) = 0;
virtual srs_utime_t get_dash_timeshift(std::string vhost) = 0;
virtual std::string get_dash_path(std::string vhost) = 0;
virtual std::string get_dash_mpd_file(std::string vhost) = 0;
virtual int get_dash_window_size(std::string vhost) = 0;
virtual bool get_dash_cleanup(std::string vhost) = 0;
virtual srs_utime_t get_dash_dispose(std::string vhost) = 0;
virtual bool get_forward_enabled(std::string vhost) = 0;
virtual SrsConfDirective *get_forwards(std::string vhost) = 0;
virtual srs_utime_t get_queue_length(std::string vhost) = 0;
@ -482,6 +543,12 @@ public:
virtual bool get_reduce_sequence_header(std::string vhost) = 0;
virtual bool get_parse_sps(std::string vhost) = 0;
public:
// DVR config
virtual std::string get_dvr_path(std::string vhost) = 0;
virtual int get_dvr_time_jitter(std::string vhost) = 0;
virtual bool get_dvr_wait_keyframe(std::string vhost) = 0;
public:
// HTTP remux config
virtual bool get_vhost_http_remux_enabled(std::string vhost) = 0;
@ -492,6 +559,63 @@ public:
virtual bool get_vhost_http_remux_has_video(std::string vhost) = 0;
virtual bool get_vhost_http_remux_guess_has_av(std::string vhost) = 0;
virtual std::string get_vhost_http_remux_mount(std::string vhost) = 0;
public:
virtual std::string get_vhost_edge_protocol(std::string vhost) = 0;
virtual bool get_vhost_edge_follow_client(std::string vhost) = 0;
virtual std::string get_vhost_edge_transform_vhost(std::string vhost) = 0;
virtual SrsConfDirective *get_vhost_on_dvr(std::string vhost) = 0;
virtual std::string get_dvr_plan(std::string vhost) = 0;
virtual bool get_dvr_enabled(std::string vhost) = 0;
virtual SrsConfDirective *get_dvr_apply(std::string vhost) = 0;
virtual srs_utime_t get_dvr_duration(std::string vhost) = 0;
public:
// Exec config
virtual bool get_exec_enabled(std::string vhost) = 0;
virtual std::vector<SrsConfDirective *> get_exec_publishs(std::string vhost) = 0;
public:
// Ingest config
virtual std::vector<SrsConfDirective *> get_ingesters(std::string vhost) = 0;
virtual SrsConfDirective *get_ingest_by_id(std::string vhost, std::string ingest_id) = 0;
virtual bool get_ingest_enabled(SrsConfDirective *conf) = 0;
virtual std::string get_ingest_ffmpeg(SrsConfDirective *conf) = 0;
virtual std::string get_ingest_input_type(SrsConfDirective *conf) = 0;
virtual std::string get_ingest_input_url(SrsConfDirective *conf) = 0;
public:
// FFmpeg log config
virtual bool get_ff_log_enabled() = 0;
virtual std::string get_ff_log_dir() = 0;
virtual std::string get_ff_log_level() = 0;
public:
// Transcode/Engine config
virtual SrsConfDirective *get_transcode(std::string vhost, std::string scope) = 0;
virtual bool get_transcode_enabled(SrsConfDirective *conf) = 0;
virtual std::string get_transcode_ffmpeg(SrsConfDirective *conf) = 0;
virtual std::vector<SrsConfDirective *> get_transcode_engines(SrsConfDirective *conf) = 0;
virtual bool get_engine_enabled(SrsConfDirective *conf) = 0;
virtual std::vector<std::string> get_engine_perfile(SrsConfDirective *conf) = 0;
virtual std::string get_engine_iformat(SrsConfDirective *conf) = 0;
virtual std::vector<std::string> get_engine_vfilter(SrsConfDirective *conf) = 0;
virtual std::string get_engine_vcodec(SrsConfDirective *conf) = 0;
virtual int get_engine_vbitrate(SrsConfDirective *conf) = 0;
virtual double get_engine_vfps(SrsConfDirective *conf) = 0;
virtual int get_engine_vwidth(SrsConfDirective *conf) = 0;
virtual int get_engine_vheight(SrsConfDirective *conf) = 0;
virtual int get_engine_vthreads(SrsConfDirective *conf) = 0;
virtual std::string get_engine_vprofile(SrsConfDirective *conf) = 0;
virtual std::string get_engine_vpreset(SrsConfDirective *conf) = 0;
virtual std::vector<std::string> get_engine_vparams(SrsConfDirective *conf) = 0;
virtual std::string get_engine_acodec(SrsConfDirective *conf) = 0;
virtual int get_engine_abitrate(SrsConfDirective *conf) = 0;
virtual int get_engine_asample_rate(SrsConfDirective *conf) = 0;
virtual int get_engine_achannels(SrsConfDirective *conf) = 0;
virtual std::vector<std::string> get_engine_aparams(SrsConfDirective *conf) = 0;
virtual std::string get_engine_oformat(SrsConfDirective *conf) = 0;
virtual std::string get_engine_output(SrsConfDirective *conf) = 0;
};
// The config service provider.
@ -503,7 +627,8 @@ class SrsConfig : public ISrsAppConfig
{
friend class SrsConfDirective;
// user command
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Whether show help and exit.
bool show_help_;
// Whether test config file and exit.
@ -516,29 +641,35 @@ private:
// Set it by argv "-e" or env "SRS_ENV_ONLY=on".
bool env_only_;
// global env variables.
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The user parameters, the argc and argv.
// The argv is " ".join(argv), where argv is from main(argc, argv).
std::string argv_;
// current working directory.
std::string cwd_;
// Config section
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The last parsed config file.
// If reload, reload the config file.
std::string config_file_;
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
// The directive root.
SrsConfDirective *root_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The cache for parsing the config from environment variables.
SrsConfDirective *env_cache_;
// Reload section
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The reload subscribers, when reload, callback all handlers.
std::vector<ISrsReloadHandler *> subscribes_;
std::vector<ISrsReloadHandler *>
subscribes_;
public:
SrsConfig();
@ -554,37 +685,46 @@ public:
// @remark, user can test the config before reload it.
virtual srs_error_t reload(SrsReloadState *pstate);
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
// Reload from the config.
// @remark, use protected for the utest to override with mock.
virtual srs_error_t reload_conf(SrsConfig *conf);
virtual srs_error_t
reload_conf(SrsConfig *conf);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Parse options and file
public:
// Parse the cli, the main(argc,argv) function.
virtual srs_error_t parse_options(int argc, char **argv);
virtual srs_error_t
parse_options(int argc, char **argv);
// initialize the cwd for server,
// because we may change the workdir.
virtual srs_error_t initialize_cwd();
// Marshal current config to file.
virtual srs_error_t persistence();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_persistence(SrsFileWriter *fw);
public:
// Dumps the http_api sections to json for raw api info.
virtual srs_error_t raw_to_json(SrsJsonObject *obj);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
public:
// Get the config file path.
virtual std::string config();
virtual std::string
config();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Parse each argv.
virtual srs_error_t parse_argv(int &i, char **argv);
virtual srs_error_t
parse_argv(int &i, char **argv);
// Print help and exit.
virtual void print_help(char **argv);
@ -592,23 +732,28 @@ public:
// Parse the config file, which is specified by cli.
virtual srs_error_t parse_file(const char *filename);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Build a buffer from a src, which is string content or filename.
virtual srs_error_t build_buffer(std::string src, srs_internal::SrsConfigBuffer **pbuffer);
virtual srs_error_t
build_buffer(std::string src, srs_internal::SrsConfigBuffer **pbuffer);
public:
// Check the parsed config.
virtual srs_error_t check_config();
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
virtual srs_error_t check_normal_config();
virtual srs_error_t check_number_connections();
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
// Parse config from the buffer.
// @param buffer, the config buffer, user must delete it.
// @remark, use protected for the utest to override with mock.
virtual srs_error_t parse_buffer(srs_internal::SrsConfigBuffer *buffer);
virtual srs_error_t
parse_buffer(srs_internal::SrsConfigBuffer *buffer);
// global env
public:
// Get the current work directory.
@ -628,9 +773,11 @@ public:
// Whether srs in docker.
virtual bool get_in_docker();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Whether user use full.conf
virtual bool is_full_config();
virtual bool
is_full_config();
public:
// Get the server id, generated a random one if not configured.
@ -742,7 +889,8 @@ public:
virtual bool get_rtc_server_black_hole();
virtual std::string get_rtc_server_black_hole_addr();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual int get_rtc_server_reuseport2();
public:
@ -872,9 +1020,11 @@ public:
virtual srs_utime_t get_publish_kickoff_for_idle(std::string vhost);
virtual srs_utime_t get_publish_kickoff_for_idle(SrsConfDirective *vhost);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Get the global chunk size.
virtual int get_global_chunk_size();
virtual int
get_global_chunk_size();
// forward section
public:
// Whether the forwarder enabled.
@ -925,7 +1075,8 @@ public:
// Get the default streamid when client doesn't provide one.
virtual std::string get_srt_default_streamid();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsConfDirective *get_srt(std::string vhost);
public:
@ -934,9 +1085,11 @@ public:
bool get_srt_to_rtmp(std::string vhost);
// http_hooks section
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Get the http_hooks directive of vhost.
virtual SrsConfDirective *get_vhost_http_hooks(std::string vhost);
virtual SrsConfDirective *
get_vhost_http_hooks(std::string vhost);
public:
// Whether vhost http-hooks enabled.
@ -1082,9 +1235,11 @@ public:
// @remark, we will use some variable, for instance, [vhost] to substitude with vhost.
virtual std::string get_engine_output(SrsConfDirective *conf);
// vhost exec secion
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Get the exec directive of vhost.
virtual SrsConfDirective *get_exec(std::string vhost);
virtual SrsConfDirective *
get_exec(std::string vhost);
public:
// Whether the exec is enabled of vhost.
@ -1123,7 +1278,8 @@ public:
// The ffmpeg log level.
virtual std::string get_ff_log_level();
// The MPEG-DASH section.
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual SrsConfDirective *get_dash(std::string vhost);
public:
@ -1147,9 +1303,11 @@ public:
// The timeout in srs_utime_t to dispose the dash.
virtual srs_utime_t get_dash_dispose(std::string vhost);
// hls section
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Get the hls directive of vhost.
virtual SrsConfDirective *get_hls(std::string vhost);
virtual SrsConfDirective *
get_hls(std::string vhost);
public:
// Whether HLS is enabled.
@ -1216,9 +1374,11 @@ public:
// Old fragments are kept. Default is on.
virtual bool get_hls_recover(std::string vhost);
// hds section
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Get the hds directive of vhost.
virtual SrsConfDirective *get_hds(const std::string &vhost);
virtual SrsConfDirective *
get_hds(const std::string &vhost);
public:
// Whether HDS is enabled.
@ -1232,9 +1392,11 @@ public:
// a window is a set of hds fragments.
virtual srs_utime_t get_hds_window(const std::string &vhost);
// dvr section
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Get the dvr directive.
virtual SrsConfDirective *get_dvr(std::string vhost);
virtual SrsConfDirective *
get_dvr(std::string vhost);
public:
// Whether dvr is enabled.
@ -1254,9 +1416,11 @@ public:
// Get the time_jitter algorithm for dvr.
virtual int get_dvr_time_jitter(std::string vhost);
// http api section
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Whether http api enabled
virtual bool get_http_api_enabled(SrsConfDirective *conf);
virtual bool
get_http_api_enabled(SrsConfDirective *conf);
public:
// Whether http api enabled.
@ -1280,7 +1444,8 @@ public:
// Get the http api auth password.
virtual std::string get_http_api_auth_password();
// https api section
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsConfDirective *get_https_api();
public:
@ -1289,9 +1454,11 @@ public:
virtual std::string get_https_api_ssl_key();
virtual std::string get_https_api_ssl_cert();
// http stream section
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Whether http stream enabled.
virtual bool get_http_stream_enabled(SrsConfDirective *conf);
virtual bool
get_http_stream_enabled(SrsConfDirective *conf);
public:
// Whether http stream enabled.
@ -1303,7 +1470,8 @@ public:
// Whether enable crossdomain for http static and stream server.
virtual bool get_http_stream_crossdomain();
// https api section
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsConfDirective *get_https_stream();
public:
@ -1313,7 +1481,8 @@ public:
virtual std::string get_https_stream_ssl_key();
virtual std::string get_https_stream_ssl_cert();
// rtmps section
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsConfDirective *get_rtmps();
public:
@ -1350,9 +1519,11 @@ public:
// used to generate the flv stream mount path.
virtual std::string get_vhost_http_remux_mount(std::string vhost);
// http heartbeat section
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Get the heartbeat directive.
virtual SrsConfDirective *get_heartbeat();
virtual SrsConfDirective *
get_heartbeat();
public:
// Whether heartbeat enabled.
@ -1365,11 +1536,13 @@ public:
virtual std::string get_heartbeat_device_id();
// Whether report with summaries of http api: /api/v1/summaries.
virtual bool get_heartbeat_summaries();
bool get_heartbeat_ports();
virtual bool get_heartbeat_ports();
// stats section
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Get the stats directive.
virtual SrsConfDirective *get_stats();
virtual SrsConfDirective *
get_stats();
public:
// Whether enabled stats.

View File

@ -19,13 +19,16 @@ class SrsLiveSource;
// For origin cluster.
class SrsCoWorkers
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
static SrsCoWorkers *instance_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::map<std::string, ISrsRequest *> streams_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsCoWorkers();
virtual ~SrsCoWorkers();
@ -35,7 +38,8 @@ public:
public:
virtual SrsJsonAny *dumps(std::string vhost, std::string coworker, std::string app, std::string stream);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual ISrsRequest *find_stream_info(std::string vhost, std::string app, std::string stream);
public:

View File

@ -7,6 +7,7 @@
#include <srs_app_dash.hpp>
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_rtmp_source.hpp>
#include <srs_app_utility.hpp>
#include <srs_core_autofree.hpp>
@ -35,23 +36,33 @@ string srs_time_to_utc_format_str(srs_utime_t u)
return std::string(print_buf, ret);
}
ISrsInitMp4::ISrsInitMp4()
{
}
ISrsInitMp4::~ISrsInitMp4()
{
}
SrsInitMp4::SrsInitMp4()
{
fw_ = new SrsFileWriter();
init_ = new SrsMp4M2tsInitEncoder();
fragment_ = new SrsFragment();
}
SrsInitMp4::~SrsInitMp4()
{
srs_freep(init_);
srs_freep(fw_);
srs_freep(fragment_);
}
srs_error_t SrsInitMp4::write(SrsFormat *format, bool video, int tid)
{
srs_error_t err = srs_success;
string path_tmp = tmppath();
string path_tmp = fragment_->tmppath();
if ((err = fw_->open(path_tmp)) != srs_success) {
return srs_error_wrap(err, "Open init mp4 failed, path=%s", path_tmp.c_str());
}
@ -67,19 +78,88 @@ srs_error_t SrsInitMp4::write(SrsFormat *format, bool video, int tid)
return err;
}
void SrsInitMp4::set_path(std::string v)
{
fragment_->set_path(v);
}
std::string SrsInitMp4::tmppath()
{
return fragment_->tmppath();
}
srs_error_t SrsInitMp4::rename()
{
return fragment_->rename();
}
void SrsInitMp4::append(int64_t dts)
{
fragment_->append(dts);
}
srs_error_t SrsInitMp4::create_dir()
{
return fragment_->create_dir();
}
void SrsInitMp4::set_number(uint64_t n)
{
fragment_->set_number(n);
}
uint64_t SrsInitMp4::number()
{
return fragment_->number();
}
srs_utime_t SrsInitMp4::duration()
{
return fragment_->duration();
}
srs_error_t SrsInitMp4::unlink_tmpfile()
{
return fragment_->unlink_tmpfile();
}
srs_utime_t SrsInitMp4::get_start_dts()
{
return fragment_->get_start_dts();
}
srs_error_t SrsInitMp4::unlink_file()
{
return fragment_->unlink_file();
}
ISrsFragmentedMp4::ISrsFragmentedMp4()
{
}
ISrsFragmentedMp4::~ISrsFragmentedMp4()
{
}
SrsFragmentedMp4::SrsFragmentedMp4()
{
fw_ = new SrsFileWriter();
enc_ = new SrsMp4M2tsSegmentEncoder();
fragment_ = new SrsFragment();
config_ = _srs_config;
}
SrsFragmentedMp4::~SrsFragmentedMp4()
{
srs_freep(enc_);
srs_freep(fw_);
srs_freep(fragment_);
config_ = NULL;
}
srs_error_t SrsFragmentedMp4::initialize(ISrsRequest *r, bool video, int64_t time, SrsMpdWriter *mpd, uint32_t tid)
srs_error_t SrsFragmentedMp4::initialize(ISrsRequest *r, bool video, int64_t time, ISrsMpdWriter *mpd, uint32_t tid)
{
srs_error_t err = srs_success;
@ -91,16 +171,16 @@ srs_error_t SrsFragmentedMp4::initialize(ISrsRequest *r, bool video, int64_t tim
(uint32_t)sequence_number, file_home.c_str(), file_name.c_str());
}
string home = _srs_config->get_dash_path(r->vhost_);
set_path(home + "/" + file_home + "/" + file_name);
string home = config_->get_dash_path(r->vhost_);
fragment_->set_path(home + "/" + file_home + "/" + file_name);
// Set number of the fragment, use in mpd SegmentTemplate@startNumber later.
set_number(sequence_number);
fragment_->set_number(sequence_number);
if ((err = create_dir()) != srs_success) {
if ((err = fragment_->create_dir()) != srs_success) {
return srs_error_wrap(err, "create dir");
}
string path_tmp = tmppath();
string path_tmp = fragment_->tmppath();
if ((err = fw_->open(path_tmp)) != srs_success) {
return srs_error_wrap(err, "Open fmp4 failed, path=%s", path_tmp.c_str());
}
@ -136,7 +216,7 @@ srs_error_t SrsFragmentedMp4::write(SrsMediaPacket *shared_msg, SrsFormat *forma
return err;
}
append(shared_msg->timestamp_);
fragment_->append(shared_msg->timestamp_);
return err;
}
@ -151,13 +231,76 @@ srs_error_t SrsFragmentedMp4::reap(uint64_t &dts)
srs_freep(fw_);
if ((err = rename()) != srs_success) {
if ((err = fragment_->rename()) != srs_success) {
return srs_error_wrap(err, "rename");
}
return err;
}
void SrsFragmentedMp4::set_path(std::string v)
{
fragment_->set_path(v);
}
std::string SrsFragmentedMp4::tmppath()
{
return fragment_->tmppath();
}
srs_error_t SrsFragmentedMp4::rename()
{
return fragment_->rename();
}
void SrsFragmentedMp4::append(int64_t dts)
{
fragment_->append(dts);
}
srs_error_t SrsFragmentedMp4::create_dir()
{
return fragment_->create_dir();
}
void SrsFragmentedMp4::set_number(uint64_t n)
{
fragment_->set_number(n);
}
srs_utime_t SrsFragmentedMp4::duration()
{
return fragment_->duration();
}
srs_error_t SrsFragmentedMp4::unlink_tmpfile()
{
return fragment_->unlink_tmpfile();
}
uint64_t SrsFragmentedMp4::number()
{
return fragment_->number();
}
srs_utime_t SrsFragmentedMp4::get_start_dts()
{
return fragment_->get_start_dts();
}
srs_error_t SrsFragmentedMp4::unlink_file()
{
return fragment_->unlink_file();
}
ISrsMpdWriter::ISrsMpdWriter()
{
}
ISrsMpdWriter::~ISrsMpdWriter()
{
}
SrsMpdWriter::SrsMpdWriter()
{
req_ = NULL;
@ -168,10 +311,15 @@ SrsMpdWriter::SrsMpdWriter()
video_number_ = 0;
audio_number_ = 0;
config_ = _srs_config;
app_factory_ = _srs_app_factory;
}
SrsMpdWriter::~SrsMpdWriter()
{
config_ = NULL;
app_factory_ = NULL;
}
void SrsMpdWriter::dispose()
@ -204,16 +352,16 @@ srs_error_t SrsMpdWriter::on_publish()
{
ISrsRequest *r = req_;
fragment_ = _srs_config->get_dash_fragment(r->vhost_);
update_period_ = _srs_config->get_dash_update_period(r->vhost_);
timeshit_ = _srs_config->get_dash_timeshift(r->vhost_);
home_ = _srs_config->get_dash_path(r->vhost_);
mpd_file_ = _srs_config->get_dash_mpd_file(r->vhost_);
fragment_ = config_->get_dash_fragment(r->vhost_);
update_period_ = config_->get_dash_update_period(r->vhost_);
timeshit_ = config_->get_dash_timeshift(r->vhost_);
home_ = config_->get_dash_path(r->vhost_);
mpd_file_ = config_->get_dash_mpd_file(r->vhost_);
SrsPath path;
string mpd_path = srs_path_build_stream(mpd_file_, req_->vhost_, req_->app_, req_->stream_);
fragment_home_ = path.filepath_dir(mpd_path) + "/" + req_->stream_;
window_size_ = _srs_config->get_dash_window_size(r->vhost_);
window_size_ = config_->get_dash_window_size(r->vhost_);
srs_trace("DASH: Config fragment=%dms, period=%dms, window=%d, timeshit=%dms, home=%s, mpd=%s",
srsu2msi(fragment_), srsu2msi(update_period_), window_size_, srsu2msi(timeshit_), home_.c_str(), mpd_file_.c_str());
@ -225,7 +373,7 @@ void SrsMpdWriter::on_unpublish()
{
}
srs_error_t SrsMpdWriter::write(SrsFormat *format, SrsFragmentWindow *afragments, SrsFragmentWindow *vfragments)
srs_error_t SrsMpdWriter::write(SrsFormat *format, ISrsFragmentWindow *afragments, ISrsFragmentWindow *vfragments)
{
srs_error_t err = srs_success;
@ -305,7 +453,7 @@ srs_error_t SrsMpdWriter::write(SrsFormat *format, SrsFragmentWindow *afragments
ss << " </Period>" << endl;
ss << "</MPD>" << endl;
SrsUniquePtr<SrsFileWriter> fw(new SrsFileWriter());
SrsUniquePtr<ISrsFileWriter> fw(app_factory_->create_file_writer());
string full_path_tmp = full_path + ".tmp";
if ((err = fw->open(full_path_tmp)) != srs_success) {
@ -357,6 +505,14 @@ srs_utime_t SrsMpdWriter::get_availability_start_time()
return availability_start_time_;
}
ISrsDashController::ISrsDashController()
{
}
ISrsDashController::~ISrsDashController()
{
}
SrsDashController::SrsDashController()
{
req_ = NULL;
@ -372,6 +528,9 @@ SrsDashController::SrsDashController()
first_dts_ = -1;
video_reaped_ = false;
fragment_ = 0;
app_factory_ = _srs_app_factory;
config_ = _srs_config;
}
SrsDashController::~SrsDashController()
@ -381,6 +540,9 @@ SrsDashController::~SrsDashController()
srs_freep(acurrent_);
srs_freep(vfragments_);
srs_freep(afragments_);
app_factory_ = NULL;
config_ = NULL;
}
void SrsDashController::dispose()
@ -430,8 +592,8 @@ srs_error_t SrsDashController::on_publish()
ISrsRequest *r = req_;
fragment_ = _srs_config->get_dash_fragment(r->vhost_);
home_ = _srs_config->get_dash_path(r->vhost_);
fragment_ = config_->get_dash_fragment(r->vhost_);
home_ = config_->get_dash_path(r->vhost_);
if ((err = mpd_->on_publish()) != srs_success) {
return srs_error_wrap(err, "mpd");
@ -439,11 +601,11 @@ srs_error_t SrsDashController::on_publish()
srs_freep(vcurrent_);
srs_freep(vfragments_);
vfragments_ = new SrsFragmentWindow();
vfragments_ = app_factory_->create_fragment_window();
srs_freep(acurrent_);
srs_freep(afragments_);
afragments_ = new SrsFragmentWindow();
afragments_ = app_factory_->create_fragment_window();
audio_dts_ = 0;
video_dts_ = 0;
@ -498,7 +660,7 @@ srs_error_t SrsDashController::on_audio(SrsMediaPacket *shared_audio, SrsFormat
audio_dts_ = shared_audio->timestamp_;
if (!acurrent_) {
acurrent_ = new SrsFragmentedMp4();
acurrent_ = app_factory_->create_fragmented_mp4();
if ((err = acurrent_->initialize(req_, false, audio_dts_ * SRS_UTIME_MILLISECONDS, mpd_, audio_track_id_)) != srs_success) {
return srs_error_wrap(err, "Initialize the audio fragment failed");
@ -521,7 +683,7 @@ srs_error_t SrsDashController::on_audio(SrsMediaPacket *shared_audio, SrsFormat
}
afragments_->append(acurrent_);
acurrent_ = new SrsFragmentedMp4();
acurrent_ = app_factory_->create_fragmented_mp4();
if ((err = acurrent_->initialize(req_, false, audio_dts_ * SRS_UTIME_MILLISECONDS, mpd_, audio_track_id_)) != srs_success) {
return srs_error_wrap(err, "Initialize the audio fragment failed");
@ -536,8 +698,8 @@ srs_error_t SrsDashController::on_audio(SrsMediaPacket *shared_audio, SrsFormat
return srs_error_wrap(err, "Write audio to fragment failed");
}
srs_utime_t fragment = _srs_config->get_dash_fragment(req_->vhost_);
int window_size = _srs_config->get_dash_window_size(req_->vhost_);
srs_utime_t fragment = config_->get_dash_fragment(req_->vhost_);
int window_size = config_->get_dash_window_size(req_->vhost_);
int dash_window = 2 * window_size * fragment;
if (afragments_->size() > window_size) {
int w = 0;
@ -550,7 +712,7 @@ srs_error_t SrsDashController::on_audio(SrsMediaPacket *shared_audio, SrsFormat
afragments_->shrink(dash_window);
}
bool dash_cleanup = _srs_config->get_dash_cleanup(req_->vhost_);
bool dash_cleanup = config_->get_dash_cleanup(req_->vhost_);
// remove the m4s file.
afragments_->clear_expired(dash_cleanup);
@ -570,7 +732,7 @@ srs_error_t SrsDashController::on_video(SrsMediaPacket *shared_video, SrsFormat
video_dts_ = shared_video->timestamp_;
if (!vcurrent_) {
vcurrent_ = new SrsFragmentedMp4();
vcurrent_ = app_factory_->create_fragmented_mp4();
if ((err = vcurrent_->initialize(req_, true, video_dts_ * SRS_UTIME_MILLISECONDS, mpd_, video_track_id_)) != srs_success) {
return srs_error_wrap(err, "Initialize the video fragment failed");
@ -594,7 +756,7 @@ srs_error_t SrsDashController::on_video(SrsMediaPacket *shared_video, SrsFormat
video_reaped_ = true;
vfragments_->append(vcurrent_);
vcurrent_ = new SrsFragmentedMp4();
vcurrent_ = app_factory_->create_fragmented_mp4();
if ((err = vcurrent_->initialize(req_, true, video_dts_ * SRS_UTIME_MILLISECONDS, mpd_, video_track_id_)) != srs_success) {
return srs_error_wrap(err, "Initialize the video fragment failed");
@ -609,8 +771,8 @@ srs_error_t SrsDashController::on_video(SrsMediaPacket *shared_video, SrsFormat
return srs_error_wrap(err, "Write video to fragment failed");
}
srs_utime_t fragment = _srs_config->get_dash_fragment(req_->vhost_);
int window_size = _srs_config->get_dash_window_size(req_->vhost_);
srs_utime_t fragment = config_->get_dash_fragment(req_->vhost_);
int window_size = config_->get_dash_window_size(req_->vhost_);
int dash_window = 2 * window_size * fragment;
if (vfragments_->size() > window_size) {
int w = 0;
@ -623,7 +785,7 @@ srs_error_t SrsDashController::on_video(SrsMediaPacket *shared_video, SrsFormat
vfragments_->shrink(dash_window);
}
bool dash_cleanup = _srs_config->get_dash_cleanup(req_->vhost_);
bool dash_cleanup = config_->get_dash_cleanup(req_->vhost_);
// remove the m4s file.
vfragments_->clear_expired(dash_cleanup);
@ -668,7 +830,7 @@ srs_error_t SrsDashController::refresh_init_mp4(SrsMediaPacket *msg, SrsFormat *
path += "/audio-init.mp4";
}
SrsUniquePtr<SrsInitMp4> init_mp4(new SrsInitMp4());
SrsUniquePtr<ISrsInitMp4> init_mp4(app_factory_->create_init_mp4());
init_mp4->set_path(path);
@ -703,11 +865,15 @@ SrsDash::SrsDash()
enabled_ = false;
disposable_ = false;
last_update_time_ = 0;
config_ = _srs_config;
}
SrsDash::~SrsDash()
{
srs_freep(controller_);
config_ = NULL;
}
void SrsDash::dispose()
@ -717,7 +883,7 @@ void SrsDash::dispose()
}
// Ignore when dash_dispose disabled.
srs_utime_t dash_dispose = _srs_config->get_dash_dispose(req_->vhost_);
srs_utime_t dash_dispose = config_->get_dash_dispose(req_->vhost_);
if (!dash_dispose) {
return;
}
@ -737,7 +903,7 @@ srs_error_t SrsDash::cycle()
return err;
}
srs_utime_t dash_dispose = _srs_config->get_dash_dispose(req_->vhost_);
srs_utime_t dash_dispose = config_->get_dash_dispose(req_->vhost_);
if (dash_dispose <= 0) {
return err;
}
@ -760,7 +926,7 @@ srs_error_t SrsDash::cycle()
srs_utime_t SrsDash::cleanup_delay()
{
// We use larger timeout to cleanup the HLS, after disposed it if required.
return _srs_config->get_dash_dispose(req_->vhost_) * 1.1;
return config_->get_dash_dispose(req_->vhost_) * 1.1;
}
// CRITICAL: This method is called AFTER the source has been added to the source pool
@ -769,7 +935,7 @@ srs_utime_t SrsDash::cleanup_delay()
// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches.
// This prevents the race condition where multiple coroutines could create duplicate sources
// for the same stream when context switches occurred during initialization.
srs_error_t SrsDash::initialize(SrsOriginHub *h, ISrsRequest *r)
srs_error_t SrsDash::initialize(ISrsOriginHub *h, ISrsRequest *r)
{
srs_error_t err = srs_success;
@ -792,7 +958,7 @@ srs_error_t SrsDash::on_publish()
return err;
}
if (!_srs_config->get_dash_enabled(req_->vhost_)) {
if (!config_->get_dash_enabled(req_->vhost_)) {
return err;
}
enabled_ = true;

View File

@ -16,19 +16,44 @@
class ISrsRequest;
class SrsOriginHub;
class ISrsOriginHub;
class SrsMediaPacket;
class SrsFormat;
class SrsFileWriter;
class ISrsFileWriter;
class SrsMpdWriter;
class ISrsMpdWriter;
class SrsMp4M2tsInitEncoder;
class ISrsMp4M2tsInitEncoder;
class SrsMp4M2tsSegmentEncoder;
class ISrsMp4M2tsSegmentEncoder;
class SrsFragment;
class ISrsFragment;
class ISrsAppFactory;
class ISrsDashController;
class ISrsFragmentWindow;
class ISrsAppConfig;
// The init mp4 fragment interface.
class ISrsInitMp4 : public ISrsFragment
{
public:
ISrsInitMp4();
virtual ~ISrsInitMp4();
public:
// Write the init mp4 file, with the tid(track id).
virtual srs_error_t write(SrsFormat *format, bool video, int tid) = 0;
};
// The init mp4 for FMP4.
class SrsInitMp4 : public SrsFragment
class SrsInitMp4 : public ISrsInitMp4
{
private:
SrsFileWriter *fw_;
SrsMp4M2tsInitEncoder *init_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsFileWriter *fw_;
ISrsMp4M2tsInitEncoder *init_;
ISrsFragment *fragment_;
public:
SrsInitMp4();
@ -37,14 +62,50 @@ public:
public:
// Write the init mp4 file, with the tid(track id).
virtual srs_error_t write(SrsFormat *format, bool video, int tid);
public:
// ISrsFragment interface implementations - delegate to fragment_
virtual void set_path(std::string v);
virtual std::string tmppath();
virtual srs_error_t rename();
virtual void append(int64_t dts);
virtual srs_error_t create_dir();
virtual void set_number(uint64_t n);
virtual uint64_t number();
virtual srs_utime_t duration();
virtual srs_error_t unlink_tmpfile();
virtual srs_utime_t get_start_dts();
virtual srs_error_t unlink_file();
};
// The FMP4(Fragmented MP4) for DASH streaming.
class SrsFragmentedMp4 : public SrsFragment
class ISrsFragmentedMp4 : public ISrsFragment
{
private:
SrsFileWriter *fw_;
SrsMp4M2tsSegmentEncoder *enc_;
public:
ISrsFragmentedMp4();
virtual ~ISrsFragmentedMp4();
public:
// Initialize the fragment, create the home dir, open the file.
virtual srs_error_t initialize(ISrsRequest *r, bool video, int64_t time, ISrsMpdWriter *mpd, uint32_t tid) = 0;
// Write media message to fragment.
virtual srs_error_t write(SrsMediaPacket *shared_msg, SrsFormat *format) = 0;
// Reap the fragment, close the fd and rename tmp to official file.
virtual srs_error_t reap(uint64_t &dts) = 0;
};
// The FMP4(Fragmented MP4) for DASH streaming.
class SrsFragmentedMp4 : public ISrsFragmentedMp4
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsFileWriter *fw_;
ISrsMp4M2tsSegmentEncoder *enc_;
ISrsFragment *fragment_;
public:
SrsFragmentedMp4();
@ -52,20 +113,67 @@ public:
public:
// Initialize the fragment, create the home dir, open the file.
virtual srs_error_t initialize(ISrsRequest *r, bool video, int64_t time, SrsMpdWriter *mpd, uint32_t tid);
virtual srs_error_t initialize(ISrsRequest *r, bool video, int64_t time, ISrsMpdWriter *mpd, uint32_t tid);
// Write media message to fragment.
virtual srs_error_t write(SrsMediaPacket *shared_msg, SrsFormat *format);
// Reap the fragment, close the fd and rename tmp to official file.
virtual srs_error_t reap(uint64_t &dts);
public:
// ISrsFragment interface implementations - delegate to fragment_
virtual void set_path(std::string v);
virtual std::string tmppath();
virtual srs_error_t rename();
virtual void append(int64_t dts);
virtual srs_error_t create_dir();
virtual void set_number(uint64_t n);
virtual uint64_t number();
virtual srs_utime_t duration();
virtual srs_error_t unlink_tmpfile();
virtual srs_utime_t get_start_dts();
virtual srs_error_t unlink_file();
};
// The writer to write MPD for DASH.
class SrsMpdWriter
class ISrsMpdWriter
{
private:
public:
ISrsMpdWriter();
virtual ~ISrsMpdWriter();
public:
virtual void dispose() = 0;
public:
virtual srs_error_t initialize(ISrsRequest *r) = 0;
virtual srs_error_t on_publish() = 0;
virtual void on_unpublish() = 0;
// Write MPD according to parsed format of stream.
virtual srs_error_t write(SrsFormat *format, ISrsFragmentWindow *afragments, ISrsFragmentWindow *vfragments) = 0;
public:
// Get the fragment relative home and filename.
// The basetime is the absolute time in srs_utime_t, while the sn(sequence number) is basetime/fragment.
virtual srs_error_t get_fragment(bool video, std::string &home, std::string &filename, int64_t time, int64_t &sn) = 0;
// Set the availabilityStartTime once, map the timestamp in media to utc time.
virtual void set_availability_start_time(srs_utime_t t) = 0;
virtual srs_utime_t get_availability_start_time() = 0;
};
// The writer to write MPD for DASH.
class SrsMpdWriter : public ISrsMpdWriter
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The duration of fragment in srs_utime_t.
srs_utime_t fragment_;
// The period to update the mpd in srs_utime_t.
@ -85,7 +193,8 @@ private:
// The number of current audio segment.
uint64_t audio_number_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The home for fragment, relative to home.
std::string fragment_home_;
@ -101,7 +210,7 @@ public:
virtual srs_error_t on_publish();
virtual void on_unpublish();
// Write MPD according to parsed format of stream.
virtual srs_error_t write(SrsFormat *format, SrsFragmentWindow *afragments, SrsFragmentWindow *vfragments);
virtual srs_error_t write(SrsFormat *format, ISrsFragmentWindow *afragments, ISrsFragmentWindow *vfragments);
public:
// Get the fragment relative home and filename.
@ -112,19 +221,44 @@ public:
virtual srs_utime_t get_availability_start_time();
};
// The controller for DASH, control the MPD and FMP4 generating system.
class SrsDashController
// The DASH controller interface.
class ISrsDashController
{
private:
public:
ISrsDashController();
virtual ~ISrsDashController();
public:
virtual void dispose() = 0;
public:
virtual srs_error_t initialize(ISrsRequest *r) = 0;
virtual srs_error_t on_publish() = 0;
virtual void on_unpublish() = 0;
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio, SrsFormat *format) = 0;
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format) = 0;
};
// The controller for DASH, control the MPD and FMP4 generating system.
class SrsDashController : public ISrsDashController
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
SrsFormat *format_;
SrsMpdWriter *mpd_;
ISrsMpdWriter *mpd_;
private:
SrsFragmentedMp4 *vcurrent_;
SrsFragmentWindow *vfragments_;
SrsFragmentedMp4 *acurrent_;
SrsFragmentWindow *afragments_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsFragmentedMp4 *vcurrent_;
ISrsFragmentWindow *vfragments_;
ISrsFragmentedMp4 *acurrent_;
ISrsFragmentWindow *afragments_;
// Current audio dts.
uint64_t audio_dts_;
// Current video dts.
@ -134,11 +268,13 @@ private:
// Had the video reaped, use to align audio/video segment's timestamp.
bool video_reaped_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The fragment duration in srs_utime_t to reap it.
srs_utime_t fragment_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string home_;
int video_track_id_;
int audio_track_id_;
@ -157,7 +293,8 @@ public:
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio, SrsFormat *format);
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t refresh_mpd(SrsFormat *format);
virtual srs_error_t refresh_init_mp4(SrsMediaPacket *msg, SrsFormat *format);
};
@ -175,7 +312,7 @@ public:
virtual srs_utime_t cleanup_delay() = 0;
public:
virtual srs_error_t initialize(SrsOriginHub *h, ISrsRequest *r) = 0;
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsRequest *r) = 0;
virtual srs_error_t on_publish() = 0;
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio, SrsFormat *format) = 0;
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format) = 0;
@ -185,15 +322,21 @@ public:
// The MPEG-DASH encoder, transmux RTMP to DASH.
class SrsDash : public ISrsDash
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool enabled_;
bool disposable_;
srs_utime_t last_update_time_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
SrsOriginHub *hub_;
SrsDashController *controller_;
ISrsOriginHub *hub_;
ISrsDashController *controller_;
public:
SrsDash();
@ -206,7 +349,7 @@ public:
public:
// Initalize the encoder.
virtual srs_error_t initialize(SrsOriginHub *h, ISrsRequest *r);
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsRequest *r);
// When stream start publishing.
virtual srs_error_t on_publish();
// When got an shared audio message.

View File

@ -12,6 +12,7 @@
using namespace std;
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_fragment.hpp>
#include <srs_app_http_hooks.hpp>
#include <srs_app_utility.hpp>
@ -28,6 +29,14 @@ using namespace std;
#define SRS_FWRITE_CACHE_SIZE 65536
ISrsDvrSegmenter::ISrsDvrSegmenter()
{
}
ISrsDvrSegmenter::~ISrsDvrSegmenter()
{
}
SrsDvrSegmenter::SrsDvrSegmenter()
{
req_ = NULL;
@ -39,16 +48,23 @@ SrsDvrSegmenter::SrsDvrSegmenter()
fs_ = new SrsFileWriter();
jitter_algorithm_ = SrsRtmpJitterAlgorithmOFF;
_srs_config->subscribe(this);
config_ = _srs_config;
}
void SrsDvrSegmenter::assemble()
{
config_->subscribe(this);
}
SrsDvrSegmenter::~SrsDvrSegmenter()
{
_srs_config->unsubscribe(this);
config_->unsubscribe(this);
srs_freep(fragment_);
srs_freep(jitter_);
srs_freep(fs_);
config_ = NULL;
}
// CRITICAL: This method is called AFTER the source has been added to the source pool
@ -57,13 +73,13 @@ SrsDvrSegmenter::~SrsDvrSegmenter()
// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches.
// This prevents the race condition where multiple coroutines could create duplicate sources
// for the same stream when context switches occurred during initialization.
srs_error_t SrsDvrSegmenter::initialize(SrsDvrPlan *p, ISrsRequest *r)
srs_error_t SrsDvrSegmenter::initialize(ISrsDvrPlan *p, ISrsRequest *r)
{
req_ = r;
plan_ = p;
jitter_algorithm_ = (SrsRtmpJitterAlgorithm)_srs_config->get_dvr_time_jitter(req_->vhost_);
wait_keyframe_ = _srs_config->get_dvr_wait_keyframe(req_->vhost_);
jitter_algorithm_ = (SrsRtmpJitterAlgorithm)config_->get_dvr_time_jitter(req_->vhost_);
wait_keyframe_ = config_->get_dvr_wait_keyframe(req_->vhost_);
return srs_success;
}
@ -201,7 +217,7 @@ string SrsDvrSegmenter::generate_path()
{
// the path in config, for example,
// /data/[vhost]/[app]/[stream]/[2006]/[01]/[02]/[15].[04].[05].[999].flv
std::string path_config = _srs_config->get_dvr_path(req_->vhost_);
std::string path_config = config_->get_dvr_path(req_->vhost_);
// add [stream].[timestamp].flv as filename for dir
if (!srs_strings_ends_with(path_config, ".flv", ".mp4")) {
@ -230,11 +246,15 @@ SrsDvrFlvSegmenter::SrsDvrFlvSegmenter()
filesize_offset_ = 0;
has_keyframe_ = false;
app_factory_ = _srs_app_factory;
}
SrsDvrFlvSegmenter::~SrsDvrFlvSegmenter()
{
srs_freep(enc_);
app_factory_ = NULL;
}
srs_error_t SrsDvrFlvSegmenter::refresh_metadata()
@ -297,7 +317,7 @@ srs_error_t SrsDvrFlvSegmenter::open_encoder()
filesize_offset_ = 0;
srs_freep(enc_);
enc_ = new SrsFlvTransmuxer();
enc_ = app_factory_->create_flv_transmuxer();
if ((err = enc_->initialize(fs_)) != srs_success) {
return srs_error_wrap(err, "init encoder");
@ -414,11 +434,15 @@ srs_error_t SrsDvrFlvSegmenter::close_encoder()
SrsDvrMp4Segmenter::SrsDvrMp4Segmenter()
{
enc_ = new SrsMp4Encoder();
app_factory_ = _srs_app_factory;
}
SrsDvrMp4Segmenter::~SrsDvrMp4Segmenter()
{
srs_freep(enc_);
app_factory_ = NULL;
}
srs_error_t SrsDvrMp4Segmenter::refresh_metadata()
@ -431,7 +455,7 @@ srs_error_t SrsDvrMp4Segmenter::open_encoder()
srs_error_t err = srs_success;
srs_freep(enc_);
enc_ = new SrsMp4Encoder();
enc_ = app_factory_->create_mp4_encoder();
if ((err = enc_->initialize(fs_)) != srs_success) {
return srs_error_wrap(err, "init encoder");
@ -456,10 +480,7 @@ srs_error_t SrsDvrMp4Segmenter::encode_audio(SrsMediaPacket *audio, SrsFormat *f
SrsAudioAacFrameTrait ct = format->audio_->aac_packet_type_;
if (ct == SrsAudioAacFrameTraitSequenceHeader || ct == SrsAudioMp3FrameTraitSequenceHeader) {
enc_->acodec_ = sound_format;
enc_->sample_rate_ = sound_rate;
enc_->sound_bits_ = sound_size;
enc_->channels_ = channels;
enc_->set_audio_codec(sound_format, sound_rate, sound_size, channels);
}
uint8_t *sample = (uint8_t *)format->raw_;
@ -515,18 +536,24 @@ SrsDvrAsyncCallOnDvr::SrsDvrAsyncCallOnDvr(SrsContextId c, ISrsRequest *r, strin
cid_ = c;
req_ = r->copy();
path_ = p;
hooks_ = _srs_hooks;
config_ = _srs_config;
}
SrsDvrAsyncCallOnDvr::~SrsDvrAsyncCallOnDvr()
{
srs_freep(req_);
hooks_ = NULL;
config_ = NULL;
}
srs_error_t SrsDvrAsyncCallOnDvr::call()
{
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;
}
@ -536,7 +563,7 @@ srs_error_t SrsDvrAsyncCallOnDvr::call()
vector<string> hooks;
if (true) {
SrsConfDirective *conf = _srs_config->get_vhost_on_dvr(req_->vhost_);
SrsConfDirective *conf = config_->get_vhost_on_dvr(req_->vhost_);
if (conf) {
hooks = conf->args_;
}
@ -544,7 +571,7 @@ srs_error_t SrsDvrAsyncCallOnDvr::call()
for (int i = 0; i < (int)hooks.size(); i++) {
std::string url = hooks.at(i);
if ((err = _srs_hooks->on_dvr(cid_, url, req_, path_)) != srs_success) {
if ((err = hooks_->on_dvr(cid_, url, req_, path_)) != srs_success) {
return srs_error_wrap(err, "callback on_dvr %s", url.c_str());
}
}
@ -559,6 +586,14 @@ string SrsDvrAsyncCallOnDvr::to_string()
return ss.str();
}
ISrsDvrPlan::ISrsDvrPlan()
{
}
ISrsDvrPlan::~ISrsDvrPlan()
{
}
SrsDvrPlan::SrsDvrPlan()
{
req_ = NULL;
@ -566,12 +601,18 @@ SrsDvrPlan::SrsDvrPlan()
dvr_enabled_ = false;
segment_ = NULL;
async_ = _srs_dvr_async;
config_ = _srs_config;
}
SrsDvrPlan::~SrsDvrPlan()
{
srs_freep(segment_);
srs_freep(req_);
async_ = NULL;
config_ = NULL;
}
// CRITICAL: This method is called AFTER the source has been added to the source pool
@ -580,7 +621,7 @@ SrsDvrPlan::~SrsDvrPlan()
// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches.
// This prevents the race condition where multiple coroutines could create duplicate sources
// for the same stream when context switches occurred during initialization.
srs_error_t SrsDvrPlan::initialize(SrsOriginHub *h, SrsDvrSegmenter *s, ISrsRequest *r)
srs_error_t SrsDvrPlan::initialize(ISrsOriginHub *h, ISrsDvrSegmenter *s, ISrsRequest *r)
{
srs_error_t err = srs_success;
@ -658,7 +699,7 @@ srs_error_t SrsDvrPlan::on_reap_segment()
SrsFragment *fragment = segment_->current();
string fullpath = fragment->fullpath();
if ((err = _srs_dvr_async->execute(new SrsDvrAsyncCallOnDvr(cid, req_, fullpath))) != srs_success) {
if ((err = async_->execute(new SrsDvrAsyncCallOnDvr(cid, req_, fullpath))) != srs_success) {
return srs_error_wrap(err, "reap segment");
}
@ -671,9 +712,9 @@ srs_error_t SrsDvrPlan::on_reap_segment()
// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches.
// This prevents the race condition where multiple coroutines could create duplicate sources
// for the same stream when context switches occurred during initialization.
srs_error_t SrsDvrPlan::create_plan(string vhost, SrsDvrPlan **pplan)
srs_error_t SrsDvrPlan::create_plan(ISrsAppConfig *config, string vhost, ISrsDvrPlan **pplan)
{
std::string plan = _srs_config->get_dvr_plan(vhost);
std::string plan = config->get_dvr_plan(vhost);
if (srs_config_dvr_is_plan_segment(plan)) {
*pplan = new SrsDvrSegmentPlan();
} else if (srs_config_dvr_is_plan_session(plan)) {
@ -707,7 +748,7 @@ srs_error_t SrsDvrSessionPlan::on_publish(ISrsRequest *r)
return err;
}
if (!_srs_config->get_dvr_enabled(req_->vhost_)) {
if (!config_->get_dvr_enabled(req_->vhost_)) {
return err;
}
@ -734,7 +775,7 @@ void SrsDvrSessionPlan::on_unpublish()
// ignore error.
srs_error_t err = segment_->close();
if (err != srs_success) {
srs_warn("ignore flv close error %s", srs_error_desc(err).c_str());
srs_warn("ignore dvr segment close failed. ret=%d", srs_error_code(err));
srs_freep(err);
}
@ -756,7 +797,7 @@ SrsDvrSegmentPlan::~SrsDvrSegmentPlan()
{
}
srs_error_t SrsDvrSegmentPlan::initialize(SrsOriginHub *h, SrsDvrSegmenter *s, ISrsRequest *r)
srs_error_t SrsDvrSegmentPlan::initialize(ISrsOriginHub *h, ISrsDvrSegmenter *s, ISrsRequest *r)
{
srs_error_t err = srs_success;
@ -764,9 +805,9 @@ srs_error_t SrsDvrSegmentPlan::initialize(SrsOriginHub *h, SrsDvrSegmenter *s, I
return srs_error_wrap(err, "segment plan");
}
wait_keyframe_ = _srs_config->get_dvr_wait_keyframe(req_->vhost_);
wait_keyframe_ = config_->get_dvr_wait_keyframe(req_->vhost_);
cduration_ = _srs_config->get_dvr_duration(req_->vhost_);
cduration_ = config_->get_dvr_duration(req_->vhost_);
return srs_success;
}
@ -784,7 +825,7 @@ srs_error_t SrsDvrSegmentPlan::on_publish(ISrsRequest *r)
return err;
}
if (!_srs_config->get_dvr_enabled(req_->vhost_)) {
if (!config_->get_dvr_enabled(req_->vhost_)) {
return err;
}
@ -919,15 +960,24 @@ SrsDvr::SrsDvr()
req_ = NULL;
actived_ = false;
_srs_config->subscribe(this);
config_ = _srs_config;
app_factory_ = _srs_app_factory;
}
void SrsDvr::assemble()
{
config_->subscribe(this);
}
SrsDvr::~SrsDvr()
{
_srs_config->unsubscribe(this);
config_->unsubscribe(this);
srs_freep(plan_);
srs_freep(req_);
config_ = NULL;
app_factory_ = NULL;
}
// CRITICAL: This method is called AFTER the source has been added to the source pool
@ -936,28 +986,29 @@ SrsDvr::~SrsDvr()
// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches.
// This prevents the race condition where multiple coroutines could create duplicate sources
// for the same stream when context switches occurred during initialization.
srs_error_t SrsDvr::initialize(SrsOriginHub *h, ISrsRequest *r)
srs_error_t SrsDvr::initialize(ISrsOriginHub *h, ISrsRequest *r)
{
srs_error_t err = srs_success;
req_ = r->copy();
hub_ = h;
SrsConfDirective *conf = _srs_config->get_dvr_apply(r->vhost_);
SrsConfDirective *conf = config_->get_dvr_apply(r->vhost_);
actived_ = srs_config_apply_filter(conf, r);
srs_freep(plan_);
if ((err = SrsDvrPlan::create_plan(r->vhost_, &plan_)) != srs_success) {
if ((err = SrsDvrPlan::create_plan(config_, r->vhost_, &plan_)) != srs_success) {
return srs_error_wrap(err, "create plan");
}
std::string path = _srs_config->get_dvr_path(r->vhost_);
SrsDvrSegmenter *segmenter = NULL;
std::string path = config_->get_dvr_path(r->vhost_);
ISrsDvrSegmenter *segmenter = NULL;
if (srs_strings_ends_with(path, ".mp4")) {
segmenter = new SrsDvrMp4Segmenter();
segmenter = app_factory_->create_dvr_mp4_segmenter();
} else {
segmenter = new SrsDvrFlvSegmenter();
segmenter = app_factory_->create_dvr_flv_segmenter();
}
segmenter->assemble();
if ((err = plan_->initialize(hub_, segmenter, r)) != srs_success) {
return srs_error_wrap(err, "plan initialize");

View File

@ -27,37 +27,70 @@ class SrsThread;
class SrsMp4Encoder;
class SrsFragment;
class SrsFormat;
class ISrsFileWriter;
class ISrsDvrPlan;
class ISrsMp4Encoder;
class ISrsOriginHub;
class ISrsAppConfig;
class ISrsAppFactory;
class ISrsAsyncCallWorker;
#include <srs_app_async_call.hpp>
#include <srs_app_reload.hpp>
#include <srs_app_rtmp_source.hpp>
// The segmenter for DVR, to write a segment file in flv/mp4.
class SrsDvrSegmenter : public ISrsReloadHandler
// The segmenter interface.
class ISrsDvrSegmenter
{
protected:
public:
ISrsDvrSegmenter();
virtual void assemble() = 0;
virtual ~ISrsDvrSegmenter();
public:
virtual srs_error_t initialize(ISrsDvrPlan *p, ISrsRequest *r) = 0;
virtual SrsFragment *current() = 0;
virtual srs_error_t open() = 0;
virtual srs_error_t write_metadata(SrsMediaPacket *metadata) = 0;
virtual srs_error_t write_audio(SrsMediaPacket *shared_audio, SrsFormat *format) = 0;
virtual srs_error_t write_video(SrsMediaPacket *shared_video, SrsFormat *format) = 0;
virtual srs_error_t close() = 0;
};
// The segmenter for DVR, to write a segment file in flv/mp4.
class SrsDvrSegmenter : public ISrsReloadHandler, public ISrsDvrSegmenter
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
// The underlayer file object.
SrsFileWriter *fs_;
ISrsFileWriter *fs_;
// Whether wait keyframe to reap segment.
bool wait_keyframe_;
// The FLV/MP4 fragment file.
SrsFragment *fragment_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
SrsDvrPlan *plan_;
ISrsDvrPlan *plan_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsRtmpJitter *jitter_;
SrsRtmpJitterAlgorithm jitter_algorithm_;
public:
SrsDvrSegmenter();
void assemble();
virtual ~SrsDvrSegmenter();
public:
// Initialize the segment.
virtual srs_error_t initialize(SrsDvrPlan *p, ISrsRequest *r);
virtual srs_error_t initialize(ISrsDvrPlan *p, ISrsRequest *r);
// Get the current framgnet.
virtual SrsFragment *current();
// Open new segment file.
@ -80,16 +113,19 @@ public:
// @remark ignore when already closed.
virtual srs_error_t close();
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
virtual srs_error_t open_encoder() = 0;
virtual srs_error_t encode_metadata(SrsMediaPacket *metadata) = 0;
virtual srs_error_t encode_audio(SrsMediaPacket *audio, SrsFormat *format) = 0;
virtual srs_error_t encode_video(SrsMediaPacket *video, SrsFormat *format) = 0;
virtual srs_error_t close_encoder() = 0;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Generate the flv segment path.
virtual std::string generate_path();
virtual std::string
generate_path();
// When update the duration of segment by rtmp msg.
virtual srs_error_t on_update_duration(SrsMediaPacket *msg);
};
@ -97,11 +133,17 @@ private:
// The FLV segmenter to use FLV encoder to write file.
class SrsDvrFlvSegmenter : public SrsDvrSegmenter
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The FLV encoder, for FLV target.
ISrsFlvTransmuxer *enc_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The offset of file for duration value.
// The next 8 bytes is the double value.
int64_t duration_offset_;
@ -118,7 +160,8 @@ public:
public:
virtual srs_error_t refresh_metadata();
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
virtual srs_error_t open_encoder();
virtual srs_error_t encode_metadata(SrsMediaPacket *metadata);
virtual srs_error_t encode_audio(SrsMediaPacket *audio, SrsFormat *format);
@ -129,9 +172,14 @@ protected:
// The MP4 segmenter to use MP4 encoder to write file.
class SrsDvrMp4Segmenter : public SrsDvrSegmenter
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The MP4 encoder, for MP4 target.
SrsMp4Encoder *enc_;
ISrsMp4Encoder *enc_;
public:
SrsDvrMp4Segmenter();
@ -140,7 +188,8 @@ public:
public:
virtual srs_error_t refresh_metadata();
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
virtual srs_error_t open_encoder();
virtual srs_error_t encode_metadata(SrsMediaPacket *metadata);
virtual srs_error_t encode_audio(SrsMediaPacket *audio, SrsFormat *format);
@ -151,7 +200,13 @@ protected:
// the dvr async call.
class SrsDvrAsyncCallOnDvr : public ISrsAsyncCallTask
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsHttpHooks *hooks_;
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsContextId cid_;
std::string path_;
ISrsRequest *req_;
@ -165,15 +220,38 @@ public:
virtual std::string to_string();
};
// The DVR plan, when and how to reap segment.
class SrsDvrPlan : public ISrsReloadHandler
// The DVR plan interface.
class ISrsDvrPlan
{
public:
ISrsDvrPlan();
virtual ~ISrsDvrPlan();
public:
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsDvrSegmenter *s, ISrsRequest *r) = 0;
virtual srs_error_t on_publish(ISrsRequest *r) = 0;
virtual void on_unpublish() = 0;
virtual srs_error_t on_meta_data(SrsMediaPacket *shared_metadata) = 0;
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio, SrsFormat *format) = 0;
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format) = 0;
virtual srs_error_t on_reap_segment() = 0;
};
// The DVR plan, when and how to reap segment.
class SrsDvrPlan : public ISrsReloadHandler, public ISrsDvrPlan
{
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
ISrsAsyncCallWorker *async_;
ISrsAppConfig *config_;
public:
ISrsRequest *req_;
protected:
SrsOriginHub *hub_;
SrsDvrSegmenter *segment_;
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
ISrsOriginHub *hub_;
ISrsDvrSegmenter *segment_;
bool dvr_enabled_;
public:
@ -181,7 +259,7 @@ public:
virtual ~SrsDvrPlan();
public:
virtual srs_error_t initialize(SrsOriginHub *h, SrsDvrSegmenter *s, ISrsRequest *r);
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsDvrSegmenter *s, ISrsRequest *r);
virtual srs_error_t on_publish(ISrsRequest *r);
virtual void on_unpublish();
virtual srs_error_t on_meta_data(SrsMediaPacket *shared_metadata);
@ -193,7 +271,7 @@ public:
virtual srs_error_t on_reap_segment();
public:
static srs_error_t create_plan(std::string vhost, SrsDvrPlan **pplan);
static srs_error_t create_plan(ISrsAppConfig *config, std::string vhost, ISrsDvrPlan **pplan);
};
// The DVR session plan: reap flv when session complete(unpublish)
@ -211,7 +289,8 @@ public:
// The DVR segment plan: reap flv when duration exceed.
class SrsDvrSegmentPlan : public SrsDvrPlan
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// in config, in srs_utime_t
srs_utime_t cduration_;
bool wait_keyframe_;
@ -223,13 +302,14 @@ public:
virtual ~SrsDvrSegmentPlan();
public:
virtual srs_error_t initialize(SrsOriginHub *h, SrsDvrSegmenter *s, ISrsRequest *r);
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsDvrSegmenter *s, ISrsRequest *r);
virtual srs_error_t on_publish(ISrsRequest *r);
virtual void on_unpublish();
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio, SrsFormat *format);
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t update_duration(SrsMediaPacket *msg);
};
@ -238,10 +318,11 @@ class ISrsDvr
{
public:
ISrsDvr();
virtual void assemble() = 0;
virtual ~ISrsDvr();
public:
virtual srs_error_t initialize(SrsOriginHub *h, ISrsRequest *r) = 0;
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsRequest *r) = 0;
virtual srs_error_t on_publish(ISrsRequest *r) = 0;
virtual void on_unpublish() = 0;
virtual srs_error_t on_meta_data(SrsMediaPacket *metadata) = 0;
@ -252,12 +333,19 @@ public:
// DVR(Digital Video Recorder) to record RTMP stream to flv/mp4 file.
class SrsDvr : public ISrsReloadHandler, public ISrsDvr
{
private:
SrsOriginHub *hub_;
SrsDvrPlan *plan_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsOriginHub *hub_;
ISrsDvrPlan *plan_;
ISrsRequest *req_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// whether the dvr is actived by filter, which is specified by dvr_apply.
// we always initialize the dvr, which crote plan and segment object,
// but they never create actual piece of file util the apply active it.
@ -265,13 +353,14 @@ private:
public:
SrsDvr();
void assemble();
virtual ~SrsDvr();
public:
// initialize dvr, create dvr plan.
// when system initialize(encoder publish at first time, or reload),
// initialize the dvr will reinitialize the plan, the whole dvr framework.
virtual srs_error_t initialize(SrsOriginHub *h, ISrsRequest *r);
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsRequest *r);
// publish stream event,
// when encoder start to publish RTMP stream.
// @param fetch_sequence_header whether fetch sequence from source.

View File

@ -21,6 +21,7 @@ using namespace std;
#include <srs_app_st.hpp>
#include <srs_kernel_pithy_print.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_utility.hpp>
#include <srs_core_autofree.hpp>
#include <srs_kernel_balance.hpp>
@ -42,11 +43,11 @@ using namespace std;
// when edge error, wait for quit
#define SRS_EDGE_FORWARDER_TIMEOUT (150 * SRS_UTIME_MILLISECONDS)
SrsEdgeUpstream::SrsEdgeUpstream()
ISrsEdgeUpstream::ISrsEdgeUpstream()
{
}
SrsEdgeUpstream::~SrsEdgeUpstream()
ISrsEdgeUpstream::~ISrsEdgeUpstream()
{
}
@ -55,11 +56,17 @@ SrsEdgeRtmpUpstream::SrsEdgeRtmpUpstream(string r)
redirect_ = r;
sdk_ = NULL;
selected_port_ = 0;
config_ = _srs_config;
app_factory_ = _srs_app_factory;
}
SrsEdgeRtmpUpstream::~SrsEdgeRtmpUpstream()
{
close();
config_ = NULL;
app_factory_ = NULL;
}
srs_error_t SrsEdgeRtmpUpstream::connect(ISrsRequest *r, ISrsLbRoundRobin *lb)
@ -70,7 +77,7 @@ srs_error_t SrsEdgeRtmpUpstream::connect(ISrsRequest *r, ISrsLbRoundRobin *lb)
std::string url;
if (true) {
SrsConfDirective *conf = _srs_config->get_vhost_edge_origin(req->vhost_);
SrsConfDirective *conf = config_->get_vhost_edge_origin(req->vhost_);
// when origin is error, for instance, server is shutdown,
// then user remove the vhost then reload, the conf is empty.
@ -95,7 +102,7 @@ srs_error_t SrsEdgeRtmpUpstream::connect(ISrsRequest *r, ISrsLbRoundRobin *lb)
selected_port_ = port;
// support vhost tranform for edge,
std::string vhost = _srs_config->get_vhost_edge_transform_vhost(req->vhost_);
std::string vhost = config_->get_vhost_edge_transform_vhost(req->vhost_);
vhost = srs_strings_replace(vhost, "[vhost]", req->vhost_);
url = srs_net_url_encode_rtmp_url(server, port, req->host_, vhost, req->app_, req->stream_, req->param_);
@ -104,7 +111,8 @@ srs_error_t SrsEdgeRtmpUpstream::connect(ISrsRequest *r, ISrsLbRoundRobin *lb)
srs_freep(sdk_);
srs_utime_t cto = SRS_EDGE_INGESTER_TIMEOUT;
srs_utime_t sto = SRS_CONSTS_RTMP_PULSE;
sdk_ = new SrsSimpleRtmpClient(url, cto, sto);
// Use factory to create client.
sdk_ = app_factory_->create_rtmp_client(url, cto, sto);
if ((err = sdk_->connect()) != srs_success) {
return srs_error_wrap(err, "edge pull %s failed, cto=%dms, sto=%dms.", url.c_str(), srsu2msi(cto), srsu2msi(sto));
@ -113,7 +121,7 @@ srs_error_t SrsEdgeRtmpUpstream::connect(ISrsRequest *r, ISrsLbRoundRobin *lb)
// For RTMP client, we pass the vhost in tcUrl when connecting,
// so we publish without vhost in stream.
string stream;
if ((err = sdk_->play(_srs_config->get_chunk_size(req->vhost_), false, &stream)) != srs_success) {
if ((err = sdk_->play(config_->get_chunk_size(req->vhost_), false, &stream)) != srs_success) {
return srs_error_wrap(err, "edge pull %s stream failed", url.c_str());
}
@ -163,11 +171,17 @@ SrsEdgeFlvUpstream::SrsEdgeFlvUpstream(std::string schema)
reader_ = NULL;
decoder_ = NULL;
req_ = NULL;
config_ = _srs_config;
app_factory_ = _srs_app_factory;
}
SrsEdgeFlvUpstream::~SrsEdgeFlvUpstream()
{
close();
config_ = NULL;
app_factory_ = NULL;
}
srs_error_t SrsEdgeFlvUpstream::connect(ISrsRequest *r, ISrsLbRoundRobin *lb)
@ -189,7 +203,7 @@ srs_error_t SrsEdgeFlvUpstream::do_connect(ISrsRequest *r, ISrsLbRoundRobin *lb,
ISrsRequest *req = r;
if (redirect_depth == 0) {
SrsConfDirective *conf = _srs_config->get_vhost_edge_origin(req->vhost_);
SrsConfDirective *conf = config_->get_vhost_edge_origin(req->vhost_);
// when origin is error, for instance, server is shutdown,
// then user remove the vhost then reload, the conf is empty.
@ -216,7 +230,7 @@ srs_error_t SrsEdgeFlvUpstream::do_connect(ISrsRequest *r, ISrsLbRoundRobin *lb,
}
srs_freep(sdk_);
sdk_ = new SrsHttpClient();
sdk_ = app_factory_->create_http_client();
string path = "/" + req->app_ + "/" + req->stream_;
if (!srs_strings_ends_with(req->stream_, ".flv")) {
@ -275,10 +289,10 @@ srs_error_t SrsEdgeFlvUpstream::do_connect(ISrsRequest *r, ISrsLbRoundRobin *lb,
}
srs_freep(reader_);
reader_ = new SrsHttpFileReader(hr_->body_reader());
reader_ = app_factory_->create_http_file_reader(hr_->body_reader());
srs_freep(decoder_);
decoder_ = new SrsFlvDecoder();
decoder_ = app_factory_->create_flv_decoder();
if ((err = decoder_->initialize(reader_)) != srs_success) {
return srs_error_wrap(err, "init decoder");
@ -383,6 +397,14 @@ void SrsEdgeFlvUpstream::kbps_sample(const char *label, srs_utime_t age)
sdk_->kbps_sample(label, age);
}
ISrsEdgeIngester::ISrsEdgeIngester()
{
}
ISrsEdgeIngester::~ISrsEdgeIngester()
{
}
SrsEdgeIngester::SrsEdgeIngester()
{
source_ = NULL;
@ -392,6 +414,8 @@ SrsEdgeIngester::SrsEdgeIngester()
upstream_ = new SrsEdgeRtmpUpstream("");
lb_ = new SrsLbRoundRobin();
trd_ = new SrsDummyCoroutine();
config_ = _srs_config;
}
SrsEdgeIngester::~SrsEdgeIngester()
@ -401,6 +425,8 @@ SrsEdgeIngester::~SrsEdgeIngester()
srs_freep(upstream_);
srs_freep(lb_);
srs_freep(trd_);
config_ = NULL;
}
// CRITICAL: This method is called AFTER the source has been added to the source pool
@ -409,7 +435,7 @@ SrsEdgeIngester::~SrsEdgeIngester()
// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches.
// This prevents the race condition where multiple coroutines could create duplicate sources
// for the same stream when context switches occurred during initialization.
srs_error_t SrsEdgeIngester::initialize(SrsSharedPtr<SrsLiveSource> s, SrsPlayEdge *e, ISrsRequest *r)
srs_error_t SrsEdgeIngester::initialize(SrsSharedPtr<SrsLiveSource> s, ISrsPlayEdge *e, ISrsRequest *r)
{
// Because source references to this object, so we should directly use the source ptr.
source_ = s.get();
@ -490,10 +516,10 @@ srs_error_t SrsEdgeIngester::do_cycle()
}
// Use protocol in config.
string edge_protocol = _srs_config->get_vhost_edge_protocol(req_->vhost_);
string edge_protocol = config_->get_vhost_edge_protocol(req_->vhost_);
// If follow client protocol, change to protocol of client.
bool follow_client = _srs_config->get_vhost_edge_follow_client(req_->vhost_);
bool follow_client = config_->get_vhost_edge_follow_client(req_->vhost_);
if (follow_client && !req_->protocol_.empty()) {
edge_protocol = req_->protocol_;
}
@ -676,6 +702,14 @@ srs_error_t SrsEdgeIngester::process_publish_message(SrsRtmpCommonMessage *msg,
return err;
}
ISrsEdgeForwarder::ISrsEdgeForwarder()
{
}
ISrsEdgeForwarder::~ISrsEdgeForwarder()
{
}
SrsEdgeForwarder::SrsEdgeForwarder()
{
edge_ = NULL;
@ -687,6 +721,8 @@ SrsEdgeForwarder::SrsEdgeForwarder()
lb_ = new SrsLbRoundRobin();
trd_ = new SrsDummyCoroutine();
queue_ = new SrsMessageQueue();
config_ = _srs_config;
}
SrsEdgeForwarder::~SrsEdgeForwarder()
@ -696,6 +732,8 @@ SrsEdgeForwarder::~SrsEdgeForwarder()
srs_freep(lb_);
srs_freep(trd_);
srs_freep(queue_);
config_ = NULL;
}
void SrsEdgeForwarder::set_queue_size(srs_utime_t queue_size)
@ -709,7 +747,7 @@ void SrsEdgeForwarder::set_queue_size(srs_utime_t queue_size)
// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches.
// This prevents the race condition where multiple coroutines could create duplicate sources
// for the same stream when context switches occurred during initialization.
srs_error_t SrsEdgeForwarder::initialize(SrsSharedPtr<SrsLiveSource> s, SrsPublishEdge *e, ISrsRequest *r)
srs_error_t SrsEdgeForwarder::initialize(SrsSharedPtr<SrsLiveSource> s, ISrsPublishEdge *e, ISrsRequest *r)
{
// Because source references to this object, so we should directly use the source ptr.
source_ = s.get();
@ -729,7 +767,7 @@ srs_error_t SrsEdgeForwarder::start()
std::string url;
if (true) {
SrsConfDirective *conf = _srs_config->get_vhost_edge_origin(req_->vhost_);
SrsConfDirective *conf = config_->get_vhost_edge_origin(req_->vhost_);
srs_assert(conf);
// select the origin.
@ -738,7 +776,7 @@ srs_error_t SrsEdgeForwarder::start()
srs_net_split_hostport(server, server, port);
// support vhost tranform for edge,
std::string vhost = _srs_config->get_vhost_edge_transform_vhost(req_->vhost_);
std::string vhost = config_->get_vhost_edge_transform_vhost(req_->vhost_);
vhost = srs_strings_replace(vhost, "[vhost]", req_->vhost_);
url = srs_net_url_encode_rtmp_url(server, port, req_->host_, vhost, req_->app_, req_->stream_, req_->param_);
@ -761,7 +799,7 @@ srs_error_t SrsEdgeForwarder::start()
// For RTMP client, we pass the vhost in tcUrl when connecting,
// so we publish without vhost in stream.
string stream;
if ((err = sdk_->publish(_srs_config->get_chunk_size(req_->vhost_), false, &stream)) != srs_success) {
if ((err = sdk_->publish(config_->get_chunk_size(req_->vhost_), false, &stream)) != srs_success) {
return srs_error_wrap(err, "sdk publish");
}
@ -905,6 +943,14 @@ srs_error_t SrsEdgeForwarder::proxy(SrsRtmpCommonMessage *msg)
return err;
}
ISrsPlayEdge::ISrsPlayEdge()
{
}
ISrsPlayEdge::~ISrsPlayEdge()
{
}
SrsPlayEdge::SrsPlayEdge()
{
state_ = SrsEdgeStateInit;
@ -983,6 +1029,14 @@ srs_error_t SrsPlayEdge::on_ingest_play()
return err;
}
ISrsPublishEdge::ISrsPublishEdge()
{
}
ISrsPublishEdge::~ISrsPublishEdge()
{
}
SrsPublishEdge::SrsPublishEdge()
{
state_ = SrsEdgeStateInit;

View File

@ -33,6 +33,15 @@ class SrsHttpClient;
class ISrsHttpMessage;
class SrsHttpFileReader;
class SrsFlvDecoder;
class ISrsAppConfig;
class ISrsBasicRtmpClient;
class ISrsHttpClient;
class ISrsFileReader;
class ISrsFlvDecoder;
class ISrsLiveSource;
class ISrsPlayEdge;
class ISrsPublishEdge;
class ISrsAppFactory;
// The state of edge, auto machine
enum SrsEdgeState {
@ -57,11 +66,11 @@ enum SrsEdgeUserState {
};
// The upstream of edge, can be rtmp or http.
class SrsEdgeUpstream
class ISrsEdgeUpstream
{
public:
SrsEdgeUpstream();
virtual ~SrsEdgeUpstream();
ISrsEdgeUpstream();
virtual ~ISrsEdgeUpstream();
public:
virtual srs_error_t connect(ISrsRequest *r, ISrsLbRoundRobin *lb) = 0;
@ -75,15 +84,23 @@ public:
virtual void kbps_sample(const char *label, srs_utime_t age) = 0;
};
class SrsEdgeRtmpUpstream : public SrsEdgeUpstream
// The RTMP upstream of edge.
class SrsEdgeRtmpUpstream : public ISrsEdgeUpstream
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// For RTMP 302, if not empty,
// use this <ip[:port]> as upstream.
std::string redirect_;
SrsSimpleRtmpClient *sdk_;
ISrsBasicRtmpClient *sdk_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Current selected server, the ip:port.
std::string selected_ip_;
int selected_port_;
@ -105,18 +122,27 @@ public:
virtual void kbps_sample(const char *label, srs_utime_t age);
};
class SrsEdgeFlvUpstream : public SrsEdgeUpstream
// The HTTP FLV upstream of edge.
class SrsEdgeFlvUpstream : public ISrsEdgeUpstream
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string schema_;
SrsHttpClient *sdk_;
ISrsHttpClient *sdk_;
ISrsHttpMessage *hr_;
private:
SrsHttpFileReader *reader_;
SrsFlvDecoder *decoder_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsFileReader *reader_;
ISrsFlvDecoder *decoder_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// We might modify the request by HTTP redirect.
ISrsRequest *req_;
// Current selected server, the ip:port.
@ -130,7 +156,8 @@ public:
public:
virtual srs_error_t connect(ISrsRequest *r, ISrsLbRoundRobin *lb);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_connect(ISrsRequest *r, ISrsLbRoundRobin *lb, int redirect_depth);
public:
@ -144,26 +171,48 @@ public:
virtual void kbps_sample(const char *label, srs_utime_t age);
};
// The edge used to ingest stream from origin.
class SrsEdgeIngester : public ISrsCoroutineHandler
// The interface for edge ingester.
class ISrsEdgeIngester
{
private:
// Because source references to this object, so we should directly use the source ptr.
SrsLiveSource *source_;
public:
ISrsEdgeIngester();
virtual ~ISrsEdgeIngester();
private:
SrsPlayEdge *edge_;
public:
// Initialize the ingester.
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> s, ISrsPlayEdge *e, ISrsRequest *r) = 0;
// Start the ingester.
virtual srs_error_t start() = 0;
// Stop the ingester.
virtual void stop() = 0;
};
// The edge used to ingest stream from origin.
class SrsEdgeIngester : public ISrsCoroutineHandler, public ISrsEdgeIngester
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Because source references to this object, so we should directly use the source ptr.
ISrsLiveSource *source_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsPlayEdge *edge_;
ISrsRequest *req_;
ISrsCoroutine *trd_;
ISrsLbRoundRobin *lb_;
SrsEdgeUpstream *upstream_;
ISrsEdgeUpstream *upstream_;
public:
SrsEdgeIngester();
virtual ~SrsEdgeIngester();
public:
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> s, SrsPlayEdge *e, ISrsRequest *r);
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> s, ISrsPlayEdge *e, ISrsRequest *r);
virtual srs_error_t start();
virtual void stop();
@ -171,23 +220,51 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t ingest(std::string &redirect);
virtual srs_error_t process_publish_message(SrsRtmpCommonMessage *msg, std::string &redirect);
};
// The edge used to forward stream to origin.
class SrsEdgeForwarder : public ISrsCoroutineHandler
// The interface for edge forwarder.
class ISrsEdgeForwarder
{
private:
// Because source references to this object, so we should directly use the source ptr.
SrsLiveSource *source_;
public:
ISrsEdgeForwarder();
virtual ~ISrsEdgeForwarder();
private:
SrsPublishEdge *edge_;
public:
// Set the queue size.
virtual void set_queue_size(srs_utime_t queue_size) = 0;
// Initialize the forwarder.
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> s, ISrsPublishEdge *e, ISrsRequest *r) = 0;
// Start the forwarder.
virtual srs_error_t start() = 0;
// Stop the forwarder.
virtual void stop() = 0;
// Proxy publish stream to edge.
virtual srs_error_t proxy(SrsRtmpCommonMessage *msg) = 0;
};
// The edge used to forward stream to origin.
class SrsEdgeForwarder : public ISrsCoroutineHandler, public ISrsEdgeForwarder
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Because source references to this object, so we should directly use the source ptr.
ISrsLiveSource *source_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsPublishEdge *edge_;
ISrsRequest *req_;
ISrsCoroutine *trd_;
SrsSimpleRtmpClient *sdk_;
@ -208,26 +285,40 @@ public:
virtual void set_queue_size(srs_utime_t queue_size);
public:
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> s, SrsPublishEdge *e, ISrsRequest *r);
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> s, ISrsPublishEdge *e, ISrsRequest *r);
virtual srs_error_t start();
virtual void stop();
// Interface ISrsReusableThread2Handler
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_cycle();
public:
virtual srs_error_t proxy(SrsRtmpCommonMessage *msg);
};
// The play edge control service.
class SrsPlayEdge
// The interface for play edge.
class ISrsPlayEdge
{
private:
public:
ISrsPlayEdge();
virtual ~ISrsPlayEdge();
public:
// When ingester start to play stream.
virtual srs_error_t on_ingest_play() = 0;
};
// The play edge control service.
class SrsPlayEdge : public ISrsPlayEdge
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsEdgeState state_;
SrsEdgeIngester *ingester_;
ISrsEdgeIngester *ingester_;
public:
SrsPlayEdge();
@ -248,12 +339,23 @@ public:
virtual srs_error_t on_ingest_play();
};
// The publish edge control service.
class SrsPublishEdge
// The interface for publish edge.
class ISrsPublishEdge
{
private:
public:
ISrsPublishEdge();
virtual ~ISrsPublishEdge();
public:
};
// The publish edge control service.
class SrsPublishEdge : public ISrsPublishEdge
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsEdgeState state_;
SrsEdgeForwarder *forwarder_;
ISrsEdgeForwarder *forwarder_;
public:
SrsPublishEdge();

View File

@ -10,6 +10,7 @@
using namespace std;
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_ffmpeg.hpp>
#include <srs_app_utility.hpp>
#include <srs_kernel_error.hpp>
@ -33,6 +34,9 @@ SrsEncoder::SrsEncoder()
{
trd_ = new SrsDummyCoroutine();
pprint_ = SrsPithyPrint::create_encoder();
config_ = _srs_config;
app_factory_ = _srs_app_factory;
}
SrsEncoder::~SrsEncoder()
@ -41,6 +45,9 @@ SrsEncoder::~SrsEncoder()
srs_freep(trd_);
srs_freep(pprint_);
config_ = NULL;
app_factory_ = NULL;
}
srs_error_t SrsEncoder::on_publish(ISrsRequest *req)
@ -64,7 +71,7 @@ srs_error_t SrsEncoder::on_publish(ISrsRequest *req)
// start thread to run all encoding engines.
srs_freep(trd_);
trd_ = new SrsSTCoroutine("encoder", this, _srs_context->get_id());
trd_ = app_factory_->create_coroutine("encoder", this, _srs_context->get_id());
if ((err = trd_->start()) != srs_success) {
return srs_error_wrap(err, "start encoder");
}
@ -102,10 +109,10 @@ srs_error_t SrsEncoder::cycle()
}
// kill ffmpeg when finished and it alive
std::vector<SrsFFMPEG *>::iterator it;
std::vector<ISrsFFMPEG *>::iterator it;
for (it = ffmpegs_.begin(); it != ffmpegs_.end(); ++it) {
SrsFFMPEG *ffmpeg = *it;
ISrsFFMPEG *ffmpeg = *it;
ffmpeg->stop();
}
@ -116,9 +123,9 @@ srs_error_t SrsEncoder::do_cycle()
{
srs_error_t err = srs_success;
std::vector<SrsFFMPEG *>::iterator it;
std::vector<ISrsFFMPEG *>::iterator it;
for (it = ffmpegs_.begin(); it != ffmpegs_.end(); ++it) {
SrsFFMPEG *ffmpeg = *it;
ISrsFFMPEG *ffmpeg = *it;
// start all ffmpegs.
if ((err = ffmpeg->start()) != srs_success) {
@ -139,10 +146,10 @@ srs_error_t SrsEncoder::do_cycle()
void SrsEncoder::clear_engines()
{
std::vector<SrsFFMPEG *>::iterator it;
std::vector<ISrsFFMPEG *>::iterator it;
for (it = ffmpegs_.begin(); it != ffmpegs_.end(); ++it) {
SrsFFMPEG *ffmpeg = *it;
ISrsFFMPEG *ffmpeg = *it;
std::string output = ffmpeg->output();
@ -158,7 +165,7 @@ void SrsEncoder::clear_engines()
ffmpegs_.clear();
}
SrsFFMPEG *SrsEncoder::at(int index)
ISrsFFMPEG *SrsEncoder::at(int index)
{
return ffmpegs_[index];
}
@ -172,14 +179,14 @@ srs_error_t SrsEncoder::parse_scope_engines(ISrsRequest *req)
// parse vhost scope engines
std::string scope = "";
if ((conf = _srs_config->get_transcode(req->vhost_, scope)) != NULL) {
if ((conf = config_->get_transcode(req->vhost_, scope)) != NULL) {
if ((err = parse_ffmpeg(req, conf)) != srs_success) {
return srs_error_wrap(err, "parse ffmpeg");
}
}
// parse app scope engines
scope = req->app_;
if ((conf = _srs_config->get_transcode(req->vhost_, scope)) != NULL) {
if ((conf = config_->get_transcode(req->vhost_, scope)) != NULL) {
if ((err = parse_ffmpeg(req, conf)) != srs_success) {
return srs_error_wrap(err, "parse ffmpeg");
}
@ -187,7 +194,7 @@ srs_error_t SrsEncoder::parse_scope_engines(ISrsRequest *req)
// parse stream scope engines
scope += "/";
scope += req->stream_;
if ((conf = _srs_config->get_transcode(req->vhost_, scope)) != NULL) {
if ((conf = config_->get_transcode(req->vhost_, scope)) != NULL) {
if ((err = parse_ffmpeg(req, conf)) != srs_success) {
return srs_error_wrap(err, "parse ffmpeg");
}
@ -203,20 +210,20 @@ srs_error_t SrsEncoder::parse_ffmpeg(ISrsRequest *req, SrsConfDirective *conf)
srs_assert(conf);
// enabled
if (!_srs_config->get_transcode_enabled(conf)) {
if (!config_->get_transcode_enabled(conf)) {
srs_trace("ignore the disabled transcode: %s", conf->arg0().c_str());
return err;
}
// ffmpeg
std::string ffmpeg_bin = _srs_config->get_transcode_ffmpeg(conf);
std::string ffmpeg_bin = config_->get_transcode_ffmpeg(conf);
if (ffmpeg_bin.empty()) {
srs_trace("ignore the empty ffmpeg transcode: %s", conf->arg0().c_str());
return err;
}
// get all engines.
std::vector<SrsConfDirective *> engines = _srs_config->get_transcode_engines(conf);
std::vector<SrsConfDirective *> engines = config_->get_transcode_engines(conf);
if (engines.empty()) {
srs_trace("ignore the empty transcode engine: %s", conf->arg0().c_str());
return err;
@ -225,12 +232,12 @@ srs_error_t SrsEncoder::parse_ffmpeg(ISrsRequest *req, SrsConfDirective *conf)
// create engine
for (int i = 0; i < (int)engines.size(); i++) {
SrsConfDirective *engine = engines[i];
if (!_srs_config->get_engine_enabled(engine)) {
if (!config_->get_engine_enabled(engine)) {
srs_trace("ignore the diabled transcode engine: %s %s", conf->arg0().c_str(), engine->arg0().c_str());
continue;
}
SrsFFMPEG *ffmpeg = new SrsFFMPEG(ffmpeg_bin);
ISrsFFMPEG *ffmpeg = app_factory_->create_ffmpeg(ffmpeg_bin);
if ((err = initialize_ffmpeg(ffmpeg, req, engine)) != srs_success) {
srs_freep(ffmpeg);
return srs_error_wrap(err, "init ffmpeg");
@ -242,7 +249,7 @@ srs_error_t SrsEncoder::parse_ffmpeg(ISrsRequest *req, SrsConfDirective *conf)
return err;
}
srs_error_t SrsEncoder::initialize_ffmpeg(SrsFFMPEG *ffmpeg, ISrsRequest *req, SrsConfDirective *engine)
srs_error_t SrsEncoder::initialize_ffmpeg(ISrsFFMPEG *ffmpeg, ISrsRequest *req, SrsConfDirective *engine)
{
srs_error_t err = srs_success;
@ -267,7 +274,7 @@ srs_error_t SrsEncoder::initialize_ffmpeg(SrsFFMPEG *ffmpeg, ISrsRequest *req, S
input_stream_name_ += "/";
input_stream_name_ += req->stream_;
std::string output = _srs_config->get_engine_output(engine);
std::string output = config_->get_engine_output(engine);
// output stream, to other/self server
// ie. rtmp://localhost:1935/live/livestream_sd
output = srs_strings_replace(output, "[vhost]", req->vhost_);
@ -280,8 +287,8 @@ srs_error_t SrsEncoder::initialize_ffmpeg(SrsFFMPEG *ffmpeg, ISrsRequest *req, S
std::string log_file = SRS_CONSTS_NULL_FILE; // disabled
// write ffmpeg info to log file.
if (_srs_config->get_ff_log_enabled()) {
log_file = _srs_config->get_ff_log_dir();
if (config_->get_ff_log_enabled()) {
log_file = config_->get_ff_log_dir();
log_file += "/";
log_file += "ffmpeg-encoder";
log_file += "-";

View File

@ -17,7 +17,11 @@
class SrsConfDirective;
class ISrsRequest;
class SrsPithyPrint;
class ISrsPithyPrint;
class SrsFFMPEG;
class ISrsFFMPEG;
class ISrsAppConfig;
class ISrsAppFactory;
// The encoder interface.
class ISrsMediaEncoder
@ -38,13 +42,20 @@ public:
// ffmpegs to transcode the specified stream.
class SrsEncoder : public ISrsCoroutineHandler, public ISrsMediaEncoder
{
private:
std::string input_stream_name_;
std::vector<SrsFFMPEG *> ffmpegs_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsAppFactory *app_factory_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string input_stream_name_;
std::vector<ISrsFFMPEG *> ffmpegs_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsCoroutine *trd_;
SrsPithyPrint *pprint_;
ISrsPithyPrint *pprint_;
public:
SrsEncoder();
@ -57,15 +68,17 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual void clear_engines();
virtual SrsFFMPEG *at(int index);
virtual ISrsFFMPEG *at(int index);
virtual srs_error_t parse_scope_engines(ISrsRequest *req);
virtual srs_error_t parse_ffmpeg(ISrsRequest *req, SrsConfDirective *conf);
virtual srs_error_t initialize_ffmpeg(SrsFFMPEG *ffmpeg, ISrsRequest *req, SrsConfDirective *engine);
virtual srs_error_t initialize_ffmpeg(ISrsFFMPEG *ffmpeg, ISrsRequest *req, SrsConfDirective *engine);
virtual void show_encode_log_message();
};

View File

@ -6,21 +6,49 @@
#include <srs_app_factory.hpp>
#include <srs_app_caster_flv.hpp>
#include <srs_app_config.hpp>
#include <srs_app_dash.hpp>
#include <srs_app_dvr.hpp>
#include <srs_app_ffmpeg.hpp>
#include <srs_app_fragment.hpp>
#ifdef SRS_GB28181
#include <srs_app_gb28181.hpp>
#endif
#include <srs_app_ingest.hpp>
#include <srs_app_listener.hpp>
#include <srs_app_rtc_conn.hpp>
#include <srs_app_rtmp_conn.hpp>
#include <srs_app_rtmp_source.hpp>
#ifdef SRS_RTSP
#include <srs_app_rtsp_source.hpp>
#endif
#include <srs_app_st.hpp>
#include <srs_kernel_file.hpp>
#include <srs_kernel_flv.hpp>
#include <srs_kernel_hourglass.hpp>
#include <srs_kernel_mp4.hpp>
#include <srs_kernel_ts.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_protocol_http_client.hpp>
#include <srs_protocol_st.hpp>
ISrsAppFactory::ISrsAppFactory()
{
}
ISrsAppFactory::~ISrsAppFactory()
{
}
SrsAppFactory::SrsAppFactory()
{
kernel_factory_ = new SrsFinalFactory();
}
SrsAppFactory::~SrsAppFactory()
{
srs_freep(kernel_factory_);
}
ISrsFileWriter *SrsAppFactory::create_file_writer()
@ -60,6 +88,127 @@ ISrsHourGlass *SrsAppFactory::create_hourglass(const std::string &name, ISrsHour
return new SrsHourGlass(name, handler, interval);
}
ISrsBasicRtmpClient *SrsAppFactory::create_rtmp_client(std::string url, srs_utime_t cto, srs_utime_t sto)
{
return new SrsSimpleRtmpClient(url, cto, sto);
}
ISrsHttpClient *SrsAppFactory::create_http_client()
{
return new SrsHttpClient();
}
ISrsFileReader *SrsAppFactory::create_http_file_reader(ISrsHttpResponseReader *r)
{
return new SrsHttpFileReader(r);
}
ISrsFlvDecoder *SrsAppFactory::create_flv_decoder()
{
return new SrsFlvDecoder();
}
#ifdef SRS_RTSP
ISrsRtspSendTrack *SrsAppFactory::create_rtsp_audio_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc)
{
return new SrsRtspAudioSendTrack(session, track_desc);
}
ISrsRtspSendTrack *SrsAppFactory::create_rtsp_video_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc)
{
return new SrsRtspVideoSendTrack(session, track_desc);
}
#endif
ISrsFlvTransmuxer *SrsAppFactory::create_flv_transmuxer()
{
return new SrsFlvTransmuxer();
}
ISrsMp4Encoder *SrsAppFactory::create_mp4_encoder()
{
return new SrsMp4Encoder();
}
ISrsDvrSegmenter *SrsAppFactory::create_dvr_flv_segmenter()
{
return new SrsDvrFlvSegmenter();
}
ISrsDvrSegmenter *SrsAppFactory::create_dvr_mp4_segmenter()
{
return new SrsDvrMp4Segmenter();
}
#ifdef SRS_GB28181
ISrsGbMediaTcpConn *SrsAppFactory::create_gb_media_tcp_conn()
{
return new SrsGbMediaTcpConn();
}
ISrsGbSession *SrsAppFactory::create_gb_session()
{
return new SrsGbSession();
}
#endif
ISrsInitMp4 *SrsAppFactory::create_init_mp4()
{
return new SrsInitMp4();
}
ISrsFragmentWindow *SrsAppFactory::create_fragment_window()
{
return new SrsFragmentWindow();
}
ISrsFragmentedMp4 *SrsAppFactory::create_fragmented_mp4()
{
return new SrsFragmentedMp4();
}
ISrsIpListener *SrsAppFactory::create_tcp_listener(ISrsTcpHandler *handler)
{
return new SrsTcpListener(handler);
}
ISrsRtcConnection *SrsAppFactory::create_rtc_connection(ISrsExecRtcAsyncTask *exec, const SrsContextId &cid)
{
SrsRtcConnection *session = new SrsRtcConnection(exec, cid);
session->assemble();
return session;
}
ISrsFFMPEG *SrsAppFactory::create_ffmpeg(std::string ffmpeg_bin)
{
return new SrsFFMPEG(ffmpeg_bin);
}
ISrsIngesterFFMPEG *SrsAppFactory::create_ingester_ffmpeg()
{
return new SrsIngesterFFMPEG();
}
ISrsCoroutine *SrsAppFactory::create_coroutine(const std::string &name, ISrsCoroutineHandler *handler, SrsContextId cid)
{
return kernel_factory_->create_coroutine(name, handler, cid);
}
ISrsTime *SrsAppFactory::create_time()
{
return kernel_factory_->create_time();
}
ISrsConfig *SrsAppFactory::create_config()
{
return kernel_factory_->create_config();
}
ISrsCond *SrsAppFactory::create_cond()
{
return kernel_factory_->create_cond();
}
SrsFinalFactory::SrsFinalFactory()
{
}

View File

@ -18,10 +18,78 @@ class SrsLiveSource;
class ISrsOriginHub;
class ISrsHourGlass;
class ISrsHourGlassHandler;
class ISrsBasicRtmpClient;
class ISrsHttpClient;
class ISrsFileReader;
class ISrsFlvDecoder;
class ISrsHttpResponseReader;
class ISrsRtspSendTrack;
class ISrsRtspConnection;
class SrsRtcTrackDescription;
class ISrsFlvTransmuxer;
class ISrsMp4Encoder;
class ISrsDvrSegmenter;
class ISrsGbMediaTcpConn;
class ISrsGbSession;
class ISrsFragment;
class ISrsInitMp4;
class ISrsFragmentWindow;
class ISrsFragmentedMp4;
class SrsFinalFactory;
class ISrsIpListener;
class ISrsTcpHandler;
class ISrsRtcConnection;
class ISrsExecRtcAsyncTask;
class ISrsFFMPEG;
class ISrsIngesterFFMPEG;
// The factory to create app objects.
class SrsAppFactory
class ISrsAppFactory : public ISrsKernelFactory
{
public:
ISrsAppFactory();
virtual ~ISrsAppFactory();
public:
virtual ISrsFileWriter *create_file_writer() = 0;
virtual ISrsFileWriter *create_enc_file_writer() = 0;
virtual ISrsFileReader *create_file_reader() = 0;
virtual SrsPath *create_path() = 0;
virtual SrsLiveSource *create_live_source() = 0;
virtual ISrsOriginHub *create_origin_hub() = 0;
virtual ISrsHourGlass *create_hourglass(const std::string &name, ISrsHourGlassHandler *handler, srs_utime_t interval) = 0;
virtual ISrsBasicRtmpClient *create_rtmp_client(std::string url, srs_utime_t cto, srs_utime_t sto) = 0;
virtual ISrsHttpClient *create_http_client() = 0;
virtual ISrsFileReader *create_http_file_reader(ISrsHttpResponseReader *r) = 0;
virtual ISrsFlvDecoder *create_flv_decoder() = 0;
#ifdef SRS_RTSP
virtual ISrsRtspSendTrack *create_rtsp_audio_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc) = 0;
virtual ISrsRtspSendTrack *create_rtsp_video_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc) = 0;
#endif
virtual ISrsFlvTransmuxer *create_flv_transmuxer() = 0;
virtual ISrsMp4Encoder *create_mp4_encoder() = 0;
virtual ISrsDvrSegmenter *create_dvr_flv_segmenter() = 0;
virtual ISrsDvrSegmenter *create_dvr_mp4_segmenter() = 0;
#ifdef SRS_GB28181
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn() = 0;
virtual ISrsGbSession *create_gb_session() = 0;
#endif
virtual ISrsInitMp4 *create_init_mp4() = 0;
virtual ISrsFragmentWindow *create_fragment_window() = 0;
virtual ISrsFragmentedMp4 *create_fragmented_mp4() = 0;
virtual ISrsIpListener *create_tcp_listener(ISrsTcpHandler *handler) = 0;
virtual ISrsRtcConnection *create_rtc_connection(ISrsExecRtcAsyncTask *exec, const SrsContextId &cid) = 0;
virtual ISrsFFMPEG *create_ffmpeg(std::string ffmpeg_bin) = 0;
virtual ISrsIngesterFFMPEG *create_ingester_ffmpeg() = 0;
};
// The factory to create app objects.
class SrsAppFactory : public ISrsAppFactory
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsKernelFactory *kernel_factory_;
public:
SrsAppFactory();
virtual ~SrsAppFactory();
@ -34,9 +102,38 @@ public:
virtual SrsLiveSource *create_live_source();
virtual ISrsOriginHub *create_origin_hub();
virtual ISrsHourGlass *create_hourglass(const std::string &name, ISrsHourGlassHandler *handler, srs_utime_t interval);
virtual ISrsBasicRtmpClient *create_rtmp_client(std::string url, srs_utime_t cto, srs_utime_t sto);
virtual ISrsHttpClient *create_http_client();
virtual ISrsFileReader *create_http_file_reader(ISrsHttpResponseReader *r);
virtual ISrsFlvDecoder *create_flv_decoder();
#ifdef SRS_RTSP
virtual ISrsRtspSendTrack *create_rtsp_audio_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc);
virtual ISrsRtspSendTrack *create_rtsp_video_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc);
#endif
virtual ISrsFlvTransmuxer *create_flv_transmuxer();
virtual ISrsMp4Encoder *create_mp4_encoder();
virtual ISrsDvrSegmenter *create_dvr_flv_segmenter();
virtual ISrsDvrSegmenter *create_dvr_mp4_segmenter();
#ifdef SRS_GB28181
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn();
virtual ISrsGbSession *create_gb_session();
#endif
virtual ISrsInitMp4 *create_init_mp4();
virtual ISrsFragmentWindow *create_fragment_window();
virtual ISrsFragmentedMp4 *create_fragmented_mp4();
virtual ISrsIpListener *create_tcp_listener(ISrsTcpHandler *handler);
virtual ISrsRtcConnection *create_rtc_connection(ISrsExecRtcAsyncTask *exec, const SrsContextId &cid);
virtual ISrsFFMPEG *create_ffmpeg(std::string ffmpeg_bin);
virtual ISrsIngesterFFMPEG *create_ingester_ffmpeg();
public:
virtual ISrsCoroutine *create_coroutine(const std::string &name, ISrsCoroutineHandler *handler, SrsContextId cid);
virtual ISrsTime *create_time();
virtual ISrsConfig *create_config();
virtual ISrsCond *create_cond();
};
extern SrsAppFactory *_srs_app_factory;
extern ISrsAppFactory *_srs_app_factory;
// The factory to create kernel objects.
class SrsFinalFactory : public ISrsKernelFactory

View File

@ -44,6 +44,14 @@ using namespace std;
#define SRS_RTMP_ENCODER_LIBAACPLUS "libaacplus"
#define SRS_RTMP_ENCODER_LIBFDKAAC "libfdk_aac"
ISrsFFMPEG::ISrsFFMPEG()
{
}
ISrsFFMPEG::~ISrsFFMPEG()
{
}
SrsFFMPEG::SrsFFMPEG(std::string ffmpeg_bin)
{
ffmpeg_ = ffmpeg_bin;
@ -58,6 +66,8 @@ SrsFFMPEG::SrsFFMPEG(std::string ffmpeg_bin)
achannels_ = 0;
process_ = new SrsProcess();
config_ = _srs_config;
}
SrsFFMPEG::~SrsFFMPEG()
@ -65,6 +75,8 @@ SrsFFMPEG::~SrsFFMPEG()
stop();
srs_freep(process_);
config_ = NULL;
}
void SrsFFMPEG::append_iparam(string iparam)
@ -97,24 +109,24 @@ srs_error_t SrsFFMPEG::initialize_transcode(SrsConfDirective *engine)
{
srs_error_t err = srs_success;
perfile_ = _srs_config->get_engine_perfile(engine);
iformat_ = _srs_config->get_engine_iformat(engine);
vfilter_ = _srs_config->get_engine_vfilter(engine);
vcodec_ = _srs_config->get_engine_vcodec(engine);
vbitrate_ = _srs_config->get_engine_vbitrate(engine);
vfps_ = _srs_config->get_engine_vfps(engine);
vwidth_ = _srs_config->get_engine_vwidth(engine);
vheight_ = _srs_config->get_engine_vheight(engine);
vthreads_ = _srs_config->get_engine_vthreads(engine);
vprofile_ = _srs_config->get_engine_vprofile(engine);
vpreset_ = _srs_config->get_engine_vpreset(engine);
vparams_ = _srs_config->get_engine_vparams(engine);
acodec_ = _srs_config->get_engine_acodec(engine);
abitrate_ = _srs_config->get_engine_abitrate(engine);
asample_rate_ = _srs_config->get_engine_asample_rate(engine);
achannels_ = _srs_config->get_engine_achannels(engine);
aparams_ = _srs_config->get_engine_aparams(engine);
oformat_ = _srs_config->get_engine_oformat(engine);
perfile_ = config_->get_engine_perfile(engine);
iformat_ = config_->get_engine_iformat(engine);
vfilter_ = config_->get_engine_vfilter(engine);
vcodec_ = config_->get_engine_vcodec(engine);
vbitrate_ = config_->get_engine_vbitrate(engine);
vfps_ = config_->get_engine_vfps(engine);
vwidth_ = config_->get_engine_vwidth(engine);
vheight_ = config_->get_engine_vheight(engine);
vthreads_ = config_->get_engine_vthreads(engine);
vprofile_ = config_->get_engine_vprofile(engine);
vpreset_ = config_->get_engine_vpreset(engine);
vparams_ = config_->get_engine_vparams(engine);
acodec_ = config_->get_engine_acodec(engine);
abitrate_ = config_->get_engine_abitrate(engine);
asample_rate_ = config_->get_engine_asample_rate(engine);
achannels_ = config_->get_engine_achannels(engine);
aparams_ = config_->get_engine_aparams(engine);
oformat_ = config_->get_engine_oformat(engine);
// ensure the size is even.
vwidth_ -= vwidth_ % 2;

View File

@ -16,19 +16,56 @@
class SrsConfDirective;
class SrsPithyPrint;
class ISrsPithyPrint;
class SrsProcess;
class ISrsProcess;
class ISrsAppConfig;
// The ffmpeg interface.
class ISrsFFMPEG
{
public:
ISrsFFMPEG();
virtual ~ISrsFFMPEG();
public:
virtual void append_iparam(std::string iparam) = 0;
virtual void set_oformat(std::string format) = 0;
virtual std::string output() = 0;
public:
virtual srs_error_t initialize(std::string in, std::string out, std::string log) = 0;
virtual srs_error_t initialize_transcode(SrsConfDirective *engine) = 0;
virtual srs_error_t initialize_copy() = 0;
public:
virtual srs_error_t start() = 0;
virtual srs_error_t cycle() = 0;
virtual void stop() = 0;
public:
virtual void fast_stop() = 0;
virtual void fast_kill() = 0;
};
// A transcode engine: ffmepg, used to transcode a stream to another.
class SrsFFMPEG
class SrsFFMPEG : public ISrsFFMPEG
{
private:
SrsProcess *process_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsProcess *process_;
std::vector<std::string> params_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string log_file_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string ffmpeg_;
std::vector<std::string> iparams_;
std::vector<std::string> perfile_;

View File

@ -45,19 +45,23 @@ public:
// Forward the stream to other servers.
class SrsForwarder : public ISrsCoroutineHandler, public ISrsForwarder
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The ep to forward, server[:port].
std::string ep_forward_;
ISrsRequest *req_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The source or stream context id to bind to.
SrsContextId source_cid_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsCoroutine *trd_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsOriginHub *hub_;
SrsSimpleRtmpClient *sdk_;
SrsRtmpJitter *jitter_;
@ -90,10 +94,12 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t forward();
};

View File

@ -14,6 +14,14 @@
#include <unistd.h>
using namespace std;
ISrsFragment::ISrsFragment()
{
}
ISrsFragment::~ISrsFragment()
{
}
SrsFragment::SrsFragment()
{
dur_ = 0;
@ -155,22 +163,30 @@ uint64_t SrsFragment::number()
return number_;
}
ISrsFragmentWindow::ISrsFragmentWindow()
{
}
ISrsFragmentWindow::~ISrsFragmentWindow()
{
}
SrsFragmentWindow::SrsFragmentWindow()
{
}
SrsFragmentWindow::~SrsFragmentWindow()
{
vector<SrsFragment *>::iterator it;
vector<ISrsFragment *>::iterator it;
for (it = fragments_.begin(); it != fragments_.end(); ++it) {
SrsFragment *fragment = *it;
ISrsFragment *fragment = *it;
srs_freep(fragment);
}
fragments_.clear();
for (it = expired_fragments_.begin(); it != expired_fragments_.end(); ++it) {
SrsFragment *fragment = *it;
ISrsFragment *fragment = *it;
srs_freep(fragment);
}
expired_fragments_.clear();
@ -180,10 +196,10 @@ void SrsFragmentWindow::dispose()
{
srs_error_t err = srs_success;
std::vector<SrsFragment *>::iterator it;
std::vector<ISrsFragment *>::iterator it;
for (it = fragments_.begin(); it != fragments_.end(); ++it) {
SrsFragment *fragment = *it;
ISrsFragment *fragment = *it;
if ((err = fragment->unlink_file()) != srs_success) {
srs_warn("Unlink ts failed %s", srs_error_desc(err).c_str());
srs_freep(err);
@ -193,7 +209,7 @@ void SrsFragmentWindow::dispose()
fragments_.clear();
for (it = expired_fragments_.begin(); it != expired_fragments_.end(); ++it) {
SrsFragment *fragment = *it;
ISrsFragment *fragment = *it;
if ((err = fragment->unlink_file()) != srs_success) {
srs_warn("Unlink ts failed %s", srs_error_desc(err).c_str());
srs_freep(err);
@ -203,7 +219,7 @@ void SrsFragmentWindow::dispose()
expired_fragments_.clear();
}
void SrsFragmentWindow::append(SrsFragment *fragment)
void SrsFragmentWindow::append(ISrsFragment *fragment)
{
fragments_.push_back(fragment);
}
@ -215,7 +231,7 @@ void SrsFragmentWindow::shrink(srs_utime_t window)
int remove_index = -1;
for (int i = (int)fragments_.size() - 1; i >= 0; i--) {
SrsFragment *fragment = fragments_[i];
ISrsFragment *fragment = fragments_[i];
duration += fragment->duration();
if (duration > window) {
@ -225,7 +241,7 @@ void SrsFragmentWindow::shrink(srs_utime_t window)
}
for (int i = 0; i < remove_index && !fragments_.empty(); i++) {
SrsFragment *fragment = *fragments_.begin();
ISrsFragment *fragment = *fragments_.begin();
fragments_.erase(fragments_.begin());
expired_fragments_.push_back(fragment);
}
@ -235,10 +251,10 @@ void SrsFragmentWindow::clear_expired(bool delete_files)
{
srs_error_t err = srs_success;
std::vector<SrsFragment *>::iterator it;
std::vector<ISrsFragment *>::iterator it;
for (it = expired_fragments_.begin(); it != expired_fragments_.end(); ++it) {
SrsFragment *fragment = *it;
ISrsFragment *fragment = *it;
if (delete_files && (err = fragment->unlink_file()) != srs_success) {
srs_warn("Unlink ts failed, %s", srs_error_desc(err).c_str());
srs_freep(err);
@ -253,10 +269,10 @@ srs_utime_t SrsFragmentWindow::max_duration()
{
srs_utime_t v = 0;
std::vector<SrsFragment *>::iterator it;
std::vector<ISrsFragment *>::iterator it;
for (it = fragments_.begin(); it != fragments_.end(); ++it) {
SrsFragment *fragment = *it;
ISrsFragment *fragment = *it;
v = srs_max(v, fragment->duration());
}
@ -268,7 +284,7 @@ bool SrsFragmentWindow::empty()
return fragments_.empty();
}
SrsFragment *SrsFragmentWindow::first()
ISrsFragment *SrsFragmentWindow::first()
{
return fragments_.at(0);
}
@ -278,7 +294,7 @@ int SrsFragmentWindow::size()
return (int)fragments_.size();
}
SrsFragment *SrsFragmentWindow::at(int index)
ISrsFragment *SrsFragmentWindow::at(int index)
{
return fragments_.at(index);
}

View File

@ -12,11 +12,47 @@
#include <string>
#include <vector>
// Forward declarations
class SrsFormat;
// The fragment interface.
class ISrsFragment
{
public:
ISrsFragment();
virtual ~ISrsFragment();
public:
// Set the full path of fragment.
virtual void set_path(std::string v) = 0;
// Get the temporary path for file.
virtual std::string tmppath() = 0;
// Rename the temp file to final file.
virtual srs_error_t rename() = 0;
// Append a frame with dts into fragment.
virtual void append(int64_t dts) = 0;
// Create the dir for file recursively.
virtual srs_error_t create_dir() = 0;
// Set the number of this fragment.
virtual void set_number(uint64_t n) = 0;
// Get the number of this fragment.
virtual uint64_t number() = 0;
// Get the duration of fragment in srs_utime_t.
virtual srs_utime_t duration() = 0;
// Unlink the temporary file.
virtual srs_error_t unlink_tmpfile() = 0;
// Get the start dts of fragment.
virtual srs_utime_t get_start_dts() = 0;
// Unlink the fragment, to delete the file.
virtual srs_error_t unlink_file() = 0;
};
// Represent a fragment, such as HLS segment, DVR segment or DASH segment.
// It's a media file, for example FLV or MP4, with duration.
class SrsFragment
class SrsFragment : public ISrsFragment
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The duration in srs_utime_t.
srs_utime_t dur_;
// The full file path of fragment.
@ -68,13 +104,40 @@ public:
virtual uint64_t number();
};
// The fragment window manage a series of fragment.
class SrsFragmentWindow
// The fragment window interface.
class ISrsFragmentWindow
{
private:
std::vector<SrsFragment *> fragments_;
public:
ISrsFragmentWindow();
virtual ~ISrsFragmentWindow();
public:
// Dispose all fragments, delete the files.
virtual void dispose() = 0;
// Append a new fragment, which is ready to delivery to client.
virtual void append(ISrsFragment *fragment) = 0;
// Shrink the window, push the expired fragment to a queue.
virtual void shrink(srs_utime_t window) = 0;
// Clear the expired fragments.
virtual void clear_expired(bool delete_files) = 0;
// Get the max duration in srs_utime_t of all fragments.
virtual srs_utime_t max_duration() = 0;
public:
virtual bool empty() = 0;
virtual ISrsFragment *first() = 0;
virtual int size() = 0;
virtual ISrsFragment *at(int index) = 0;
};
// The fragment window manage a series of fragment.
class SrsFragmentWindow : public ISrsFragmentWindow
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::vector<ISrsFragment *> fragments_;
// The expired fragments, need to be free in future.
std::vector<SrsFragment *> expired_fragments_;
std::vector<ISrsFragment *> expired_fragments_;
public:
SrsFragmentWindow();
@ -84,7 +147,7 @@ public:
// Dispose all fragments, delete the files.
virtual void dispose();
// Append a new fragment, which is ready to delivery to client.
virtual void append(SrsFragment *fragment);
virtual void append(ISrsFragment *fragment);
// Shrink the window, push the expired fragment to a queue.
virtual void shrink(srs_utime_t window);
// Clear the expired fragments.
@ -94,9 +157,9 @@ public:
public:
virtual bool empty();
virtual SrsFragment *first();
virtual ISrsFragment *first();
virtual int size();
virtual SrsFragment *at(int index);
virtual ISrsFragment *at(int index);
};
#endif

View File

@ -7,6 +7,7 @@
#include <srs_app_gb28181.hpp>
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_http_api.hpp>
#include <srs_app_listener.hpp>
#include <srs_app_rtmp_conn.hpp>
@ -55,6 +56,14 @@ std::string srs_gb_state(SrsGbSessionState ostate, SrsGbSessionState state)
return srs_fmt_sprintf("%s->%s", srs_gb_session_state(ostate).c_str(), srs_gb_session_state(state).c_str());
}
ISrsGbSession::ISrsGbSession()
{
}
ISrsGbSession::~ISrsGbSession()
{
}
SrsGbSession::SrsGbSession() : media_(new SrsGbMediaTcpConn())
{
wrapper_ = NULL;
@ -86,23 +95,27 @@ SrsGbSession::SrsGbSession() : media_(new SrsGbMediaTcpConn())
cid_ = _srs_context->generate_id();
_srs_context->set_id(cid_); // Also change current coroutine cid as session's.
config_ = _srs_config;
}
SrsGbSession::~SrsGbSession()
{
srs_freep(muxer_);
srs_freep(ppp_);
config_ = NULL;
}
void SrsGbSession::setup(SrsConfDirective *conf)
{
std::string output = _srs_config->get_stream_caster_output(conf);
std::string output = config_->get_stream_caster_output(conf);
muxer_->setup(output);
srs_trace("Session: Start output=%s", output.c_str());
}
void SrsGbSession::setup_owner(SrsSharedResource<SrsGbSession> *wrapper, ISrsInterruptable *owner_coroutine, ISrsContextIdSetter *owner_cid)
void SrsGbSession::setup_owner(SrsSharedResource<ISrsGbSession> *wrapper, ISrsInterruptable *owner_coroutine, ISrsContextIdSetter *owner_cid)
{
wrapper_ = wrapper;
owner_coroutine_ = owner_coroutine;
@ -114,7 +127,7 @@ void SrsGbSession::on_executor_done(ISrsInterruptable *executor)
owner_coroutine_ = NULL;
}
void SrsGbSession::on_ps_pack(SrsPackContext *ctx, SrsPsPacket *ps, const std::vector<SrsTsMessage *> &msgs)
void SrsGbSession::on_ps_pack(ISrsPackContext *ctx, SrsPsPacket *ps, const std::vector<SrsTsMessage *> &msgs)
{
// Got a new context, that is new media transport.
if (media_id_ != ctx->media_id_) {
@ -172,7 +185,7 @@ void SrsGbSession::on_ps_pack(SrsPackContext *ctx, SrsPsPacket *ps, const std::v
}
}
void SrsGbSession::on_media_transport(SrsSharedResource<SrsGbMediaTcpConn> media)
void SrsGbSession::on_media_transport(SrsSharedResource<ISrsGbMediaTcpConn> media)
{
media_ = media;
@ -301,29 +314,54 @@ std::string SrsGbSession::desc()
return "GBS";
}
ISrsGbListener::ISrsGbListener()
{
}
ISrsGbListener::~ISrsGbListener()
{
}
SrsGbListener::SrsGbListener()
{
conf_ = NULL;
media_listener_ = new SrsTcpListener(this);
config_ = _srs_config;
api_server_owner_ = NULL;
gb_manager_ = _srs_gb_manager;
app_factory_ = _srs_app_factory;
}
SrsGbListener::~SrsGbListener()
{
srs_freep(conf_);
srs_freep(media_listener_);
config_ = NULL;
api_server_owner_ = NULL;
gb_manager_ = NULL;
app_factory_ = NULL;
}
srs_error_t SrsGbListener::initialize(SrsConfDirective *conf)
{
srs_error_t err = srs_success;
// We should initialize the owner in initialize, because the SRS server
// is not ready in the constructor.
if (!api_server_owner_) {
api_server_owner_ = _srs_server;
}
srs_freep(conf_);
conf_ = conf->copy();
string ip = srs_net_address_any();
if (true) {
int port = _srs_config->get_stream_caster_listen(conf);
media_listener_->set_endpoint(ip, port)->set_label("GB-TCP");
int port = config_->get_stream_caster_listen(conf);
media_listener_->set_endpoint(ip, port);
media_listener_->set_label("GB-TCP");
}
return err;
@ -348,7 +386,11 @@ srs_error_t SrsGbListener::listen_api()
{
srs_error_t err = srs_success;
ISrsHttpServeMux *mux = _srs_server->api_server();
ISrsCommonHttpHandler *mux = api_server_owner_->api_server();
if (!mux) {
return err;
}
if ((err = mux->handle("/gb/v1/publish/", new SrsGoApiGbPublish(conf_))) != srs_success) {
return srs_error_wrap(err, "handle publish");
}
@ -366,13 +408,13 @@ srs_error_t SrsGbListener::on_tcp_client(ISrsListener *listener, srs_netfd_t stf
// Handle TCP connections.
if (listener == media_listener_) {
SrsGbMediaTcpConn *raw_conn = new SrsGbMediaTcpConn();
ISrsGbMediaTcpConn *raw_conn = app_factory_->create_gb_media_tcp_conn();
raw_conn->setup(stfd);
SrsSharedResource<SrsGbMediaTcpConn> *conn = new SrsSharedResource<SrsGbMediaTcpConn>(raw_conn);
_srs_gb_manager->add(conn, NULL);
SrsSharedResource<ISrsGbMediaTcpConn> *conn = new SrsSharedResource<ISrsGbMediaTcpConn>(raw_conn);
gb_manager_->add(conn, NULL);
SrsExecutorCoroutine *executor = new SrsExecutorCoroutine(_srs_gb_manager, conn, raw_conn, raw_conn);
SrsExecutorCoroutine *executor = new SrsExecutorCoroutine(gb_manager_, conn, raw_conn, raw_conn);
raw_conn->setup_owner(conn, executor, executor);
if ((err = executor->start()) != srs_success) {
@ -395,6 +437,14 @@ ISrsPsPackHandler::~ISrsPsPackHandler()
{
}
ISrsGbMediaTcpConn::ISrsGbMediaTcpConn()
{
}
ISrsGbMediaTcpConn::~ISrsGbMediaTcpConn()
{
}
SrsGbMediaTcpConn::SrsGbMediaTcpConn()
{
pack_ = new SrsPackContext(this);
@ -409,6 +459,8 @@ SrsGbMediaTcpConn::SrsGbMediaTcpConn()
session_ = NULL;
connected_ = false;
nn_rtcp_ = 0;
gb_manager_ = _srs_gb_manager;
}
SrsGbMediaTcpConn::~SrsGbMediaTcpConn()
@ -416,6 +468,8 @@ SrsGbMediaTcpConn::~SrsGbMediaTcpConn()
srs_freep(conn_);
srs_freepa(buffer_);
srs_freep(pack_);
gb_manager_ = NULL;
}
void SrsGbMediaTcpConn::setup(srs_netfd_t stfd)
@ -424,7 +478,7 @@ void SrsGbMediaTcpConn::setup(srs_netfd_t stfd)
conn_ = new SrsTcpConnection(stfd);
}
void SrsGbMediaTcpConn::setup_owner(SrsSharedResource<SrsGbMediaTcpConn> *wrapper, ISrsInterruptable *owner_coroutine, ISrsContextIdSetter *owner_cid)
void SrsGbMediaTcpConn::setup_owner(SrsSharedResource<ISrsGbMediaTcpConn> *wrapper, ISrsInterruptable *owner_coroutine, ISrsContextIdSetter *owner_cid)
{
wrapper_ = wrapper;
owner_coroutine_ = owner_coroutine;
@ -511,7 +565,7 @@ srs_error_t SrsGbMediaTcpConn::do_cycle()
SrsRecoverablePsContext context;
// If bytes is not enough(defined by SRS_PS_MIN_REQUIRED), ignore.
context.ctx_.set_detect_ps_integrity(true);
context.ctx_->set_detect_ps_integrity(true);
// Previous left bytes, to parse in next loop.
uint32_t reserved = 0;
@ -538,8 +592,8 @@ srs_error_t SrsGbMediaTcpConn::do_cycle()
}
if (length > SRS_GB_LARGE_PACKET) {
const SrsPsDecodeHelper &h = context.ctx_.helper_;
srs_warn("PS: Large length=%u, previous-seq=%u, previous-ts=%u", length, h.rtp_seq_, h.rtp_ts_);
const SrsPsDecodeHelper *h = context.ctx_->helper();
srs_warn("PS: Large length=%u, previous-seq=%u, previous-ts=%u", length, h->rtp_seq_, h->rtp_ts_);
}
// Read length of bytes of RTP packet.
@ -629,7 +683,7 @@ srs_error_t SrsGbMediaTcpConn::on_ps_pack(SrsPsPacket *ps, const std::vector<Srs
return err;
}
srs_error_t SrsGbMediaTcpConn::bind_session(uint32_t ssrc, SrsGbSession **psession)
srs_error_t SrsGbMediaTcpConn::bind_session(uint32_t ssrc, ISrsGbSession **psession)
{
srs_error_t err = srs_success;
@ -637,11 +691,11 @@ srs_error_t SrsGbMediaTcpConn::bind_session(uint32_t ssrc, SrsGbSession **psessi
return err;
// Find exists session for register, might be created by another object and still alive.
SrsSharedResource<SrsGbSession> *session = dynamic_cast<SrsSharedResource<SrsGbSession> *>(_srs_gb_manager->find_by_fast_id(ssrc));
SrsSharedResource<ISrsGbSession> *session = dynamic_cast<SrsSharedResource<ISrsGbSession> *>(gb_manager_->find_by_fast_id(ssrc));
if (!session)
return err;
SrsGbSession *raw_session = (*session).get();
ISrsGbSession *raw_session = (*session).get();
srs_assert(raw_session);
// Notice session to use current media connection.
@ -651,6 +705,14 @@ srs_error_t SrsGbMediaTcpConn::bind_session(uint32_t ssrc, SrsGbSession **psessi
return err;
}
ISrsMpegpsQueue::ISrsMpegpsQueue()
{
}
ISrsMpegpsQueue::~ISrsMpegpsQueue()
{
}
SrsMpegpsQueue::SrsMpegpsQueue()
{
nb_audios_ = nb_videos_ = 0;
@ -725,7 +787,15 @@ SrsMediaPacket *SrsMpegpsQueue::dequeue()
return NULL;
}
SrsGbMuxer::SrsGbMuxer(SrsGbSession *session)
ISrsGbMuxer::ISrsGbMuxer()
{
}
ISrsGbMuxer::~ISrsGbMuxer()
{
}
SrsGbMuxer::SrsGbMuxer(ISrsGbSession *session)
{
sdk_ = NULL;
session_ = session;
@ -743,6 +813,8 @@ SrsGbMuxer::SrsGbMuxer(SrsGbSession *session)
queue_ = new SrsMpegpsQueue();
pprint_ = SrsPithyPrint::create_caster();
app_factory_ = _srs_app_factory;
}
SrsGbMuxer::~SrsGbMuxer()
@ -754,6 +826,8 @@ SrsGbMuxer::~SrsGbMuxer()
srs_freep(aac_);
srs_freep(queue_);
srs_freep(pprint_);
app_factory_ = NULL;
}
void SrsGbMuxer::setup(std::string output)
@ -1272,7 +1346,7 @@ srs_error_t SrsGbMuxer::connect()
srs_utime_t cto = SRS_CONSTS_RTMP_TIMEOUT;
srs_utime_t sto = SRS_CONSTS_RTMP_PULSE;
sdk_ = new SrsSimpleRtmpClient(url, cto, sto);
sdk_ = app_factory_->create_rtmp_client(url, cto, sto);
if ((err = sdk_->connect()) != srs_success) {
close();
@ -1300,7 +1374,7 @@ void SrsGbMuxer::close()
h264_pps_ = "";
}
SrsPackContext::SrsPackContext(ISrsPsPackHandler *handler)
ISrsPackContext::ISrsPackContext()
{
static uint32_t gid = 0;
media_id_ = ++gid;
@ -1309,7 +1383,14 @@ SrsPackContext::SrsPackContext(ISrsPsPackHandler *handler)
media_nn_recovered_ = 0;
media_nn_msgs_dropped_ = 0;
media_reserved_ = 0;
}
ISrsPackContext::~ISrsPackContext()
{
}
SrsPackContext::SrsPackContext(ISrsPsPackHandler *handler)
{
ps_ = new SrsPsPacket(NULL);
handler_ = handler;
}
@ -1391,13 +1472,23 @@ void SrsPackContext::on_recover_mode(int nn_recover)
}
}
ISrsRecoverablePsContext::ISrsRecoverablePsContext()
{
}
ISrsRecoverablePsContext::~ISrsRecoverablePsContext()
{
}
SrsRecoverablePsContext::SrsRecoverablePsContext()
{
recover_ = 0;
ctx_ = new SrsPsContext();
}
SrsRecoverablePsContext::~SrsRecoverablePsContext()
{
srs_freep(ctx_);
}
srs_error_t SrsRecoverablePsContext::decode_rtp(SrsBuffer *stream, int reserved, ISrsPsMessageHandler *handler)
@ -1434,9 +1525,9 @@ srs_error_t SrsRecoverablePsContext::decode_rtp(SrsBuffer *stream, int reserved,
SrsBuffer b((char *)rtp_raw->payload_, rtp_raw->nn_payload_);
// srs_trace("GB: Got RTP length=%d, payload=%d, seq=%u, ts=%d", length, rtp_raw->nn_payload, rtp.header_.get_sequence(), rtp.header_.get_timestamp());
ctx_.helper_.rtp_seq_ = rtp.header_.get_sequence();
ctx_.helper_.rtp_ts_ = rtp.header_.get_timestamp();
ctx_.helper_.rtp_pt_ = rtp.header_.get_payload_type();
ctx_->helper()->rtp_seq_ = rtp.header_.get_sequence();
ctx_->helper()->rtp_ts_ = rtp.header_.get_timestamp();
ctx_->helper()->rtp_pt_ = rtp.header_.get_payload_type();
if ((err = decode(&b, handler)) != srs_success) {
return srs_error_wrap(err, "decode");
}
@ -1466,7 +1557,7 @@ srs_error_t SrsRecoverablePsContext::decode(SrsBuffer *stream, ISrsPsMessageHand
}
// Got packet to decode.
if ((err = ctx_.decode(stream, handler)) != srs_success) {
if ((err = ctx_->decode(stream, handler)) != srs_success) {
return enter_recover_mode(stream, handler, stream->pos(), srs_error_wrap(err, "decode pack"));
}
return err;
@ -1482,13 +1573,13 @@ srs_error_t SrsRecoverablePsContext::enter_recover_mode(SrsBuffer *stream, ISrsP
stream->skip(pos - stream->pos());
string bytes = srs_strings_dumps_hex(stream->head(), stream->left(), 8);
SrsPsDecodeHelper &h = ctx_.helper_;
uint16_t pack_seq = h.pack_first_seq_;
uint16_t pack_msgs = h.pack_nn_msgs_;
uint16_t lsopm = h.pack_pre_msg_last_seq_;
SrsTsMessage *last = ctx_.last();
SrsPsDecodeHelper *h = ctx_->helper();
uint16_t pack_seq = h->pack_first_seq_;
uint16_t pack_msgs = h->pack_nn_msgs_;
uint16_t lsopm = h->pack_pre_msg_last_seq_;
SrsTsMessage *last = ctx_->last();
srs_warn("PS: Enter recover=%d, seq=%u, ts=%u, pt=%u, pack=%u, msgs=%u, lsopm=%u, last=%u/%u, bytes=[%s], pos=%d, left=%d for err %s",
recover_, h.rtp_seq_, h.rtp_ts_, h.rtp_pt_, pack_seq, pack_msgs, lsopm, last->PES_packet_length_, last->payload_->length(),
recover_, h->rtp_seq_, h->rtp_ts_, h->rtp_pt_, pack_seq, pack_msgs, lsopm, last->PES_packet_length_, last->payload_->length(),
bytes.c_str(), npos, stream->left(), srs_error_desc(err).c_str());
// If RTP packet exceed SRS_GB_LARGE_PACKET, which is large packet, might be correct length and impossible to
@ -1500,11 +1591,11 @@ srs_error_t SrsRecoverablePsContext::enter_recover_mode(SrsBuffer *stream, ISrsP
// Sometimes, we're unable to recover it, so we limit the max retry.
if (recover_ > SRS_GB_MAX_RECOVER) {
return srs_error_wrap(err, "exceed max recover, pack=%u, pack-seq=%u, seq=%u",
h.pack_id_, h.pack_first_seq_, h.rtp_seq_);
h->pack_id_, h->pack_first_seq_, h->rtp_seq_);
}
// Reap and dispose last incomplete message.
SrsTsMessage *msg = ctx_.reap();
SrsTsMessage *msg = ctx_->reap();
srs_freep(msg);
// Skip all left bytes in buffer, reset error because recovered.
stream->skip(stream->left());
@ -1519,7 +1610,7 @@ srs_error_t SrsRecoverablePsContext::enter_recover_mode(SrsBuffer *stream, ISrsP
void SrsRecoverablePsContext::quit_recover_mode(SrsBuffer *stream, ISrsPsMessageHandler *handler)
{
string bytes = srs_strings_dumps_hex(stream->head(), stream->left(), 8);
srs_warn("PS: Quit recover=%d, seq=%u, bytes=[%s], pos=%d, left=%d", recover_, ctx_.helper_.rtp_seq_,
srs_warn("PS: Quit recover=%d, seq=%u, bytes=[%s], pos=%d, left=%d", recover_, ctx_->helper()->rtp_seq_,
bytes.c_str(), stream->pos(), stream->left());
recover_ = 0;
}
@ -1550,11 +1641,19 @@ bool srs_skip_util_pack(SrsBuffer *stream)
SrsGoApiGbPublish::SrsGoApiGbPublish(SrsConfDirective *conf)
{
conf_ = conf->copy();
config_ = _srs_config;
gb_manager_ = _srs_gb_manager;
app_factory_ = _srs_app_factory;
}
SrsGoApiGbPublish::~SrsGoApiGbPublish()
{
srs_freep(conf_);
config_ = NULL;
gb_manager_ = NULL;
app_factory_ = NULL;
}
srs_error_t SrsGoApiGbPublish::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
@ -1615,7 +1714,7 @@ srs_error_t SrsGoApiGbPublish::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttp
}
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
int port = _srs_config->get_stream_caster_listen(conf_);
int port = config_->get_stream_caster_listen(conf_);
res->set("port", SrsJsonAny::integer(port));
res->set("is_tcp", SrsJsonAny::boolean(true)); // only tcp supported
@ -1628,26 +1727,26 @@ srs_error_t SrsGoApiGbPublish::bind_session(std::string id, uint64_t ssrc)
{
srs_error_t err = srs_success;
SrsSharedResource<SrsGbSession> *session = NULL;
session = dynamic_cast<SrsSharedResource<SrsGbSession> *>(_srs_gb_manager->find_by_id(id));
SrsSharedResource<ISrsGbSession> *session = NULL;
session = dynamic_cast<SrsSharedResource<ISrsGbSession> *>(gb_manager_->find_by_id(id));
if (session) {
return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "stream already exists");
}
session = dynamic_cast<SrsSharedResource<SrsGbSession> *>(_srs_gb_manager->find_by_fast_id(ssrc));
session = dynamic_cast<SrsSharedResource<ISrsGbSession> *>(gb_manager_->find_by_fast_id(ssrc));
if (session) {
return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "ssrc already exists");
}
// Create new GB session.
SrsGbSession *raw_session = new SrsGbSession();
ISrsGbSession *raw_session = app_factory_->create_gb_session();
raw_session->setup(conf_);
session = new SrsSharedResource<SrsGbSession>(raw_session);
_srs_gb_manager->add_with_id(id, session);
_srs_gb_manager->add_with_fast_id(ssrc, session);
session = new SrsSharedResource<ISrsGbSession>(raw_session);
gb_manager_->add_with_id(id, session);
gb_manager_->add_with_fast_id(ssrc, session);
SrsExecutorCoroutine *executor = new SrsExecutorCoroutine(_srs_gb_manager, session, raw_session, raw_session);
SrsExecutorCoroutine *executor = new SrsExecutorCoroutine(gb_manager_, session, raw_session, raw_session);
raw_session->setup_owner(session, executor, executor);
raw_session->device_id_ = id;

View File

@ -24,11 +24,8 @@ class SrsTcpConnection;
class ISrsCoroutine;
class SrsPackContext;
class SrsBuffer;
class SrsGbSession;
class SrsGbMediaTcpConn;
class SrsAlonePithyPrint;
class SrsGbMuxer;
class SrsSimpleRtmpClient;
@ -38,7 +35,28 @@ class SrsRawHEVCStream;
class SrsMediaPacket;
class SrsPithyPrint;
class SrsRawAacStream;
class ISrsHttpServeMux;
class ISrsCommonHttpHandler;
class ISrsGbMuxer;
class ISrsGbSession;
class ISrsPackContext;
class ISrsMpegpsQueue;
class ISrsPsContext;
class ISrsListener;
class ISrsProtocolReadWriter;
class ISrsRawH264Stream;
class ISrsRawHEVCStream;
class ISrsRawAacStream;
class ISrsPithyPrint;
class ISrsBasicRtmpClient;
class SrsTsMessage;
class SrsPsPacket;
class ISrsGbSession;
class ISrsGbMediaTcpConn;
class ISrsAppConfig;
class ISrsApiServerOwner;
class ISrsResourceManager;
class ISrsAppFactory;
class ISrsIpListener;
// The state machine for GB session.
// init:
@ -55,6 +73,7 @@ enum SrsGbSessionState {
SrsGbSessionStateEstablished,
};
std::string srs_gb_session_state(SrsGbSessionState state);
std::string srs_gb_state(SrsGbSessionState ostate, SrsGbSessionState state);
// For external SIP server mode, where SRS acts only as a media relay server
// 1. SIP server POST request via HTTP API with stream ID and SSRC
@ -72,7 +91,14 @@ std::string srs_gb_session_state(SrsGbSessionState state);
// {"port":9000, "is_tcp": true}
class SrsGoApiGbPublish : public ISrsHttpHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsResourceManager *gb_manager_;
ISrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsConfDirective *conf_;
public:
@ -82,34 +108,65 @@ public:
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, SrsJsonObject *res);
srs_error_t bind_session(std::string stream, uint64_t ssrc);
};
// The interface for GB session.
class ISrsGbSession : public ISrsResource, public ISrsCoroutineHandler, public ISrsExecutorHandler
{
public:
std::string device_id_;
public:
ISrsGbSession();
virtual ~ISrsGbSession();
public:
// Initialize the GB session.
virtual void setup(SrsConfDirective *conf) = 0;
// Setup the owner, the wrapper is the shared ptr, the interruptable object is the coroutine, and the cid is the context id.
virtual void setup_owner(SrsSharedResource<ISrsGbSession> *wrapper, ISrsInterruptable *owner_coroutine, ISrsContextIdSetter *owner_cid) = 0;
// Notice session to use current media connection.
virtual void on_media_transport(SrsSharedResource<ISrsGbMediaTcpConn> media) = 0;
public:
virtual void on_ps_pack(ISrsPackContext *ctx, SrsPsPacket *ps, const std::vector<SrsTsMessage *> &msgs) = 0;
};
// The main logic object for GB, the session.
// Each session contains a media object, that are managed by session. This means session always
// lives longer than media, and session will dispose media when session disposed. In another word,
// media objects use directly pointer to session, while session use shared ptr.
class SrsGbSession : public ISrsResource, public ISrsCoroutineHandler, public ISrsExecutorHandler
class SrsGbSession : public ISrsGbSession
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsContextId cid_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The shared resource which own this object, we should never free it because it's managed by shared ptr.
SrsSharedResource<SrsGbSession> *wrapper_;
SrsSharedResource<ISrsGbSession> *wrapper_;
// The owner coroutine, allow user to interrupt the loop.
ISrsInterruptable *owner_coroutine_;
ISrsContextIdSetter *owner_cid_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsGbSessionState state_;
SrsSharedResource<SrsGbMediaTcpConn> media_;
SrsGbMuxer *muxer_;
SrsSharedResource<ISrsGbMediaTcpConn> media_;
ISrsGbMuxer *muxer_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// When wait for media connecting, timeout if exceed.
srs_utime_t connecting_starttime_;
// The time we enter reinviting state.
@ -117,7 +174,8 @@ private:
// The number of timeout, dispose session if exceed.
uint32_t nn_timeout_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsAlonePithyPrint *ppp_;
srs_utime_t startime_;
uint64_t total_packs_;
@ -126,7 +184,8 @@ private:
uint64_t total_msgs_dropped_;
uint64_t total_reserved_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
uint32_t media_id_;
srs_utime_t media_starttime_;
uint64_t media_msgs_;
@ -148,27 +207,29 @@ public:
// Initialize the GB session.
void setup(SrsConfDirective *conf);
// Setup the owner, the wrapper is the shared ptr, the interruptable object is the coroutine, and the cid is the context id.
void setup_owner(SrsSharedResource<SrsGbSession> *wrapper, ISrsInterruptable *owner_coroutine, ISrsContextIdSetter *owner_cid);
void setup_owner(SrsSharedResource<ISrsGbSession> *wrapper, ISrsInterruptable *owner_coroutine, ISrsContextIdSetter *owner_cid);
// Interface ISrsExecutorHandler
public:
virtual void on_executor_done(ISrsInterruptable *executor);
public:
// When got a pack of messages.
void on_ps_pack(SrsPackContext *ctx, SrsPsPacket *ps, const std::vector<SrsTsMessage *> &msgs);
void on_ps_pack(ISrsPackContext *ctx, SrsPsPacket *ps, const std::vector<SrsTsMessage *> &msgs);
// When got available media transport.
void on_media_transport(SrsSharedResource<SrsGbMediaTcpConn> media);
void on_media_transport(SrsSharedResource<ISrsGbMediaTcpConn> media);
// Interface ISrsCoroutineHandler
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_cycle();
srs_error_t drive_state();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsGbSessionState set_state(SrsGbSessionState v);
// Interface ISrsResource
public:
@ -176,12 +237,30 @@ public:
virtual std::string desc();
};
// The Media listener for GB.
class SrsGbListener : public ISrsListener, public ISrsTcpHandler
// The listener for GB.
class ISrsGbListener : public ISrsListener
{
private:
public:
ISrsGbListener();
virtual ~ISrsGbListener();
public:
};
// The Media listener for GB.
class SrsGbListener : public ISrsGbListener, public ISrsTcpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsApiServerOwner *api_server_owner_;
ISrsResourceManager *gb_manager_;
ISrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsConfDirective *conf_;
SrsTcpListener *media_listener_;
ISrsIpListener *media_listener_;
public:
SrsGbListener();
@ -195,7 +274,8 @@ public:
public:
virtual srs_error_t on_tcp_client(ISrsListener *listener, srs_netfd_t stfd);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t listen_api();
};
@ -212,26 +292,54 @@ public:
virtual srs_error_t on_ps_pack(SrsPsPacket *ps, const std::vector<SrsTsMessage *> &msgs) = 0;
};
// A GB28181 TCP media connection, for PS stream.
class SrsGbMediaTcpConn : public ISrsResource, public ISrsCoroutineHandler, public ISrsPsPackHandler, public ISrsExecutorHandler
// The interface for GB media transport.
class ISrsGbMediaTcpConn : public ISrsResource, public ISrsCoroutineHandler, public ISrsExecutorHandler
{
private:
public:
ISrsGbMediaTcpConn();
virtual ~ISrsGbMediaTcpConn();
public:
// Setup object, to keep empty constructor.
virtual void setup(srs_netfd_t stfd) = 0;
// Setup the owner, the wrapper is the shared ptr, the interruptable object is the coroutine, and the cid is the context id.
virtual void setup_owner(SrsSharedResource<ISrsGbMediaTcpConn> *wrapper, ISrsInterruptable *owner_coroutine, ISrsContextIdSetter *owner_cid) = 0;
// Whether media is connected.
virtual bool is_connected() = 0;
// Interrupt transport by session.
virtual void interrupt() = 0;
// Set the cid of all coroutines.
virtual void set_cid(const SrsContextId &cid) = 0;
};
// A GB28181 TCP media connection, for PS stream.
class SrsGbMediaTcpConn : public ISrsGbMediaTcpConn, // It's a resource, coroutine handler, and executor handler.
public ISrsPsPackHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsResourceManager *gb_manager_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool connected_;
// The owner session object, note that we use the raw pointer and should never free it.
SrsGbSession *session_;
ISrsGbSession *session_;
uint32_t nn_rtcp_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The shared resource which own this object, we should never free it because it's managed by shared ptr.
SrsSharedResource<SrsGbMediaTcpConn> *wrapper_;
SrsSharedResource<ISrsGbMediaTcpConn> *wrapper_;
// The owner coroutine, allow user to interrupt the loop.
ISrsInterruptable *owner_coroutine_;
ISrsContextIdSetter *owner_cid_;
SrsContextId cid_;
private:
SrsPackContext *pack_;
SrsTcpConnection *conn_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsPackContext *pack_;
ISrsProtocolReadWriter *conn_;
uint8_t *buffer_;
public:
@ -242,7 +350,7 @@ public:
// Setup object, to keep empty constructor.
void setup(srs_netfd_t stfd);
// Setup the owner, the wrapper is the shared ptr, the interruptable object is the coroutine, and the cid is the context id.
void setup_owner(SrsSharedResource<SrsGbMediaTcpConn> *wrapper, ISrsInterruptable *owner_coroutine, ISrsContextIdSetter *owner_cid);
void setup_owner(SrsSharedResource<ISrsGbMediaTcpConn> *wrapper, ISrsInterruptable *owner_coroutine, ISrsContextIdSetter *owner_cid);
// Interface ISrsExecutorHandler
public:
virtual void on_executor_done(ISrsInterruptable *executor);
@ -262,25 +370,42 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_cycle();
// Interface ISrsPsPackHandler
public:
virtual srs_error_t on_ps_pack(SrsPsPacket *ps, const std::vector<SrsTsMessage *> &msgs);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Create session if no one, or bind to an existed session.
srs_error_t bind_session(uint32_t ssrc, SrsGbSession **psession);
srs_error_t
bind_session(uint32_t ssrc, ISrsGbSession **psession);
};
// The interface for mpegps queue.
class ISrsMpegpsQueue
{
public:
ISrsMpegpsQueue();
virtual ~ISrsMpegpsQueue();
public:
virtual srs_error_t push(SrsMediaPacket *msg) = 0;
virtual SrsMediaPacket *dequeue() = 0;
};
// The queue for mpegts over udp to send packets.
// For the aac in mpegts contains many flv packets in a pes packet,
// we must recalc the timestamp.
class SrsMpegpsQueue
class SrsMpegpsQueue : public ISrsMpegpsQueue
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The key: dts, value: msg.
std::map<int64_t, SrsMediaPacket *> msgs_;
std::map<int64_t, SrsMediaPacket *>
msgs_;
int nb_audios_;
int nb_videos_;
@ -293,47 +418,68 @@ public:
virtual SrsMediaPacket *dequeue();
};
// Mux GB28181 to RTMP.
class SrsGbMuxer
// The interface for GB muxer.
class ISrsGbMuxer
{
private:
// The owner session object, note that we use the raw pointer and should never free it.
SrsGbSession *session_;
std::string output_;
SrsSimpleRtmpClient *sdk_;
public:
ISrsGbMuxer();
virtual ~ISrsGbMuxer();
private:
SrsRawH264Stream *avc_;
public:
virtual void setup(std::string output) = 0;
virtual srs_error_t on_ts_message(SrsTsMessage *msg) = 0;
};
// Mux GB28181 to RTMP.
class SrsGbMuxer : public ISrsGbMuxer
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The owner session object, note that we use the raw pointer and should never free it.
ISrsGbSession *session_;
std::string output_;
ISrsBasicRtmpClient *sdk_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRawH264Stream *avc_;
std::string h264_sps_;
bool h264_sps_changed_;
std::string h264_pps_;
bool h264_pps_changed_;
bool h264_sps_pps_sent_;
SrsRawHEVCStream *hevc_;
ISrsRawHEVCStream *hevc_;
bool vps_sps_pps_change_;
std::string h265_vps_;
std::string h265_sps_;
std::string h265_pps_;
bool vps_sps_pps_sent_;
private:
SrsRawAacStream *aac_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRawAacStream *aac_;
std::string aac_specific_config_;
private:
SrsMpegpsQueue *queue_;
SrsPithyPrint *pprint_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsMpegpsQueue *queue_;
ISrsPithyPrint *pprint_;
public:
SrsGbMuxer(SrsGbSession *session);
SrsGbMuxer(ISrsGbSession *session);
virtual ~SrsGbMuxer();
public:
void setup(std::string output);
srs_error_t on_ts_message(SrsTsMessage *msg);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t on_ts_video(SrsTsMessage *msg, SrsBuffer *avs);
virtual srs_error_t mux_h264(SrsTsMessage *msg, SrsBuffer *avs);
virtual srs_error_t write_h264_sps_pps(uint32_t dts, uint32_t pts);
@ -345,20 +491,33 @@ private:
virtual srs_error_t write_audio_raw_frame(char *frame, int frame_size, SrsRawAacStreamCodec *codec, uint32_t dts);
virtual srs_error_t rtmp_write_packet(char type, uint32_t timestamp, char *data, int size);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Connect to RTMP server.
virtual srs_error_t connect();
virtual srs_error_t
connect();
// Close the connection to RTMP server.
virtual void close();
};
// Recoverable PS context for GB28181.
class SrsRecoverablePsContext
// The interface for recoverable PS context.
class ISrsRecoverablePsContext
{
public:
SrsPsContext ctx_;
ISrsRecoverablePsContext();
virtual ~ISrsRecoverablePsContext();
private:
public:
};
// Recoverable PS context for GB28181.
class SrsRecoverablePsContext : public ISrsRecoverablePsContext
{
public:
ISrsPsContext *ctx_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// If decoding error, enter the recover mode. Drop all left bytes util next pack header.
int recover_;
@ -371,22 +530,19 @@ public:
// parsed by previous decoding, we should move to the start of payload bytes.
virtual srs_error_t decode_rtp(SrsBuffer *stream, int reserved, ISrsPsMessageHandler *handler);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Decode the RTP payload as PS pack stream.
virtual srs_error_t decode(SrsBuffer *stream, ISrsPsMessageHandler *handler);
virtual srs_error_t
decode(SrsBuffer *stream, ISrsPsMessageHandler *handler);
// When got error, drop data and enter recover mode.
srs_error_t enter_recover_mode(SrsBuffer *stream, ISrsPsMessageHandler *handler, int pos, srs_error_t err);
// Quit Recover mode when got pack header.
void quit_recover_mode(SrsBuffer *stream, ISrsPsMessageHandler *handler);
};
// The PS pack context, for GB28181 to process based on PS pack, which contains a video and audios messages. For large
// video frame, it might be split to multiple PES packets, which must be group to one video frame.
// Please note that a pack might contain multiple audio frames, so size of audio PES packet should not exceed 64KB,
// which is limited by the 16 bits PES_packet_length.
// We also correct the timestamp, or DTS/PTS of video frames, which might be 0 if more than one video PES packets in a
// PS pack stream.
class SrsPackContext : public ISrsPsMessageHandler
// The interface for PS pack context.
class ISrsPackContext : public ISrsPsMessageHandler
{
public:
// Each media transport only use one context, so the context id is the media id.
@ -396,7 +552,21 @@ public:
uint64_t media_nn_msgs_dropped_;
uint64_t media_reserved_;
private:
public:
ISrsPackContext();
virtual ~ISrsPackContext();
};
// The PS pack context, for GB28181 to process based on PS pack, which contains a video and audios messages. For large
// video frame, it might be split to multiple PES packets, which must be group to one video frame.
// Please note that a pack might contain multiple audio frames, so size of audio PES packet should not exceed 64KB,
// which is limited by the 16 bits PES_packet_length.
// We also correct the timestamp, or DTS/PTS of video frames, which might be 0 if more than one video PES packets in a
// PS pack stream.
class SrsPackContext : public ISrsPackContext
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// To process a pack of TS/PS messages.
ISrsPsPackHandler *handler_;
// Note that it might be freed, so never use its fields.
@ -408,8 +578,9 @@ public:
SrsPackContext(ISrsPsPackHandler *handler);
virtual ~SrsPackContext();
private:
public:
void clear();
// Interface ISrsPsMessageHandler
public:
virtual srs_error_t on_ts_message(SrsTsMessage *msg);

View File

@ -45,12 +45,14 @@ public:
srs_error_t on_video(SrsMediaPacket *msg);
srs_error_t on_audio(SrsMediaPacket *msg);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t flush_mainfest();
srs_error_t flush_bootstrap();
void adjust_windows();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::list<SrsHdsFragment *> fragments_;
SrsHdsFragment *currentSegment_;
int fragment_index_;

View File

@ -10,6 +10,7 @@
using namespace std;
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_http_client.hpp>
#include <srs_app_http_conn.hpp>
#include <srs_app_statistic.hpp>
@ -23,10 +24,14 @@ using namespace std;
SrsHttpHeartbeat::SrsHttpHeartbeat()
{
config_ = _srs_config;
app_factory_ = _srs_app_factory;
}
SrsHttpHeartbeat::~SrsHttpHeartbeat()
{
config_ = NULL;
app_factory_ = NULL;
}
void SrsHttpHeartbeat::heartbeat()
@ -43,7 +48,7 @@ srs_error_t SrsHttpHeartbeat::do_heartbeat()
{
srs_error_t err = srs_success;
std::string url = _srs_config->get_heartbeat_url();
std::string url = config_->get_heartbeat_url();
SrsHttpUri uri;
if ((err = uri.initialize(url)) != srs_success) {
@ -51,7 +56,7 @@ srs_error_t SrsHttpHeartbeat::do_heartbeat()
}
string ip;
std::string device_id = _srs_config->get_heartbeat_device_id();
std::string device_id = config_->get_heartbeat_device_id();
// Try to load the ip from the environment variable.
ip = srs_getenv("srs.device.ip"); // SRS_DEVICE_IP
@ -60,7 +65,7 @@ srs_error_t SrsHttpHeartbeat::do_heartbeat()
SrsProtocolUtility utility;
vector<SrsIPAddress *> &ips = utility.local_ips();
if (!ips.empty()) {
ip = ips[_srs_config->get_stats_network() % (int)ips.size()]->ip_;
ip = ips[config_->get_stats_network() % (int)ips.size()]->ip_;
}
}
@ -74,82 +79,82 @@ srs_error_t SrsHttpHeartbeat::do_heartbeat()
obj->set("service", SrsJsonAny::str(stat->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat->service_pid().c_str()));
if (_srs_config->get_heartbeat_summaries()) {
if (config_->get_heartbeat_summaries()) {
SrsJsonObject *summaries = SrsJsonAny::object();
obj->set("summaries", summaries);
srs_api_dump_summaries(summaries);
}
if (_srs_config->get_heartbeat_ports()) {
if (config_->get_heartbeat_ports()) {
// For RTMP listen endpoints.
if (true) {
SrsJsonArray *o = SrsJsonAny::array();
obj->set("rtmp", o);
vector<string> endpoints = _srs_config->get_listens();
vector<string> endpoints = config_->get_listens();
for (int i = 0; i < (int)endpoints.size(); i++) {
o->append(SrsJsonAny::str(endpoints.at(i).c_str()));
}
}
// For HTTP Stream listen endpoints.
if (_srs_config->get_http_stream_enabled()) {
if (config_->get_http_stream_enabled()) {
SrsJsonArray *o = SrsJsonAny::array();
obj->set("http", o);
vector<string> endpoints = _srs_config->get_http_stream_listens();
vector<string> endpoints = config_->get_http_stream_listens();
for (int i = 0; i < (int)endpoints.size(); i++) {
o->append(SrsJsonAny::str(endpoints.at(i).c_str()));
}
}
// For HTTP API listen endpoints.
if (_srs_config->get_http_api_enabled()) {
if (config_->get_http_api_enabled()) {
SrsJsonArray *o = SrsJsonAny::array();
obj->set("api", o);
vector<string> endpoints = _srs_config->get_http_api_listens();
vector<string> endpoints = config_->get_http_api_listens();
for (int i = 0; i < (int)endpoints.size(); i++) {
o->append(SrsJsonAny::str(endpoints.at(i).c_str()));
}
}
// For SRT listen endpoints.
if (_srs_config->get_srt_enabled()) {
if (config_->get_srt_enabled()) {
SrsJsonArray *o = SrsJsonAny::array();
obj->set("srt", o);
vector<string> endpoints = _srs_config->get_srt_listens();
vector<string> endpoints = config_->get_srt_listens();
for (int i = 0; i < (int)endpoints.size(); i++) {
o->append(SrsJsonAny::str(endpoints.at(i).c_str()));
}
}
// For RTSP listen endpoints.
if (_srs_config->get_rtsp_server_enabled()) {
if (config_->get_rtsp_server_enabled()) {
SrsJsonArray *o = SrsJsonAny::array();
obj->set("rtsp", o);
vector<string> endpoints = _srs_config->get_rtsp_server_listens();
vector<string> endpoints = config_->get_rtsp_server_listens();
for (int i = 0; i < (int)endpoints.size(); i++) {
o->append(SrsJsonAny::str(endpoints.at(i).c_str()));
}
}
// For WebRTC listen endpoints.
if (_srs_config->get_rtc_server_enabled()) {
if (config_->get_rtc_server_enabled()) {
SrsJsonArray *o = SrsJsonAny::array();
obj->set("rtc", o);
vector<string> endpoints = _srs_config->get_rtc_server_listens();
vector<string> endpoints = config_->get_rtc_server_listens();
for (int i = 0; i < (int)endpoints.size(); i++) {
string endpoint = srs_fmt_sprintf("udp://%s", endpoints.at(i).c_str());
o->append(SrsJsonAny::str(endpoint.c_str()));
}
if (_srs_config->get_rtc_server_tcp_enabled()) {
vector<string> endpoints = _srs_config->get_rtc_server_tcp_listens();
if (config_->get_rtc_server_tcp_enabled()) {
vector<string> endpoints = config_->get_rtc_server_tcp_listens();
for (int i = 0; i < (int)endpoints.size(); i++) {
string endpoint = srs_fmt_sprintf("tcp://%s", endpoints.at(i).c_str());
o->append(SrsJsonAny::str(endpoint.c_str()));
@ -158,14 +163,14 @@ srs_error_t SrsHttpHeartbeat::do_heartbeat()
}
}
SrsHttpClient http;
if ((err = http.initialize(uri.get_schema(), uri.get_host(), uri.get_port())) != srs_success) {
SrsUniquePtr<ISrsHttpClient> http(app_factory_->create_http_client());
if ((err = http->initialize(uri.get_schema(), uri.get_host(), uri.get_port())) != srs_success) {
return srs_error_wrap(err, "init uri=%s", uri.get_url().c_str());
}
std::string req = obj->dumps();
ISrsHttpMessage *msg_raw = NULL;
if ((err = http.post(uri.get_path(), req, &msg_raw)) != srs_success) {
if ((err = http->post(uri.get_path(), req, &msg_raw)) != srs_success) {
return srs_error_wrap(err, "http post hartbeart uri failed. url=%s, request=%s", url.c_str(), req.c_str());
}

View File

@ -9,9 +9,17 @@
#include <srs_core.hpp>
class ISrsAppConfig;
class ISrsAppFactory;
// The http heartbeat to api-server to notice api that the information of SRS.
class SrsHttpHeartbeat
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsAppFactory *app_factory_;
public:
SrsHttpHeartbeat();
virtual ~SrsHttpHeartbeat();
@ -19,7 +27,8 @@ public:
public:
virtual void heartbeat();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_heartbeat();
};

View File

@ -38,7 +38,7 @@ class SrsTsContext;
class SrsFmp4SegmentEncoder;
class ISrsHttpHooks;
class ISrsAppConfig;
class SrsAppFactory;
class ISrsAppFactory;
// The wrapper of m3u8 segment from specification:
//
@ -73,11 +73,13 @@ public:
class SrsInitMp4Segment : public SrsFragment
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsFileWriter *fw_;
SrsMp4M2tsInitEncoder init_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Key ID for encryption
unsigned char kid_[16];
// Constant IV for encryption
@ -96,14 +98,16 @@ public:
virtual srs_error_t write_video_only(SrsFormat *format, int v_tid);
virtual srs_error_t write_audio_only(SrsFormat *format, int a_tid);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t init_encoder();
};
// TODO: merge this code with SrsFragmentedMp4 in dash
class SrsHlsM4sSegment : public SrsFragment
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsFileWriter *fw_;
SrsFmp4SegmentEncoder enc_;
@ -130,11 +134,13 @@ public:
// The hls async call: on_hls
class SrsDvrAsyncCallOnHls : public ISrsAsyncCallTask
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsHttpHooks *hooks_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsContextId cid_;
std::string path_;
std::string ts_url_;
@ -157,11 +163,13 @@ public:
// The hls async call: on_hls_notify
class SrsDvrAsyncCallOnHlsNotify : public ISrsAsyncCallTask
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsHttpHooks *hooks_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsContextId cid_;
std::string ts_url_;
ISrsRequest *req_;
@ -184,14 +192,17 @@ public:
// TODO: Rename to SrsHlsTsMuxer, for TS file only.
class SrsHlsMuxer
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
SrsAppFactory *app_factory_;
ISrsAppFactory *app_factory_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string hls_entry_prefix_;
std::string hls_path_;
std::string hls_ts_file_;
@ -204,7 +215,8 @@ private:
srs_utime_t hls_window_;
SrsAsyncCallWorker *async_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Whether use floor algorithm for timestamp.
bool hls_ts_floor_;
// The deviation in piece to adjust the fragment to be more
@ -215,7 +227,8 @@ private:
int64_t accept_floor_ts_;
int64_t previous_floor_ts_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Whether encrypted or not
bool hls_keys_;
int hls_fragments_per_key_;
@ -231,13 +244,15 @@ private:
// The underlayer file writer.
ISrsFileWriter *writer_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
int sequence_no_;
srs_utime_t max_td_;
std::string m3u8_;
std::string m3u8_url_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The available cached segments in m3u8.
SrsFragmentWindow *segments_;
// The current writing segment.
@ -245,7 +260,8 @@ private:
// The ts context, to keep cc continous between ts.
SrsTsContext *context_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Latest audio codec, parsed from stream.
SrsAudioCodecId latest_acodec_;
// Latest audio codec, parsed from stream.
@ -306,7 +322,8 @@ public:
// Close segment(ts).
virtual srs_error_t segment_close();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_segment_close();
virtual srs_error_t write_hls_key();
virtual srs_error_t refresh_m3u8();
@ -318,7 +335,8 @@ public:
// HLS recover mode.
srs_error_t recover_hls();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_recover_hls();
};
@ -327,14 +345,17 @@ private:
// to flush video/audio, without any mechenisms.
class SrsHlsFmp4Muxer
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
SrsAppFactory *app_factory_;
ISrsAppFactory *app_factory_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string hls_entry_prefix_;
std::string hls_path_;
std::string hls_m4s_file_;
@ -347,7 +368,8 @@ private:
srs_utime_t hls_window_;
SrsAsyncCallWorker *async_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Whether use floor algorithm for timestamp.
bool hls_ts_floor_;
// The deviation in piece to adjust the fragment to be more
@ -359,7 +381,8 @@ private:
int64_t previous_floor_ts_;
bool init_mp4_ready_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Whether encrypted or not
// TODO: fmp4 encryption is not yet implemented.
// fmp4 support four kinds of protection scheme: 'cenc', 'cbc1', 'cens', 'cbcs'.
@ -385,7 +408,8 @@ private:
// The underlayer file writer.
ISrsFileWriter *writer_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
int sequence_no_;
srs_utime_t max_td_;
std::string m3u8_;
@ -395,13 +419,15 @@ private:
int audio_track_id_;
uint64_t video_dts_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The available cached segments in m3u8.
SrsFragmentWindow *segments_;
// The current writing segment.
SrsHlsM4sSegment *current_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Latest audio codec, parsed from stream.
SrsAudioCodecId latest_acodec_;
// Latest audio codec, parsed from stream.
@ -461,7 +487,8 @@ public:
// Close segment(ts).
virtual srs_error_t segment_close();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_segment_close();
virtual srs_error_t write_hls_key();
virtual srs_error_t refresh_m3u8();
@ -513,10 +540,12 @@ public:
// TODO: Rename to SrsHlsTsController, for TS file only.
class SrsHlsController : public ISrsHlsController
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The HLS muxer to reap ts and m3u8.
// The TS is cached to SrsTsMessageCache then flush to ts segment.
SrsHlsMuxer *muxer_;
@ -557,39 +586,47 @@ public:
// write video to muxer.
virtual srs_error_t write_video(SrsMediaPacket *shared_video, SrsFormat *format);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Reopen the muxer for a new hls segment,
// close current segment, open a new segment,
// then write the key frame to the new segment.
// so, user must reap_segment then flush_video to hls muxer.
virtual srs_error_t reap_segment();
virtual srs_error_t
reap_segment();
};
// HLS controller for fMP4 (.m4s) segments with init.mp4.
// Direct sample processing without caching, simpler than TS controller.
class SrsHlsMp4Controller : public ISrsHlsController
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool has_video_sh_;
bool has_audio_sh_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
int video_track_id_;
int audio_track_id_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Current audio dts.
uint64_t audio_dts_;
// Current video dts.
uint64_t video_dts_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsHlsFmp4Muxer *muxer_;
public:
@ -637,13 +674,16 @@ public:
// TODO: FIXME: add utest for hls.
class SrsHls : public ISrsHls
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsHlsController *controller_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
// Whether the HLS is enabled.
bool enabled_;
@ -657,7 +697,8 @@ private:
// To detect heartbeat and dispose it if configured.
srs_utime_t last_update_time_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsOriginHub *hub_;
SrsRtmpJitter *jitter_;
SrsPithyPrint *pprint_;
@ -669,7 +710,8 @@ public:
public:
virtual void async_reload();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t reload();
srs_error_t do_reload(int *reloading, int *reloaded, int *refreshed);
@ -697,7 +739,8 @@ public:
// TODO: FIXME: Remove param is_sps_pps.
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual void hls_show_mux_log();
};

View File

@ -170,22 +170,22 @@ srs_error_t srs_api_response_code(ISrsHttpResponseWriter *w, ISrsHttpMessage *r,
SrsGoApiRoot::SrsGoApiRoot()
{
stat_ = _srs_stat;
}
SrsGoApiRoot::~SrsGoApiRoot()
{
stat_ = NULL;
}
srs_error_t SrsGoApiRoot::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
SrsStatistic *stat = _srs_stat;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
SrsJsonObject *urls = SrsJsonAny::object();
obj->set("urls", urls);
@ -209,22 +209,22 @@ srs_error_t SrsGoApiRoot::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage
SrsGoApiApi::SrsGoApiApi()
{
stat_ = _srs_stat;
}
SrsGoApiApi::~SrsGoApiApi()
{
stat_ = NULL;
}
srs_error_t SrsGoApiApi::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
SrsStatistic *stat = _srs_stat;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
SrsJsonObject *urls = SrsJsonAny::object();
obj->set("urls", urls);
@ -236,22 +236,22 @@ srs_error_t SrsGoApiApi::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *
SrsGoApiV1::SrsGoApiV1()
{
stat_ = _srs_stat;
}
SrsGoApiV1::~SrsGoApiV1()
{
stat_ = NULL;
}
srs_error_t SrsGoApiV1::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
SrsStatistic *stat = _srs_stat;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
SrsJsonObject *urls = SrsJsonAny::object();
obj->set("urls", urls);
@ -292,22 +292,22 @@ srs_error_t SrsGoApiV1::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r
SrsGoApiVersion::SrsGoApiVersion()
{
stat_ = _srs_stat;
}
SrsGoApiVersion::~SrsGoApiVersion()
{
stat_ = NULL;
}
srs_error_t SrsGoApiVersion::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
SrsStatistic *stat = _srs_stat;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
SrsJsonObject *data = SrsJsonAny::object();
obj->set("data", data);
@ -322,22 +322,22 @@ srs_error_t SrsGoApiVersion::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
SrsGoApiSummaries::SrsGoApiSummaries()
{
stat_ = _srs_stat;
}
SrsGoApiSummaries::~SrsGoApiSummaries()
{
stat_ = NULL;
}
srs_error_t SrsGoApiSummaries::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
SrsStatistic *stat = _srs_stat;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
srs_api_dump_summaries(obj.get());
@ -346,22 +346,22 @@ srs_error_t SrsGoApiSummaries::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMes
SrsGoApiRusages::SrsGoApiRusages()
{
stat_ = _srs_stat;
}
SrsGoApiRusages::~SrsGoApiRusages()
{
stat_ = NULL;
}
srs_error_t SrsGoApiRusages::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
SrsStatistic *stat = _srs_stat;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
SrsJsonObject *data = SrsJsonAny::object();
obj->set("data", data);
@ -392,22 +392,22 @@ srs_error_t SrsGoApiRusages::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
SrsGoApiSelfProcStats::SrsGoApiSelfProcStats()
{
stat_ = _srs_stat;
}
SrsGoApiSelfProcStats::~SrsGoApiSelfProcStats()
{
stat_ = NULL;
}
srs_error_t SrsGoApiSelfProcStats::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
SrsStatistic *stat = _srs_stat;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
SrsJsonObject *data = SrsJsonAny::object();
obj->set("data", data);
@ -470,22 +470,22 @@ srs_error_t SrsGoApiSelfProcStats::serve_http(ISrsHttpResponseWriter *w, ISrsHtt
SrsGoApiSystemProcStats::SrsGoApiSystemProcStats()
{
stat_ = _srs_stat;
}
SrsGoApiSystemProcStats::~SrsGoApiSystemProcStats()
{
stat_ = NULL;
}
srs_error_t SrsGoApiSystemProcStats::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
SrsStatistic *stat = _srs_stat;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
SrsJsonObject *data = SrsJsonAny::object();
obj->set("data", data);
@ -510,22 +510,22 @@ srs_error_t SrsGoApiSystemProcStats::serve_http(ISrsHttpResponseWriter *w, ISrsH
SrsGoApiMemInfos::SrsGoApiMemInfos()
{
stat_ = _srs_stat;
}
SrsGoApiMemInfos::~SrsGoApiMemInfos()
{
stat_ = NULL;
}
srs_error_t SrsGoApiMemInfos::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
SrsStatistic *stat = _srs_stat;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
SrsJsonObject *data = SrsJsonAny::object();
obj->set("data", data);
@ -551,22 +551,22 @@ srs_error_t SrsGoApiMemInfos::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMess
SrsGoApiAuthors::SrsGoApiAuthors()
{
stat_ = _srs_stat;
}
SrsGoApiAuthors::~SrsGoApiAuthors()
{
stat_ = NULL;
}
srs_error_t SrsGoApiAuthors::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
SrsStatistic *stat = _srs_stat;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
SrsJsonObject *data = SrsJsonAny::object();
obj->set("data", data);
@ -579,22 +579,22 @@ srs_error_t SrsGoApiAuthors::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
SrsGoApiFeatures::SrsGoApiFeatures()
{
stat_ = _srs_stat;
}
SrsGoApiFeatures::~SrsGoApiFeatures()
{
stat_ = NULL;
}
srs_error_t SrsGoApiFeatures::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
SrsStatistic *stat = _srs_stat;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
SrsJsonObject *data = SrsJsonAny::object();
obj->set("data", data);
@ -648,22 +648,22 @@ srs_error_t SrsGoApiFeatures::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMess
SrsGoApiRequests::SrsGoApiRequests()
{
stat_ = _srs_stat;
}
SrsGoApiRequests::~SrsGoApiRequests()
{
stat_ = NULL;
}
srs_error_t SrsGoApiRequests::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
SrsStatistic *stat = _srs_stat;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
SrsJsonObject *data = SrsJsonAny::object();
obj->set("data", data);
@ -693,40 +693,40 @@ srs_error_t SrsGoApiRequests::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMess
SrsGoApiVhosts::SrsGoApiVhosts()
{
stat_ = _srs_stat;
}
SrsGoApiVhosts::~SrsGoApiVhosts()
{
stat_ = NULL;
}
srs_error_t SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
srs_error_t err = srs_success;
SrsStatistic *stat = _srs_stat;
// path: {pattern}{vhost_id}
// e.g. /api/v1/vhosts/100 pattern= /api/v1/vhosts/, vhost_id=100
string vid = r->parse_rest_id(entry_->pattern);
SrsStatisticVhost *vhost = NULL;
if (!vid.empty() && (vhost = stat->find_vhost_by_id(vid)) == NULL) {
if (!vid.empty() && (vhost = stat_->find_vhost_by_id(vid)) == NULL) {
return srs_api_response_code(w, r, ERROR_RTMP_VHOST_NOT_FOUND);
}
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
if (r->is_http_get()) {
if (!vhost) {
SrsJsonArray *data = SrsJsonAny::array();
obj->set("vhosts", data);
if ((err = stat->dumps_vhosts(data)) != srs_success) {
if ((err = stat_->dumps_vhosts(data)) != srs_success) {
int code = srs_error_code(err);
srs_freep(err);
return srs_api_response_code(w, r, code);
@ -751,33 +751,33 @@ srs_error_t SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessag
SrsGoApiStreams::SrsGoApiStreams()
{
stat_ = _srs_stat;
}
SrsGoApiStreams::~SrsGoApiStreams()
{
stat_ = NULL;
}
srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
srs_error_t err = srs_success;
SrsStatistic *stat = _srs_stat;
// path: {pattern}{stream_id}
// e.g. /api/v1/streams/100 pattern= /api/v1/streams/, stream_id=100
string sid = r->parse_rest_id(entry_->pattern);
SrsStatisticStream *stream = NULL;
if (!sid.empty() && (stream = stat->find_stream(sid)) == NULL) {
if (!sid.empty() && (stream = stat_->find_stream(sid)) == NULL) {
return srs_api_response_code(w, r, ERROR_RTMP_STREAM_NOT_FOUND);
}
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
if (r->is_http_get()) {
if (!stream) {
@ -788,7 +788,7 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
std::string rcount = r->query_get("count");
int start = srs_max(0, atoi(rstart.c_str()));
int count = srs_max(10, atoi(rcount.c_str()));
if ((err = stat->dumps_streams(data, start, count)) != srs_success) {
if ((err = stat_->dumps_streams(data, start, count)) != srs_success) {
int code = srs_error_code(err);
srs_freep(err);
return srs_api_response_code(w, r, code);
@ -813,33 +813,33 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
SrsGoApiClients::SrsGoApiClients()
{
stat_ = _srs_stat;
}
SrsGoApiClients::~SrsGoApiClients()
{
stat_ = NULL;
}
srs_error_t SrsGoApiClients::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
srs_error_t err = srs_success;
SrsStatistic *stat = _srs_stat;
// path: {pattern}{client_id}
// e.g. /api/v1/clients/100 pattern= /api/v1/clients/, client_id=100
string client_id = r->parse_rest_id(entry_->pattern);
SrsStatisticClient *client = NULL;
if (!client_id.empty() && (client = stat->find_client(client_id)) == NULL) {
if (!client_id.empty() && (client = stat_->find_client(client_id)) == NULL) {
return srs_api_response_code(w, r, ERROR_RTMP_CLIENT_NOT_FOUND);
}
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
obj->set("server", SrsJsonAny::str(stat->server_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("server", SrsJsonAny::str(stat_->server_id().c_str()));
obj->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
obj->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
if (r->is_http_get()) {
if (!client) {
@ -850,7 +850,7 @@ srs_error_t SrsGoApiClients::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
std::string rcount = r->query_get("count");
int start = srs_max(0, atoi(rstart.c_str()));
int count = srs_max(10, atoi(rcount.c_str()));
if ((err = stat->dumps_clients(data, start, count)) != srs_success) {
if ((err = stat_->dumps_clients(data, start, count)) != srs_success) {
int code = srs_error_code(err);
srs_freep(err);
return srs_api_response_code(w, r, code);
@ -884,21 +884,30 @@ srs_error_t SrsGoApiClients::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
return srs_api_response(w, r, obj->dumps());
}
SrsGoApiRaw::SrsGoApiRaw(SrsServer *svr)
SrsGoApiRaw::SrsGoApiRaw(ISrsSignalHandler *handler)
{
server_ = svr;
handler_ = handler;
raw_api_ = _srs_config->get_raw_api();
allow_reload_ = _srs_config->get_raw_api_allow_reload();
allow_query_ = _srs_config->get_raw_api_allow_query();
allow_update_ = _srs_config->get_raw_api_allow_update();
stat_ = _srs_stat;
config_ = _srs_config;
}
_srs_config->subscribe(this);
void SrsGoApiRaw::assemble()
{
raw_api_ = config_->get_raw_api();
allow_reload_ = config_->get_raw_api_allow_reload();
allow_query_ = config_->get_raw_api_allow_query();
allow_update_ = config_->get_raw_api_allow_update();
config_->subscribe(this);
}
SrsGoApiRaw::~SrsGoApiRaw()
{
_srs_config->unsubscribe(this);
config_->unsubscribe(this);
stat_ = NULL;
config_ = NULL;
}
extern srs_error_t _srs_reload_err;
@ -918,7 +927,7 @@ srs_error_t SrsGoApiRaw::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *
// for rpc=raw, to query the raw api config for http api.
if (rpc == "raw") {
// query global scope.
if ((err = _srs_config->raw_to_json(obj.get())) != srs_success) {
if ((err = config_->raw_to_json(obj.get())) != srs_success) {
int code = srs_error_code(err);
srs_freep(err);
return srs_api_response_code(w, r, code);
@ -945,7 +954,7 @@ srs_error_t SrsGoApiRaw::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *
return srs_api_response_code(w, r, ERROR_SYSTEM_CONFIG_RAW_DISABLED);
}
server_->on_signal(SRS_SIGNAL_RELOAD);
handler_->on_signal(SRS_SIGNAL_RELOAD);
return srs_api_response_code(w, r, ERROR_SUCCESS);
} else if (rpc == "reload-fetch") {
SrsJsonObject *data = SrsJsonAny::object();
@ -964,10 +973,12 @@ srs_error_t SrsGoApiRaw::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *
SrsGoApiClusters::SrsGoApiClusters()
{
stat_ = _srs_stat;
}
SrsGoApiClusters::~SrsGoApiClusters()
{
stat_ = NULL;
}
srs_error_t SrsGoApiClusters::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
@ -997,10 +1008,12 @@ srs_error_t SrsGoApiClusters::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMess
SrsGoApiError::SrsGoApiError()
{
stat_ = _srs_stat;
}
SrsGoApiError::~SrsGoApiError()
{
stat_ = NULL;
}
srs_error_t SrsGoApiError::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
@ -1013,10 +1026,12 @@ srs_error_t SrsGoApiError::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage
SrsGoApiTcmalloc::SrsGoApiTcmalloc()
{
stat_ = _srs_stat;
}
SrsGoApiTcmalloc::~SrsGoApiTcmalloc()
{
stat_ = NULL;
}
srs_error_t SrsGoApiTcmalloc::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
@ -1097,11 +1112,15 @@ srs_error_t SrsGoApiTcmalloc::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMess
SrsGoApiValgrind::SrsGoApiValgrind()
{
trd_ = NULL;
stat_ = _srs_stat;
}
SrsGoApiValgrind::~SrsGoApiValgrind()
{
srs_freep(trd_);
stat_ = NULL;
}
srs_error_t SrsGoApiValgrind::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
@ -1199,10 +1218,12 @@ srs_error_t SrsGoApiValgrind::cycle()
#ifdef SRS_SIGNAL_API
SrsGoApiSignal::SrsGoApiSignal()
{
stat_ = _srs_stat;
}
SrsGoApiSignal::~SrsGoApiSignal()
{
stat_ = NULL;
}
srs_error_t SrsGoApiSignal::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
@ -1244,13 +1265,21 @@ srs_error_t SrsGoApiSignal::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessag
SrsGoApiMetrics::SrsGoApiMetrics()
{
enabled_ = _srs_config->get_exporter_enabled();
label_ = _srs_config->get_exporter_label();
tag_ = _srs_config->get_exporter_tag();
stat_ = _srs_stat;
config_ = _srs_config;
}
void SrsGoApiMetrics::assemble()
{
enabled_ = config_->get_exporter_enabled();
label_ = config_->get_exporter_label();
tag_ = config_->get_exporter_tag();
}
SrsGoApiMetrics::~SrsGoApiMetrics()
{
stat_ = NULL;
config_ = NULL;
}
srs_error_t SrsGoApiMetrics::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
@ -1273,7 +1302,6 @@ srs_error_t SrsGoApiMetrics::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
* error counter
*/
SrsStatistic *stat = _srs_stat;
std::stringstream ss;
#if defined(__linux__) || defined(SRS_OSX)
@ -1295,9 +1323,9 @@ srs_error_t SrsGoApiMetrics::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
ss << "# HELP srs_build_info A metric with a constant '1' value labeled by build_date, version from which SRS was built.\n"
<< "# TYPE srs_build_info gauge\n"
<< "srs_build_info{"
<< "server=\"" << stat->server_id() << "\","
<< "service=\"" << stat->service_id() << "\","
<< "pid=\"" << stat->service_pid() << "\","
<< "server=\"" << stat_->server_id() << "\","
<< "service=\"" << stat_->service_id() << "\","
<< "pid=\"" << stat_->service_pid() << "\","
<< "build_date=\"" << SRS_BUILD_DATE << "\","
<< "major=\"" << VERSION_MAJOR << "\","
<< "version=\"" << RTMP_SIG_SRS_VERSION << "\","
@ -1328,7 +1356,7 @@ srs_error_t SrsGoApiMetrics::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
// Dump metrics by statistic.
int64_t send_bytes, recv_bytes, nstreams, nclients, total_nclients, nerrs;
stat->dumps_metrics(send_bytes, recv_bytes, nstreams, nclients, total_nclients, nerrs);
stat_->dumps_metrics(send_bytes, recv_bytes, nstreams, nclients, total_nclients, nerrs);
// The total of bytes sent.
ss << "# HELP srs_send_bytes_total SRS total sent bytes.\n"

View File

@ -19,6 +19,9 @@ class SrsSdp;
class ISrsRequest;
class ISrsHttpResponseWriter;
class SrsHttpConn;
class ISrsSignalHandler;
class ISrsStatistic;
class ISrsAppConfig;
#include <string>
@ -35,6 +38,10 @@ extern srs_error_t srs_api_response_code(ISrsHttpResponseWriter *w, ISrsHttpMess
// For http root.
class SrsGoApiRoot : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiRoot();
virtual ~SrsGoApiRoot();
@ -45,6 +52,10 @@ public:
class SrsGoApiApi : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiApi();
virtual ~SrsGoApiApi();
@ -55,6 +66,10 @@ public:
class SrsGoApiV1 : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiV1();
virtual ~SrsGoApiV1();
@ -65,6 +80,10 @@ public:
class SrsGoApiVersion : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiVersion();
virtual ~SrsGoApiVersion();
@ -75,6 +94,10 @@ public:
class SrsGoApiSummaries : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiSummaries();
virtual ~SrsGoApiSummaries();
@ -85,6 +108,10 @@ public:
class SrsGoApiRusages : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiRusages();
virtual ~SrsGoApiRusages();
@ -95,6 +122,10 @@ public:
class SrsGoApiSelfProcStats : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiSelfProcStats();
virtual ~SrsGoApiSelfProcStats();
@ -105,6 +136,10 @@ public:
class SrsGoApiSystemProcStats : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiSystemProcStats();
virtual ~SrsGoApiSystemProcStats();
@ -115,6 +150,10 @@ public:
class SrsGoApiMemInfos : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiMemInfos();
virtual ~SrsGoApiMemInfos();
@ -125,6 +164,10 @@ public:
class SrsGoApiAuthors : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiAuthors();
virtual ~SrsGoApiAuthors();
@ -135,6 +178,10 @@ public:
class SrsGoApiFeatures : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiFeatures();
virtual ~SrsGoApiFeatures();
@ -145,6 +192,10 @@ public:
class SrsGoApiRequests : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiRequests();
virtual ~SrsGoApiRequests();
@ -155,6 +206,10 @@ public:
class SrsGoApiVhosts : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiVhosts();
virtual ~SrsGoApiVhosts();
@ -165,6 +220,10 @@ public:
class SrsGoApiStreams : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiStreams();
virtual ~SrsGoApiStreams();
@ -175,6 +234,10 @@ public:
class SrsGoApiClients : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiClients();
virtual ~SrsGoApiClients();
@ -185,17 +248,25 @@ public:
class SrsGoApiRaw : public ISrsHttpHandler, public ISrsReloadHandler
{
private:
SrsServer *server_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
ISrsAppConfig *config_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsSignalHandler *handler_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool raw_api_;
bool allow_reload_;
bool allow_query_;
bool allow_update_;
public:
SrsGoApiRaw(SrsServer *svr);
SrsGoApiRaw(ISrsSignalHandler *handler);
void assemble();
virtual ~SrsGoApiRaw();
public:
@ -204,6 +275,10 @@ public:
class SrsGoApiClusters : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiClusters();
virtual ~SrsGoApiClusters();
@ -214,6 +289,10 @@ public:
class SrsGoApiError : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiError();
virtual ~SrsGoApiError();
@ -225,6 +304,10 @@ public:
#ifdef SRS_GPERF
class SrsGoApiTcmalloc : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiTcmalloc();
virtual ~SrsGoApiTcmalloc();
@ -237,7 +320,12 @@ public:
#ifdef SRS_VALGRIND
class SrsGoApiValgrind : public ISrsHttpHandler, public ISrsCoroutineHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsCoroutine *trd_;
std::string task_;
@ -256,6 +344,10 @@ public:
#ifdef SRS_SIGNAL_API
class SrsGoApiSignal : public ISrsHttpHandler
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsGoApiSignal();
virtual ~SrsGoApiSignal();
@ -267,13 +359,20 @@ public:
class SrsGoApiMetrics : public ISrsHttpHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool enabled_;
std::string label_;
std::string tag_;
public:
SrsGoApiMetrics();
void assemble();
virtual ~SrsGoApiMetrics();
public:

View File

@ -49,7 +49,15 @@ ISrsHttpConnOwner::~ISrsHttpConnOwner()
{
}
SrsHttpConn::SrsHttpConn(ISrsHttpConnOwner *handler, ISrsProtocolReadWriter *fd, ISrsHttpServeMux *m, string cip, int cport)
ISrsHttpConn::ISrsHttpConn()
{
}
ISrsHttpConn::~ISrsHttpConn()
{
}
SrsHttpConn::SrsHttpConn(ISrsHttpConnOwner *handler, ISrsProtocolReadWriter *fd, ISrsCommonHttpHandler *m, string cip, int cport)
{
parser_ = new SrsHttpParser();
auth_ = new SrsHttpAuthMux(m);
@ -65,6 +73,8 @@ SrsHttpConn::SrsHttpConn(ISrsHttpConnOwner *handler, ISrsProtocolReadWriter *fd,
delta_ = new SrsNetworkDelta();
delta_->set_io(skt_, skt_);
trd_ = new SrsSTCoroutine("http", this, _srs_context->get_id());
config_ = _srs_config;
}
SrsHttpConn::~SrsHttpConn()
@ -77,6 +87,8 @@ SrsHttpConn::~SrsHttpConn()
srs_freep(auth_);
srs_freep(delta_);
config_ = NULL;
}
std::string SrsHttpConn::desc()
@ -269,8 +281,8 @@ srs_error_t SrsHttpConn::set_auth_enabled(bool auth_enabled)
// initialize the auth, which will proxy to mux.
if ((err = auth_->initialize(auth_enabled,
_srs_config->get_http_api_auth_username(),
_srs_config->get_http_api_auth_password())) != srs_success) {
config_->get_http_api_auth_username(),
config_->get_http_api_auth_password())) != srs_success) {
return srs_error_wrap(err, "init auth");
}
@ -298,7 +310,15 @@ void SrsHttpConn::expire()
trd_->interrupt();
}
SrsHttpxConn::SrsHttpxConn(ISrsResourceManager *cm, ISrsProtocolReadWriter *io, ISrsHttpServeMux *m, string cip, int port, string key, string cert) : manager_(cm), io_(io), enable_stat_(false), ssl_key_file_(key), ssl_cert_file_(cert)
ISrsHttpxConn::ISrsHttpxConn()
{
}
ISrsHttpxConn::~ISrsHttpxConn()
{
}
SrsHttpxConn::SrsHttpxConn(ISrsResourceManager *cm, ISrsProtocolReadWriter *io, ISrsCommonHttpHandler *m, string cip, int port, string key, string cert) : manager_(cm), io_(io), enable_stat_(false), ssl_key_file_(key), ssl_cert_file_(cert)
{
// Create a identify for this client.
_srs_context->set_id(_srs_context->generate_id());
@ -312,16 +332,18 @@ SrsHttpxConn::SrsHttpxConn(ISrsResourceManager *cm, ISrsProtocolReadWriter *io,
conn_ = new SrsHttpConn(this, io_, m, cip, port);
}
_srs_config->subscribe(this);
config_ = _srs_config;
stat_ = _srs_stat;
}
SrsHttpxConn::~SrsHttpxConn()
{
_srs_config->unsubscribe(this);
srs_freep(conn_);
srs_freep(ssl_);
srs_freep(io_);
config_ = NULL;
stat_ = NULL;
}
void SrsHttpxConn::set_enable_stat(bool v)
@ -390,7 +412,7 @@ srs_error_t SrsHttpxConn::on_start()
return err;
}
srs_error_t SrsHttpxConn::on_http_message(ISrsHttpMessage *r, SrsHttpResponseWriter *w)
srs_error_t SrsHttpxConn::on_http_message(ISrsHttpMessage *r, ISrsHttpResponseWriter *w)
{
srs_error_t err = srs_success;
@ -407,7 +429,7 @@ srs_error_t SrsHttpxConn::on_http_message(ISrsHttpMessage *r, SrsHttpResponseWri
return err;
}
srs_error_t SrsHttpxConn::on_message_done(ISrsHttpMessage *r, SrsHttpResponseWriter *w)
srs_error_t SrsHttpxConn::on_message_done(ISrsHttpMessage *r, ISrsHttpResponseWriter *w)
{
return srs_success;
}
@ -416,8 +438,8 @@ srs_error_t SrsHttpxConn::on_conn_done(srs_error_t r0)
{
// Only stat the HTTP streaming clients, ignore all API clients.
if (enable_stat_) {
_srs_stat->on_disconnect(get_id().c_str(), r0);
_srs_stat->kbps_add_delta(get_id().c_str(), conn_->delta());
stat_->on_disconnect(get_id().c_str(), r0);
stat_->kbps_add_delta(get_id().c_str(), conn_->delta());
}
// Because we use manager to manage this object,
@ -456,12 +478,12 @@ srs_error_t SrsHttpxConn::start()
{
srs_error_t err = srs_success;
bool v = _srs_config->get_http_stream_crossdomain();
bool v = config_->get_http_stream_crossdomain();
if ((err = conn_->set_crossdomain_enabled(v)) != srs_success) {
return srs_error_wrap(err, "set cors=%d", v);
}
bool auth_enabled = _srs_config->get_http_api_auth_enabled();
bool auth_enabled = config_->get_http_api_auth_enabled();
if ((err = conn_->set_auth_enabled(auth_enabled)) != srs_success) {
return srs_error_wrap(err, "set auth");
}
@ -474,6 +496,14 @@ ISrsKbpsDelta *SrsHttpxConn::delta()
return conn_->delta();
}
ISrsHttpServer::ISrsHttpServer()
{
}
ISrsHttpServer::~ISrsHttpServer()
{
}
SrsHttpServer::SrsHttpServer()
{
http_stream_ = new SrsHttpStreamServer();
@ -493,7 +523,7 @@ srs_error_t SrsHttpServer::initialize()
srs_error_t err = srs_success;
// for SRS go-sharp to detect the status of HTTP server of SRS HTTP FLV Cluster.
if ((err = http_static_->mux_.handle("/api/v1/versions", new SrsGoApiVersion())) != srs_success) {
if ((err = http_static_->mux()->handle("/api/v1/versions", new SrsGoApiVersion())) != srs_success) {
return srs_error_wrap(err, "handle versions");
}
@ -510,7 +540,7 @@ srs_error_t SrsHttpServer::initialize()
srs_error_t SrsHttpServer::handle(std::string pattern, ISrsHttpHandler *handler)
{
return http_static_->mux_.handle(pattern, handler);
return http_static_->mux()->handle(pattern, handler);
}
srs_error_t SrsHttpServer::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
@ -525,21 +555,21 @@ srs_error_t SrsHttpServer::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage
bool is_api = memcmp(p, "/api/", 5) == 0;
bool is_console = path.length() > 8 && memcmp(p, "/console/", 9) == 0;
if (is_api || is_console) {
return http_static_->mux_.serve_http(w, r);
return http_static_->mux()->serve_http(w, r);
}
}
// Try http stream first, then http static if not found.
ISrsHttpHandler *h = NULL;
if ((err = http_stream_->mux_.find_handler(r, &h)) != srs_success) {
if ((err = http_stream_->mux()->find_handler(r, &h)) != srs_success) {
return srs_error_wrap(err, "find handler");
}
if (!h->is_not_found()) {
return http_stream_->mux_.serve_http(w, r);
return http_stream_->mux()->serve_http(w, r);
}
// Use http static as default server.
return http_static_->mux_.serve_http(w, r);
return http_static_->mux()->serve_http(w, r);
}
srs_error_t SrsHttpServer::http_mount(ISrsRequest *r)

View File

@ -26,6 +26,7 @@ class ISrsRequest;
class SrsLiveConsumer;
class SrsStSocket;
class SrsHttpParser;
class ISrsHttpParser;
class ISrsHttpMessage;
class SrsHttpHandler;
class SrsMessageQueue;
@ -34,8 +35,20 @@ class SrsFastStream;
class SrsHttpUri;
class SrsHttpMessage;
class SrsHttpStreamServer;
class ISrsHttpStreamServer;
class SrsHttpStaticServer;
class ISrsHttpStaticServer;
class SrsNetworkDelta;
class ISrsNetworkDelta;
class SrsHttpCorsMux;
class ISrsHttpCorsMux;
class SrsHttpAuthMux;
class ISrsHttpAuthMux;
class SrsSslConnection;
class ISrsSslConnection;
class ISrsHttpConn;
class ISrsAppConfig;
class ISrsStatistic;
// The owner of HTTP connection.
class ISrsHttpConnOwner
@ -50,26 +63,52 @@ public:
// Handle the HTTP message r, which may be parsed partially.
// For the static service or api, discard any body.
// For the stream caster, for instance, http flv streaming, may discard the flv header or not.
virtual srs_error_t on_http_message(ISrsHttpMessage *r, SrsHttpResponseWriter *w) = 0;
virtual srs_error_t on_http_message(ISrsHttpMessage *r, ISrsHttpResponseWriter *w) = 0;
// When message is processed, we may need to do more things.
virtual srs_error_t on_message_done(ISrsHttpMessage *r, SrsHttpResponseWriter *w) = 0;
virtual srs_error_t on_message_done(ISrsHttpMessage *r, ISrsHttpResponseWriter *w) = 0;
// When connection is destroy, should use manager to dispose it.
// The r0 is the original error, we will use the returned new error.
virtual srs_error_t on_conn_done(srs_error_t r0) = 0;
};
// The HTTP connection, for HTTP stream or static file.
class ISrsHttpConn : public ISrsConnection, public ISrsStartable, public ISrsCoroutineHandler, public ISrsExpire
{
public:
ISrsHttpConn();
virtual ~ISrsHttpConn();
public:
// Get the delta object for statistics.
virtual ISrsKbpsDelta *delta() = 0;
// Whether the connection coroutine is error or terminated.
virtual srs_error_t pull() = 0;
// Whether enable the CORS(cross-domain).
virtual srs_error_t set_crossdomain_enabled(bool v) = 0;
// Whether enable the Auth.
virtual srs_error_t set_auth_enabled(bool auth_enabled) = 0;
// Whether enable the JSONP.
virtual srs_error_t set_jsonp(bool v) = 0;
};
// TODO: FIXME: Should rename to roundtrip or responder, not connection.
// The http connection which request the static or stream content.
class SrsHttpConn : public ISrsConnection, public ISrsStartable, public ISrsCoroutineHandler, public ISrsExpire
class SrsHttpConn : public ISrsHttpConn
{
protected:
SrsHttpParser *parser_;
ISrsHttpServeMux *http_mux_;
SrsHttpCorsMux *cors_;
SrsHttpAuthMux *auth_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
ISrsHttpParser *parser_;
ISrsCommonHttpHandler *http_mux_;
ISrsHttpCorsMux *cors_;
ISrsHttpAuthMux *auth_;
ISrsHttpConnOwner *handler_;
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
ISrsProtocolReadWriter *skt_;
// Each connection start a green thread,
// when thread stop, the connection will be delete by server.
@ -78,15 +117,16 @@ protected:
std::string ip_;
int port_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The delta for statistic.
SrsNetworkDelta *delta_;
ISrsNetworkDelta *delta_;
// The create time in microseconds.
// for current connection to log self create time and calculate the living time.
srs_utime_t create_time_;
public:
SrsHttpConn(ISrsHttpConnOwner *handler, ISrsProtocolReadWriter *fd, ISrsHttpServeMux *m, std::string cip, int port);
SrsHttpConn(ISrsHttpConnOwner *handler, ISrsProtocolReadWriter *fd, ISrsCommonHttpHandler *m, std::string cip, int port);
virtual ~SrsHttpConn();
// Interface ISrsResource.
public:
@ -101,7 +141,8 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_cycle();
virtual srs_error_t process_requests(ISrsRequest **preq);
virtual srs_error_t process_request(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, int rid);
@ -130,15 +171,31 @@ public:
virtual void expire();
};
// Drop body of request, only process the response.
class SrsHttpxConn : public ISrsConnection, public ISrsStartable, public ISrsHttpConnOwner, public ISrsReloadHandler
// The HTTP connection manager.
class ISrsHttpxConn : public ISrsConnection, public ISrsStartable, public ISrsHttpConnOwner
{
private:
public:
ISrsHttpxConn();
virtual ~ISrsHttpxConn();
public:
};
// Drop body of request, only process the response.
class SrsHttpxConn : public ISrsHttpxConn
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsStatistic *stat_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The manager object to manage the connection.
ISrsResourceManager *manager_;
ISrsProtocolReadWriter *io_;
SrsSslConnection *ssl_;
SrsHttpConn *conn_;
ISrsSslConnection *ssl_;
ISrsHttpConn *conn_;
// We should never enable the stat, unless HTTP stream connection requires.
bool enable_stat_;
// ssl key & cert file
@ -146,7 +203,7 @@ private:
const std::string ssl_cert_file_;
public:
SrsHttpxConn(ISrsResourceManager *cm, ISrsProtocolReadWriter *io, ISrsHttpServeMux *m, std::string cip, int port, std::string key, std::string cert);
SrsHttpxConn(ISrsResourceManager *cm, ISrsProtocolReadWriter *io, ISrsCommonHttpHandler *m, std::string cip, int port, std::string key, std::string cert);
virtual ~SrsHttpxConn();
public:
@ -161,8 +218,8 @@ public:
// Interface ISrsHttpConnOwner.
public:
virtual srs_error_t on_start();
virtual srs_error_t on_http_message(ISrsHttpMessage *r, SrsHttpResponseWriter *w);
virtual srs_error_t on_message_done(ISrsHttpMessage *r, SrsHttpResponseWriter *w);
virtual srs_error_t on_http_message(ISrsHttpMessage *r, ISrsHttpResponseWriter *w);
virtual srs_error_t on_message_done(ISrsHttpMessage *r, ISrsHttpResponseWriter *w);
virtual srs_error_t on_conn_done(srs_error_t r0);
// Interface ISrsResource.
public:
@ -180,11 +237,22 @@ public:
};
// The http server, use http stream or static server to serve requests.
class SrsHttpServer : public ISrsHttpServeMux
class ISrsHttpServer : public ISrsCommonHttpHandler
{
private:
SrsHttpStaticServer *http_static_;
SrsHttpStreamServer *http_stream_;
public:
ISrsHttpServer();
virtual ~ISrsHttpServer();
public:
};
// The http server, use http stream or static server to serve requests.
class SrsHttpServer : public ISrsHttpServer
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsHttpStaticServer *http_static_;
ISrsHttpStreamServer *http_stream_;
public:
SrsHttpServer();
@ -192,7 +260,7 @@ public:
public:
virtual srs_error_t initialize();
// Interface ISrsHttpServeMux
// Interface ISrsCommonHttpHandler
public:
virtual srs_error_t handle(std::string pattern, ISrsHttpHandler *handler);
// Interface ISrsHttpHandler

View File

@ -11,6 +11,7 @@ using namespace std;
#include <srs_app_config.hpp>
#include <srs_app_dvr.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_http_client.hpp>
#include <srs_app_http_conn.hpp>
#include <srs_app_st.hpp>
@ -46,10 +47,16 @@ ISrsHttpHooks::~ISrsHttpHooks()
SrsHttpHooks::SrsHttpHooks()
{
factory_ = _srs_app_factory;
stat_ = _srs_stat;
config_ = _srs_config;
}
SrsHttpHooks::~SrsHttpHooks()
{
factory_ = NULL;
stat_ = NULL;
config_ = NULL;
}
srs_error_t SrsHttpHooks::on_connect(string url, ISrsRequest *req)
@ -57,7 +64,7 @@ srs_error_t SrsHttpHooks::on_connect(string url, ISrsRequest *req)
srs_error_t err = srs_success;
SrsContextId cid = _srs_context->get_id();
SrsStatistic *stat = _srs_stat;
ISrsStatistic *stat = stat_;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
@ -76,8 +83,8 @@ srs_error_t SrsHttpHooks::on_connect(string url, ISrsRequest *req)
std::string res;
int status_code;
SrsHttpClient http;
if ((err = do_post(&http, url, data, status_code, res)) != srs_success) {
SrsUniquePtr<ISrsHttpClient> http(factory_->create_http_client());
if ((err = do_post(http.get(), url, data, status_code, res)) != srs_success) {
return srs_error_wrap(err, "http: on_connect failed, client_id=%s, url=%s, request=%s, response=%s, code=%d",
cid.c_str(), url.c_str(), data.c_str(), res.c_str(), status_code);
}
@ -93,7 +100,7 @@ void SrsHttpHooks::on_close(string url, ISrsRequest *req, int64_t send_bytes, in
srs_error_t err = srs_success;
SrsContextId cid = _srs_context->get_id();
SrsStatistic *stat = _srs_stat;
ISrsStatistic *stat = stat_;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
@ -110,8 +117,8 @@ void SrsHttpHooks::on_close(string url, ISrsRequest *req, int64_t send_bytes, in
std::string res;
int status_code;
SrsHttpClient http;
if ((err = do_post(&http, url, data, status_code, res)) != srs_success) {
SrsUniquePtr<ISrsHttpClient> http(factory_->create_http_client());
if ((err = do_post(http.get(), url, data, status_code, res)) != srs_success) {
int ret = srs_error_code(err);
srs_freep(err);
srs_warn("http: ignore on_close failed, client_id=%s, url=%s, request=%s, response=%s, code=%d, ret=%d",
@ -130,7 +137,7 @@ srs_error_t SrsHttpHooks::on_publish(string url, ISrsRequest *req)
srs_error_t err = srs_success;
SrsContextId cid = _srs_context->get_id();
SrsStatistic *stat = _srs_stat;
ISrsStatistic *stat = stat_;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
@ -154,8 +161,8 @@ srs_error_t SrsHttpHooks::on_publish(string url, ISrsRequest *req)
std::string res;
int status_code;
SrsHttpClient http;
if ((err = do_post(&http, url, data, status_code, res)) != srs_success) {
SrsUniquePtr<ISrsHttpClient> http(factory_->create_http_client());
if ((err = do_post(http.get(), url, data, status_code, res)) != srs_success) {
return srs_error_wrap(err, "http: on_publish failed, client_id=%s, url=%s, request=%s, response=%s, code=%d",
cid.c_str(), url.c_str(), data.c_str(), res.c_str(), status_code);
}
@ -171,7 +178,7 @@ void SrsHttpHooks::on_unpublish(string url, ISrsRequest *req)
srs_error_t err = srs_success;
SrsContextId cid = _srs_context->get_id();
SrsStatistic *stat = _srs_stat;
ISrsStatistic *stat = stat_;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
@ -195,8 +202,8 @@ void SrsHttpHooks::on_unpublish(string url, ISrsRequest *req)
std::string res;
int status_code;
SrsHttpClient http;
if ((err = do_post(&http, url, data, status_code, res)) != srs_success) {
SrsUniquePtr<ISrsHttpClient> http(factory_->create_http_client());
if ((err = do_post(http.get(), url, data, status_code, res)) != srs_success) {
int ret = srs_error_code(err);
srs_freep(err);
srs_warn("http: ignore on_unpublish failed, client_id=%s, url=%s, request=%s, response=%s, status=%d, ret=%d",
@ -215,7 +222,7 @@ srs_error_t SrsHttpHooks::on_play(string url, ISrsRequest *req)
srs_error_t err = srs_success;
SrsContextId cid = _srs_context->get_id();
SrsStatistic *stat = _srs_stat;
ISrsStatistic *stat = stat_;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
@ -240,8 +247,8 @@ srs_error_t SrsHttpHooks::on_play(string url, ISrsRequest *req)
std::string res;
int status_code;
SrsHttpClient http;
if ((err = do_post(&http, url, data, status_code, res)) != srs_success) {
SrsUniquePtr<ISrsHttpClient> http(factory_->create_http_client());
if ((err = do_post(http.get(), url, data, status_code, res)) != srs_success) {
return srs_error_wrap(err, "http: on_play failed, client_id=%s, url=%s, request=%s, response=%s, status=%d",
cid.c_str(), url.c_str(), data.c_str(), res.c_str(), status_code);
}
@ -257,7 +264,7 @@ void SrsHttpHooks::on_stop(string url, ISrsRequest *req)
srs_error_t err = srs_success;
SrsContextId cid = _srs_context->get_id();
SrsStatistic *stat = _srs_stat;
ISrsStatistic *stat = stat_;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
@ -281,8 +288,8 @@ void SrsHttpHooks::on_stop(string url, ISrsRequest *req)
std::string res;
int status_code;
SrsHttpClient http;
if ((err = do_post(&http, url, data, status_code, res)) != srs_success) {
SrsUniquePtr<ISrsHttpClient> http(factory_->create_http_client());
if ((err = do_post(http.get(), url, data, status_code, res)) != srs_success) {
int ret = srs_error_code(err);
srs_freep(err);
srs_warn("http: ignore on_stop failed, client_id=%s, url=%s, request=%s, response=%s, code=%d, ret=%d",
@ -301,9 +308,9 @@ srs_error_t SrsHttpHooks::on_dvr(SrsContextId c, string url, ISrsRequest *req, s
srs_error_t err = srs_success;
SrsContextId cid = c;
std::string cwd = _srs_config->cwd();
std::string cwd = config_->cwd();
SrsStatistic *stat = _srs_stat;
ISrsStatistic *stat = stat_;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
@ -329,8 +336,8 @@ srs_error_t SrsHttpHooks::on_dvr(SrsContextId c, string url, ISrsRequest *req, s
std::string res;
int status_code;
SrsHttpClient http;
if ((err = do_post(&http, url, data, status_code, res)) != srs_success) {
SrsUniquePtr<ISrsHttpClient> http(factory_->create_http_client());
if ((err = do_post(http.get(), url, data, status_code, res)) != srs_success) {
return srs_error_wrap(err, "http post on_dvr uri failed, client_id=%s, url=%s, request=%s, response=%s, code=%d",
cid.c_str(), url.c_str(), data.c_str(), res.c_str(), status_code);
}
@ -346,7 +353,7 @@ srs_error_t SrsHttpHooks::on_hls(SrsContextId c, string url, ISrsRequest *req, s
srs_error_t err = srs_success;
SrsContextId cid = c;
std::string cwd = _srs_config->cwd();
std::string cwd = config_->cwd();
// the ts_url is under the same dir of m3u8_url.
SrsPath path;
@ -355,7 +362,7 @@ srs_error_t SrsHttpHooks::on_hls(SrsContextId c, string url, ISrsRequest *req, s
ts_url = prefix + "/" + ts_url;
}
SrsStatistic *stat = _srs_stat;
ISrsStatistic *stat = stat_;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str()));
@ -386,8 +393,8 @@ srs_error_t SrsHttpHooks::on_hls(SrsContextId c, string url, ISrsRequest *req, s
std::string res;
int status_code;
SrsHttpClient http;
if ((err = do_post(&http, url, data, status_code, res)) != srs_success) {
SrsUniquePtr<ISrsHttpClient> http(factory_->create_http_client());
if ((err = do_post(http.get(), url, data, status_code, res)) != srs_success) {
return srs_error_wrap(err, "http: post %s with %s, status=%d, res=%s", url.c_str(), data.c_str(), status_code, res.c_str());
}
@ -402,13 +409,13 @@ srs_error_t SrsHttpHooks::on_hls_notify(SrsContextId c, std::string url, ISrsReq
srs_error_t err = srs_success;
SrsContextId cid = c;
std::string cwd = _srs_config->cwd();
std::string cwd = config_->cwd();
if (srs_net_url_is_http(ts_url)) {
url = ts_url;
}
SrsStatistic *stat = _srs_stat;
ISrsStatistic *stat = stat_;
url = srs_strings_replace(url, "[server_id]", stat->server_id().c_str());
url = srs_strings_replace(url, "[service_id]", stat->service_id().c_str());
@ -424,8 +431,8 @@ srs_error_t SrsHttpHooks::on_hls_notify(SrsContextId c, std::string url, ISrsReq
return srs_error_wrap(err, "http: init url=%s", url.c_str());
}
SrsHttpClient http;
if ((err = http.initialize(uri.get_schema(), uri.get_host(), uri.get_port(), SRS_HLS_NOTIFY_TIMEOUT)) != srs_success) {
SrsUniquePtr<ISrsHttpClient> http(factory_->create_http_client());
if ((err = http->initialize(uri.get_schema(), uri.get_host(), uri.get_port(), SRS_HLS_NOTIFY_TIMEOUT)) != srs_success) {
return srs_error_wrap(err, "http: init client for %s", url.c_str());
}
@ -440,7 +447,7 @@ srs_error_t SrsHttpHooks::on_hls_notify(SrsContextId c, std::string url, ISrsReq
srs_info("GET %s", path.c_str());
ISrsHttpMessage *msg_raw = NULL;
if ((err = http.get(path.c_str(), "", &msg_raw)) != srs_success) {
if ((err = http->get(path.c_str(), "", &msg_raw)) != srs_success) {
return srs_error_wrap(err, "http: get %s", url.c_str());
}
SrsUniquePtr<ISrsHttpMessage> msg(msg_raw);
@ -474,8 +481,8 @@ srs_error_t SrsHttpHooks::discover_co_workers(string url, string &host, int &por
std::string res;
int status_code;
SrsHttpClient http;
if ((err = do_post(&http, url, "", status_code, res)) != srs_success) {
SrsUniquePtr<ISrsHttpClient> http(factory_->create_http_client());
if ((err = do_post(http.get(), url, "", status_code, res)) != srs_success) {
return srs_error_wrap(err, "http: post %s, status=%d, res=%s", url.c_str(), status_code, res.c_str());
}
@ -527,7 +534,7 @@ srs_error_t SrsHttpHooks::on_forward_backend(string url, ISrsRequest *req, std::
SrsContextId cid = _srs_context->get_id();
SrsStatistic *stat = _srs_stat;
ISrsStatistic *stat = stat_;
SrsUniquePtr<SrsJsonObject> obj(SrsJsonAny::object());
obj->set("action", SrsJsonAny::str("on_forward"));
@ -545,8 +552,8 @@ srs_error_t SrsHttpHooks::on_forward_backend(string url, ISrsRequest *req, std::
std::string res;
int status_code;
SrsHttpClient http;
if ((err = do_post(&http, url, data, status_code, res)) != srs_success) {
SrsUniquePtr<ISrsHttpClient> http(factory_->create_http_client());
if ((err = do_post(http.get(), url, data, status_code, res)) != srs_success) {
return srs_error_wrap(err, "http: on_forward_backend failed, client_id=%s, url=%s, request=%s, response=%s, code=%d",
cid.c_str(), url.c_str(), data.c_str(), res.c_str(), status_code);
}
@ -589,7 +596,7 @@ srs_error_t SrsHttpHooks::on_forward_backend(string url, ISrsRequest *req, std::
return err;
}
srs_error_t SrsHttpHooks::do_post(SrsHttpClient *hc, std::string url, std::string req, int &code, string &res)
srs_error_t SrsHttpHooks::do_post(ISrsHttpClient *hc, std::string url, std::string req, int &code, string &res)
{
srs_error_t err = srs_success;

View File

@ -17,6 +17,10 @@ class SrsStSocket;
class ISrsRequest;
class SrsHttpParser;
class SrsHttpClient;
class ISrsAppFactory;
class ISrsHttpClient;
class ISrsStatistic;
class ISrsAppConfig;
// HTTP hooks interface for SRS server event callbacks.
//
@ -149,6 +153,12 @@ public:
class SrsHttpHooks : public ISrsHttpHooks
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppFactory *factory_;
ISrsStatistic *stat_;
ISrsAppConfig *config_;
public:
SrsHttpHooks();
virtual ~SrsHttpHooks();
@ -167,8 +177,9 @@ public:
srs_error_t discover_co_workers(std::string url, std::string &host, int &port);
srs_error_t on_forward_backend(std::string url, ISrsRequest *req, std::vector<std::string> &rtmp_urls);
private:
srs_error_t do_post(SrsHttpClient *hc, std::string url, std::string req, int &code, std::string &res);
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t do_post(ISrsHttpClient *hc, std::string url, std::string req, int &code, std::string &res);
};
// Global HTTP hooks instance

View File

@ -599,14 +599,27 @@ srs_error_t SrsVodStream::serve_ts_ctx(ISrsHttpResponseWriter *w, ISrsHttpMessag
return err;
}
ISrsHttpStaticServer::ISrsHttpStaticServer()
{
}
ISrsHttpStaticServer::~ISrsHttpStaticServer()
{
}
SrsHttpStaticServer::SrsHttpStaticServer()
{
_srs_config->subscribe(this);
mux_ = new SrsHttpServeMux();
}
SrsHttpStaticServer::~SrsHttpStaticServer()
{
_srs_config->unsubscribe(this);
srs_freep(mux_);
}
srs_error_t SrsHttpStaticServer::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
{
return mux_->serve_http(w, r);
}
srs_error_t SrsHttpStaticServer::initialize()
@ -640,7 +653,7 @@ srs_error_t SrsHttpStaticServer::initialize()
if (!default_root_exists) {
// add root
std::string dir = _srs_config->get_http_stream_dir();
if ((err = mux_.handle("/", new SrsVodStream(dir))) != srs_success) {
if ((err = mux_->handle("/", new SrsVodStream(dir))) != srs_success) {
return srs_error_wrap(err, "mount root dir=%s", dir.c_str());
}
srs_trace("http: root mount to %s", dir.c_str());
@ -649,6 +662,11 @@ srs_error_t SrsHttpStaticServer::initialize()
return err;
}
ISrsHttpServeMux *SrsHttpStaticServer::mux()
{
return mux_;
}
srs_error_t SrsHttpStaticServer::mount_vhost(string vhost, string &pmount)
{
srs_error_t err = srs_success;
@ -679,7 +697,7 @@ srs_error_t SrsHttpStaticServer::mount_vhost(string vhost, string &pmount)
}
// mount the http of vhost.
if ((err = mux_.handle(mount, new SrsVodStream(dir))) != srs_success) {
if ((err = mux_->handle(mount, new SrsVodStream(dir))) != srs_success) {
return srs_error_wrap(err, "mux handle");
}
srs_trace("http: vhost=%s mount to %s at %s", vhost.c_str(), mount.c_str(), dir.c_str());

View File

@ -12,6 +12,8 @@
#include <srs_core.hpp>
class ISrsFileReaderFactory;
class ISrsCommonHttpHandler;
class ISrsHttpServeMux;
// HLS virtual connection, build on query string ctx of hls stream.
class SrsHlsVirtualConn : public ISrsExpire
@ -33,9 +35,11 @@ public:
// Server HLS streaming.
class SrsHlsStream : public ISrsFastTimerHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The period of validity of the ctx
std::map<std::string, SrsHlsVirtualConn *> map_ctx_info_;
std::map<std::string, SrsHlsVirtualConn *>
map_ctx_info_;
public:
SrsHlsStream();
@ -45,7 +49,8 @@ public:
virtual srs_error_t serve_m3u8_ctx(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, ISrsFileReaderFactory *factory, std::string fullpath, ISrsRequest *req, bool *served);
virtual void on_serve_ts_ctx(ISrsHttpResponseWriter *w, ISrsHttpMessage *r);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t serve_new_session(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, ISrsRequest *req, std::string &ctx);
srs_error_t serve_exists_session(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, ISrsFileReaderFactory *factory, std::string fullpath);
bool ctx_is_exist(std::string ctx);
@ -54,29 +59,34 @@ private:
void http_hooks_on_stop(ISrsRequest *req);
bool is_interrupt(std::string id);
// interface ISrsFastTimerHandler
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t on_timer(srs_utime_t interval);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsSecurity *security_;
};
// The Vod streaming, like FLV, MP4 or HLS streaming.
class SrsVodStream : public SrsHttpFileServer
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsHlsStream hls_;
public:
SrsVodStream(std::string root_dir);
virtual ~SrsVodStream();
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
// The flv vod stream supports flv?start=offset-bytes.
// For example, http://server/file.flv?start=10240
// server will write flv header and sequence header,
// then seek(10240) and response flv tag data.
virtual srs_error_t serve_flv_stream(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, std::string fullpath, int64_t offset);
virtual srs_error_t
serve_flv_stream(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, std::string fullpath, int64_t offset);
// Support mp4 with start and offset in query string.
virtual srs_error_t serve_mp4_stream(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, std::string fullpath, int64_t start, int64_t end);
// Support HLS streaming with pseudo session id.
@ -86,11 +96,24 @@ protected:
};
// The http static server instance,
// serve http static file and flv/mp4 vod stream.
class SrsHttpStaticServer : public ISrsReloadHandler
class ISrsHttpStaticServer : public ISrsHttpHandler
{
public:
SrsHttpServeMux mux_;
ISrsHttpStaticServer();
virtual ~ISrsHttpStaticServer();
public:
virtual srs_error_t initialize() = 0;
virtual ISrsHttpServeMux *mux() = 0;
};
// The http static server instance,
// serve http static file and flv/mp4 vod stream.
class SrsHttpStaticServer : public ISrsHttpStaticServer
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsHttpServeMux *mux_;
public:
SrsHttpStaticServer();
@ -98,8 +121,14 @@ public:
public:
virtual srs_error_t initialize();
virtual ISrsHttpServeMux *mux();
private:
// Interface ISrsHttpHandler
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r);
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t mount_vhost(std::string vhost, std::string &pmount);
};

View File

@ -1046,24 +1046,36 @@ bool SrsLiveEntry::is_mp3()
return is_mp3_;
}
ISrsHttpStreamServer::ISrsHttpStreamServer()
{
}
ISrsHttpStreamServer::~ISrsHttpStreamServer()
{
}
SrsHttpStreamServer::SrsHttpStreamServer()
{
async_ = new SrsAsyncCallWorker();
mux_.add_dynamic_matcher(this);
mux_ = new SrsHttpServeMux();
config_ = _srs_config;
}
void SrsHttpStreamServer::assemble()
{
config_->subscribe(this);
SrsHttpServeMux *mux = dynamic_cast<SrsHttpServeMux *>(mux_);
if (!mux) {
mux->add_dynamic_matcher(this);
}
}
SrsHttpStreamServer::~SrsHttpStreamServer()
{
mux_.remove_dynamic_matcher(this);
config_->unsubscribe(this);
SrsHttpServeMux *mux = dynamic_cast<SrsHttpServeMux *>(mux_);
if (mux) {
mux->remove_dynamic_matcher(this);
}
async_->stop();
srs_freep(async_);
@ -1104,6 +1116,11 @@ srs_error_t SrsHttpStreamServer::initialize()
return err;
}
ISrsHttpServeMux *SrsHttpStreamServer::mux()
{
return mux_;
}
// TODO: FIXME: rename for HTTP FLV mount.
srs_error_t SrsHttpStreamServer::http_mount(ISrsRequest *r)
{
@ -1152,7 +1169,7 @@ srs_error_t SrsHttpStreamServer::http_mount(ISrsRequest *r)
// mount the http flv stream.
// we must register the handler, then start the thread,
// for the thread will cause thread switch context.
if ((err = mux_.handle(mount, entry->stream_)) != srs_success) {
if ((err = mux_->handle(mount, entry->stream_)) != srs_success) {
return srs_error_wrap(err, "http: mount flv stream for vhost=%s failed", sid.c_str());
}
@ -1200,7 +1217,7 @@ void SrsHttpStreamServer::http_unmount(ISrsRequest *r)
// Use async worker to execute the task, which will destroy the stream.
srs_error_t err = srs_success;
if ((err = async_->execute(new SrsHttpStreamDestroy(&mux_, &streamHandlers_, sid))) != srs_success) {
if ((err = async_->execute(new SrsHttpStreamDestroy(mux_, &streamHandlers_, sid))) != srs_success) {
srs_warn("http: ignore unmount stream failed, sid=%s, err=%s", sid.c_str(), srs_error_desc(err).c_str());
srs_freep(err);
}
@ -1353,7 +1370,7 @@ srs_error_t SrsHttpStreamServer::initialize_flv_entry(std::string vhost)
return err;
}
SrsHttpStreamDestroy::SrsHttpStreamDestroy(SrsHttpServeMux *mux, map<std::string, SrsLiveEntry *> *handlers, string sid)
SrsHttpStreamDestroy::SrsHttpStreamDestroy(ISrsHttpServeMux *mux, map<std::string, SrsLiveEntry *> *handlers, string sid)
{
mux_ = mux;
sid_ = sid;

View File

@ -29,6 +29,7 @@ class ISrsTsTransmuxer;
class ISrsAacTransmuxer;
class ISrsBufferCache;
class ISrsMp3Transmuxer;
class ISrsCommonHttpHandler;
// The cache for HTTP Live Streaming encoder.
class ISrsBufferCache
@ -50,14 +51,17 @@ public:
// A cache for HTTP Live Streaming encoder, to make android(weixin) happy.
class SrsBufferCache : public ISrsCoroutineHandler, public ISrsBufferCache
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsLiveSourceManager *live_sources_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_utime_t fast_cache_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsMessageQueue *queue_;
ISrsRequest *req_;
ISrsCoroutine *trd_;
@ -106,7 +110,8 @@ public:
// Transmux RTMP to HTTP Live Streaming.
class SrsFlvStreamEncoder : public ISrsBufferEncoder
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsFlvTransmuxer *enc_;
bool header_written_;
bool has_audio_;
@ -137,14 +142,16 @@ public:
// Write the tags in a time.
virtual srs_error_t write_tags(SrsMediaPacket **msgs, int count);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t write_header(bool has_video, bool has_audio);
};
// Transmux RTMP to HTTP TS Streaming.
class SrsTsStreamEncoder : public ISrsBufferEncoder
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsTsTransmuxer *enc_;
public:
@ -170,7 +177,8 @@ public:
// Transmux RTMP with AAC stream to HTTP AAC Streaming.
class SrsAacStreamEncoder : public ISrsBufferEncoder
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAacTransmuxer *enc_;
ISrsBufferCache *cache_;
@ -192,7 +200,8 @@ public:
// Transmux RTMP with MP3 stream to HTTP MP3 Streaming.
class SrsMp3StreamEncoder : public ISrsBufferEncoder
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsMp3Transmuxer *enc_;
ISrsBufferCache *cache_;
@ -214,7 +223,8 @@ public:
// Write stream to http response direclty.
class SrsBufferWriter : public SrsFileWriter
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsHttpResponseWriter *writer_;
public:
@ -250,13 +260,15 @@ public:
// TODO: FIXME: Rename to SrsHttpLive
class SrsLiveStream : public ISrsLiveStream
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsLiveSourceManager *live_sources_;
ISrsStatistic *stat_;
ISrsHttpHooks *hooks_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
ISrsBufferCache *cache_;
ISrsSecurity *security_;
@ -273,7 +285,8 @@ public:
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t serve_http_impl(ISrsHttpResponseWriter *w, ISrsHttpMessage *r);
public:
@ -282,7 +295,8 @@ public:
public:
virtual void expire();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_serve_http(SrsLiveSource *source, ISrsLiveConsumer *consumer, ISrsHttpResponseWriter *w, ISrsHttpMessage *r);
virtual srs_error_t http_hooks_on_play(ISrsHttpMessage *r);
virtual void http_hooks_on_stop(ISrsHttpMessage *r);
@ -291,7 +305,8 @@ private:
// The Live Entry, to handle HTTP Live Streaming.
struct SrsLiveEntry {
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool is_flv_;
bool is_ts_;
bool is_aac_;
@ -322,17 +337,35 @@ public:
};
// The HTTP Live Streaming Server, to serve FLV/TS/MP3/AAC stream.
// TODO: Support multiple stream.
class SrsHttpStreamServer : public ISrsReloadHandler, public ISrsHttpDynamicMatcher
class ISrsHttpStreamServer : public ISrsHttpDynamicMatcher
{
private:
ISrsAppConfig *config_;
public:
ISrsHttpStreamServer();
virtual ~ISrsHttpStreamServer();
private:
public:
virtual void assemble() = 0;
virtual srs_error_t initialize() = 0;
// HTTP flv/ts/mp3/aac stream
virtual srs_error_t http_mount(ISrsRequest *r) = 0;
virtual void http_unmount(ISrsRequest *r) = 0;
virtual ISrsHttpServeMux *mux() = 0;
};
// The HTTP Live Streaming Server, to serve FLV/TS/MP3/AAC stream.
// TODO: Support multiple stream.
class SrsHttpStreamServer : public ISrsHttpStreamServer
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsHttpServeMux *mux_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAsyncCallWorker *async_;
public:
SrsHttpServeMux mux_;
// The http live streaming template, to create streams.
std::map<std::string, SrsLiveEntry *> templateHandlers_;
// The http live streaming streams, created by template.
@ -345,6 +378,7 @@ public:
public:
virtual srs_error_t initialize();
virtual ISrsHttpServeMux *mux();
public:
// HTTP flv/ts/mp3/aac stream
@ -355,20 +389,22 @@ public:
public:
virtual srs_error_t dynamic_match(ISrsHttpMessage *request, ISrsHttpHandler **ph);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t initialize_flv_streaming();
virtual srs_error_t initialize_flv_entry(std::string vhost);
};
class SrsHttpStreamDestroy : public ISrsAsyncCallTask
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string sid_;
std::map<std::string, SrsLiveEntry *> *streamHandlers_;
SrsHttpServeMux *mux_;
ISrsHttpServeMux *mux_;
public:
SrsHttpStreamDestroy(SrsHttpServeMux *mux, std::map<std::string, SrsLiveEntry *> *handlers, std::string sid);
SrsHttpStreamDestroy(ISrsHttpServeMux *mux, std::map<std::string, SrsLiveEntry *> *handlers, std::string sid);
virtual ~SrsHttpStreamDestroy();
public:

View File

@ -10,6 +10,7 @@
using namespace std;
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_ffmpeg.hpp>
#include <srs_app_utility.hpp>
#include <srs_kernel_error.hpp>
@ -18,6 +19,14 @@ using namespace std;
#include <srs_kernel_utility.hpp>
#include <srs_protocol_utility.hpp>
ISrsIngesterFFMPEG::ISrsIngesterFFMPEG()
{
}
ISrsIngesterFFMPEG::~ISrsIngesterFFMPEG()
{
}
SrsIngesterFFMPEG::SrsIngesterFFMPEG()
{
ffmpeg_ = NULL;
@ -29,7 +38,7 @@ SrsIngesterFFMPEG::~SrsIngesterFFMPEG()
srs_freep(ffmpeg_);
}
srs_error_t SrsIngesterFFMPEG::initialize(SrsFFMPEG *ff, string v, string i)
srs_error_t SrsIngesterFFMPEG::initialize(ISrsFFMPEG *ff, string v, string i)
{
srs_error_t err = srs_success;
@ -86,24 +95,34 @@ void SrsIngesterFFMPEG::fast_kill()
ffmpeg_->fast_kill();
}
ISrsIngester::ISrsIngester()
{
}
ISrsIngester::~ISrsIngester()
{
}
SrsIngester::SrsIngester()
{
_srs_config->subscribe(this);
expired_ = false;
disposed_ = false;
trd_ = new SrsDummyCoroutine();
pprint_ = SrsPithyPrint::create_ingester();
app_factory_ = _srs_app_factory;
config_ = _srs_config;
}
SrsIngester::~SrsIngester()
{
_srs_config->unsubscribe(this);
srs_freep(trd_);
clear_engines();
srs_freep(pprint_);
app_factory_ = NULL;
config_ = NULL;
}
void SrsIngester::dispose()
@ -116,7 +135,8 @@ void SrsIngester::dispose()
// first, use fast stop to notice all FFMPEG to quit gracefully.
fast_stop();
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
SrsUniquePtr<ISrsTime> time(app_factory_->create_time());
time->usleep(100 * SRS_UTIME_MILLISECONDS);
// then, use fast kill to ensure FFMPEG quit.
fast_kill();
@ -136,7 +156,7 @@ srs_error_t SrsIngester::start()
// start thread to run all encoding engines.
srs_freep(trd_);
trd_ = new SrsSTCoroutine("ingest", this, _srs_context->get_id());
trd_ = app_factory_->create_coroutine("ingest", this, _srs_context->get_id());
if ((err = trd_->start()) != srs_success) {
return srs_error_wrap(err, "start coroutine");
@ -153,9 +173,9 @@ void SrsIngester::stop()
void SrsIngester::fast_stop()
{
std::vector<SrsIngesterFFMPEG *>::iterator it;
std::vector<ISrsIngesterFFMPEG *>::iterator it;
for (it = ingesters_.begin(); it != ingesters_.end(); ++it) {
SrsIngesterFFMPEG *ingester = *it;
ISrsIngesterFFMPEG *ingester = *it;
ingester->fast_stop();
}
@ -166,9 +186,9 @@ void SrsIngester::fast_stop()
void SrsIngester::fast_kill()
{
std::vector<SrsIngesterFFMPEG *>::iterator it;
std::vector<ISrsIngesterFFMPEG *>::iterator it;
for (it = ingesters_.begin(); it != ingesters_.end(); ++it) {
SrsIngesterFFMPEG *ingester = *it;
ISrsIngesterFFMPEG *ingester = *it;
ingester->fast_kill();
}
@ -185,6 +205,8 @@ srs_error_t SrsIngester::cycle()
{
srs_error_t err = srs_success;
SrsUniquePtr<ISrsTime> time(app_factory_->create_time());
while (!disposed_) {
// We always check status first.
// @see https://github.com/ossrs/srs/issues/1634#issuecomment-597571561
@ -197,7 +219,7 @@ srs_error_t SrsIngester::cycle()
srs_freep(err);
}
srs_usleep(SRS_INGESTER_CIMS);
time->usleep(SRS_INGESTER_CIMS);
}
return err;
@ -222,9 +244,9 @@ srs_error_t SrsIngester::do_cycle()
}
// cycle exists ingesters.
std::vector<SrsIngesterFFMPEG *>::iterator it;
std::vector<ISrsIngesterFFMPEG *>::iterator it;
for (it = ingesters_.begin(); it != ingesters_.end(); ++it) {
SrsIngesterFFMPEG *ingester = *it;
ISrsIngesterFFMPEG *ingester = *it;
// start all ffmpegs.
if ((err = ingester->start()) != srs_success) {
@ -245,10 +267,10 @@ srs_error_t SrsIngester::do_cycle()
void SrsIngester::clear_engines()
{
std::vector<SrsIngesterFFMPEG *>::iterator it;
std::vector<ISrsIngesterFFMPEG *>::iterator it;
for (it = ingesters_.begin(); it != ingesters_.end(); ++it) {
SrsIngesterFFMPEG *ingester = *it;
ISrsIngesterFFMPEG *ingester = *it;
srs_freep(ingester);
}
@ -261,7 +283,7 @@ srs_error_t SrsIngester::parse()
// parse ingesters
std::vector<SrsConfDirective *> vhosts;
_srs_config->get_vhosts(vhosts);
config_->get_vhosts(vhosts);
for (int i = 0; i < (int)vhosts.size(); i++) {
SrsConfDirective *vhost = vhosts[i];
@ -278,11 +300,11 @@ srs_error_t SrsIngester::parse_ingesters(SrsConfDirective *vhost)
srs_error_t err = srs_success;
// when vhost disabled, ignore any ingesters.
if (!_srs_config->get_vhost_enabled(vhost)) {
if (!config_->get_vhost_enabled(vhost)) {
return err;
}
std::vector<SrsConfDirective *> ingesters = _srs_config->get_ingesters(vhost->arg0());
std::vector<SrsConfDirective *> ingesters = config_->get_ingesters(vhost->arg0());
// create engine
for (int i = 0; i < (int)ingesters.size(); i++) {
@ -299,27 +321,27 @@ srs_error_t SrsIngester::parse_engines(SrsConfDirective *vhost, SrsConfDirective
{
srs_error_t err = srs_success;
if (!_srs_config->get_ingest_enabled(ingest)) {
if (!config_->get_ingest_enabled(ingest)) {
return err;
}
std::string ffmpeg_bin = _srs_config->get_ingest_ffmpeg(ingest);
std::string ffmpeg_bin = config_->get_ingest_ffmpeg(ingest);
if (ffmpeg_bin.empty()) {
return srs_error_new(ERROR_ENCODER_PARSE, "parse ffmpeg");
}
// get all engines.
std::vector<SrsConfDirective *> engines = _srs_config->get_transcode_engines(ingest);
std::vector<SrsConfDirective *> engines = config_->get_transcode_engines(ingest);
// create ingesters without engines.
if (engines.empty()) {
SrsFFMPEG *ffmpeg = new SrsFFMPEG(ffmpeg_bin);
ISrsFFMPEG *ffmpeg = app_factory_->create_ffmpeg(ffmpeg_bin);
if ((err = initialize_ffmpeg(ffmpeg, vhost, ingest, NULL)) != srs_success) {
srs_freep(ffmpeg);
return srs_error_wrap(err, "init ffmpeg");
}
SrsIngesterFFMPEG *ingester = new SrsIngesterFFMPEG();
ISrsIngesterFFMPEG *ingester = app_factory_->create_ingester_ffmpeg();
if ((err = ingester->initialize(ffmpeg, vhost->arg0(), ingest->arg0())) != srs_success) {
srs_freep(ingester);
return srs_error_wrap(err, "init ingester");
@ -332,13 +354,13 @@ srs_error_t SrsIngester::parse_engines(SrsConfDirective *vhost, SrsConfDirective
// create ingesters with engine
for (int i = 0; i < (int)engines.size(); i++) {
SrsConfDirective *engine = engines[i];
SrsFFMPEG *ffmpeg = new SrsFFMPEG(ffmpeg_bin);
ISrsFFMPEG *ffmpeg = app_factory_->create_ffmpeg(ffmpeg_bin);
if ((err = initialize_ffmpeg(ffmpeg, vhost, ingest, engine)) != srs_success) {
srs_freep(ffmpeg);
return srs_error_wrap(err, "init ffmpeg");
}
SrsIngesterFFMPEG *ingester = new SrsIngesterFFMPEG();
ISrsIngesterFFMPEG *ingester = app_factory_->create_ingester_ffmpeg();
if ((err = ingester->initialize(ffmpeg, vhost->arg0(), ingest->arg0())) != srs_success) {
srs_freep(ingester);
return srs_error_wrap(err, "init ingester");
@ -350,13 +372,13 @@ srs_error_t SrsIngester::parse_engines(SrsConfDirective *vhost, SrsConfDirective
return err;
}
srs_error_t SrsIngester::initialize_ffmpeg(SrsFFMPEG *ffmpeg, SrsConfDirective *vhost, SrsConfDirective *ingest, SrsConfDirective *engine)
srs_error_t SrsIngester::initialize_ffmpeg(ISrsFFMPEG *ffmpeg, SrsConfDirective *vhost, SrsConfDirective *ingest, SrsConfDirective *engine)
{
srs_error_t err = srs_success;
int port;
if (true) {
std::vector<std::string> ip_ports = _srs_config->get_listens();
std::vector<std::string> ip_ports = config_->get_listens();
srs_assert(ip_ports.size() > 0);
std::string ip;
@ -364,7 +386,7 @@ srs_error_t SrsIngester::initialize_ffmpeg(SrsFFMPEG *ffmpeg, SrsConfDirective *
srs_net_split_for_listener(ep, ip, port);
}
std::string output = _srs_config->get_engine_output(engine);
std::string output = config_->get_engine_output(engine);
// output stream, to other/self server
// ie. rtmp://localhost:1935/live/livestream_sd
output = srs_strings_replace(output, "[vhost]", vhost->arg0());
@ -390,8 +412,8 @@ srs_error_t SrsIngester::initialize_ffmpeg(SrsFFMPEG *ffmpeg, SrsConfDirective *
std::string log_file = SRS_CONSTS_NULL_FILE; // disabled
// write ffmpeg info to log file.
if (_srs_config->get_ff_log_enabled()) {
log_file = _srs_config->get_ff_log_dir();
if (config_->get_ff_log_enabled()) {
log_file = config_->get_ff_log_dir();
log_file += "/";
log_file += "ffmpeg-ingest";
log_file += "-";
@ -403,20 +425,20 @@ srs_error_t SrsIngester::initialize_ffmpeg(SrsFFMPEG *ffmpeg, SrsConfDirective *
log_file += ".log";
}
std::string log_level = _srs_config->get_ff_log_level();
std::string log_level = config_->get_ff_log_level();
if (!log_level.empty()) {
ffmpeg->append_iparam("-loglevel");
ffmpeg->append_iparam(log_level);
}
// input
std::string input_type = _srs_config->get_ingest_input_type(ingest);
std::string input_type = config_->get_ingest_input_type(ingest);
if (input_type.empty()) {
return srs_error_new(ERROR_ENCODER_NO_INPUT, "empty intput type, ingest=%s", ingest->arg0().c_str());
}
if (srs_config_ingest_is_file(input_type)) {
std::string input_url = _srs_config->get_ingest_input_url(ingest);
std::string input_url = config_->get_ingest_input_url(ingest);
if (input_url.empty()) {
return srs_error_new(ERROR_ENCODER_NO_INPUT, "empty intput url, ingest=%s", ingest->arg0().c_str());
}
@ -428,7 +450,7 @@ srs_error_t SrsIngester::initialize_ffmpeg(SrsFFMPEG *ffmpeg, SrsConfDirective *
return srs_error_wrap(err, "init ffmpeg");
}
} else if (srs_config_ingest_is_stream(input_type)) {
std::string input_url = _srs_config->get_ingest_input_url(ingest);
std::string input_url = config_->get_ingest_input_url(ingest);
if (input_url.empty()) {
return srs_error_new(ERROR_ENCODER_NO_INPUT, "empty intput url, ingest=%s", ingest->arg0().c_str());
}
@ -446,10 +468,10 @@ srs_error_t SrsIngester::initialize_ffmpeg(SrsFFMPEG *ffmpeg, SrsConfDirective *
// set output format to flv for RTMP
ffmpeg->set_oformat("flv");
std::string vcodec = _srs_config->get_engine_vcodec(engine);
std::string acodec = _srs_config->get_engine_acodec(engine);
std::string vcodec = config_->get_engine_vcodec(engine);
std::string acodec = config_->get_engine_acodec(engine);
// whatever the engine config, use copy as default.
bool engine_disabled = !engine || !_srs_config->get_engine_enabled(engine);
bool engine_disabled = !engine || !config_->get_engine_enabled(engine);
if (engine_disabled || vcodec.empty() || acodec.empty()) {
if ((err = ffmpeg->initialize_copy()) != srs_success) {
return srs_error_wrap(err, "init ffmpeg");
@ -476,7 +498,7 @@ void SrsIngester::show_ingest_log_message()
// random choose one ingester to report.
SrsRand rand;
int index = rand.integer() % (int)ingesters_.size();
SrsIngesterFFMPEG *ingester = ingesters_.at(index);
ISrsIngesterFFMPEG *ingester = ingesters_.at(index);
// reportable
if (pprint_->can_print()) {

View File

@ -15,16 +15,45 @@
#include <srs_app_st.hpp>
class SrsFFMPEG;
class ISrsFFMPEG;
class SrsConfDirective;
class SrsPithyPrint;
class ISrsPithyPrint;
class ISrsAppFactory;
class ISrsAppConfig;
// The ingest ffmpeg interface.
class ISrsIngesterFFMPEG
{
public:
ISrsIngesterFFMPEG();
virtual ~ISrsIngesterFFMPEG();
public:
virtual srs_error_t initialize(ISrsFFMPEG *ff, std::string v, std::string i) = 0;
// The ingest uri, [vhost]/[ingest id]
virtual std::string uri() = 0;
// The alive in srs_utime_t.
virtual srs_utime_t alive() = 0;
virtual bool equals(std::string v, std::string i) = 0;
virtual bool equals(std::string v) = 0;
public:
virtual srs_error_t start() = 0;
virtual void stop() = 0;
virtual srs_error_t cycle() = 0;
virtual void fast_stop() = 0;
virtual void fast_kill() = 0;
};
// Ingester ffmpeg object.
class SrsIngesterFFMPEG
class SrsIngesterFFMPEG : public ISrsIngesterFFMPEG
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string vhost_;
std::string id_;
SrsFFMPEG *ffmpeg_;
ISrsFFMPEG *ffmpeg_;
srs_utime_t starttime_;
public:
@ -32,7 +61,7 @@ public:
virtual ~SrsIngesterFFMPEG();
public:
virtual srs_error_t initialize(SrsFFMPEG *ff, std::string v, std::string i);
virtual srs_error_t initialize(ISrsFFMPEG *ff, std::string v, std::string i);
// The ingest uri, [vhost]/[ingest id]
virtual std::string uri();
// The alive in srs_utime_t.
@ -44,22 +73,38 @@ public:
virtual srs_error_t start();
virtual void stop();
virtual srs_error_t cycle();
// @see SrsFFMPEG.fast_stop().
virtual void fast_stop();
virtual void fast_kill();
};
// The ingest interface.
class ISrsIngester
{
public:
ISrsIngester();
virtual ~ISrsIngester();
public:
};
// Ingest file/stream/device,
// encode with FFMPEG(optional),
// push to SRS(or any RTMP server) over RTMP.
class SrsIngester : public ISrsCoroutineHandler, public ISrsReloadHandler
class SrsIngester : public ISrsIngester, public ISrsCoroutineHandler
{
private:
std::vector<SrsIngesterFFMPEG *> ingesters_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppFactory *app_factory_;
ISrsAppConfig *config_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::vector<ISrsIngesterFFMPEG *> ingesters_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsCoroutine *trd_;
SrsPithyPrint *pprint_;
ISrsPithyPrint *pprint_;
// Whether the ingesters are expired, for example, the listen port changed,
// all ingesters must be restart.
bool expired_;
@ -77,24 +122,28 @@ public:
virtual srs_error_t start();
virtual void stop();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Notify FFMPEG to fast stop.
virtual void fast_stop();
virtual void
fast_stop();
// When SRS quit, directly kill FFMPEG after fast stop.
virtual void fast_kill();
// Interface ISrsReusableThreadHandler.
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual void clear_engines();
virtual srs_error_t parse();
virtual srs_error_t parse_ingesters(SrsConfDirective *vhost);
virtual srs_error_t parse_engines(SrsConfDirective *vhost, SrsConfDirective *ingest);
virtual srs_error_t initialize_ffmpeg(SrsFFMPEG *ffmpeg, SrsConfDirective *vhost, SrsConfDirective *ingest, SrsConfDirective *engine);
virtual srs_error_t initialize_ffmpeg(ISrsFFMPEG *ffmpeg, SrsConfDirective *vhost, SrsConfDirective *ingest, SrsConfDirective *engine);
virtual void show_ingest_log_message();
};

View File

@ -11,6 +11,7 @@
#include <srs_app_http_conn.hpp>
#include <srs_app_statistic.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_utility.hpp>
#include <srs_core_autofree.hpp>
#include <srs_kernel_error.hpp>
@ -176,11 +177,15 @@ void srs_build_features(stringstream &ss)
SrsLatestVersion::SrsLatestVersion()
{
trd_ = new SrsSTCoroutine("signal", this);
app_factory_ = _srs_app_factory;
}
SrsLatestVersion::~SrsLatestVersion()
{
srs_freep(trd_);
app_factory_ = NULL;
}
srs_error_t SrsLatestVersion::start()
@ -255,8 +260,8 @@ srs_error_t SrsLatestVersion::query_latest_version(string &url)
}
// Start HTTP request and read response.
SrsHttpClient http;
if ((err = http.initialize(uri.get_schema(), uri.get_host(), uri.get_port())) != srs_success) {
SrsUniquePtr<ISrsHttpClient> http(app_factory_->create_http_client());
if ((err = http->initialize(uri.get_schema(), uri.get_host(), uri.get_port())) != srs_success) {
return err;
}
@ -266,7 +271,7 @@ srs_error_t SrsLatestVersion::query_latest_version(string &url)
path += uri.get_query();
ISrsHttpMessage *msg_raw = NULL;
if ((err = http.get(path, "", &msg_raw)) != srs_success) {
if ((err = http->get(path, "", &msg_raw)) != srs_success) {
return err;
}

View File

@ -15,16 +15,28 @@
#include <srs_app_st.hpp>
#include <sstream>
#include <string>
class ISrsAppFactory;
// Build features string for version query
extern void srs_build_features(std::stringstream &ss);
class SrsLatestVersion : public ISrsCoroutineHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsCoroutine *trd_;
std::string server_id_;
std::string session_id_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string match_version_;
std::string stable_version_;
@ -38,7 +50,8 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t query_latest_version(std::string &url);
};

View File

@ -17,17 +17,17 @@
#include <unistd.h>
using namespace std;
#include <srs_app_factory.hpp>
#include <srs_app_server.hpp>
#include <srs_app_utility.hpp>
#include <srs_core_autofree.hpp>
#include <srs_kernel_buffer.hpp>
#include <srs_kernel_error.hpp>
#include <srs_kernel_kbps.hpp>
#include <srs_kernel_log.hpp>
#include <srs_kernel_pithy_print.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_kernel_kbps.hpp>
SrsPps *_srs_pps_rpkts = NULL;
SrsPps *_srs_pps_addrs = NULL;
SrsPps *_srs_pps_fast_addrs = NULL;
@ -64,6 +64,14 @@ ISrsListener::~ISrsListener()
{
}
ISrsIpListener::ISrsIpListener()
{
}
ISrsIpListener::~ISrsIpListener()
{
}
ISrsTcpHandler::ISrsTcpHandler()
{
}
@ -83,6 +91,8 @@ SrsUdpListener::SrsUdpListener(ISrsUdpHandler *h)
buf_ = new char[nb_buf_];
trd_ = new SrsDummyCoroutine();
factory_ = _srs_app_factory;
}
SrsUdpListener::~SrsUdpListener()
@ -90,15 +100,17 @@ SrsUdpListener::~SrsUdpListener()
srs_freep(trd_);
srs_close_stfd(lfd_);
srs_freepa(buf_);
factory_ = NULL;
}
SrsUdpListener *SrsUdpListener::set_label(const std::string &label)
ISrsListener *SrsUdpListener::set_label(const std::string &label)
{
label_ = label;
return this;
}
SrsUdpListener *SrsUdpListener::set_endpoint(const std::string &i, int p)
ISrsListener *SrsUdpListener::set_endpoint(const std::string &i, int p)
{
ip_ = i;
port_ = p;
@ -175,7 +187,7 @@ srs_error_t SrsUdpListener::listen()
set_socket_buffer();
srs_freep(trd_);
trd_ = new SrsSTCoroutine("udp", this, _srs_context->get_id());
trd_ = factory_->create_coroutine("udp", this, _srs_context->get_id());
if ((err = trd_->start()) != srs_success) {
return srs_error_wrap(err, "start thread");
}
@ -242,28 +254,32 @@ SrsTcpListener::SrsTcpListener(ISrsTcpHandler *h)
lfd_ = NULL;
label_ = "TCP";
trd_ = new SrsDummyCoroutine();
factory_ = _srs_app_factory;
}
SrsTcpListener::~SrsTcpListener()
{
srs_freep(trd_);
srs_close_stfd(lfd_);
factory_ = NULL;
}
SrsTcpListener *SrsTcpListener::set_label(const std::string &label)
ISrsListener *SrsTcpListener::set_label(const std::string &label)
{
label_ = label;
return this;
}
SrsTcpListener *SrsTcpListener::set_endpoint(const std::string &i, int p)
ISrsListener *SrsTcpListener::set_endpoint(const std::string &i, int p)
{
ip_ = i;
port_ = p;
return this;
}
SrsTcpListener *SrsTcpListener::set_endpoint(const std::string &endpoint)
ISrsListener *SrsTcpListener::set_endpoint(const std::string &endpoint)
{
std::string ip;
int port_;
@ -290,7 +306,7 @@ srs_error_t SrsTcpListener::listen()
}
srs_freep(trd_);
trd_ = new SrsSTCoroutine("tcp", this);
trd_ = factory_->create_coroutine("tcp", this, _srs_context->get_id());
if ((err = trd_->start()) != srs_success) {
return srs_error_wrap(err, "start coroutine");
}
@ -348,35 +364,50 @@ srs_error_t SrsTcpListener::do_cycle()
SrsMultipleTcpListeners::SrsMultipleTcpListeners(ISrsTcpHandler *h)
{
handler_ = h;
factory_ = _srs_app_factory;
}
SrsMultipleTcpListeners::~SrsMultipleTcpListeners()
{
for (vector<SrsTcpListener *>::iterator it = listeners_.begin(); it != listeners_.end(); ++it) {
SrsTcpListener *l = *it;
for (vector<ISrsIpListener *>::iterator it = listeners_.begin(); it != listeners_.end(); ++it) {
ISrsIpListener *l = *it;
srs_freep(l);
}
factory_ = NULL;
}
SrsMultipleTcpListeners *SrsMultipleTcpListeners::set_label(const std::string &label)
ISrsListener *SrsMultipleTcpListeners::set_label(const std::string &label)
{
for (vector<SrsTcpListener *>::iterator it = listeners_.begin(); it != listeners_.end(); ++it) {
SrsTcpListener *l = *it;
for (vector<ISrsIpListener *>::iterator it = listeners_.begin(); it != listeners_.end(); ++it) {
ISrsIpListener *l = *it;
l->set_label(label);
}
return this;
}
SrsMultipleTcpListeners *SrsMultipleTcpListeners::add(const std::vector<std::string> &endpoints)
ISrsListener *SrsMultipleTcpListeners::set_endpoint(const std::string &i, int p)
{
for (vector<ISrsIpListener *>::iterator it = listeners_.begin(); it != listeners_.end(); ++it) {
ISrsIpListener *l = *it;
l->set_endpoint(i, p);
}
return this;
}
ISrsIpListener *SrsMultipleTcpListeners::add(const std::vector<std::string> &endpoints)
{
for (int i = 0; i < (int)endpoints.size(); i++) {
string ip;
int port;
srs_net_split_for_listener(endpoints[i], ip, port);
SrsTcpListener *l = new SrsTcpListener(this);
listeners_.push_back(l->set_endpoint(ip, port));
ISrsIpListener *l = factory_->create_tcp_listener(this);
l->set_endpoint(ip, port);
listeners_.push_back(l);
}
return this;
@ -386,8 +417,8 @@ srs_error_t SrsMultipleTcpListeners::listen()
{
srs_error_t err = srs_success;
for (vector<SrsTcpListener *>::iterator it = listeners_.begin(); it != listeners_.end(); ++it) {
SrsTcpListener *l = *it;
for (vector<ISrsIpListener *>::iterator it = listeners_.begin(); it != listeners_.end(); ++it) {
ISrsIpListener *l = *it;
if ((err = l->listen()) != srs_success) {
return srs_error_wrap(err, "listen");
@ -399,8 +430,8 @@ srs_error_t SrsMultipleTcpListeners::listen()
void SrsMultipleTcpListeners::close()
{
for (vector<SrsTcpListener *>::iterator it = listeners_.begin(); it != listeners_.end(); ++it) {
SrsTcpListener *l = *it;
for (vector<ISrsIpListener *>::iterator it = listeners_.begin(); it != listeners_.end(); ++it) {
ISrsIpListener *l = *it;
srs_freep(l);
}
listeners_.clear();
@ -411,6 +442,14 @@ srs_error_t SrsMultipleTcpListeners::on_tcp_client(ISrsListener *listener, srs_n
return handler_->on_tcp_client(this, stfd);
}
ISrsUdpMuxSocket::ISrsUdpMuxSocket()
{
}
ISrsUdpMuxSocket::~ISrsUdpMuxSocket()
{
}
SrsUdpMuxSocket::SrsUdpMuxSocket(srs_netfd_t fd)
{
nn_msgs_for_yield_ = 0;
@ -593,7 +632,7 @@ SrsBuffer *SrsUdpMuxSocket::buffer()
return cache_buffer_;
}
SrsUdpMuxSocket *SrsUdpMuxSocket::copy_sendonly()
ISrsUdpMuxSocket *SrsUdpMuxSocket::copy_sendonly()
{
SrsUdpMuxSocket *sendonly = new SrsUdpMuxSocket(lfd_);
@ -628,6 +667,8 @@ SrsUdpMuxListener::SrsUdpMuxListener(ISrsUdpMuxHandler *h, std::string i, int p)
trd_ = new SrsDummyCoroutine();
cid_ = _srs_context->generate_id();
factory_ = _srs_app_factory;
}
SrsUdpMuxListener::~SrsUdpMuxListener()
@ -635,6 +676,8 @@ SrsUdpMuxListener::~SrsUdpMuxListener()
srs_freep(trd_);
srs_close_stfd(lfd_);
srs_freepa(buf_);
factory_ = NULL;
}
int SrsUdpMuxListener::fd()
@ -656,7 +699,7 @@ srs_error_t SrsUdpMuxListener::listen()
}
srs_freep(trd_);
trd_ = new SrsSTCoroutine("udp", this, cid_);
trd_ = factory_->create_coroutine("udp", this, cid_);
// change stack size to 256K, fix crash when call some 3rd-part api.
((SrsSTCoroutine *)trd_)->set_stack_size(1 << 18);
@ -727,7 +770,8 @@ srs_error_t SrsUdpMuxListener::cycle()
// Because we have to decrypt the cipher of received packet payload,
// and the size is not determined, so we think there is at least one copy,
// and we can reuse the plaintext h264/opus with players when got plaintext.
SrsUdpMuxSocket skt(lfd_);
SrsUniquePtr<SrsUdpMuxSocket> skt_ptr(new SrsUdpMuxSocket(lfd_));
ISrsUdpMuxSocket *skt = skt_ptr.get();
// How many messages to run a yield.
uint32_t nn_msgs_for_yield = 0;
@ -739,7 +783,7 @@ srs_error_t SrsUdpMuxListener::cycle()
nn_loop++;
int nread = skt.recvfrom(SRS_UTIME_NO_TIMEOUT);
int nread = skt->recvfrom(SRS_UTIME_NO_TIMEOUT);
if (nread <= 0) {
if (nread < 0) {
srs_warn("udp recv error nn=%d", nread);
@ -752,7 +796,7 @@ srs_error_t SrsUdpMuxListener::cycle()
nn_msgs_stage++;
// Handle the UDP packet.
err = handler_->on_udp_packet(&skt);
err = handler_->on_udp_packet(skt);
// Use pithy print to show more smart information.
if (err != srs_success) {
@ -762,7 +806,7 @@ srs_error_t SrsUdpMuxListener::cycle()
_srs_context->set_id(cid_);
// Append more information.
err = srs_error_wrap(err, "size=%u, data=[%s]", skt.size(), srs_strings_dumps_hex(skt.data(), skt.size(), 8).c_str());
err = srs_error_wrap(err, "size=%u, data=[%s]", skt->size(), srs_strings_dumps_hex(skt->data(), skt->size(), 8).c_str());
srs_warn("handle udp pkt, count=%u/%u, err: %s", pp_pkt_handler_err->nn_count_, nn, srs_error_desc(err).c_str());
}
srs_freep(err);

View File

@ -23,6 +23,8 @@ struct sockaddr;
class SrsBuffer;
class SrsUdpMuxSocket;
class ISrsListener;
class ISrsAppFactory;
class ISrsUdpMuxSocket;
// The udp packet handler.
class ISrsUdpHandler
@ -50,7 +52,7 @@ public:
virtual ~ISrsUdpMuxHandler();
public:
virtual srs_error_t on_udp_packet(SrsUdpMuxSocket *skt) = 0;
virtual srs_error_t on_udp_packet(ISrsUdpMuxSocket *skt) = 0;
};
// All listener should support listen method.
@ -64,6 +66,19 @@ public:
virtual srs_error_t listen() = 0;
};
// The IP layer TCP/UDP listener.
class ISrsIpListener : public ISrsListener
{
public:
ISrsIpListener();
virtual ~ISrsIpListener();
public:
virtual ISrsListener *set_endpoint(const std::string &i, int p) = 0;
virtual ISrsListener *set_label(const std::string &label) = 0;
virtual void close() = 0;
};
// The tcp connection handler.
class ISrsTcpHandler
{
@ -77,18 +92,25 @@ public:
};
// Bind udp port, start thread to recv packet and handler it.
class SrsUdpListener : public ISrsCoroutineHandler
class SrsUdpListener : public ISrsCoroutineHandler, public ISrsIpListener
{
protected:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppFactory *factory_;
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
std::string label_;
srs_netfd_t lfd_;
ISrsCoroutine *trd_;
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
char *buf_;
int nb_buf_;
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
ISrsUdpHandler *handler_;
std::string ip_;
int port_;
@ -98,14 +120,16 @@ public:
virtual ~SrsUdpListener();
public:
SrsUdpListener *set_label(const std::string &label);
SrsUdpListener *set_endpoint(const std::string &i, int p);
ISrsListener *set_label(const std::string &label);
ISrsListener *set_endpoint(const std::string &i, int p);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual int fd();
virtual srs_netfd_t stfd();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
void set_socket_buffer();
public:
@ -115,19 +139,26 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t do_cycle();
};
// Bind and listen tcp port, use handler to process the client.
class SrsTcpListener : public ISrsCoroutineHandler, public ISrsListener
class SrsTcpListener : public ISrsCoroutineHandler, public ISrsIpListener
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppFactory *factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string label_;
srs_netfd_t lfd_;
ISrsCoroutine *trd_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsTcpHandler *handler_;
std::string ip_;
int port_;
@ -137,9 +168,9 @@ public:
virtual ~SrsTcpListener();
public:
SrsTcpListener *set_label(const std::string &label);
SrsTcpListener *set_endpoint(const std::string &i, int p);
SrsTcpListener *set_endpoint(const std::string &endpoint);
ISrsListener *set_label(const std::string &label);
ISrsListener *set_endpoint(const std::string &i, int p);
ISrsListener *set_endpoint(const std::string &endpoint);
int port();
public:
@ -149,24 +180,31 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t do_cycle();
};
// Bind and listen tcp port, use handler to process the client.
class SrsMultipleTcpListeners : public ISrsListener, public ISrsTcpHandler
class SrsMultipleTcpListeners : public ISrsIpListener, public ISrsTcpHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppFactory *factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsTcpHandler *handler_;
std::vector<SrsTcpListener *> listeners_;
std::vector<ISrsIpListener *> listeners_;
public:
SrsMultipleTcpListeners(ISrsTcpHandler *h);
virtual ~SrsMultipleTcpListeners();
public:
SrsMultipleTcpListeners *set_label(const std::string &label);
SrsMultipleTcpListeners *add(const std::vector<std::string> &endpoints);
ISrsListener *set_label(const std::string &label);
ISrsListener *set_endpoint(const std::string &i, int p);
ISrsIpListener *add(const std::vector<std::string> &endpoints);
public:
srs_error_t listen();
@ -176,16 +214,37 @@ public:
virtual srs_error_t on_tcp_client(ISrsListener *listener, srs_netfd_t stfd);
};
// TODO: FIXME: Rename it. Refine it for performance issue.
class SrsUdpMuxSocket
// The UDP socket interface.
class ISrsUdpMuxSocket
{
private:
public:
ISrsUdpMuxSocket();
virtual ~ISrsUdpMuxSocket();
public:
virtual srs_error_t sendto(void *data, int size, srs_utime_t timeout) = 0;
virtual std::string get_peer_ip() const = 0;
virtual int get_peer_port() const = 0;
virtual std::string peer_id() = 0;
virtual uint64_t fast_id() = 0;
virtual ISrsUdpMuxSocket *copy_sendonly() = 0;
virtual int recvfrom(srs_utime_t timeout) = 0;
virtual char *data() = 0;
virtual int size() = 0;
};
// TODO: FIXME: Rename it. Refine it for performance issue.
class SrsUdpMuxSocket : public ISrsUdpMuxSocket
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// For sender yield only.
uint32_t nn_msgs_for_yield_;
std::map<uint32_t, std::string> cache_;
SrsBuffer *cache_buffer_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
char *buf_;
int nb_buf_;
int nread_;
@ -193,11 +252,13 @@ private:
sockaddr_storage from_;
int fromlen_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string peer_ip_;
int peer_port_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Cache for peer id.
std::string peer_id_;
// If the address changed, we should generate the peer_id.
@ -222,21 +283,28 @@ public:
std::string peer_id();
uint64_t fast_id();
SrsBuffer *buffer();
SrsUdpMuxSocket *copy_sendonly();
ISrsUdpMuxSocket *copy_sendonly();
};
class SrsUdpMuxListener : public ISrsCoroutineHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppFactory *factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_netfd_t lfd_;
ISrsCoroutine *trd_;
SrsContextId cid_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
char *buf_;
int nb_buf_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsUdpMuxHandler *handler_;
std::string ip_;
int port_;
@ -255,7 +323,8 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
void set_socket_buffer();
};

View File

@ -20,11 +20,13 @@
// when you want to use different level, override this classs, set the protected _level.
class SrsFileLog : public ISrsLog, public ISrsReloadHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Defined in SrsLogLevel.
SrsLogLevel level_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
char *log_data_;
// Log to file if specified srs_log_file
int fd_;
@ -42,7 +44,8 @@ public:
virtual void reopen();
virtual void log(SrsLogLevel level, const char *tag, const SrsContextId &context_id, const char *fmt, va_list args);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual void write_log(int &fd, char *str_log, int size, int level);
virtual void open_log_file();
};

View File

@ -14,6 +14,7 @@
using namespace std;
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_rtmp_conn.hpp>
#include <srs_app_st.hpp>
#include <srs_app_utility.hpp>
@ -35,24 +36,29 @@ SrsUdpCasterListener::SrsUdpCasterListener()
{
caster_ = new SrsMpegtsOverUdp();
listener_ = new SrsUdpListener(caster_);
config_ = _srs_config;
}
SrsUdpCasterListener::~SrsUdpCasterListener()
{
srs_freep(listener_);
srs_freep(caster_);
config_ = NULL;
}
srs_error_t SrsUdpCasterListener::initialize(SrsConfDirective *conf)
{
srs_error_t err = srs_success;
int port = _srs_config->get_stream_caster_listen(conf);
int port = config_->get_stream_caster_listen(conf);
if (port <= 0) {
return srs_error_new(ERROR_STREAM_CASTER_PORT, "invalid port=%d", port);
}
listener_->set_endpoint(srs_net_address_any(), port)->set_label("MPEGTS");
listener_->set_endpoint(srs_net_address_any(), port);
listener_->set_label("MPEGTS");
if ((err = caster_->initialize(conf)) != srs_success) {
return srs_error_wrap(err, "init caster port=%d", port);
@ -77,6 +83,14 @@ void SrsUdpCasterListener::close()
listener_->close();
}
ISrsMpegtsQueue::ISrsMpegtsQueue()
{
}
ISrsMpegtsQueue::~ISrsMpegtsQueue()
{
}
SrsMpegtsQueue::SrsMpegtsQueue()
{
nb_audios_ = nb_videos_ = 0;
@ -151,6 +165,14 @@ SrsMediaPacket *SrsMpegtsQueue::dequeue()
return NULL;
}
ISrsMpegtsOverUdp::ISrsMpegtsOverUdp()
{
}
ISrsMpegtsOverUdp::~ISrsMpegtsOverUdp()
{
}
SrsMpegtsOverUdp::SrsMpegtsOverUdp()
{
context_ = new SrsTsContext();
@ -165,6 +187,9 @@ SrsMpegtsOverUdp::SrsMpegtsOverUdp()
h264_sps_pps_sent_ = false;
queue_ = new SrsMpegtsQueue();
pprint_ = SrsPithyPrint::create_caster();
config_ = _srs_config;
app_factory_ = _srs_app_factory;
}
SrsMpegtsOverUdp::~SrsMpegtsOverUdp()
@ -177,11 +202,14 @@ SrsMpegtsOverUdp::~SrsMpegtsOverUdp()
srs_freep(aac_);
srs_freep(queue_);
srs_freep(pprint_);
config_ = NULL;
app_factory_ = NULL;
}
srs_error_t SrsMpegtsOverUdp::initialize(SrsConfDirective *c)
{
output_ = _srs_config->get_stream_caster_output(c);
output_ = config_->get_stream_caster_output(c);
return srs_success;
}
@ -653,7 +681,7 @@ srs_error_t SrsMpegtsOverUdp::connect()
srs_utime_t cto = SRS_CONSTS_RTMP_TIMEOUT;
srs_utime_t sto = SRS_CONSTS_RTMP_PULSE;
sdk_ = new SrsSimpleRtmpClient(output_, cto, sto);
sdk_ = app_factory_->create_rtmp_client(output_, cto, sto);
if ((err = sdk_->connect()) != srs_success) {
close();

View File

@ -15,18 +15,27 @@ struct sockaddr;
class SrsBuffer;
class SrsTsContext;
class ISrsTsContext;
class SrsConfDirective;
class SrsSimpleStream;
class SrsRtmpClient;
class SrsStSocket;
class ISrsRequest;
class SrsRawH264Stream;
class ISrsRawH264Stream;
class SrsMediaPacket;
class SrsRawAacStream;
class ISrsRawAacStream;
struct SrsRawAacStreamCodec;
class SrsPithyPrint;
class ISrsPithyPrint;
class SrsSimpleRtmpClient;
class ISrsBasicRtmpClient;
class SrsMpegtsOverUdp;
class ISrsIpListener;
class ISrsMpegtsOverUdp;
class ISrsAppConfig;
class ISrsAppFactory;
#include <srs_app_listener.hpp>
#include <srs_app_st.hpp>
@ -35,9 +44,14 @@ class SrsMpegtsOverUdp;
// A UDP listener, for udp stream caster server.
class SrsUdpCasterListener : public ISrsListener
{
private:
SrsUdpListener *listener_;
SrsMpegtsOverUdp *caster_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsIpListener *listener_;
ISrsMpegtsOverUdp *caster_;
public:
SrsUdpCasterListener();
@ -49,14 +63,28 @@ public:
void close();
};
// The interface for mpegts queue.
class ISrsMpegtsQueue
{
public:
ISrsMpegtsQueue();
virtual ~ISrsMpegtsQueue();
public:
virtual srs_error_t push(SrsMediaPacket *msg) = 0;
virtual SrsMediaPacket *dequeue() = 0;
};
// The queue for mpegts over udp to send packets.
// For the aac in mpegts contains many flv packets in a pes packet,
// we must recalc the timestamp.
class SrsMpegtsQueue
class SrsMpegtsQueue : public ISrsMpegtsQueue
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The key: dts, value: msg.
std::map<int64_t, SrsMediaPacket *> msgs_;
std::map<int64_t, SrsMediaPacket *>
msgs_;
int nb_audios_;
int nb_videos_;
@ -69,32 +97,53 @@ public:
virtual SrsMediaPacket *dequeue();
};
// The mpegts over udp stream caster.
class SrsMpegtsOverUdp : public ISrsTsHandler, public ISrsUdpHandler
// The interface for mpegts over udp.
class ISrsMpegtsOverUdp : public ISrsTsHandler, public ISrsUdpHandler
{
private:
SrsTsContext *context_;
public:
ISrsMpegtsOverUdp();
virtual ~ISrsMpegtsOverUdp();
public:
virtual srs_error_t initialize(SrsConfDirective *c) = 0;
};
// The mpegts over udp stream caster.
class SrsMpegtsOverUdp : public ISrsMpegtsOverUdp
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsTsContext *context_;
SrsSimpleStream *buffer_;
std::string output_;
private:
SrsSimpleRtmpClient *sdk_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsBasicRtmpClient *sdk_;
private:
SrsRawH264Stream *avc_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRawH264Stream *avc_;
std::string h264_sps_;
bool h264_sps_changed_;
std::string h264_pps_;
bool h264_pps_changed_;
bool h264_sps_pps_sent_;
private:
SrsRawAacStream *aac_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRawAacStream *aac_;
std::string aac_specific_config_;
private:
SrsMpegtsQueue *queue_;
SrsPithyPrint *pprint_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsMpegtsQueue *queue_;
ISrsPithyPrint *pprint_;
public:
SrsMpegtsOverUdp();
@ -106,25 +155,30 @@ public:
public:
virtual srs_error_t on_udp_packet(const sockaddr *from, const int fromlen, char *buf, int nb_buf);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t on_udp_bytes(std::string host, int port, char *buf, int nb_buf);
// Interface ISrsTsHandler
public:
virtual srs_error_t on_ts_message(SrsTsMessage *msg);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t on_ts_video(SrsTsMessage *msg, SrsBuffer *avs);
virtual srs_error_t write_h264_sps_pps(uint32_t dts, uint32_t pts);
virtual srs_error_t write_h264_ipb_frame(char *frame, int frame_size, uint32_t dts, uint32_t pts);
virtual srs_error_t on_ts_audio(SrsTsMessage *msg, SrsBuffer *avs);
virtual srs_error_t write_audio_raw_frame(char *frame, int frame_size, SrsRawAacStreamCodec *codec, uint32_t dts);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t rtmp_write_packet(char type, uint32_t timestamp, char *data, int size);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Connect to RTMP server.
virtual srs_error_t connect();
virtual srs_error_t
connect();
// Close the connection to RTMP server.
virtual void close();
};

View File

@ -32,6 +32,8 @@ SrsNgExec::SrsNgExec()
{
trd_ = new SrsDummyCoroutine();
pprint_ = SrsPithyPrint::create_exec();
config_ = _srs_config;
}
SrsNgExec::~SrsNgExec()
@ -40,6 +42,8 @@ SrsNgExec::~SrsNgExec()
srs_freep(trd_);
srs_freep(pprint_);
config_ = NULL;
}
srs_error_t SrsNgExec::on_publish(ISrsRequest *req)
@ -132,7 +136,7 @@ srs_error_t SrsNgExec::parse_exec_publish(ISrsRequest *req)
{
srs_error_t err = srs_success;
if (!_srs_config->get_exec_enabled(req->vhost_)) {
if (!config_->get_exec_enabled(req->vhost_)) {
srs_trace("ignore disabled exec for vhost=%s", req->vhost_.c_str());
return err;
}
@ -144,7 +148,7 @@ srs_error_t SrsNgExec::parse_exec_publish(ISrsRequest *req)
input_stream_name_ += "/";
input_stream_name_ += req->stream_;
std::vector<SrsConfDirective *> eps = _srs_config->get_exec_publishs(req->vhost_);
std::vector<SrsConfDirective *> eps = config_->get_exec_publishs(req->vhost_);
for (int i = 0; i < (int)eps.size(); i++) {
SrsConfDirective *ep = eps.at(i);
SrsProcess *process = new SrsProcess();

View File

@ -17,6 +17,7 @@
class ISrsRequest;
class SrsPithyPrint;
class SrsProcess;
class ISrsAppConfig;
// The ng-exec interface.
class ISrsNgExec
@ -36,7 +37,12 @@ public:
// @see https://github.com/ossrs/srs/issues/367
class SrsNgExec : public ISrsCoroutineHandler, public ISrsNgExec
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsCoroutine *trd_;
SrsPithyPrint *pprint_;
std::string input_stream_name_;
@ -53,10 +59,12 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t parse_exec_publish(ISrsRequest *req);
virtual void clear_exec_publish();
virtual void show_exec_log_message();

View File

@ -27,6 +27,14 @@ using namespace std;
#include <srs_kernel_utility.hpp>
#include <srs_protocol_utility.hpp>
ISrsProcess::ISrsProcess()
{
}
ISrsProcess::~ISrsProcess()
{
}
SrsProcess::SrsProcess()
{
is_started_ = false;

View File

@ -12,6 +12,36 @@
#include <string>
#include <vector>
// The process interface.
class ISrsProcess
{
public:
ISrsProcess();
virtual ~ISrsProcess();
public:
// Get pid of process.
virtual int get_pid() = 0;
// whether process is already started.
virtual bool started() = 0;
// Initialize the process with binary and argv.
virtual srs_error_t initialize(std::string binary, std::vector<std::string> argv) = 0;
public:
// Start the process, ignore when already started.
virtual srs_error_t start() = 0;
// cycle check the process, update the state of process.
virtual srs_error_t cycle() = 0;
// Send SIGTERM then SIGKILL to ensure the process stopped.
virtual void stop() = 0;
public:
// The fast stop is to send a SIGTERM.
virtual void fast_stop() = 0;
// Directly kill process, never use it except server quiting.
virtual void fast_kill() = 0;
};
// Start and stop a process. Call cycle to restart the process when terminated.
// The usage:
// // the binary is the process to fork.
@ -25,15 +55,17 @@
// if ((ret = process->cycle()) != ERROR_SUCCESS) { return ret; }
// process->fast_stop();
// process->stop();
class SrsProcess
class SrsProcess : public ISrsProcess
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool is_started_;
// Whether SIGTERM send but need to wait or SIGKILL.
bool fast_stopped_;
pid_t pid_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string bin_;
std::string stdout_file_;
std::string stderr_file_;
@ -57,9 +89,11 @@ public:
// @remark the argv[0] must be the binary.
virtual srs_error_t initialize(std::string binary, std::vector<std::string> argv);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Redirect standard I/O.
virtual srs_error_t redirect_io();
virtual srs_error_t
redirect_io();
public:
// Start the process, ignore when already started.

View File

@ -39,6 +39,14 @@ ISrsMessagePumper::~ISrsMessagePumper()
{
}
ISrsRecvThread::ISrsRecvThread()
{
}
ISrsRecvThread::~ISrsRecvThread()
{
}
SrsRecvThread::SrsRecvThread(ISrsMessagePumper *p, ISrsRtmpServer *r, srs_utime_t tm, SrsContextId parent_cid)
{
rtmp_ = r;
@ -144,12 +152,20 @@ srs_error_t SrsRecvThread::do_cycle()
return err;
}
SrsQueueRecvThread::SrsQueueRecvThread(SrsLiveConsumer *consumer, ISrsRtmpServer *rtmp_sdk, srs_utime_t tm, SrsContextId parent_cid)
: trd_(this, rtmp_sdk, tm, parent_cid)
ISrsQueueRecvThread::ISrsQueueRecvThread()
{
_consumer = consumer;
}
ISrsQueueRecvThread::~ISrsQueueRecvThread()
{
}
SrsQueueRecvThread::SrsQueueRecvThread(SrsLiveConsumer *consumer, ISrsRtmpServer *rtmp_sdk, srs_utime_t tm, SrsContextId parent_cid)
{
consumer_ = consumer;
rtmp_ = rtmp_sdk;
recv_error_ = srs_success;
trd_ = new SrsRecvThread(this, rtmp_sdk, tm, parent_cid);
}
SrsQueueRecvThread::~SrsQueueRecvThread()
@ -165,13 +181,14 @@ SrsQueueRecvThread::~SrsQueueRecvThread()
queue_.clear();
srs_freep(recv_error_);
srs_freep(trd_);
}
srs_error_t SrsQueueRecvThread::start()
{
srs_error_t err = srs_success;
if ((err = trd_.start()) != srs_success) {
if ((err = trd_->start()) != srs_success) {
return srs_error_wrap(err, "queue recv thread");
}
@ -180,7 +197,7 @@ srs_error_t SrsQueueRecvThread::start()
void SrsQueueRecvThread::stop()
{
trd_.stop();
trd_->stop();
}
bool SrsQueueRecvThread::empty()
@ -215,8 +232,8 @@ srs_error_t SrsQueueRecvThread::consume(SrsRtmpCommonMessage *msg)
// @see SrsRtmpConn::process_play_control_msg
queue_.push_back(msg);
#ifdef SRS_PERF_QUEUE_COND_WAIT
if (_consumer) {
_consumer->wakeup();
if (consumer_) {
consumer_->wakeup();
}
#endif
return srs_success;
@ -237,8 +254,8 @@ void SrsQueueRecvThread::interrupt(srs_error_t err)
recv_error_ = srs_error_copy(err);
#ifdef SRS_PERF_QUEUE_COND_WAIT
if (_consumer) {
_consumer->wakeup();
if (consumer_) {
consumer_->wakeup();
}
#endif
}
@ -257,40 +274,52 @@ void SrsQueueRecvThread::on_stop()
rtmp_->set_auto_response(true);
}
ISrsPublishRecvThread::ISrsPublishRecvThread()
{
}
ISrsPublishRecvThread::~ISrsPublishRecvThread()
{
}
SrsPublishRecvThread::SrsPublishRecvThread(ISrsRtmpServer *rtmp_sdk, ISrsRequest *_req,
int mr_sock_fd, srs_utime_t tm, SrsRtmpConn *conn, SrsSharedPtr<SrsLiveSource> source, SrsContextId parent_cid)
: trd_(this, rtmp_sdk, tm, parent_cid)
{
rtmp_ = rtmp_sdk;
_conn = conn;
conn_ = conn;
source_ = source;
nn_msgs_for_yield_ = 0;
recv_error_ = srs_success;
_nb_msgs = 0;
nb_msgs_ = 0;
video_frames_ = 0;
error_ = srs_cond_new();
req_ = _req;
mr_fd_ = mr_sock_fd;
// the mr settings,
mr_ = _srs_config->get_mr_enabled(req_->vhost_);
mr_sleep_ = _srs_config->get_mr_sleep(req_->vhost_);
trd_ = new SrsRecvThread(this, rtmp_sdk, tm, parent_cid);
realtime_ = _srs_config->get_realtime_enabled(req_->vhost_, false);
config_ = _srs_config;
}
_srs_config->subscribe(this);
void SrsPublishRecvThread::assemble()
{
mr_ = config_->get_mr_enabled(req_->vhost_);
mr_sleep_ = config_->get_mr_sleep(req_->vhost_);
realtime_ = config_->get_realtime_enabled(req_->vhost_, false);
}
SrsPublishRecvThread::~SrsPublishRecvThread()
{
_srs_config->unsubscribe(this);
trd_->stop();
trd_.stop();
srs_cond_destroy(error_);
srs_freep(recv_error_);
srs_freep(trd_);
config_ = NULL;
}
srs_error_t SrsPublishRecvThread::wait(srs_utime_t tm)
@ -307,7 +336,7 @@ srs_error_t SrsPublishRecvThread::wait(srs_utime_t tm)
int64_t SrsPublishRecvThread::nb_msgs()
{
return _nb_msgs;
return nb_msgs_;
}
uint64_t SrsPublishRecvThread::nb_video_frames()
@ -334,18 +363,18 @@ srs_error_t SrsPublishRecvThread::start()
{
srs_error_t err = srs_success;
if ((err = trd_.start()) != srs_success) {
if ((err = trd_->start()) != srs_success) {
err = srs_error_wrap(err, "publish recv thread");
}
ncid_ = cid_ = trd_.cid();
ncid_ = cid_ = trd_->cid();
return err;
}
void SrsPublishRecvThread::stop()
{
trd_.stop();
trd_->stop();
}
srs_error_t SrsPublishRecvThread::consume(SrsRtmpCommonMessage *msg)
@ -358,7 +387,7 @@ srs_error_t SrsPublishRecvThread::consume(SrsRtmpCommonMessage *msg)
cid_ = ncid_;
}
_nb_msgs++;
nb_msgs_++;
if (msg->header_.is_video()) {
video_frames_++;
@ -369,7 +398,7 @@ srs_error_t SrsPublishRecvThread::consume(SrsRtmpCommonMessage *msg)
srs_time_now_realtime(), msg->header_.timestamp, msg->size);
// the rtmp connection will handle this message
err = _conn->handle_publish_message(source_, msg);
err = conn_->handle_publish_message(source_, msg);
// must always free it,
// the source will copy it if need to use.
@ -492,6 +521,14 @@ void SrsPublishRecvThread::set_socket_buffer(srs_utime_t sleep_v)
rtmp_->set_recv_buffer(nb_rbuf);
}
ISrsHttpRecvThread::ISrsHttpRecvThread()
{
}
ISrsHttpRecvThread::~ISrsHttpRecvThread()
{
}
SrsHttpRecvThread::SrsHttpRecvThread(SrsHttpxConn *c)
{
conn_ = c;

View File

@ -27,6 +27,9 @@ class SrsLiveConsumer;
class SrsHttpConn;
class SrsHttpxConn;
class ISrsRtmpServer;
class SrsRecvThread;
class ISrsRecvThread;
class ISrsAppConfig;
// The message consumer which consume a message.
class ISrsMessageConsumer
@ -61,10 +64,24 @@ public:
virtual void on_stop() = 0;
};
// The recv thread, use message handler to handle each received message.
class SrsRecvThread : public ISrsCoroutineHandler
// The recv thread interface.
class ISrsRecvThread : public ISrsCoroutineHandler
{
protected:
public:
ISrsRecvThread();
virtual ~ISrsRecvThread();
public:
virtual SrsContextId cid() = 0;
virtual srs_error_t start() = 0;
virtual void stop() = 0;
};
// The recv thread, use message handler to handle each received message.
class SrsRecvThread : public ISrsRecvThread
{
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
ISrsCoroutine *trd_;
ISrsMessagePumper *pumper_;
ISrsRtmpServer *rtmp_;
@ -89,23 +106,35 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_cycle();
};
// The queue recv thread interface.
class ISrsQueueRecvThread : public ISrsMessagePumper
{
public:
ISrsQueueRecvThread();
virtual ~ISrsQueueRecvThread();
public:
};
// The recv thread used to replace the timeout recv,
// which hurt performance for the epoll_ctrl is frequently used.
// @see: SrsRtmpConn::playing
// @see: https://github.com/ossrs/srs/issues/217
class SrsQueueRecvThread : public ISrsMessagePumper
class SrsQueueRecvThread : public ISrsQueueRecvThread
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::vector<SrsRtmpCommonMessage *> queue_;
SrsRecvThread trd_;
ISrsRecvThread *trd_;
ISrsRtmpServer *rtmp_;
// The recv thread error code.
srs_error_t recv_error_;
SrsLiveConsumer *_consumer;
SrsLiveConsumer *consumer_;
public:
// TODO: FIXME: Refine timeout in time unit.
@ -130,21 +159,35 @@ public:
virtual void on_stop();
};
// The publish recv thread got message and callback the source method to process message.
// @see: https://github.com/ossrs/srs/issues/237
class SrsPublishRecvThread : public ISrsMessagePumper, public ISrsReloadHandler
// The publish recv thread interface.
class ISrsPublishRecvThread : public ISrsMessagePumper,
#ifdef SRS_PERF_MERGED_READ
,
public IMergeReadHandler
public IMergeReadHandler
#endif
{
private:
public:
ISrsPublishRecvThread();
virtual ~ISrsPublishRecvThread();
public:
};
// The publish recv thread got message and callback the source method to process message.
// @see: https://github.com/ossrs/srs/issues/237
class SrsPublishRecvThread : public ISrsPublishRecvThread
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
uint32_t nn_msgs_for_yield_;
SrsRecvThread trd_;
ISrsRecvThread *trd_;
ISrsRtmpServer *rtmp_;
ISrsRequest *req_;
// The msgs already got.
int64_t _nb_msgs;
int64_t nb_msgs_;
// The video frames we got.
uint64_t video_frames_;
// For mr(merged read),
@ -156,7 +199,7 @@ private:
bool realtime_;
// The recv thread error code.
srs_error_t recv_error_;
SrsRtmpConn *_conn;
SrsRtmpConn *conn_;
// The params for conn callback.
SrsSharedPtr<SrsLiveSource> source_;
// The error timeout cond
@ -168,6 +211,7 @@ private:
public:
SrsPublishRecvThread(ISrsRtmpServer *rtmp_sdk, ISrsRequest *_req,
int mr_sock_fd, srs_utime_t tm, SrsRtmpConn *conn, SrsSharedPtr<SrsLiveSource> source, SrsContextId parent_cid);
void assemble();
virtual ~SrsPublishRecvThread();
public:
@ -195,17 +239,29 @@ public:
virtual void on_read(ssize_t nread);
#endif
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual void set_socket_buffer(srs_utime_t sleep_v);
};
// The HTTP receive thread interface.
class ISrsHttpRecvThread : public ISrsCoroutineHandler
{
public:
ISrsHttpRecvThread();
virtual ~ISrsHttpRecvThread();
public:
};
// The HTTP receive thread, try to read messages util EOF.
// For example, the HTTP FLV serving thread will use the receive thread to break
// when client closed the request, to avoid FD leak.
// @see https://github.com/ossrs/srs/issues/636#issuecomment-298208427
class SrsHttpRecvThread : public ISrsCoroutineHandler
class SrsHttpRecvThread : public ISrsHttpRecvThread
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsHttpxConn *conn_;
ISrsCoroutine *trd_;

View File

@ -25,7 +25,8 @@ public:
// @param refer the refer in config.
virtual srs_error_t check(std::string page_url, SrsConfDirective *refer);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t check_single_refer(std::string page_url, std::string refer);
};

View File

@ -29,15 +29,27 @@ using namespace std;
// To limit user to use too long password, to cause unknown issue.
#define SRS_ICE_PWD_MAX 32
SrsGoApiRtcPlay::SrsGoApiRtcPlay(SrsServer *server)
SrsGoApiRtcPlay::SrsGoApiRtcPlay(ISrsRtcApiServer *server)
{
server_ = server;
security_ = new SrsSecurity();
config_ = _srs_config;
stat_ = _srs_stat;
rtc_sources_ = _srs_rtc_sources;
live_sources_ = _srs_sources;
hooks_ = _srs_hooks;
}
SrsGoApiRtcPlay::~SrsGoApiRtcPlay()
{
srs_freep(security_);
config_ = NULL;
stat_ = NULL;
rtc_sources_ = NULL;
live_sources_ = NULL;
hooks_ = NULL;
}
// Request:
@ -135,7 +147,7 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
ruc.req_->app_, ruc.req_->stream_, ruc.req_->port_, ruc.req_->param_);
// discovery vhost, resolve the vhost from config
SrsConfDirective *parsed_vhost = _srs_config->get_vhost(ruc.req_->vhost_);
SrsConfDirective *parsed_vhost = config_->get_vhost(ruc.req_->vhost_);
if (parsed_vhost) {
ruc.req_->vhost_ = parsed_vhost->arg0();
}
@ -162,7 +174,7 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
ruc.dtls_ = (dtls != "false");
if (srtp.empty()) {
ruc.srtp_ = _srs_config->get_rtc_server_encrypt();
ruc.srtp_ = config_->get_rtc_server_encrypt();
} else {
ruc.srtp_ = (srtp != "false");
}
@ -178,9 +190,9 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
}
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
res->set("server", SrsJsonAny::str(_srs_stat->server_id().c_str()));
res->set("service", SrsJsonAny::str(_srs_stat->service_id().c_str()));
res->set("pid", SrsJsonAny::str(_srs_stat->service_pid().c_str()));
res->set("server", SrsJsonAny::str(stat_->server_id().c_str()));
res->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
res->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
// TODO: add candidates in response json?
res->set("sdp", SrsJsonAny::str(ruc.local_sdp_str_.c_str()));
@ -200,13 +212,13 @@ srs_error_t SrsGoApiRtcPlay::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
SrsSdp local_sdp;
// Config for SDP and session.
local_sdp.session_config_.dtls_role_ = _srs_config->get_rtc_dtls_role(ruc->req_->vhost_);
local_sdp.session_config_.dtls_version_ = _srs_config->get_rtc_dtls_version(ruc->req_->vhost_);
local_sdp.session_config_.dtls_role_ = config_->get_rtc_dtls_role(ruc->req_->vhost_);
local_sdp.session_config_.dtls_version_ = config_->get_rtc_dtls_version(ruc->req_->vhost_);
// Whether enabled.
bool server_enabled = _srs_config->get_rtc_server_enabled();
bool rtc_enabled = _srs_config->get_rtc_enabled(ruc->req_->vhost_);
bool edge = _srs_config->get_vhost_is_edge(ruc->req_->vhost_);
bool server_enabled = config_->get_rtc_server_enabled();
bool rtc_enabled = config_->get_rtc_enabled(ruc->req_->vhost_);
bool edge = config_->get_vhost_is_edge(ruc->req_->vhost_);
if (rtc_enabled && edge) {
rtc_enabled = false;
@ -224,19 +236,19 @@ srs_error_t SrsGoApiRtcPlay::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
// Whether RTC stream is active.
bool is_rtc_stream_active = false;
if (true) {
SrsSharedPtr<SrsRtcSource> source = _srs_rtc_sources->fetch(ruc->req_);
SrsSharedPtr<SrsRtcSource> source = rtc_sources_->fetch(ruc->req_);
is_rtc_stream_active = (source.get() && !source->can_publish());
}
// For RTMP to RTC, fail if disabled and RTMP is active, see https://github.com/ossrs/srs/issues/2728
bool rtmp_to_rtc = _srs_config->get_rtc_from_rtmp(ruc->req_->vhost_);
bool rtmp_to_rtc = config_->get_rtc_from_rtmp(ruc->req_->vhost_);
if (rtmp_to_rtc && edge) {
rtmp_to_rtc = false;
srs_warn("disable RTMP to WebRTC for edge vhost=%s", ruc->req_->vhost_.c_str());
}
if (!is_rtc_stream_active && !rtmp_to_rtc) {
SrsSharedPtr<SrsLiveSource> live_source = _srs_sources->fetch(ruc->req_);
SrsSharedPtr<SrsLiveSource> live_source = live_sources_->fetch(ruc->req_);
if (live_source.get() && !live_source->inactive()) {
return srs_error_new(ERROR_RTC_DISABLED, "Disabled rtmp_to_rtc of %s, see #2728", ruc->req_->vhost_.c_str());
}
@ -251,7 +263,7 @@ srs_error_t SrsGoApiRtcPlay::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
}
// TODO: FIXME: When server enabled, but vhost disabled, should report error.
SrsRtcConnection *session = NULL;
ISrsRtcConnection *session = NULL;
if ((err = server_->create_rtc_session(ruc, local_sdp, &session)) != srs_success) {
return srs_error_wrap(err, "create session, dtls=%u, srtp=%u, eip=%s", ruc->dtls_, ruc->srtp_, ruc->eip_.c_str());
}
@ -310,7 +322,7 @@ srs_error_t SrsGoApiRtcPlay::http_hooks_on_play(ISrsRequest *req)
{
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;
}
@ -320,7 +332,7 @@ srs_error_t SrsGoApiRtcPlay::http_hooks_on_play(ISrsRequest *req)
vector<string> hooks;
if (true) {
SrsConfDirective *conf = _srs_config->get_vhost_on_play(req->vhost_);
SrsConfDirective *conf = config_->get_vhost_on_play(req->vhost_);
if (!conf) {
return err;
@ -331,7 +343,7 @@ srs_error_t SrsGoApiRtcPlay::http_hooks_on_play(ISrsRequest *req)
for (int i = 0; i < (int)hooks.size(); i++) {
std::string url = hooks.at(i);
if ((err = _srs_hooks->on_play(url, req)) != srs_success) {
if ((err = hooks_->on_play(url, req)) != srs_success) {
return srs_error_wrap(err, "on_play %s", url.c_str());
}
}
@ -339,15 +351,23 @@ srs_error_t SrsGoApiRtcPlay::http_hooks_on_play(ISrsRequest *req)
return err;
}
SrsGoApiRtcPublish::SrsGoApiRtcPublish(SrsServer *server)
SrsGoApiRtcPublish::SrsGoApiRtcPublish(ISrsRtcApiServer *server)
{
server_ = server;
security_ = new SrsSecurity();
config_ = _srs_config;
stat_ = _srs_stat;
hooks_ = _srs_hooks;
}
SrsGoApiRtcPublish::~SrsGoApiRtcPublish()
{
srs_freep(security_);
config_ = NULL;
stat_ = NULL;
hooks_ = NULL;
}
// Request:
@ -446,7 +466,7 @@ srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter *w, ISrsHtt
ruc.req_->param_ = srs_strings_trim_start(ruc.req_->param_ + "&upstream=rtc", "&");
// discovery vhost, resolve the vhost from config
SrsConfDirective *parsed_vhost = _srs_config->get_vhost(ruc.req_->vhost_);
SrsConfDirective *parsed_vhost = config_->get_vhost(ruc.req_->vhost_);
if (parsed_vhost) {
ruc.req_->vhost_ = parsed_vhost->arg0();
}
@ -478,9 +498,9 @@ srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter *w, ISrsHtt
}
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
res->set("server", SrsJsonAny::str(_srs_stat->server_id().c_str()));
res->set("service", SrsJsonAny::str(_srs_stat->service_id().c_str()));
res->set("pid", SrsJsonAny::str(_srs_stat->service_pid().c_str()));
res->set("server", SrsJsonAny::str(stat_->server_id().c_str()));
res->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
res->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
// TODO: add candidates in response json?
res->set("sdp", SrsJsonAny::str(ruc.local_sdp_str_.c_str()));
@ -501,13 +521,13 @@ srs_error_t SrsGoApiRtcPublish::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
// TODO: FIXME: move to create_session.
// Config for SDP and session.
local_sdp.session_config_.dtls_role_ = _srs_config->get_rtc_dtls_role(ruc->req_->vhost_);
local_sdp.session_config_.dtls_version_ = _srs_config->get_rtc_dtls_version(ruc->req_->vhost_);
local_sdp.session_config_.dtls_role_ = config_->get_rtc_dtls_role(ruc->req_->vhost_);
local_sdp.session_config_.dtls_version_ = config_->get_rtc_dtls_version(ruc->req_->vhost_);
// Whether enabled.
bool server_enabled = _srs_config->get_rtc_server_enabled();
bool rtc_enabled = _srs_config->get_rtc_enabled(ruc->req_->vhost_);
bool edge = _srs_config->get_vhost_is_edge(ruc->req_->vhost_);
bool server_enabled = config_->get_rtc_server_enabled();
bool rtc_enabled = config_->get_rtc_enabled(ruc->req_->vhost_);
bool edge = config_->get_vhost_is_edge(ruc->req_->vhost_);
if (rtc_enabled && edge) {
rtc_enabled = false;
@ -524,7 +544,7 @@ srs_error_t SrsGoApiRtcPublish::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
// TODO: FIXME: When server enabled, but vhost disabled, should report error.
// We must do stat the client before hooks, because hooks depends on it.
SrsRtcConnection *session = NULL;
ISrsRtcConnection *session = NULL;
if ((err = server_->create_rtc_session(ruc, local_sdp, &session)) != srs_success) {
return srs_error_wrap(err, "create session");
}
@ -592,7 +612,7 @@ srs_error_t SrsGoApiRtcPublish::http_hooks_on_publish(ISrsRequest *req)
{
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;
}
@ -602,7 +622,7 @@ srs_error_t SrsGoApiRtcPublish::http_hooks_on_publish(ISrsRequest *req)
vector<string> hooks;
if (true) {
SrsConfDirective *conf = _srs_config->get_vhost_on_publish(req->vhost_);
SrsConfDirective *conf = config_->get_vhost_on_publish(req->vhost_);
if (!conf) {
return err;
}
@ -611,7 +631,7 @@ srs_error_t SrsGoApiRtcPublish::http_hooks_on_publish(ISrsRequest *req)
for (int i = 0; i < (int)hooks.size(); i++) {
std::string url = hooks.at(i);
if ((err = _srs_hooks->on_publish(url, req)) != srs_success) {
if ((err = hooks_->on_publish(url, req)) != srs_success) {
return srs_error_wrap(err, "rtmp on_publish %s", url.c_str());
}
}
@ -619,17 +639,21 @@ srs_error_t SrsGoApiRtcPublish::http_hooks_on_publish(ISrsRequest *req)
return err;
}
SrsGoApiRtcWhip::SrsGoApiRtcWhip(SrsServer *server)
SrsGoApiRtcWhip::SrsGoApiRtcWhip(ISrsRtcApiServer *server)
{
server_ = server;
publish_ = new SrsGoApiRtcPublish(server);
play_ = new SrsGoApiRtcPlay(server);
config_ = _srs_config;
}
SrsGoApiRtcWhip::~SrsGoApiRtcWhip()
{
srs_freep(publish_);
srs_freep(play_);
config_ = NULL;
}
srs_error_t SrsGoApiRtcWhip::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
@ -648,7 +672,7 @@ srs_error_t SrsGoApiRtcWhip::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
return srs_error_new(ERROR_RTC_INVALID_SESSION, "token empty");
}
SrsRtcConnection *session = server_->find_rtc_session_by_username(username);
ISrsRtcConnection *session = server_->find_rtc_session_by_username(username);
if (session && token != session->token()) {
return srs_error_new(ERROR_RTC_INVALID_SESSION, "token %s not match", token.c_str());
}
@ -740,7 +764,7 @@ srs_error_t SrsGoApiRtcWhip::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
}
// discovery vhost, resolve the vhost from config
SrsConfDirective *parsed_vhost = _srs_config->get_vhost(ruc->req_->vhost_);
SrsConfDirective *parsed_vhost = config_->get_vhost(ruc->req_->vhost_);
if (parsed_vhost) {
ruc->req_->vhost_ = parsed_vhost->arg0();
}
@ -761,7 +785,7 @@ srs_error_t SrsGoApiRtcWhip::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
// For client to specifies whether encrypt by SRTP.
ruc->dtls_ = (dtls != "false");
if (srtp.empty()) {
ruc->srtp_ = _srs_config->get_rtc_server_encrypt();
ruc->srtp_ = config_->get_rtc_server_encrypt();
} else {
ruc->srtp_ = (srtp != "false");
}
@ -780,7 +804,7 @@ srs_error_t SrsGoApiRtcWhip::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
return err;
}
SrsGoApiRtcNACK::SrsGoApiRtcNACK(SrsServer *server)
SrsGoApiRtcNACK::SrsGoApiRtcNACK(ISrsRtcApiServer *server)
{
server_ = server;
}
@ -823,7 +847,7 @@ srs_error_t SrsGoApiRtcNACK::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
return srs_error_new(ERROR_RTC_INVALID_PARAMS, "invalid drop=%s/%d", dropv.c_str(), drop);
}
SrsRtcConnection *session = server_->find_rtc_session_by_username(username);
ISrsRtcConnection *session = server_->find_rtc_session_by_username(username);
if (!session) {
return srs_error_new(ERROR_RTC_NO_SESSION, "no session username=%s", username.c_str());
}

View File

@ -15,91 +15,128 @@ class SrsServer;
class ISrsRequest;
class SrsSdp;
class SrsRtcUserConfig;
class ISrsRtcApiServer;
class ISrsSecurity;
class ISrsAppConfig;
class ISrsStatistic;
class ISrsRtcSourceManager;
class ISrsLiveSourceManager;
class ISrsHttpHooks;
class SrsGoApiRtcPlay : public ISrsHttpHandler
{
private:
SrsServer *server_;
SrsSecurity *security_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsStatistic *stat_;
ISrsRtcSourceManager *rtc_sources_;
ISrsLiveSourceManager *live_sources_;
ISrsHttpHooks *hooks_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRtcApiServer *server_;
ISrsSecurity *security_;
public:
SrsGoApiRtcPlay(SrsServer *server);
SrsGoApiRtcPlay(ISrsRtcApiServer *server);
virtual ~SrsGoApiRtcPlay();
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, SrsJsonObject *res);
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, SrsRtcUserConfig *ruc);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t check_remote_sdp(const SrsSdp &remote_sdp);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t http_hooks_on_play(ISrsRequest *req);
};
class SrsGoApiRtcPublish : public ISrsHttpHandler
{
private:
SrsServer *server_;
SrsSecurity *security_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsStatistic *stat_;
ISrsHttpHooks *hooks_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRtcApiServer *server_;
ISrsSecurity *security_;
public:
SrsGoApiRtcPublish(SrsServer *server);
SrsGoApiRtcPublish(ISrsRtcApiServer *server);
virtual ~SrsGoApiRtcPublish();
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, SrsJsonObject *res);
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, SrsRtcUserConfig *ruc);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t check_remote_sdp(const SrsSdp &remote_sdp);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t http_hooks_on_publish(ISrsRequest *req);
};
// See https://datatracker.ietf.org/doc/draft-ietf-wish-whip/
class SrsGoApiRtcWhip : public ISrsHttpHandler
{
private:
SrsServer *server_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRtcApiServer *server_;
SrsGoApiRtcPublish *publish_;
SrsGoApiRtcPlay *play_;
public:
SrsGoApiRtcWhip(SrsServer *server);
SrsGoApiRtcWhip(ISrsRtcApiServer *server);
virtual ~SrsGoApiRtcWhip();
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, SrsRtcUserConfig *ruc);
};
class SrsGoApiRtcNACK : public ISrsHttpHandler
{
private:
SrsServer *server_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRtcApiServer *server_;
public:
SrsGoApiRtcNACK(SrsServer *server);
SrsGoApiRtcNACK(ISrsRtcApiServer *server);
virtual ~SrsGoApiRtcNACK();
public:
virtual srs_error_t serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, SrsJsonObject *res);
};

View File

@ -58,7 +58,8 @@ public:
// The audio transcoder, transcode audio from one codec to another.
class SrsAudioTranscoder : public ISrsAudioTranscoder
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
AVCodecContext *dec_;
AVFrame *dec_frame_;
AVPacket *dec_packet_;
@ -95,7 +96,8 @@ public:
// @remark User should never free the data, it's managed by this transcoder.
void aac_codec_header(uint8_t **data, int *len);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t init_dec(SrsAudioCodecId from);
srs_error_t init_enc(SrsAudioCodecId to, int channels, int samplerate, int bit_rate);
srs_error_t init_swr(AVCodecContext *decoder);

View File

@ -1816,6 +1816,14 @@ void SrsRtcPublishStream::update_send_report_time(uint32_t ssrc, const SrsNtp &n
}
}
ISrsRtcConnection::ISrsRtcConnection()
{
}
ISrsRtcConnection::~ISrsRtcConnection()
{
}
ISrsRtcConnectionNackTimerHandler::ISrsRtcConnectionNackTimerHandler()
{
}
@ -2401,17 +2409,22 @@ bool SrsRtcConnection::is_alive()
return last_stun_time_ + session_timeout_ > srs_time_now_cached();
}
bool SrsRtcConnection::is_disposing()
{
return disposing_;
}
void SrsRtcConnection::alive()
{
last_stun_time_ = srs_time_now_cached();
}
SrsRtcUdpNetwork *SrsRtcConnection::udp()
ISrsRtcNetwork *SrsRtcConnection::udp()
{
return networks_->udp();
}
SrsRtcTcpNetwork *SrsRtcConnection::tcp()
ISrsRtcNetwork *SrsRtcConnection::tcp()
{
return networks_->tcp();
}

View File

@ -103,7 +103,8 @@ public:
// The security transport, use DTLS/SRTP to protect the data.
class SrsSecurityTransport : public ISrsRtcTransport
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRtcNetwork *network_;
ISrsDtls *dtls_;
ISrsSRTP *srtp_;
@ -134,7 +135,8 @@ public:
virtual srs_error_t on_dtls_application_data(const char *data, const int len);
virtual srs_error_t write_dtls_data(void *data, int size);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t srtp_initialize();
};
@ -155,7 +157,8 @@ public:
// Plaintext transport, without DTLS or SRTP.
class SrsPlaintextTransport : public ISrsRtcTransport
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRtcNetwork *network_;
public:
@ -192,14 +195,17 @@ public:
// A worker coroutine to request the PLI.
class SrsRtcPliWorker : public ISrsCoroutineHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsCoroutine *trd_;
ISrsCond *wait_;
ISrsRtcPliWorkerHandler *handler_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// 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:
SrsRtcPliWorker(ISrsRtcPliWorkerHandler *h);
@ -216,7 +222,8 @@ public:
// the rtc on_stop async call.
class SrsRtcAsyncCallOnStop : public ISrsAsyncCallTask
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsContextId cid_;
ISrsRequest *req_;
ISrsHttpHooks *hooks_;
@ -235,22 +242,26 @@ public:
// A RTC play stream, client pull and play stream from SRS.
class SrsRtcPlayStream : public ISrsCoroutineHandler, public ISrsReloadHandler, public ISrsRtcPliWorkerHandler, public ISrsRtcSourceChangeCallback
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsExecRtcAsyncTask *exec_;
ISrsExpire *expire_;
ISrsRtcPacketSender *sender_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsRtcSourceManager *rtc_sources_;
ISrsStatistic *stat_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsContextId cid_;
SrsFastCoroutine *trd_;
SrsRtcPliWorker *pli_worker_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
SrsSharedPtr<SrsRtcSource> source_;
// key: publish_ssrc, value: send track to process rtp/rtcp
@ -259,7 +270,8 @@ private:
// The pithy print for special stage.
SrsErrorPithyPrint *nack_epp_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Fast cache for tracks.
uint32_t cache_ssrc0_;
uint32_t cache_ssrc1_;
@ -268,7 +280,8 @@ private:
SrsRtcSendTrack *cache_track1_;
SrsRtcSendTrack *cache_track2_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// For merged-write messages.
int mw_msgs_;
bool realtime_;
@ -276,7 +289,8 @@ private:
bool nack_enabled_;
bool nack_no_copy_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Whether player started.
bool is_started_;
@ -300,7 +314,8 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t send_packet(SrsRtpPacket *&pkt);
public:
@ -310,7 +325,8 @@ public:
public:
srs_error_t on_rtcp(SrsRtcpCommon *rtcp);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t on_rtcp_xr(SrsRtcpXr *rtcp);
srs_error_t on_rtcp_nack(SrsRtcpNack *rtcp);
srs_error_t on_rtcp_ps_feedback(SrsRtcpFbCommon *rtcp);
@ -341,7 +357,8 @@ public:
// A fast timer for publish stream, for RTCP feedback.
class SrsRtcPublishRtcpTimer : public ISrsFastTimerHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRtcRtcpSender *sender_;
srs_mutex_t lock_;
@ -349,17 +366,20 @@ public:
SrsRtcPublishRtcpTimer(ISrsRtcRtcpSender *sender);
virtual ~SrsRtcPublishRtcpTimer();
// interface ISrsFastTimerHandler
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t on_timer(srs_utime_t interval);
};
// A fast timer for publish stream, for TWCC feedback.
class SrsRtcPublishTwccTimer : public ISrsFastTimerHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsCircuitBreaker *circuit_breaker_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRtcRtcpSender *sender_;
srs_mutex_t lock_;
@ -367,18 +387,21 @@ public:
SrsRtcPublishTwccTimer(ISrsRtcRtcpSender *sender);
virtual ~SrsRtcPublishTwccTimer();
// interface ISrsFastTimerHandler
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t on_timer(srs_utime_t interval);
};
// the rtc on_unpublish async call.
class SrsRtcAsyncCallOnUnpublish : public ISrsAsyncCallTask
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsHttpHooks *hooks_;
ISrsAppConfig *config_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsContextId cid_;
ISrsRequest *req_;
@ -394,54 +417,64 @@ public:
// A RTC publish stream, client push and publish stream to SRS.
class SrsRtcPublishStream : public ISrsRtpPacketDecodeHandler, public ISrsRtcPublishStream, public ISrsRtcPliWorkerHandler, public ISrsRtcRtcpSender
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsExecRtcAsyncTask *exec_;
ISrsExpire *expire_;
ISrsRtcPacketReceiver *receiver_;
ISrsCircuitBreaker *circuit_breaker_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
ISrsAppConfig *config_;
ISrsRtcSourceManager *rtc_sources_;
ISrsLiveSourceManager *live_sources_;
ISrsSrtSourceManager *srt_sources_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
friend class SrsRtcPublishRtcpTimer;
friend class SrsRtcPublishTwccTimer;
SrsRtcPublishRtcpTimer *timer_rtcp_;
SrsRtcPublishTwccTimer *timer_twcc_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsContextId cid_;
uint64_t nn_audio_frames_;
SrsRtcPliWorker *pli_worker_;
SrsErrorPithyPrint *twcc_epp_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
uint16_t pt_to_drop_;
// Whether enabled nack.
bool nack_enabled_;
bool nack_no_copy_;
bool twcc_enabled_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool request_keyframe_;
SrsErrorPithyPrint *pli_epp_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
SrsSharedPtr<SrsRtcSource> source_;
// Simulators.
int nn_simulate_nack_drop_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// track vector
std::vector<SrsRtcAudioRecvTrack *> audio_tracks_;
std::vector<SrsRtcAudioRecvTrack *>
audio_tracks_;
std::vector<SrsRtcVideoRecvTrack *> video_tracks_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
int twcc_id_;
uint8_t twcc_fb_count_;
SrsRtcpTWCC rtcp_twcc_;
@ -460,7 +493,8 @@ public:
void set_all_tracks_status(bool status);
virtual const SrsContextId &context_id();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool is_sender_started();
bool is_sender_twcc_enabled();
srs_error_t send_rtcp_rr();
@ -470,7 +504,8 @@ public:
srs_error_t on_rtp_cipher(char *buf, int nb_buf);
srs_error_t on_rtp_plaintext(char *buf, int nb_buf);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t do_on_rtp_plaintext(SrsRtpPacket *&pkt, SrsBuffer *buf);
public:
@ -479,13 +514,15 @@ public:
public:
virtual void on_before_decode_payload(SrsRtpPacket *pkt, SrsBuffer *buf, ISrsRtpPayloader **ppayload, SrsRtpPacketPayloadType *ppt);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t send_periodic_twcc();
public:
srs_error_t on_rtcp(SrsRtcpCommon *rtcp);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t on_rtcp_sr(SrsRtcpSR *rtcp);
srs_error_t on_rtcp_xr(SrsRtcpXr *rtcp);
@ -496,10 +533,12 @@ public:
public:
void simulate_nack_drop(int nn);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
void simulate_drop_packet(SrsRtpHeader *h, int nn_bytes);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t on_twcc(uint16_t sn);
SrsRtcAudioRecvTrack *get_audio_track(uint32_t ssrc);
SrsRtcVideoRecvTrack *get_video_track(uint32_t ssrc);
@ -521,11 +560,13 @@ public:
// A fast timer for conntion, for NACK feedback.
class SrsRtcConnectionNackTimer : public ISrsFastTimerHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsSharedTimer *shared_timer_;
ISrsCircuitBreaker *circuit_breaker_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRtcConnectionNackTimerHandler *handler_;
srs_mutex_t lock_;
@ -537,7 +578,8 @@ public:
virtual srs_error_t initialize();
// interface ISrsFastTimerHandler
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t on_timer(srs_utime_t interval);
};
@ -552,21 +594,72 @@ public:
virtual srs_error_t exec_rtc_async_work(ISrsAsyncCallTask *t) = 0;
};
// The interface for RTC connection.
class ISrsRtcConnection : public ISrsResource, // It's a resource.
public ISrsDisposingHandler,
public ISrsExpire,
public ISrsRtcPacketSender,
public ISrsRtcPacketReceiver,
public ISrsRtcConnectionNackTimerHandler
{
public:
ISrsRtcConnection();
virtual ~ISrsRtcConnection();
public:
// DTLS callbacks.
virtual srs_error_t on_dtls_handshake_done() = 0;
virtual srs_error_t on_dtls_alert(std::string type, std::string desc) = 0;
// RTP/RTCP packet handling.
virtual srs_error_t on_rtp_cipher(char *data, int nb_data) = 0;
virtual srs_error_t on_rtp_plaintext(char *data, int nb_data) = 0;
virtual srs_error_t on_rtcp(char *data, int nb_data) = 0;
// STUN binding request.
virtual srs_error_t on_binding_request(SrsStunPacket *r, std::string &ice_pwd) = 0;
// Network access.
virtual ISrsRtcNetwork *udp() = 0;
virtual ISrsRtcNetwork *tcp() = 0;
// Keep alive.
virtual void alive() = 0;
virtual bool is_alive() = 0;
virtual bool is_disposing() = 0;
// Context switching.
virtual void switch_to_context() = 0;
// Session management.
virtual srs_error_t add_publisher(SrsRtcUserConfig *ruc, SrsSdp &local_sdp) = 0;
virtual srs_error_t add_player(SrsRtcUserConfig *ruc, SrsSdp &local_sdp) = 0;
virtual void set_all_tracks_status(std::string stream_uri, bool is_publish, bool status) = 0;
// SDP management.
virtual void set_remote_sdp(const SrsSdp &sdp) = 0;
virtual void set_local_sdp(const SrsSdp &sdp) = 0;
virtual void set_state_as_waiting_stun() = 0;
// Initialization.
virtual srs_error_t initialize(ISrsRequest *r, bool dtls, bool srtp, std::string username) = 0;
// Username and token access.
virtual std::string username() = 0;
virtual std::string token() = 0;
virtual void set_publish_token(SrsSharedPtr<SrsStreamPublishToken> publish_token) = 0;
// Simulation for testing.
virtual void simulate_nack_drop(int nn) = 0;
};
// A RTC Peer Connection, SDP level object.
//
// 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
class SrsRtcConnection : public ISrsResource, public ISrsDisposingHandler, public ISrsExpire, public ISrsRtcPacketSender, public ISrsRtcPacketReceiver, public ISrsRtcConnectionNackTimerHandler
class SrsRtcConnection : public ISrsRtcConnection
{
friend class SrsSecurityTransport;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsCircuitBreaker *circuit_breaker_;
ISrsResourceManager *conn_manager_;
ISrsRtcSourceManager *rtc_sources_;
ISrsAppConfig *config_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsRtcConnectionNackTimer *timer_nack_;
ISrsExecRtcAsyncTask *exec_;
SrsRtcPublisherNegotiator *publisher_negotiator_;
@ -575,13 +668,16 @@ private:
public:
bool disposing_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
iovec *cache_iov_;
SrsBuffer *cache_buffer_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// key: stream id
std::map<std::string, SrsRtcPlayStream *> players_;
std::map<std::string, SrsRtcPlayStream *>
players_;
// key: player track's ssrc
std::map<uint32_t, SrsRtcPlayStream *> players_ssrc_map_;
// key: stream id
@ -589,7 +685,8 @@ private:
// key: publisher track's ssrc
std::map<uint32_t, SrsRtcPublishStream *> publishers_ssrc_map_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The local:remote username, such as m5x0n128:jvOm where local name is m5x0n128.
std::string username_;
// The random token to verify the WHIP DELETE request etc.
@ -597,14 +694,16 @@ private:
// A group of networks, each has its own DTLS and SRTP context.
SrsRtcNetworks *networks_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// TODO: FIXME: Rename it.
// The timeout of session, keep alive by STUN ping pong.
srs_utime_t session_timeout_;
// TODO: FIXME: Rename it.
srs_utime_t last_stun_time_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// For each RTC session, we use a specified cid for debugging logs.
SrsContextId cid_;
ISrsRequest *req_;
@ -612,7 +711,8 @@ private:
SrsSdp local_sdp_;
SrsSharedPtr<SrsStreamPublishToken> publish_token_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// twcc handler
int twcc_id_;
// Simulators.
@ -620,7 +720,8 @@ private:
// Pithy print for PLI request.
SrsErrorPithyPrint *pli_epp_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool nack_enabled_;
public:
@ -672,14 +773,17 @@ public:
srs_error_t on_rtp_cipher(char *data, int nb_data);
srs_error_t on_rtp_plaintext(char *data, int nb_data);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Decode the RTP header from buf, find the publisher by SSRC.
srs_error_t find_publisher(char *buf, int size, SrsRtcPublishStream **ppublisher);
srs_error_t
find_publisher(char *buf, int size, SrsRtcPublishStream **ppublisher);
public:
srs_error_t on_rtcp(char *data, int nb_data);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t dispatch_rtcp(SrsRtcpCommon *rtcp);
public:
@ -690,11 +794,12 @@ public:
srs_error_t on_dtls_handshake_done();
srs_error_t on_dtls_alert(std::string type, std::string desc);
bool is_alive();
bool is_disposing();
void alive();
public:
SrsRtcUdpNetwork *udp();
SrsRtcTcpNetwork *tcp();
ISrsRtcNetwork *udp();
ISrsRtcNetwork *tcp();
public:
// send rtcp
@ -720,7 +825,8 @@ public:
// Notify by specified network.
srs_error_t on_binding_request(SrsStunPacket *r, std::string &ice_pwd);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t create_player(ISrsRequest *request, std::map<uint32_t, SrsRtcTrackDescription *> sub_relations);
srs_error_t create_publisher(ISrsRequest *request, SrsRtcSourceDescription *stream_desc);
};
@ -728,7 +834,8 @@ private:
// Negotiate via SDP exchange for WebRTC publisher.
class SrsRtcPublisherNegotiator
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
ISrsAppConfig *config_;
@ -748,7 +855,8 @@ public:
// Negotiate via SDP exchange for WebRTC player.
class SrsRtcPlayerNegotiator
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
ISrsAppConfig *config_;
ISrsRtcSourceManager *rtc_sources_;

View File

@ -28,12 +28,14 @@ public:
public:
virtual srs_error_t initialize() = 0;
virtual std::string get_fingerprint() = 0;
};
// The DTLS certificate.
class SrsDtlsCertificate : public ISrsDtlsCertificate
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string fingerprint_;
bool ecdsa_mode_;
X509 *dtls_cert_;
@ -103,7 +105,8 @@ enum SrsDtlsState {
class SrsDtlsImpl
{
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
SSL_CTX *dtls_ctx_;
SSL *dtls_;
BIO *bio_in_;
@ -112,7 +115,8 @@ protected:
// @remark: dtls_version_ default value is SrsDtlsVersionAuto.
SrsDtlsVersion version_;
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
// Whether the handshake is done, for us only.
// @remark For us only, means peer maybe not done, we also need to handle the DTLS packet.
bool handshake_done_for_us_;
@ -134,7 +138,8 @@ public:
virtual srs_error_t start_active_handshake();
virtual srs_error_t on_dtls(char *data, int nb_data);
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
srs_error_t do_on_dtls(char *data, int nb_data);
void state_trace(uint8_t *data, int length, bool incoming, int r0);
@ -142,7 +147,8 @@ public:
srs_error_t get_srtp_key(std::string &recv_key, std::string &send_key);
void callback_by_ssl(std::string type, std::string desc);
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
virtual srs_error_t on_handshake_done() = 0;
virtual bool is_dtls_client() = 0;
virtual srs_error_t start_arq() = 0;
@ -150,7 +156,8 @@ protected:
class SrsDtlsClientImpl : public SrsDtlsImpl, public ISrsCoroutineHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// ARQ thread, for role active(DTLS client).
// @note If passive(DTLS server), the ARQ is driven by DTLS client.
ISrsCoroutine *trd_;
@ -166,11 +173,13 @@ public:
public:
virtual srs_error_t initialize(std::string version, std::string role);
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
virtual srs_error_t on_handshake_done();
virtual bool is_dtls_client();
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
srs_error_t start_arq();
void stop_arq();
@ -187,7 +196,8 @@ public:
public:
virtual srs_error_t initialize(std::string version, std::string role);
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
virtual srs_error_t on_handshake_done();
virtual bool is_dtls_client();
srs_error_t start_arq();
@ -207,7 +217,8 @@ public:
srs_error_t get_srtp_key(std::string &recv_key, std::string &send_key);
void callback_by_ssl(std::string type, std::string desc);
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
virtual srs_error_t on_handshake_done();
virtual bool is_dtls_client();
virtual srs_error_t start_arq();
@ -230,7 +241,8 @@ public:
// The DTLS transport.
class SrsDtls : public ISrsDtls
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsDtlsImpl *impl_;
ISrsDtlsCallback *callback_;
@ -270,7 +282,8 @@ public:
// The SRTP transport.
class SrsSRTP : public ISrsSRTP
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srtp_t recv_ctx_;
srtp_t send_ctx_;

View File

@ -36,7 +36,15 @@ extern bool srs_is_dtls(const uint8_t *data, size_t len);
extern bool srs_is_rtp_or_rtcp(const uint8_t *data, size_t len);
extern bool srs_is_rtcp(const uint8_t *data, size_t len);
SrsRtcNetworks::SrsRtcNetworks(SrsRtcConnection *conn)
ISrsRtcNetworks::ISrsRtcNetworks()
{
}
ISrsRtcNetworks::~ISrsRtcNetworks()
{
}
SrsRtcNetworks::SrsRtcNetworks(ISrsRtcConnection *conn)
{
conn_ = conn;
delta_ = new SrsEphemeralDelta();
@ -74,12 +82,12 @@ void SrsRtcNetworks::set_state(SrsRtcNetworkState state)
tcp_->set_state(state);
}
SrsRtcUdpNetwork *SrsRtcNetworks::udp()
ISrsRtcNetwork *SrsRtcNetworks::udp()
{
return udp_;
}
SrsRtcTcpNetwork *SrsRtcNetworks::tcp()
ISrsRtcNetwork *SrsRtcNetworks::tcp()
{
return tcp_;
}
@ -117,6 +125,15 @@ SrsRtcDummyNetwork::~SrsRtcDummyNetwork()
{
}
srs_error_t SrsRtcDummyNetwork::initialize(SrsSessionConfig *cfg, bool dtls, bool srtp)
{
return srs_success;
}
void SrsRtcDummyNetwork::set_state(SrsRtcNetworkState state)
{
}
bool SrsRtcDummyNetwork::is_establelished()
{
return true;
@ -132,6 +149,11 @@ srs_error_t SrsRtcDummyNetwork::on_dtls_alert(std::string type, std::string desc
return srs_success;
}
srs_error_t SrsRtcDummyNetwork::on_dtls(char *data, int nb_data)
{
return srs_success;
}
srs_error_t SrsRtcDummyNetwork::protect_rtp(void *packet, int *nb_cipher)
{
return srs_success;
@ -142,12 +164,27 @@ srs_error_t SrsRtcDummyNetwork::protect_rtcp(void *packet, int *nb_cipher)
return srs_success;
}
srs_error_t SrsRtcDummyNetwork::on_stun(SrsStunPacket *r, char *data, int nb_data)
{
return srs_success;
}
srs_error_t SrsRtcDummyNetwork::on_rtp(char *data, int nb_data)
{
return srs_success;
}
srs_error_t SrsRtcDummyNetwork::on_rtcp(char *data, int nb_data)
{
return srs_success;
}
srs_error_t SrsRtcDummyNetwork::write(void *buf, size_t size, ssize_t *nwrite)
{
return srs_success;
}
SrsRtcUdpNetwork::SrsRtcUdpNetwork(SrsRtcConnection *conn, SrsEphemeralDelta *delta)
SrsRtcUdpNetwork::SrsRtcUdpNetwork(ISrsRtcConnection *conn, ISrsEphemeralDelta *delta)
{
state_ = SrsRtcNetworkStateInit;
conn_ = conn;
@ -155,6 +192,8 @@ SrsRtcUdpNetwork::SrsRtcUdpNetwork(SrsRtcConnection *conn, SrsEphemeralDelta *de
sendonly_skt_ = NULL;
pp_address_change_ = new SrsErrorPithyPrint();
transport_ = new SrsSecurityTransport(this);
conn_manager_ = _srs_conn_manager;
}
SrsRtcUdpNetwork::~SrsRtcUdpNetwork()
@ -164,13 +203,15 @@ SrsRtcUdpNetwork::~SrsRtcUdpNetwork()
// Note that we should never delete the sendonly_skt,
// it's just point to the object in peer_addresses_.
map<string, SrsUdpMuxSocket *>::iterator it;
map<string, ISrsUdpMuxSocket *>::iterator it;
for (it = peer_addresses_.begin(); it != peer_addresses_.end(); ++it) {
SrsUdpMuxSocket *addr = it->second;
ISrsUdpMuxSocket *addr = it->second;
srs_freep(addr);
}
srs_freep(pp_address_change_);
conn_manager_ = NULL;
}
srs_error_t SrsRtcUdpNetwork::initialize(SrsSessionConfig *cfg, bool dtls, bool srtp)
@ -327,7 +368,7 @@ int SrsRtcUdpNetwork::get_peer_port()
return sendonly_skt_->get_peer_port();
}
void SrsRtcUdpNetwork::update_sendonly_socket(SrsUdpMuxSocket *skt)
void SrsRtcUdpNetwork::update_sendonly_socket(ISrsUdpMuxSocket *skt)
{
// TODO: FIXME: Refine performance.
string prev_peer_id, peer_id = skt->peer_id();
@ -341,9 +382,9 @@ void SrsRtcUdpNetwork::update_sendonly_socket(SrsUdpMuxSocket *skt)
}
// Find object from cache.
SrsUdpMuxSocket *addr_cache = NULL;
ISrsUdpMuxSocket *addr_cache = NULL;
if (true) {
map<string, SrsUdpMuxSocket *>::iterator it = peer_addresses_.find(peer_id);
map<string, ISrsUdpMuxSocket *>::iterator it = peer_addresses_.find(peer_id);
if (it != peer_addresses_.end()) {
addr_cache = it->second;
}
@ -363,11 +404,11 @@ void SrsRtcUdpNetwork::update_sendonly_socket(SrsUdpMuxSocket *skt)
// If no cache, build cache and setup the relations in connection.
if (!addr_cache) {
peer_addresses_[peer_id] = addr_cache = skt->copy_sendonly();
_srs_conn_manager->add_with_id(peer_id, conn_);
conn_manager_->add_with_id(peer_id, conn_);
uint64_t fast_id = skt->fast_id();
if (fast_id) {
_srs_conn_manager->add_with_fast_id(fast_id, conn_);
conn_manager_->add_with_fast_id(fast_id, conn_);
}
}
@ -451,7 +492,7 @@ srs_error_t SrsRtcUdpNetwork::write(void *buf, size_t size, ssize_t *nwrite)
return sendonly_skt_->sendto(buf, size, SRS_UTIME_NO_TIMEOUT);
}
SrsRtcTcpNetwork::SrsRtcTcpNetwork(SrsRtcConnection *conn, SrsEphemeralDelta *delta) : owner_(new SrsRtcTcpConn())
SrsRtcTcpNetwork::SrsRtcTcpNetwork(ISrsRtcConnection *conn, ISrsEphemeralDelta *delta) : owner_(new SrsRtcTcpConn())
{
conn_ = conn;
delta_ = delta;
@ -718,6 +759,17 @@ void SrsRtcTcpConn::setup()
pkt_ = NULL;
delta_ = NULL;
skt_ = NULL;
conn_manager_ = _srs_conn_manager;
stat_ = _srs_stat;
}
ISrsRtcTcpConn::ISrsRtcTcpConn()
{
}
ISrsRtcTcpConn::~ISrsRtcTcpConn()
{
}
SrsRtcTcpConn::SrsRtcTcpConn()
@ -743,9 +795,12 @@ SrsRtcTcpConn::~SrsRtcTcpConn()
srs_freepa(pkt_);
srs_freep(delta_);
srs_freep(skt_);
conn_manager_ = NULL;
stat_ = NULL;
}
void SrsRtcTcpConn::setup_owner(SrsSharedResource<SrsRtcTcpConn> *wrapper, ISrsInterruptable *owner_coroutine, ISrsContextIdSetter *owner_cid)
void SrsRtcTcpConn::setup_owner(SrsSharedResource<ISrsRtcTcpConn> *wrapper, ISrsInterruptable *owner_coroutine, ISrsContextIdSetter *owner_cid)
{
wrapper_ = wrapper;
owner_coroutine_ = owner_coroutine;
@ -789,8 +844,8 @@ srs_error_t SrsRtcTcpConn::cycle()
srs_error_t err = do_cycle();
// Only stat the HTTP streaming clients, ignore all API clients.
_srs_stat->on_disconnect(get_id().c_str(), err);
_srs_stat->kbps_add_delta(get_id().c_str(), delta_);
stat_->on_disconnect(get_id().c_str(), err);
stat_->kbps_add_delta(get_id().c_str(), delta_);
// Only remove session when network is established, because client might use other UDP network.
if (session_ && session_->tcp()->is_establelished()) {
@ -888,7 +943,7 @@ srs_error_t SrsRtcTcpConn::handshake()
}
srs_assert(!session_);
SrsRtcConnection *session = dynamic_cast<SrsRtcConnection *>(_srs_conn_manager->find_by_name(ping.get_username()));
ISrsRtcConnection *session = dynamic_cast<ISrsRtcConnection *>(conn_manager_->find_by_name(ping.get_username()));
// TODO: FIXME: For ICE trickle, we may get STUN packets before SDP answer, so maybe should response it.
if (!session) {
return srs_error_new(ERROR_RTC_TCP_STUN, "no session, stun username=%s", ping.get_username().c_str());
@ -910,12 +965,12 @@ srs_error_t SrsRtcTcpConn::handshake()
// For each binding request, update the TCP socket.
if (ping.is_binding_request()) {
session_->tcp()->update_sendonly_socket(skt_);
session_->tcp()->set_peer_id(ip_, port_);
network->update_sendonly_socket(skt_);
network->set_peer_id(ip_, port_);
}
// Use the session network to handle packet.
return session_->tcp()->on_stun(&ping, pkt_, npkt);
return network->on_stun(&ping, pkt_, npkt);
}
srs_error_t SrsRtcTcpConn::read_packet(char *pkt, int *nb_pkt)

View File

@ -20,18 +20,24 @@
class ISrsResourceManager;
class ISrsCoroutine;
class SrsNetworkDelta;
class ISrsNetworkDelta;
class SrsTcpConnection;
class ISrsTcpConnection;
class ISrsKbpsDelta;
class SrsUdpMuxSocket;
class ISrsUdpMuxSocket;
class SrsErrorPithyPrint;
class ISrsRtcTransport;
class SrsEphemeralDelta;
class ISrsEphemeralDelta;
class ISrsKbpsDelta;
class SrsRtcUdpNetwork;
class ISrsRtcUdpNetwork;
class ISrsRtcNetwork;
class SrsRtcTcpNetwork;
class SrsRtcDummyNetwork;
class SrsRtcTcpConn;
class ISrsRtcTcpConn;
// The network stat.
enum SrsRtcNetworkState {
@ -43,25 +49,37 @@ enum SrsRtcNetworkState {
SrsRtcNetworkStateClosed = 5,
};
// A group of networks, each has its own DTLS and SRTP context.
class SrsRtcNetworks
// The network manager interface.
class ISrsRtcNetworks
{
private:
// Network over UDP.
SrsRtcUdpNetwork *udp_;
// Network over TCP
SrsRtcTcpNetwork *tcp_;
// Network over dummy
SrsRtcDummyNetwork *dummy_;
private:
// WebRTC session object.
SrsRtcConnection *conn_;
// Delta object for statistics.
SrsEphemeralDelta *delta_;
public:
ISrsRtcNetworks();
virtual ~ISrsRtcNetworks();
public:
SrsRtcNetworks(SrsRtcConnection *conn);
};
// A group of networks, each has its own DTLS and SRTP context.
class SrsRtcNetworks : public ISrsRtcNetworks
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Network over UDP.
ISrsRtcNetwork *udp_;
// Network over TCP
ISrsRtcNetwork *tcp_;
// Network over dummy
ISrsRtcNetwork *dummy_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// WebRTC session object.
ISrsRtcConnection *conn_;
// Delta object for statistics.
ISrsEphemeralDelta *delta_;
public:
SrsRtcNetworks(ISrsRtcConnection *conn);
virtual ~SrsRtcNetworks();
// DTLS transport functions.
public:
@ -71,8 +89,8 @@ public:
// Connection level state machine, for ARQ of UDP packets.
void set_state(SrsRtcNetworkState state);
// Get the UDP network object.
SrsRtcUdpNetwork *udp();
SrsRtcTcpNetwork *tcp();
ISrsRtcNetwork *udp();
ISrsRtcNetwork *tcp();
// Get an available network.
ISrsRtcNetwork *available();
@ -88,11 +106,19 @@ public:
ISrsRtcNetwork();
virtual ~ISrsRtcNetwork();
public:
// Initialize the network with DTLS and SRTP configuration.
virtual srs_error_t initialize(SrsSessionConfig *cfg, bool dtls, bool srtp) = 0;
// Set the network state.
virtual void set_state(SrsRtcNetworkState state) = 0;
public:
// Callback when DTLS connected.
virtual srs_error_t on_dtls_handshake_done() = 0;
// Callback when DTLS disconnected.
virtual srs_error_t on_dtls_alert(std::string type, std::string desc) = 0;
// Handle DTLS data.
virtual srs_error_t on_dtls(char *data, int nb_data) = 0;
public:
// Protect RTP packet by SRTP context.
@ -100,6 +126,14 @@ public:
// Protect RTCP packet by SRTP context.
virtual srs_error_t protect_rtcp(void *packet, int *nb_cipher) = 0;
public:
// Handle STUN packet.
virtual srs_error_t on_stun(SrsStunPacket *r, char *data, int nb_data) = 0;
// Handle RTP packet.
virtual srs_error_t on_rtp(char *data, int nb_data) = 0;
// Handle RTCP packet.
virtual srs_error_t on_rtcp(char *data, int nb_data) = 0;
public:
virtual bool is_establelished() = 0;
};
@ -113,12 +147,22 @@ public:
// The interface of ISrsRtcNetwork
public:
virtual srs_error_t initialize(SrsSessionConfig *cfg, bool dtls, bool srtp);
virtual void set_state(SrsRtcNetworkState state);
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 on_dtls(char *data, int nb_data);
public:
virtual srs_error_t protect_rtp(void *packet, int *nb_cipher);
virtual srs_error_t protect_rtcp(void *packet, int *nb_cipher);
public:
virtual srs_error_t on_stun(SrsStunPacket *r, char *data, int nb_data);
virtual srs_error_t on_rtp(char *data, int nb_data);
virtual srs_error_t on_rtcp(char *data, int nb_data);
public:
virtual bool is_establelished();
// Interface ISrsStreamWriter.
public:
@ -128,34 +172,41 @@ public:
// The WebRTC over UDP network.
class SrsRtcUdpNetwork : public ISrsRtcNetwork
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsResourceManager *conn_manager_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// WebRTC session object.
SrsRtcConnection *conn_;
ISrsRtcConnection *conn_;
// Delta object for statistics.
SrsEphemeralDelta *delta_;
ISrsEphemeralDelta *delta_;
SrsRtcNetworkState state_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Pithy print for address change, use port as error code.
SrsErrorPithyPrint *pp_address_change_;
// The peer address, client maybe use more than one address, it's the current selected one.
SrsUdpMuxSocket *sendonly_skt_;
ISrsUdpMuxSocket *sendonly_skt_;
// The address list, client may use multiple addresses.
std::map<std::string, SrsUdpMuxSocket *> peer_addresses_;
std::map<std::string, ISrsUdpMuxSocket *> peer_addresses_;
// The DTLS transport over this network.
ISrsRtcTransport *transport_;
public:
SrsRtcUdpNetwork(SrsRtcConnection *conn, SrsEphemeralDelta *delta);
SrsRtcUdpNetwork(ISrsRtcConnection *conn, ISrsEphemeralDelta *delta);
virtual ~SrsRtcUdpNetwork();
public:
// Update the UDP connection.
void update_sendonly_socket(SrsUdpMuxSocket *skt);
void update_sendonly_socket(ISrsUdpMuxSocket *skt);
// When got STUN ping message. The peer address may change, we can identify that by STUN messages.
srs_error_t on_stun(SrsStunPacket *r, char *data, int nb_data);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t on_binding_request(SrsStunPacket *r, std::string ice_pwd);
// DTLS transport functions.
public:
@ -184,28 +235,31 @@ public:
class SrsRtcTcpNetwork : public ISrsRtcNetwork
{
private:
SrsRtcConnection *conn_;
SrsEphemeralDelta *delta_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRtcConnection *conn_;
ISrsEphemeralDelta *delta_;
ISrsProtocolReadWriter *sendonly_skt_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The DTLS transport over this network.
ISrsRtcTransport *transport_;
SrsSharedResource<SrsRtcTcpConn> owner_;
SrsSharedResource<ISrsRtcTcpConn> owner_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string peer_ip_;
int peer_port_;
SrsRtcNetworkState state_;
public:
SrsRtcTcpNetwork(SrsRtcConnection *conn, SrsEphemeralDelta *delta);
SrsRtcTcpNetwork(ISrsRtcConnection *conn, ISrsEphemeralDelta *delta);
virtual ~SrsRtcTcpNetwork();
public:
void set_owner(SrsSharedResource<SrsRtcTcpConn> v) { owner_ = v; }
SrsSharedResource<SrsRtcTcpConn> owner() { return owner_; }
void set_owner(SrsSharedResource<ISrsRtcTcpConn> v) { owner_ = v; }
SrsSharedResource<ISrsRtcTcpConn> owner() { return owner_; }
void update_sendonly_socket(ISrsProtocolReadWriter *skt);
// ISrsRtcNetwork
public:
@ -221,7 +275,8 @@ public:
// When got STUN ping message. The peer address may change, we can identify that by STUN messages.
srs_error_t on_stun(SrsStunPacket *r, char *data, int nb_data);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t on_binding_request(SrsStunPacket *r, std::string ice_pwd);
// DTLS transport functions.
public:
@ -248,32 +303,53 @@ public:
void dispose();
};
// For WebRTC over TCP.
class SrsRtcTcpConn : public ISrsConnection, public ISrsCoroutineHandler, public ISrsExecutorHandler
// The interface for TCP connection.
class ISrsRtcTcpConn : public ISrsConnection, public ISrsCoroutineHandler, public ISrsExecutorHandler
{
private:
// Because session references to this object, so we should directly use the session ptr.
SrsRtcConnection *session_;
public:
ISrsRtcTcpConn();
virtual ~ISrsRtcTcpConn();
private:
public:
// Interrupt the TCP connection.
virtual void interrupt() = 0;
};
// For WebRTC over TCP.
class SrsRtcTcpConn : public ISrsRtcTcpConn
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsResourceManager *conn_manager_;
ISrsStatistic *stat_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Because session references to this object, so we should directly use the session ptr.
ISrsRtcConnection *session_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The ip and port of client.
std::string ip_;
int port_;
// The delta for statistic.
SrsNetworkDelta *delta_;
ISrsNetworkDelta *delta_;
ISrsProtocolReadWriter *skt_;
// Packet cache.
char *pkt_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The shared resource which own this object, we should never free it because it's managed by shared ptr.
SrsSharedResource<SrsRtcTcpConn> *wrapper_;
SrsSharedResource<ISrsRtcTcpConn> *wrapper_;
// The owner coroutine, allow user to interrupt the loop.
ISrsInterruptable *owner_coroutine_;
ISrsContextIdSetter *owner_cid_;
SrsContextId cid_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
void setup();
public:
@ -283,7 +359,7 @@ public:
public:
// Setup the owner, the wrapper is the shared ptr, the interruptable object is the coroutine, and the cid is the context id.
void setup_owner(SrsSharedResource<SrsRtcTcpConn> *wrapper, ISrsInterruptable *owner_coroutine, ISrsContextIdSetter *owner_cid);
void setup_owner(SrsSharedResource<ISrsRtcTcpConn> *wrapper, ISrsInterruptable *owner_coroutine, ISrsContextIdSetter *owner_cid);
public:
ISrsKbpsDelta *delta();
@ -303,7 +379,8 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_cycle();
srs_error_t handshake();
srs_error_t read_packet(char *pkt, int *nb_pkt);

View File

@ -12,6 +12,7 @@
using namespace std;
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_http_api.hpp>
#include <srs_app_rtc_api.hpp>
#include <srs_app_rtc_conn.hpp>
@ -177,11 +178,11 @@ bool srs_is_rtcp(const uint8_t *data, size_t len)
return (len >= 12) && (data[0] & 0x80) && (data[1] >= 192 && data[1] <= 223);
}
srs_error_t api_server_as_candidates(string api, set<string> &candidate_ips)
srs_error_t api_server_as_candidates(ISrsAppConfig *config, string api, set<string> &candidate_ips)
{
srs_error_t err = srs_success;
if (api.empty() || !_srs_config->get_api_as_candidates()) {
if (api.empty() || !config->get_api_as_candidates()) {
return err;
}
@ -194,12 +195,12 @@ srs_error_t api_server_as_candidates(string api, set<string> &candidate_ips)
}
// Whether add domain name.
if (!srs_net_is_ipv4(hostname) && _srs_config->get_keep_api_domain()) {
if (!srs_net_is_ipv4(hostname) && config->get_keep_api_domain()) {
candidate_ips.insert(hostname);
}
// Try to parse the domain name if not IP.
if (!srs_net_is_ipv4(hostname) && _srs_config->get_resolve_api_domain()) {
if (!srs_net_is_ipv4(hostname) && config->get_resolve_api_domain()) {
int family = 0;
string ip = srs_dns_resolve(hostname, family);
if (ip.empty() || ip == SRS_CONSTS_LOCALHOST || ip == SRS_CONSTS_LOOPBACK || ip == SRS_CONSTS_LOOPBACK6) {
@ -218,7 +219,7 @@ srs_error_t api_server_as_candidates(string api, set<string> &candidate_ips)
return err;
}
set<string> discover_candidates(SrsRtcUserConfig *ruc)
set<string> discover_candidates(SrsProtocolUtility *utility, ISrsAppConfig *config, SrsRtcUserConfig *ruc)
{
srs_error_t err = srs_success;
@ -229,29 +230,28 @@ set<string> discover_candidates(SrsRtcUserConfig *ruc)
}
// Try to discover from api of request, if api_as_candidates enabled.
if ((err = api_server_as_candidates(ruc->req_->host_, candidate_ips)) != srs_success) {
if ((err = api_server_as_candidates(config, ruc->req_->host_, candidate_ips)) != srs_success) {
srs_warn("ignore discovering ip from api %s, err %s", ruc->req_->host_.c_str(), srs_error_summary(err).c_str());
srs_freep(err);
}
// If not * or 0.0.0.0, use the candidate as exposed IP.
string candidate = _srs_config->get_rtc_server_candidates();
string candidate = config->get_rtc_server_candidates();
if (candidate != "*" && candidate != "0.0.0.0") {
candidate_ips.insert(candidate);
return candidate_ips;
}
// All automatically detected IP list.
SrsProtocolUtility utility;
vector<SrsIPAddress *> &ips = utility.local_ips();
vector<SrsIPAddress *> &ips = utility->local_ips();
if (ips.empty()) {
return candidate_ips;
}
// Discover from local network interface addresses.
if (_srs_config->get_use_auto_detect_network_ip()) {
if (config->get_use_auto_detect_network_ip()) {
// We try to find the best match candidates, no loopback.
string family = _srs_config->get_rtc_server_ip_family();
string family = config->get_rtc_server_ip_family();
for (int i = 0; i < (int)ips.size(); ++i) {
SrsIPAddress *ip = ips[i];
if (ip->is_loopback_) {
@ -313,12 +313,26 @@ SrsRtcUserConfig::~SrsRtcUserConfig()
SrsRtcSessionManager::SrsRtcSessionManager()
{
rtc_async_ = new SrsAsyncCallWorker();
conn_manager_ = _srs_conn_manager;
stream_publish_tokens_ = _srs_stream_publish_tokens;
rtc_sources_ = _srs_rtc_sources;
dtls_certificate_ = _srs_rtc_dtls_certificate;
config_ = _srs_config;
app_factory_ = _srs_app_factory;
}
SrsRtcSessionManager::~SrsRtcSessionManager()
{
rtc_async_->stop();
srs_freep(rtc_async_);
conn_manager_ = NULL;
stream_publish_tokens_ = NULL;
rtc_sources_ = NULL;
dtls_certificate_ = NULL;
config_ = NULL;
app_factory_ = NULL;
}
srs_error_t SrsRtcSessionManager::initialize()
@ -332,13 +346,13 @@ srs_error_t SrsRtcSessionManager::initialize()
return err;
}
SrsRtcConnection *SrsRtcSessionManager::find_rtc_session_by_username(const std::string &username)
ISrsRtcConnection *SrsRtcSessionManager::find_rtc_session_by_username(const std::string &username)
{
ISrsResource *conn = _srs_conn_manager->find_by_name(username);
return dynamic_cast<SrsRtcConnection *>(conn);
ISrsResource *conn = conn_manager_->find_by_name(username);
return dynamic_cast<ISrsRtcConnection *>(conn);
}
srs_error_t SrsRtcSessionManager::create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, SrsRtcConnection **psession)
srs_error_t SrsRtcSessionManager::create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, ISrsRtcConnection **psession)
{
srs_error_t err = srs_success;
@ -346,7 +360,7 @@ srs_error_t SrsRtcSessionManager::create_rtc_session(SrsRtcUserConfig *ruc, SrsS
// Acquire stream publish token to prevent race conditions across all protocols.
SrsStreamPublishToken *publish_token_raw = NULL;
if (ruc->publish_ && (err = _srs_stream_publish_tokens->acquire_token(req, publish_token_raw)) != srs_success) {
if (ruc->publish_ && (err = stream_publish_tokens_->acquire_token(req, publish_token_raw)) != srs_success) {
return srs_error_wrap(err, "acquire stream publish token");
}
SrsSharedPtr<SrsStreamPublishToken> publish_token(publish_token_raw);
@ -355,7 +369,7 @@ srs_error_t SrsRtcSessionManager::create_rtc_session(SrsRtcUserConfig *ruc, SrsS
}
SrsSharedPtr<SrsRtcSource> source;
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");
}
@ -365,8 +379,7 @@ srs_error_t SrsRtcSessionManager::create_rtc_session(SrsRtcUserConfig *ruc, SrsS
// TODO: FIXME: add do_create_session to error process.
SrsContextId cid = _srs_context->get_id();
SrsRtcConnection *session = new SrsRtcConnection(this, cid);
session->assemble();
ISrsRtcConnection *session = app_factory_->create_rtc_connection(this, cid);
if ((err = do_create_rtc_session(ruc, local_sdp, session)) != srs_success) {
srs_freep(session);
@ -383,7 +396,7 @@ srs_error_t SrsRtcSessionManager::create_rtc_session(SrsRtcUserConfig *ruc, SrsS
return err;
}
srs_error_t SrsRtcSessionManager::do_create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, SrsRtcConnection *session)
srs_error_t SrsRtcSessionManager::do_create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, ISrsRtcConnection *session)
{
srs_error_t err = srs_success;
@ -410,7 +423,7 @@ srs_error_t SrsRtcSessionManager::do_create_rtc_session(SrsRtcUserConfig *ruc, S
std::string username = "";
while (true) {
username = local_ufrag + ":" + ruc->remote_sdp_.get_ice_ufrag();
if (!_srs_conn_manager->find_by_name(username)) {
if (!conn_manager_->find_by_name(username)) {
break;
}
@ -421,7 +434,7 @@ srs_error_t SrsRtcSessionManager::do_create_rtc_session(SrsRtcUserConfig *ruc, S
local_sdp.set_ice_ufrag(local_ufrag);
local_sdp.set_ice_pwd(local_pwd);
local_sdp.set_fingerprint_algo("sha-256");
local_sdp.set_fingerprint(_srs_rtc_dtls_certificate->get_fingerprint());
local_sdp.set_fingerprint(dtls_certificate_->get_fingerprint());
// We allows to mock the eip of server.
if (true) {
@ -429,20 +442,21 @@ srs_error_t SrsRtcSessionManager::do_create_rtc_session(SrsRtcUserConfig *ruc, S
int udp_port = 0;
if (true) {
string udp_host;
string udp_hostport = _srs_config->get_rtc_server_listens().at(0);
string udp_hostport = config_->get_rtc_server_listens().at(0);
srs_net_split_for_listener(udp_hostport, udp_host, udp_port);
}
int tcp_port = 0;
if (true) {
string tcp_host;
string tcp_hostport = _srs_config->get_rtc_server_tcp_listens().at(0);
string tcp_hostport = config_->get_rtc_server_tcp_listens().at(0);
srs_net_split_for_listener(tcp_hostport, tcp_host, tcp_port);
}
string protocol = _srs_config->get_rtc_server_protocol();
string protocol = config_->get_rtc_server_protocol();
set<string> candidates = discover_candidates(ruc);
SrsProtocolUtility utility;
set<string> candidates = discover_candidates(&utility, config_, ruc);
for (set<string>::iterator it = candidates.begin(); it != candidates.end(); ++it) {
string hostname;
int uport = udp_port;
@ -494,7 +508,7 @@ srs_error_t SrsRtcSessionManager::do_create_rtc_session(SrsRtcUserConfig *ruc, S
}
// We allows username is optional, but it never empty here.
_srs_conn_manager->add_with_name(username, session);
conn_manager_->add_with_name(username, session);
return err;
}
@ -505,10 +519,10 @@ void SrsRtcSessionManager::srs_update_rtc_sessions()
int nn_rtc_conns = 0;
// Check all sessions and dispose the dead sessions.
for (int i = 0; i < (int)_srs_conn_manager->size(); i++) {
SrsRtcConnection *session = dynamic_cast<SrsRtcConnection *>(_srs_conn_manager->at(i));
for (int i = 0; i < (int)conn_manager_->size(); i++) {
ISrsRtcConnection *session = dynamic_cast<ISrsRtcConnection *>(conn_manager_->at(i));
// Ignore not session, or already disposing.
if (!session || session->disposing_) {
if (!session || session->is_disposing()) {
continue;
}
@ -525,7 +539,7 @@ void SrsRtcSessionManager::srs_update_rtc_sessions()
srs_trace("RTC: session destroy by timeout, username=%s", username.c_str());
// Use manager to free session and notify other objects.
_srs_conn_manager->remove(session);
conn_manager_->remove(session);
}
// Ignore stats if no RTC connections.
@ -556,11 +570,11 @@ srs_error_t SrsRtcSessionManager::exec_rtc_async_work(ISrsAsyncCallTask *t)
return rtc_async_->execute(t);
}
srs_error_t SrsRtcSessionManager::on_udp_packet(SrsUdpMuxSocket *skt)
srs_error_t SrsRtcSessionManager::on_udp_packet(ISrsUdpMuxSocket *skt)
{
srs_error_t err = srs_success;
SrsRtcConnection *session = NULL;
ISrsRtcConnection *session = NULL;
char *data = skt->data();
int size = skt->size();
bool is_rtp_or_rtcp = srs_is_rtp_or_rtcp((uint8_t *)data, size);
@ -569,11 +583,11 @@ srs_error_t SrsRtcSessionManager::on_udp_packet(SrsUdpMuxSocket *skt)
uint64_t fast_id = skt->fast_id();
// Try fast id first, if not found, search by long peer id.
if (fast_id) {
session = (SrsRtcConnection *)_srs_conn_manager->find_by_fast_id(fast_id);
session = (ISrsRtcConnection *)conn_manager_->find_by_fast_id(fast_id);
}
if (!session) {
string peer_id = skt->peer_id();
session = (SrsRtcConnection *)_srs_conn_manager->find_by_id(peer_id);
session = (ISrsRtcConnection *)conn_manager_->find_by_id(peer_id);
}
if (session) {
@ -609,7 +623,9 @@ srs_error_t SrsRtcSessionManager::on_udp_packet(SrsUdpMuxSocket *skt)
// For each binding request, update the UDP socket.
if (ping.is_binding_request()) {
session->udp()->update_sendonly_socket(skt);
SrsRtcUdpNetwork *udp_network = dynamic_cast<SrsRtcUdpNetwork *>(session->udp());
srs_assert(udp_network);
udp_network->update_sendonly_socket(skt);
}
return session->udp()->on_stun(&ping, data, size);

View File

@ -23,11 +23,19 @@
class SrsRtcServer;
class SrsHourGlass;
class SrsRtcConnection;
class ISrsRtcConnection;
class ISrsRequest;
class SrsSdp;
class SrsRtcSource;
class SrsResourceManager;
class SrsAsyncCallWorker;
class ISrsUdpMuxSocket;
class ISrsResourceManager;
class ISrsStreamPublishTokenManager;
class ISrsRtcSourceManager;
class ISrsDtlsCertificate;
class ISrsAppConfig;
class ISrsAppFactory;
// The UDP black hole, for developer to use wireshark to catch plaintext packets.
// For example, server receive UDP packets at udp://8000, and forward the plaintext packet to black hole,
@ -37,7 +45,8 @@ class SrsRtcBlackhole
public:
bool blackhole_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
sockaddr_in *blackhole_addr_;
srs_netfd_t blackhole_stfd_;
@ -84,7 +93,7 @@ public:
};
// Discover the candidates for RTC server.
extern std::set<std::string> discover_candidates(SrsRtcUserConfig *ruc);
extern std::set<std::string> discover_candidates(SrsProtocolUtility *utility, ISrsAppConfig *config, SrsRtcUserConfig *ruc);
// The dns resolve utility, return the resolved ip address.
extern std::string srs_dns_resolve(std::string host, int &family);
@ -92,7 +101,17 @@ extern std::string srs_dns_resolve(std::string host, int &family);
// RTC session manager to handle WebRTC session lifecycle and management.
class SrsRtcSessionManager : public ISrsExecRtcAsyncTask
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsResourceManager *conn_manager_;
ISrsStreamPublishTokenManager *stream_publish_tokens_;
ISrsRtcSourceManager *rtc_sources_;
ISrsDtlsCertificate *dtls_certificate_;
ISrsAppConfig *config_;
ISrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// WebRTC async call worker for non-blocking operations.
SrsAsyncCallWorker *rtc_async_;
@ -104,11 +123,12 @@ public:
virtual srs_error_t initialize();
public:
virtual SrsRtcConnection *find_rtc_session_by_username(const std::string &ufrag);
virtual srs_error_t create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, SrsRtcConnection **psession);
virtual ISrsRtcConnection *find_rtc_session_by_username(const std::string &ufrag);
virtual srs_error_t create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, ISrsRtcConnection **psession);
private:
virtual srs_error_t do_create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, SrsRtcConnection *session);
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, ISrsRtcConnection *session);
public:
virtual void srs_update_rtc_sessions();
@ -118,7 +138,11 @@ public:
virtual srs_error_t exec_rtc_async_work(ISrsAsyncCallTask *t);
public:
virtual srs_error_t on_udp_packet(SrsUdpMuxSocket *skt);
virtual srs_error_t on_udp_packet(ISrsUdpMuxSocket *skt);
};
// Helper function to discover candidate IPs from API server hostname
// Used by WebRTC ICE candidate discovery
extern srs_error_t api_server_as_candidates(ISrsAppConfig *config, std::string api, std::set<std::string> &candidate_ips);
#endif

View File

@ -119,11 +119,13 @@ public:
// The RTC stream consumer, consume packets from RTC stream source.
class SrsRtcConsumer : public ISrsRtcConsumer
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Because source references to this object, so we should directly use the source ptr.
ISrsRtcSourceForConsumer *source_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::vector<SrsRtpPacket *> queue_;
// when source id changed, notice all consumers
bool should_update_source_id_;
@ -132,7 +134,8 @@ private:
bool mw_waiting_;
int mw_min_msgs_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The callback for stream change event.
ISrsRtcSourceChangeCallback *handler_;
@ -172,7 +175,8 @@ public:
// The RTC source manager.
class SrsRtcSourceManager : public ISrsRtcSourceManager, public ISrsHourGlassHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_mutex_t lock_;
std::map<std::string, SrsSharedPtr<SrsRtcSource> > pool_;
SrsHourGlass *timer_;
@ -184,7 +188,8 @@ public:
public:
virtual srs_error_t initialize();
// interface ISrsHourGlassHandler
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t setup_ticks();
virtual srs_error_t notify(int event, srs_utime_t interval, srs_utime_t tick);
@ -233,11 +238,13 @@ public:
// A Source is a stream, to publish and to play with, binding to SrsRtcPublishStream and SrsRtcPlayStream.
class SrsRtcSource : public ISrsRtpTarget, public ISrsFastTimerHandler, public ISrsRtcSourceForConsumer
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The RTP bridge, convert RTP packets to other protocols.
ISrsRtcBridge *rtc_bridge_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Circuit breaker for protecting server resources.
ISrsCircuitBreaker *circuit_breaker_;
// For publish, it's the publish client id.
@ -252,9 +259,11 @@ private:
// Steam description for this steam.
SrsRtcSourceDescription *stream_desc_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// To delivery stream to clients.
std::vector<ISrsRtcConsumer *> consumers_;
std::vector<ISrsRtcConsumer *>
consumers_;
// Whether stream is created, that is, SDP is done.
bool is_created_;
// Whether stream is delivering data, that is, DTLS is done.
@ -262,12 +271,14 @@ private:
// Notify stream event to event handler
std::vector<ISrsRtcSourceEventHandler *> event_handlers_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The PLI for RTC2RTMP.
srs_utime_t pli_for_rtmp_;
srs_utime_t pli_elapsed_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The last die time, while die means neither publishers nor players.
srs_utime_t stream_die_at_;
@ -282,16 +293,19 @@ public:
// Whether stream is dead, which is no publisher or player.
virtual bool stream_is_dead();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
void init_for_play_before_publishing();
public:
// Update the authentication information in request.
virtual void update_auth(ISrsRequest *r);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The stream source changed.
virtual srs_error_t on_source_changed();
virtual srs_error_t
on_source_changed();
public:
// Get current source id.
@ -337,7 +351,8 @@ public:
virtual void set_stream_desc(SrsRtcSourceDescription *stream_desc);
virtual std::vector<SrsRtcTrackDescription *> get_track_desc(std::string type, std::string media_type);
// interface ISrsFastTimerHandler
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t on_timer(srs_utime_t interval);
};
@ -346,7 +361,8 @@ private:
// Convert AV frame to RTC RTP packets.
class SrsRtcRtpBuilder
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
ISrsRtpTarget *rtp_target_;
// The format, codec information.
@ -356,7 +372,8 @@ private:
// The video builder, convert frame to RTP packets.
SrsRtpVideoBuilder *video_builder_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsAudioCodecId latest_codec_;
ISrsAudioTranscoder *codec_;
bool keep_bframe_;
@ -364,11 +381,13 @@ private:
bool merge_nalus_;
uint16_t audio_sequence_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
uint32_t audio_ssrc_;
uint8_t audio_payload_type_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsSharedPtr<SrsRtcSource> source_;
// Lazy initialization flags
bool audio_initialized_;
@ -378,9 +397,11 @@ public:
SrsRtcRtpBuilder(ISrsRtpTarget *target, SrsSharedPtr<SrsRtcSource> source);
virtual ~SrsRtcRtpBuilder();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Lazy initialization methods
srs_error_t initialize_audio_track(SrsAudioCodecId codec);
srs_error_t
initialize_audio_track(SrsAudioCodecId codec);
srs_error_t initialize_video_track(SrsVideoCodecId codec);
public:
@ -389,18 +410,22 @@ public:
virtual void on_unpublish();
virtual srs_error_t on_frame(SrsMediaPacket *frame);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t on_audio(SrsMediaPacket *msg);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t init_codec(SrsAudioCodecId codec);
srs_error_t transcode(SrsParsedAudioPacket *audio);
srs_error_t package_opus(SrsParsedAudioPacket *audio, SrsRtpPacket *pkt);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t on_video(SrsMediaPacket *msg);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t filter(SrsMediaPacket *msg, SrsFormat *format, bool &has_idr, std::vector<SrsNaluSample *> &samples);
srs_error_t package_stap_a(SrsMediaPacket *msg, SrsRtpPacket *pkt);
srs_error_t package_nalus(SrsMediaPacket *msg, const std::vector<SrsNaluSample *> &samples, std::vector<SrsRtpPacket *> &pkts);
@ -413,7 +438,8 @@ private:
// TODO: Maybe should use SrsRtpRingBuffer?
class SrsRtcFrameBuilderVideoPacketCache
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
const static uint16_t cache_size_ = 512;
struct RtcPacketCache {
bool in_use_;
@ -441,7 +467,8 @@ public:
// Check if frame is complete by verifying FU-A start/end fragment counts match
bool check_frame_complete(const uint16_t start, const uint16_t end);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool is_slot_in_use(uint16_t sequence_number);
uint32_t get_rtp_timestamp(uint16_t sequence_number);
inline uint16_t cache_index(uint16_t sequence_number)
@ -453,7 +480,8 @@ private:
// Video frame detector for managing frame boundaries and packet loss detection
class SrsRtcFrameBuilderVideoFrameDetector
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsRtcFrameBuilderVideoPacketCache *video_cache_;
uint16_t header_sn_;
uint16_t lost_sn_;
@ -474,9 +502,11 @@ public:
// Audio packet cache for RTP packet jitter buffer management
class SrsRtcFrameBuilderAudioPacketCache
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Audio jitter buffer, map sequence number to packet
std::map<uint16_t, SrsRtpPacket *> audio_buffer_;
std::map<uint16_t, SrsRtpPacket *>
audio_buffer_;
// Last processed sequence number
uint16_t last_audio_seq_num_;
// Last time we processed the jitter buffer
@ -503,24 +533,29 @@ public:
// Collect and build WebRTC RTP packets to AV frames.
class SrsRtcFrameBuilder
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsFrameTarget *frame_target_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool is_first_audio_;
ISrsAudioTranscoder *audio_transcoder_;
SrsVideoCodecId video_codec_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsRtcFrameBuilderAudioPacketCache *audio_cache_;
SrsRtcFrameBuilderVideoPacketCache *video_cache_;
SrsRtcFrameBuilderVideoFrameDetector *frame_detector_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The state for timestamp sync state. -1 for init. 0 not sync. 1 sync.
int sync_state_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// For OBS WHIP, send (VPS/)SPS/PPS in dedicated RTP packet.
SrsRtpPacket *obs_whip_vps_;
SrsRtpPacket *obs_whip_sps_;
@ -536,12 +571,14 @@ public:
virtual void on_unpublish();
virtual srs_error_t on_rtp(SrsRtpPacket *pkt);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t packet_audio(SrsRtpPacket *pkt);
srs_error_t transcode_audio(SrsRtpPacket *pkt);
void packet_aac(SrsRtmpCommonMessage *audio, char *data, int len, uint32_t pts, bool is_header);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t packet_video(SrsRtpPacket *pkt);
srs_error_t packet_video_key_frame(SrsRtpPacket *pkt);
srs_error_t packet_sequence_header_avc(SrsRtpPacket *pkt);
@ -549,7 +586,8 @@ private:
srs_error_t packet_sequence_header_hevc(SrsRtpPacket *pkt);
srs_error_t do_packet_sequence_header_hevc(SrsRtpPacket *pkt, SrsNaluSample *vps, SrsNaluSample *sps, SrsNaluSample *pps);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t packet_video_rtmp(const uint16_t start, const uint16_t end);
int calculate_packet_payload_size(SrsRtpPacket *pkt);
void write_packet_payload_to_buffer(SrsRtpPacket *pkt, SrsBuffer &payload, int &nalu_len);
@ -571,7 +609,8 @@ public:
std::vector<std::string> rtcp_fbs_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The cached codec ID, corresponding to name_.
// For video, you can convert it to type SrsVideoCodecId
// For audio, you can convert it to type SrsAudioCodecId
@ -777,19 +816,23 @@ public:
// The RTC receive track.
class SrsRtcRecvTrack
{
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
SrsRtcTrackDescription *track_desc_;
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
ISrsRtcPacketReceiver *receiver_;
SrsRtpRingBuffer *rtp_queue_;
SrsRtpNackForReceiver *nack_receiver_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// By config, whether no copy.
bool nack_no_copy_;
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
// Latest sender report ntp and rtp time.
SrsNtp last_sender_report_ntp_;
int64_t last_sender_report_rtp_time_;
@ -828,7 +871,8 @@ public:
virtual srs_error_t on_rtp(SrsSharedPtr<SrsRtcSource> &source, SrsRtpPacket *pkt) = 0;
virtual srs_error_t check_send_nacks() = 0;
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
virtual srs_error_t do_check_send_nacks(uint32_t &timeout_nacks);
};
@ -864,12 +908,14 @@ public:
template <typename T, typename ST>
class SrsRtcJitter
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ST threshold_;
typedef ST (*PFN)(const T &, const T &);
PFN distance_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The value about packet.
T pkt_base_;
T pkt_last_;
@ -926,7 +972,8 @@ public:
// For RTC timestamp jitter.
class SrsRtcTsJitter
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsRtcJitter<uint32_t, int32_t> *jitter_;
public:
@ -940,7 +987,8 @@ public:
// For RTC sequence jitter.
class SrsRtcSeqJitter
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsRtcJitter<uint16_t, int16_t> *jitter_;
public:
@ -968,18 +1016,21 @@ public:
// send track description
SrsRtcTrackDescription *track_desc_;
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
// The owner connection for this track.
ISrsRtcPacketSender *sender_;
// NACK ARQ ring buffer.
SrsRtpRingBuffer *rtp_queue_;
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
// The jitter to correct ts and sequence number.
SrsRtcTsJitter *jitter_ts_;
SrsRtcSeqJitter *jitter_seq_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// By config, whether no copy.
bool nack_no_copy_;
// The pithy print for special stage.
@ -998,7 +1049,8 @@ public:
bool get_track_status();
std::string get_track_id();
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
void rebuild_packet(SrsRtpPacket *pkt);
public:
@ -1036,13 +1088,16 @@ public:
class SrsRtcSSRCGenerator
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
static SrsRtcSSRCGenerator *instance_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
uint32_t ssrc_num_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsRtcSSRCGenerator();
virtual ~SrsRtcSSRCGenerator();

View File

@ -244,7 +244,9 @@ void SrsRtmpConn::assemble()
SrsRtmpConn::~SrsRtmpConn()
{
config_->unsubscribe(this);
if (config_) {
config_->unsubscribe(this);
}
trd_->interrupt();
// wakeup the handler which need to notice.
@ -262,6 +264,7 @@ SrsRtmpConn::~SrsRtmpConn()
srs_freep(refer_);
srs_freep(security_);
config_ = NULL;
manager_ = NULL;
stream_publish_tokens_ = NULL;
live_sources_ = NULL;
@ -890,6 +893,8 @@ srs_error_t SrsRtmpConn::publishing(SrsSharedPtr<SrsLiveSource> source)
// use isolate thread to recv,
// @see: https://github.com/ossrs/srs/issues/237
SrsPublishRecvThread rtrd(rtmp_, req, srs_netfd_fileno(transport_->fd()), 0, this, source, _srs_context->get_id());
rtrd.assemble();
err = do_publishing(source, &rtrd);
rtrd.stop();
}

View File

@ -56,14 +56,16 @@ class ISrsSecurity;
// The simple rtmp client for SRS.
class SrsSimpleRtmpClient : public SrsBasicRtmpClient
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
public:
SrsSimpleRtmpClient(std::string u, srs_utime_t ctm, srs_utime_t stm);
virtual ~SrsSimpleRtmpClient();
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
virtual srs_error_t connect_app();
};
@ -106,7 +108,8 @@ public:
// The base transport layer for RTMP connections over plain TCP.
class SrsRtmpTransport : public ISrsRtmpTransport
{
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
srs_netfd_t stfd_;
SrsTcpConnection *skt_;
@ -135,10 +138,12 @@ public:
// The SSL/TLS transport layer for RTMPS connections.
class SrsRtmpsTransport : public SrsRtmpTransport
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsSslConnection *ssl_;
public:
@ -154,12 +159,18 @@ public:
virtual const char *transport_type();
};
class SrsRtmpConn : public ISrsConnection, public ISrsStartable, public ISrsReloadHandler, public ISrsCoroutineHandler, public ISrsExpire
// The RTMP connection, for client to publish or play stream.
class SrsRtmpConn : public ISrsConnection, // It's a resource.
public ISrsStartable,
public ISrsReloadHandler,
public ISrsCoroutineHandler,
public ISrsExpire
{
// For the thread to directly access any field of connection.
friend class SrsPublishRecvThread;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsResourceManager *manager_;
ISrsAppConfig *config_;
ISrsStreamPublishTokenManager *stream_publish_tokens_;
@ -172,7 +183,8 @@ private:
ISrsRtspSourceManager *rtsp_sources_;
#endif
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRtmpServer *rtmp_;
SrsRefer *refer_;
SrsBandwidth *bandwidth_;
@ -200,7 +212,8 @@ private:
// About the rtmp client.
SrsClientInfo *info_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRtmpTransport *transport_;
// Each connection start a green thread,
// when thread stop, the connection will be delete by server.
@ -223,15 +236,18 @@ public:
public:
virtual std::string desc();
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
virtual srs_error_t do_cycle();
public:
virtual ISrsKbpsDelta *delta();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// When valid and connected to vhost/app, service the client.
virtual srs_error_t service_cycle();
virtual srs_error_t
service_cycle();
// The stream(play/publish) service cycle, identify client first.
virtual srs_error_t stream_service_cycle();
virtual srs_error_t check_vhost(bool try_default_vhost);
@ -246,16 +262,20 @@ private:
virtual srs_error_t process_play_control_msg(SrsLiveConsumer *consumer, SrsRtmpCommonMessage *msg);
virtual void set_sock_options();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t check_edge_token_traverse_auth();
virtual srs_error_t do_token_traverse_auth(SrsRtmpClient *client);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// When the connection disconnect, call this method.
// e.g. log msg of connection and report to other system.
virtual srs_error_t on_disconnect();
virtual srs_error_t
on_disconnect();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t http_hooks_on_connect();
virtual void http_hooks_on_close();
virtual srs_error_t http_hooks_on_publish();

View File

@ -850,7 +850,10 @@ SrsOriginHub::SrsOriginHub()
hls_ = new SrsHls();
dash_ = new SrsDash();
dvr_ = new SrsDvr();
dvr_->assemble();
encoder_ = new SrsEncoder();
#ifdef SRS_HDS
hds_ = new SrsHds();

View File

@ -60,7 +60,7 @@ class ISrsHds;
#endif
class ISrsNgExec;
class ISrsForwarder;
class SrsAppFactory;
class ISrsAppFactory;
class ISrsLiveConsumer;
// The time jitter algorithm:
@ -77,7 +77,8 @@ int srs_time_jitter_string2int(std::string time_jitter);
// Time jitter detect and correct, to ensure the rtmp stream is monotonically.
class SrsRtmpJitter
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
int64_t last_pkt_time_;
int64_t last_pkt_correct_time_;
@ -97,7 +98,8 @@ public:
// To alloc and increase fixed space, fast remove and insert for msgs sender.
class SrsFastVector
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsMediaPacket **msgs_;
int nb_msgs_;
int count_;
@ -140,12 +142,14 @@ public:
// We limit the size in seconds, drop old messages(the whole gop) if full.
class SrsMessageQueue : public ISrsMessageQueue
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The start and end time.
srs_utime_t av_start_time_;
srs_utime_t av_end_time_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Whether do logging when shrinking.
bool _ignore_shrink;
// The max queue size, shrink if exceed it.
@ -182,10 +186,12 @@ public:
// @remark the atc/tba/tbv/ag are same to SrsLiveConsumer.enqueue().
virtual srs_error_t dump_packets(ISrsLiveConsumer *consumer, bool atc, SrsRtmpJitterAlgorithm ag);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Remove a gop from the front.
// if no iframe found, clear it.
virtual void shrink();
virtual void
shrink();
public:
// clear all messages in queue.
@ -224,11 +230,13 @@ public:
// The consumer for SrsLiveSource, that is a play client.
class SrsLiveConsumer : public ISrsWakable, public ISrsLiveConsumer
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Because source references to this object, so we should directly use the source ptr.
ISrsLiveSource *source_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsRtmpJitter *jitter_;
SrsMessageQueue *queue_;
bool paused_;
@ -285,7 +293,8 @@ public:
// To enable it to fast startup.
class SrsGopCache
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// if disabled the gop cache,
// The client will wait for the next keyframe for h264,
// and will be black-screen.
@ -360,7 +369,8 @@ public:
// The mix queue to correct the timestamp for mix_correct algorithm.
class SrsMixQueue
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
uint32_t nb_videos_;
uint32_t nb_audios_;
std::multimap<int64_t, SrsMediaPacket *> msgs_;
@ -402,6 +412,8 @@ public:
virtual srs_error_t on_publish() = 0;
// When stop publish stream.
virtual void on_unpublish() = 0;
// When DVR requests sequence header.
virtual srs_error_t on_dvr_request_sh() = 0;
};
// The hub for origin is a collection of utilities for origin only,
@ -409,20 +421,24 @@ public:
// they are meanless for edge server.
class SrsOriginHub : public ISrsReloadHandler, public ISrsOriginHub
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsStatistic *stat_;
ISrsHttpHooks *hooks_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Because source references to this object, so we should directly use the source ptr.
ISrsLiveSource *source_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
bool is_active_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// hls handler.
ISrsHls *hls_;
// The DASH encoder.
@ -482,7 +498,8 @@ public:
// For the SrsHls to callback to request the sequence headers.
virtual srs_error_t on_hls_request_sh();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t create_forwarders();
virtual srs_error_t create_backend_forwarders(bool &applied);
virtual void destroy_forwarders();
@ -492,7 +509,8 @@ private:
// This class cache and update the meta.
class SrsMetaCache
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The cached metadata, FLV script data tag.
SrsMediaPacket *meta_;
// The cached video sequence header, for example, sps/pps for h.264.
@ -570,10 +588,12 @@ public:
// The source manager to create and refresh all stream sources.
class SrsLiveSourceManager : public ISrsHourGlassHandler, public ISrsLiveSourceManager
{
private:
SrsAppFactory *app_factory_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppFactory *app_factory_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_mutex_t lock_;
std::map<std::string, SrsSharedPtr<SrsLiveSource> > pool_;
ISrsHourGlass *timer_;
@ -598,7 +618,8 @@ public:
// dispose and cycle all sources.
virtual void dispose();
// interface ISrsHourGlassHandler
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t setup_ticks();
virtual srs_error_t notify(int event, srs_utime_t interval, srs_utime_t tick);
@ -624,18 +645,30 @@ public:
virtual SrsContextId pre_source_id() = 0;
virtual SrsMetaCache *meta() = 0;
virtual SrsRtmpFormat *format() = 0;
// The source id changed.
virtual srs_error_t on_source_id_changed(SrsContextId id) = 0;
// Publish stream event notify.
virtual srs_error_t on_publish() = 0;
virtual void on_unpublish() = 0;
// Handle media messages.
virtual srs_error_t on_audio(SrsRtmpCommonMessage *audio) = 0;
virtual srs_error_t on_video(SrsRtmpCommonMessage *video) = 0;
virtual srs_error_t on_aggregate(SrsRtmpCommonMessage *msg) = 0;
virtual srs_error_t on_meta_data(SrsRtmpCommonMessage *msg, SrsOnMetaDataPacket *metadata) = 0;
};
// The live streaming source.
class SrsLiveSource : public ISrsReloadHandler, public ISrsFrameTarget, public ISrsLiveSource
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsStatistic *stat_;
ISrsLiveSourceHandler *handler_;
SrsAppFactory *app_factory_;
ISrsAppFactory *app_factory_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// For publish, it's the publish client id.
// For edge, it's the edge ingest id.
// when source id changed, for example, the edge reconnect,
@ -676,7 +709,8 @@ private:
// The format, codec information.
SrsRtmpFormat *format_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Whether source is avaiable for publishing.
bool can_publish_;
// The last die time, while die means neither publishers nor players.
@ -726,14 +760,16 @@ public:
virtual srs_error_t on_audio(SrsRtmpCommonMessage *audio);
srs_error_t on_frame(SrsMediaPacket *msg);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t on_audio_imp(SrsMediaPacket *audio);
public:
// TODO: FIXME: Use SrsMediaPacket instead.
virtual srs_error_t on_video(SrsRtmpCommonMessage *video);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t on_video_imp(SrsMediaPacket *video);
public:

View File

@ -13,8 +13,11 @@ using namespace std;
#include <sstream>
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_http_hooks.hpp>
#ifdef SRS_RTSP
#include <srs_app_rtsp_source.hpp>
#endif
#include <srs_app_security.hpp>
#include <srs_app_st.hpp>
#include <srs_app_statistic.hpp>
@ -26,7 +29,9 @@ using namespace std;
#include <srs_kernel_log.hpp>
#include <srs_kernel_pithy_print.hpp>
#include <srs_kernel_rtc_rtp.hpp>
#ifdef SRS_RTSP
#include <srs_protocol_rtsp_stack.hpp>
#endif
#include <srs_protocol_st.hpp>
#include <srs_protocol_utility.hpp>
@ -41,7 +46,15 @@ extern SrsPps *_srs_pps_rnack2;
extern SrsPps *_srs_pps_pub;
extern SrsPps *_srs_pps_conn;
SrsRtspPlayStream::SrsRtspPlayStream(SrsRtspConnection *s, const SrsContextId &cid) : source_(new SrsRtspSource())
ISrsRtspPlayStream::ISrsRtspPlayStream()
{
}
ISrsRtspPlayStream::~ISrsRtspPlayStream()
{
}
SrsRtspPlayStream::SrsRtspPlayStream(ISrsRtspConnection *s, const SrsContextId &cid) : source_(new SrsRtspSource())
{
cid_ = cid;
trd_ = NULL;
@ -53,6 +66,10 @@ SrsRtspPlayStream::SrsRtspPlayStream(SrsRtspConnection *s, const SrsContextId &c
cache_ssrc0_ = cache_ssrc1_ = cache_ssrc2_ = 0;
cache_track0_ = cache_track1_ = cache_track2_ = NULL;
app_factory_ = _srs_app_factory;
stat_ = _srs_stat;
rtsp_sources_ = _srs_rtsp_sources;
}
SrsRtspPlayStream::~SrsRtspPlayStream()
@ -61,23 +78,26 @@ SrsRtspPlayStream::~SrsRtspPlayStream()
srs_freep(req_);
if (true) {
std::map<uint32_t, SrsRtspAudioSendTrack *>::iterator it;
std::map<uint32_t, ISrsRtspSendTrack *>::iterator it;
for (it = audio_tracks_.begin(); it != audio_tracks_.end(); ++it) {
srs_freep(it->second);
}
}
if (true) {
std::map<uint32_t, SrsRtspVideoSendTrack *>::iterator it;
std::map<uint32_t, ISrsRtspSendTrack *>::iterator it;
for (it = video_tracks_.begin(); it != video_tracks_.end(); ++it) {
srs_freep(it->second);
}
}
// update the statistic when client coveried.
SrsStatistic *stat = _srs_stat;
// TODO: FIXME: Should finger out the err.
stat->on_disconnect(cid_.c_str(), srs_success);
stat_->on_disconnect(cid_.c_str(), srs_success);
app_factory_ = NULL;
stat_ = NULL;
rtsp_sources_ = NULL;
}
srs_error_t SrsRtspPlayStream::initialize(ISrsRequest *req, std::map<uint32_t, SrsRtcTrackDescription *> sub_relations)
@ -87,12 +107,11 @@ srs_error_t SrsRtspPlayStream::initialize(ISrsRequest *req, std::map<uint32_t, S
req_ = req->copy();
// We must do stat the client before hooks, because hooks depends on it.
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");
}
if ((err = _srs_rtsp_sources->fetch_or_create(req_, source_)) != srs_success) {
if ((err = rtsp_sources_->fetch_or_create(req_, source_)) != srs_success) {
return srs_error_wrap(err, "RTSP: fetch source failed");
}
@ -101,12 +120,12 @@ srs_error_t SrsRtspPlayStream::initialize(ISrsRequest *req, std::map<uint32_t, S
SrsRtcTrackDescription *desc = it->second;
if (desc->type_ == "audio") {
SrsRtspAudioSendTrack *track = new SrsRtspAudioSendTrack(session_, desc);
ISrsRtspSendTrack *track = app_factory_->create_rtsp_audio_send_track(session_, desc);
audio_tracks_.insert(make_pair(ssrc, track));
}
if (desc->type_ == "video") {
SrsRtspVideoSendTrack *track = new SrsRtspVideoSendTrack(session_, desc);
ISrsRtspSendTrack *track = app_factory_->create_rtsp_video_send_track(session_, desc);
video_tracks_.insert(make_pair(ssrc, track));
}
}
@ -125,15 +144,15 @@ void SrsRtspPlayStream::on_stream_change(SrsRtcSourceDescription *desc)
if (desc && desc->audio_track_desc_ && audio_tracks_.size() == 1) {
if (!audio_tracks_.empty()) {
uint32_t ssrc = desc->audio_track_desc_->ssrc_;
SrsRtspAudioSendTrack *track = audio_tracks_.begin()->second;
ISrsRtspSendTrack *track = audio_tracks_.begin()->second;
if (track->track_desc_->media_->pt_of_publisher_ != desc->audio_track_desc_->media_->pt_) {
track->track_desc_->media_->pt_of_publisher_ = desc->audio_track_desc_->media_->pt_;
if (track->track_desc()->media_->pt_of_publisher_ != desc->audio_track_desc_->media_->pt_) {
track->track_desc()->media_->pt_of_publisher_ = desc->audio_track_desc_->media_->pt_;
}
if (desc->audio_track_desc_->red_ && track->track_desc_->red_ &&
track->track_desc_->red_->pt_of_publisher_ != desc->audio_track_desc_->red_->pt_) {
track->track_desc_->red_->pt_of_publisher_ = desc->audio_track_desc_->red_->pt_;
if (desc->audio_track_desc_->red_ && track->track_desc()->red_ &&
track->track_desc()->red_->pt_of_publisher_ != desc->audio_track_desc_->red_->pt_) {
track->track_desc()->red_->pt_of_publisher_ = desc->audio_track_desc_->red_->pt_;
}
audio_tracks_.clear();
@ -147,15 +166,15 @@ void SrsRtspPlayStream::on_stream_change(SrsRtcSourceDescription *desc)
if (!video_tracks_.empty()) {
SrsRtcTrackDescription *vdesc = desc->video_track_descs_.at(0);
uint32_t ssrc = vdesc->ssrc_;
SrsRtspVideoSendTrack *track = video_tracks_.begin()->second;
ISrsRtspSendTrack *track = video_tracks_.begin()->second;
if (track->track_desc_->media_->pt_of_publisher_ != vdesc->media_->pt_) {
track->track_desc_->media_->pt_of_publisher_ = vdesc->media_->pt_;
if (track->track_desc()->media_->pt_of_publisher_ != vdesc->media_->pt_) {
track->track_desc()->media_->pt_of_publisher_ = vdesc->media_->pt_;
}
if (vdesc->red_ && track->track_desc_->red_ &&
track->track_desc_->red_->pt_of_publisher_ != vdesc->red_->pt_) {
track->track_desc_->red_->pt_of_publisher_ = vdesc->red_->pt_;
if (vdesc->red_ && track->track_desc()->red_ &&
track->track_desc()->red_->pt_of_publisher_ != vdesc->red_->pt_) {
track->track_desc()->red_->pt_of_publisher_ = vdesc->red_->pt_;
}
video_tracks_.clear();
@ -267,7 +286,7 @@ srs_error_t SrsRtspPlayStream::send_packet(SrsRtpPacket *&pkt)
uint32_t ssrc = pkt->header_.get_ssrc();
// Try to find track from cache.
SrsRtspSendTrack *track = NULL;
ISrsRtspSendTrack *track = NULL;
if (cache_ssrc0_ == ssrc) {
track = cache_track0_;
} else if (cache_ssrc1_ == ssrc) {
@ -279,12 +298,12 @@ srs_error_t SrsRtspPlayStream::send_packet(SrsRtpPacket *&pkt)
// Find by original tracks and build fast cache.
if (!track) {
if (pkt->is_audio()) {
map<uint32_t, SrsRtspAudioSendTrack *>::iterator it = audio_tracks_.find(ssrc);
map<uint32_t, ISrsRtspSendTrack *>::iterator it = audio_tracks_.find(ssrc);
if (it != audio_tracks_.end()) {
track = it->second;
}
} else {
map<uint32_t, SrsRtspVideoSendTrack *>::iterator it = video_tracks_.find(ssrc);
map<uint32_t, ISrsRtspSendTrack *>::iterator it = video_tracks_.find(ssrc);
if (it != video_tracks_.end()) {
track = it->second;
}
@ -324,9 +343,9 @@ void SrsRtspPlayStream::set_all_tracks_status(bool status)
// set video track status
if (true) {
std::map<uint32_t, SrsRtspVideoSendTrack *>::iterator it;
std::map<uint32_t, ISrsRtspSendTrack *>::iterator it;
for (it = video_tracks_.begin(); it != video_tracks_.end(); ++it) {
SrsRtspVideoSendTrack *track = it->second;
ISrsRtspSendTrack *track = it->second;
bool previous = track->set_track_status(status);
merged_log << "{track: " << track->get_track_id() << ", is_active: " << previous << "=>" << status << "},";
@ -335,9 +354,9 @@ void SrsRtspPlayStream::set_all_tracks_status(bool status)
// set audio track status
if (true) {
std::map<uint32_t, SrsRtspAudioSendTrack *>::iterator it;
std::map<uint32_t, ISrsRtspSendTrack *>::iterator it;
for (it = audio_tracks_.begin(); it != audio_tracks_.end(); ++it) {
SrsRtspAudioSendTrack *track = it->second;
ISrsRtspSendTrack *track = it->second;
bool previous = track->set_track_status(status);
merged_log << "{track: " << track->get_track_id() << ", is_active: " << previous << "=>" << status << "},";
@ -347,6 +366,14 @@ void SrsRtspPlayStream::set_all_tracks_status(bool status)
srs_trace("RTSP: Init tracks %s ok", merged_log.str().c_str());
}
ISrsRtspConnection::ISrsRtspConnection()
{
}
ISrsRtspConnection::~ISrsRtspConnection()
{
}
SrsRtspConnection::SrsRtspConnection(ISrsResourceManager *cm, ISrsProtocolReadWriter *skt, std::string cip, int port)
{
manager_ = cm;
@ -378,12 +405,21 @@ SrsRtspConnection::SrsRtspConnection(ISrsResourceManager *cm, ISrsProtocolReadWr
delta_ = new SrsEphemeralDelta();
security_ = new SrsSecurity();
_srs_rtsp_manager->subscribe(this);
rtsp_manager_ = _srs_rtsp_manager;
stat_ = _srs_stat;
config_ = _srs_config;
rtsp_sources_ = _srs_rtsp_sources;
hooks_ = _srs_hooks;
}
void SrsRtspConnection::assemble()
{
rtsp_manager_->subscribe(this);
}
SrsRtspConnection::~SrsRtspConnection()
{
_srs_rtsp_manager->unsubscribe(this);
rtsp_manager_->unsubscribe(this);
srs_freep(request_);
srs_freep(rtsp_);
@ -410,6 +446,12 @@ SrsRtspConnection::~SrsRtspConnection()
srs_freep(cache_iov_);
}
srs_freep(cache_buffer_);
rtsp_manager_ = NULL;
stat_ = NULL;
config_ = NULL;
rtsp_sources_ = NULL;
hooks_ = NULL;
}
srs_error_t SrsRtspConnection::do_send_packet(SrsRtpPacket *pkt)
@ -487,8 +529,7 @@ srs_error_t SrsRtspConnection::cycle()
err = do_cycle();
// Update statistic when done.
SrsStatistic *stat = _srs_stat;
stat->kbps_add_delta(get_id().c_str(), delta());
stat_->kbps_add_delta(get_id().c_str(), delta());
do_teardown();
@ -538,104 +579,116 @@ srs_error_t SrsRtspConnection::do_cycle()
if ((err = rtsp_->recv_message(&req_raw)) != srs_success) {
return srs_error_wrap(err, "recv message");
}
SrsUniquePtr<SrsRtspRequest> req(req_raw);
if (req->is_options()) {
srs_trace("RTSP: OPTIONS cseq=%ld, url=%s, client=%s:%d", req->seq_, req->uri_.c_str(), ip_.c_str(), port_);
SrsUniquePtr<SrsRtspOptionsResponse> res(new SrsRtspOptionsResponse((int)req->seq_));
if ((err = rtsp_->send_message(res.get())) != srs_success) {
return srs_error_wrap(err, "response option");
}
} else if (req->is_describe()) {
// create session.
if (session_id_.empty()) {
SrsRand rand;
session_id_ = rand.gen_str(8);
}
SrsUniquePtr<SrsRtspDescribeResponse> res(new SrsRtspDescribeResponse((int)req->seq_));
res->session_ = session_id_;
std::string sdp;
if ((err = do_describe(req.get(), sdp)) != srs_success) {
res->status_ = SRS_CONSTS_RTSP_InternalServerError;
if (srs_error_code(err) == ERROR_RTSP_NO_TRACK) {
res->status_ = SRS_CONSTS_RTSP_NotFound;
} else if (srs_error_code(err) == ERROR_SYSTEM_SECURITY_DENY) {
res->status_ = SRS_CONSTS_RTSP_Forbidden;
}
srs_warn("RTSP: DESCRIBE failed: %s", srs_error_desc(err).c_str());
srs_freep(err);
}
res->sdp_ = sdp;
if ((err = rtsp_->send_message(res.get())) != srs_success) {
return srs_error_wrap(err, "response describe");
}
// Filter the \r\n to \\r\\n for JSON.
std::string local_sdp_escaped = srs_strings_replace(sdp.c_str(), "\r\n", "\\r\\n");
srs_trace("RTSP: DESCRIBE cseq=%ld, session=%s, sdp: %s", req->seq_, session_id_.c_str(), local_sdp_escaped.c_str());
} else if (req->is_setup()) {
srs_assert(req->transport_);
SrsUniquePtr<SrsRtspSetupResponse> res(new SrsRtspSetupResponse((int)req->seq_));
res->session_ = session_id_;
uint32_t ssrc = 0;
if ((err = do_setup(req.get(), &ssrc)) != srs_success) {
if (srs_error_code(err) == ERROR_RTSP_TRANSPORT_NOT_SUPPORTED) {
res->status_ = SRS_CONSTS_RTSP_UnsupportedTransport;
srs_warn("RTSP: SETUP failed: %s", srs_error_summary(err).c_str());
} else {
res->status_ = SRS_CONSTS_RTSP_InternalServerError;
srs_warn("RTSP: SETUP failed: %s", srs_error_desc(err).c_str());
}
srs_freep(err);
}
res->transport_->copy(req->transport_);
res->session_ = session_id_;
res->ssrc_ = srs_strconv_format_int(ssrc);
res->client_port_min_ = req->transport_->client_port_min_;
res->client_port_max_ = req->transport_->client_port_max_;
// TODO: FIXME: listen local port
res->local_port_min_ = 0;
res->local_port_max_ = 0;
if ((err = rtsp_->send_message(res.get())) != srs_success) {
return srs_error_wrap(err, "response setup");
}
srs_trace("RTSP: SETUP cseq=%ld, session=%s, transport=%s/%s/%s, ssrc=%u, client_port=%d-%d",
req->seq_, session_id_.c_str(), req->transport_->transport_.c_str(), req->transport_->profile_.c_str(),
req->transport_->lower_transport_.c_str(), ssrc, req->transport_->client_port_min_, req->transport_->client_port_max_);
} else if (req->is_play()) {
SrsUniquePtr<SrsRtspResponse> res(new SrsRtspResponse((int)req->seq_));
res->session_ = session_id_;
if ((err = rtsp_->send_message(res.get())) != srs_success) {
return srs_error_wrap(err, "response record");
}
if ((err = do_play(req.get(), this)) != srs_success) {
return srs_error_wrap(err, "prepare play");
}
srs_trace("RTSP: PLAY cseq=%ld, session=%s, streaming started", req->seq_, session_id_.c_str());
} else if (req->is_teardown()) {
SrsUniquePtr<SrsRtspResponse> res(new SrsRtspResponse((int)req->seq_));
res->session_ = session_id_;
if ((err = rtsp_->send_message(res.get())) != srs_success) {
return srs_error_wrap(err, "response teardown");
}
if ((err = do_teardown()) != srs_success) {
return srs_error_wrap(err, "teardown");
}
srs_trace("RTSP: TEARDOWN cseq=%ld, session=%s, streaming stopped", req->seq_, session_id_.c_str());
if ((err = on_rtsp_request(req_raw)) != srs_success) {
return srs_error_wrap(err, "on rtsp request");
}
}
return err;
}
srs_error_t SrsRtspConnection::on_rtsp_request(SrsRtspRequest *req_raw)
{
srs_error_t err = srs_success;
SrsUniquePtr<SrsRtspRequest> req(req_raw);
if (req->is_options()) {
srs_trace("RTSP: OPTIONS cseq=%ld, url=%s, client=%s:%d", req->seq_, req->uri_.c_str(), ip_.c_str(), port_);
SrsUniquePtr<SrsRtspOptionsResponse> res(new SrsRtspOptionsResponse((int)req->seq_));
if ((err = rtsp_->send_message(res.get())) != srs_success) {
return srs_error_wrap(err, "response option");
}
} else if (req->is_describe()) {
// create session.
if (session_id_.empty()) {
SrsRand rand;
session_id_ = rand.gen_str(8);
}
SrsUniquePtr<SrsRtspDescribeResponse> res(new SrsRtspDescribeResponse((int)req->seq_));
res->session_ = session_id_;
std::string sdp;
if ((err = do_describe(req.get(), sdp)) != srs_success) {
res->status_ = SRS_CONSTS_RTSP_InternalServerError;
if (srs_error_code(err) == ERROR_RTSP_NO_TRACK) {
res->status_ = SRS_CONSTS_RTSP_NotFound;
} else if (srs_error_code(err) == ERROR_SYSTEM_SECURITY_DENY) {
res->status_ = SRS_CONSTS_RTSP_Forbidden;
}
srs_warn("RTSP: DESCRIBE failed: %s", srs_error_desc(err).c_str());
srs_freep(err);
}
res->sdp_ = sdp;
if ((err = rtsp_->send_message(res.get())) != srs_success) {
return srs_error_wrap(err, "response describe");
}
// Filter the \r\n to \\r\\n for JSON.
std::string local_sdp_escaped = srs_strings_replace(sdp.c_str(), "\r\n", "\\r\\n");
srs_trace("RTSP: DESCRIBE cseq=%ld, session=%s, sdp: %s", req->seq_, session_id_.c_str(), local_sdp_escaped.c_str());
} else if (req->is_setup()) {
srs_assert(req->transport_);
SrsUniquePtr<SrsRtspSetupResponse> res(new SrsRtspSetupResponse((int)req->seq_));
res->session_ = session_id_;
uint32_t ssrc = 0;
if ((err = do_setup(req.get(), &ssrc)) != srs_success) {
if (srs_error_code(err) == ERROR_RTSP_TRANSPORT_NOT_SUPPORTED) {
res->status_ = SRS_CONSTS_RTSP_UnsupportedTransport;
srs_warn("RTSP: SETUP failed: %s", srs_error_summary(err).c_str());
} else {
res->status_ = SRS_CONSTS_RTSP_InternalServerError;
srs_warn("RTSP: SETUP failed: %s", srs_error_desc(err).c_str());
}
srs_freep(err);
}
res->transport_->copy(req->transport_);
res->session_ = session_id_;
res->ssrc_ = srs_strconv_format_int(ssrc);
res->client_port_min_ = req->transport_->client_port_min_;
res->client_port_max_ = req->transport_->client_port_max_;
// TODO: FIXME: listen local port
res->local_port_min_ = 0;
res->local_port_max_ = 0;
if ((err = rtsp_->send_message(res.get())) != srs_success) {
return srs_error_wrap(err, "response setup");
}
srs_trace("RTSP: SETUP cseq=%ld, session=%s, transport=%s/%s/%s, ssrc=%u, client_port=%d-%d",
req->seq_, session_id_.c_str(), req->transport_->transport_.c_str(), req->transport_->profile_.c_str(),
req->transport_->lower_transport_.c_str(), ssrc, req->transport_->client_port_min_, req->transport_->client_port_max_);
} else if (req->is_play()) {
SrsUniquePtr<SrsRtspResponse> res(new SrsRtspResponse((int)req->seq_));
res->session_ = session_id_;
if ((err = rtsp_->send_message(res.get())) != srs_success) {
return srs_error_wrap(err, "response record");
}
if ((err = do_play(req.get(), this)) != srs_success) {
return srs_error_wrap(err, "prepare play");
}
srs_trace("RTSP: PLAY cseq=%ld, session=%s, streaming started", req->seq_, session_id_.c_str());
} else if (req->is_teardown()) {
SrsUniquePtr<SrsRtspResponse> res(new SrsRtspResponse((int)req->seq_));
res->session_ = session_id_;
if ((err = rtsp_->send_message(res.get())) != srs_success) {
return srs_error_wrap(err, "response teardown");
}
if ((err = do_teardown()) != srs_success) {
return srs_error_wrap(err, "teardown");
}
srs_trace("RTSP: TEARDOWN cseq=%ld, session=%s, streaming stopped", req->seq_, session_id_.c_str());
}
return err;
}
void SrsRtspConnection::on_before_dispose(ISrsResource *c)
{
if (disposing_) {
@ -690,7 +743,7 @@ srs_error_t SrsRtspConnection::do_describe(SrsRtspRequest *req, std::string &sdp
request_->app_, request_->stream_, request_->port_, request_->param_);
// discovery vhost, resolve the vhost from config
SrsConfDirective *parsed_vhost = _srs_config->get_vhost(request_->vhost_);
SrsConfDirective *parsed_vhost = config_->get_vhost(request_->vhost_);
if (parsed_vhost) {
request_->vhost_ = parsed_vhost->arg0();
}
@ -703,7 +756,7 @@ srs_error_t SrsRtspConnection::do_describe(SrsRtspRequest *req, std::string &sdp
return srs_error_wrap(err, "RTSP: http_hooks_on_play");
}
if ((err = _srs_rtsp_sources->fetch_or_create(request_, source_)) != srs_success) {
if ((err = rtsp_sources_->fetch_or_create(request_, source_)) != srs_success) {
return srs_error_wrap(err, "create source");
}
@ -855,7 +908,7 @@ srs_error_t SrsRtspConnection::http_hooks_on_play(ISrsRequest *req)
{
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;
}
@ -865,7 +918,7 @@ srs_error_t SrsRtspConnection::http_hooks_on_play(ISrsRequest *req)
std::vector<std::string> hooks;
if (true) {
SrsConfDirective *conf = _srs_config->get_vhost_on_play(req->vhost_);
SrsConfDirective *conf = config_->get_vhost_on_play(req->vhost_);
if (!conf) {
return err;
@ -876,7 +929,7 @@ srs_error_t SrsRtspConnection::http_hooks_on_play(ISrsRequest *req)
for (int i = 0; i < (int)hooks.size(); i++) {
std::string url = hooks.at(i);
if ((err = _srs_hooks->on_play(url, req)) != srs_success) {
if ((err = hooks_->on_play(url, req)) != srs_success) {
return srs_error_wrap(err, "on_play %s", url.c_str());
}
}

View File

@ -31,37 +31,72 @@ class SrsRtspConnection;
class SrsSecurity;
class SrsRtspRequest;
class SrsRtspStack;
class ISrsRtspConnection;
class ISrsRtspSendTrack;
class ISrsRtspStack;
class ISrsAppFactory;
class ISrsEphemeralDelta;
class ISrsSecurity;
class ISrsStatistic;
class ISrsRtspSourceManager;
class ISrsHttpHooks;
class ISrsAppConfig;
// The handler for RTSP play stream.
class ISrsRtspPlayStream
{
public:
ISrsRtspPlayStream();
virtual ~ISrsRtspPlayStream();
public:
virtual srs_error_t initialize(ISrsRequest *request, std::map<uint32_t, SrsRtcTrackDescription *> sub_relations) = 0;
virtual srs_error_t start() = 0;
virtual void stop() = 0;
// Directly set the status of track, generally for init to set the default value.
virtual void set_all_tracks_status(bool status) = 0;
};
// A RTSP play stream, client pull and play stream from SRS.
class SrsRtspPlayStream : public ISrsCoroutineHandler, public ISrsRtcSourceChangeCallback
class SrsRtspPlayStream : public ISrsRtspPlayStream, public ISrsCoroutineHandler, public ISrsRtcSourceChangeCallback
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppFactory *app_factory_;
ISrsStatistic *stat_;
ISrsRtspSourceManager *rtsp_sources_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsContextId cid_;
ISrsCoroutine *trd_;
SrsRtspConnection *session_;
ISrsRtspConnection *session_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
SrsSharedPtr<SrsRtspSource> source_;
// key: publish_ssrc, value: send track to process rtp/rtcp
std::map<uint32_t, SrsRtspAudioSendTrack *> audio_tracks_;
std::map<uint32_t, SrsRtspVideoSendTrack *> video_tracks_;
std::map<uint32_t, ISrsRtspSendTrack *> audio_tracks_;
std::map<uint32_t, ISrsRtspSendTrack *> video_tracks_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Fast cache for tracks.
uint32_t cache_ssrc0_;
uint32_t cache_ssrc1_;
uint32_t cache_ssrc2_;
SrsRtspSendTrack *cache_track0_;
SrsRtspSendTrack *cache_track1_;
SrsRtspSendTrack *cache_track2_;
ISrsRtspSendTrack *cache_track0_;
ISrsRtspSendTrack *cache_track1_;
ISrsRtspSendTrack *cache_track2_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Whether player started.
bool is_started;
public:
SrsRtspPlayStream(SrsRtspConnection *s, const SrsContextId &cid);
SrsRtspPlayStream(ISrsRtspConnection *s, const SrsContextId &cid);
virtual ~SrsRtspPlayStream();
public:
@ -80,7 +115,8 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t send_packet(SrsRtpPacket *&pkt);
public:
@ -88,12 +124,38 @@ public:
void set_all_tracks_status(bool status);
};
class SrsRtspConnection : public ISrsResource, public ISrsDisposingHandler, public ISrsExpire, public ISrsCoroutineHandler, public ISrsStartable
// The handler for RTSP connection send packet.
class ISrsRtspConnection : public ISrsExpire
{
private:
public:
ISrsRtspConnection();
virtual ~ISrsRtspConnection();
public:
virtual srs_error_t do_send_packet(SrsRtpPacket *pkt) = 0;
};
// A RTSP session, client request and response with RTSP.
class SrsRtspConnection : public ISrsResource, // It's a resource.
public ISrsDisposingHandler,
public ISrsCoroutineHandler,
public ISrsStartable,
public ISrsRtspConnection
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRtspSourceManager *rtsp_sources_;
ISrsResourceManager *rtsp_manager_;
ISrsStatistic *stat_;
ISrsAppConfig *config_;
ISrsHttpHooks *hooks_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool disposing_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// TODO: FIXME: Rename it.
// The timeout of session, keep alive by STUN ping pong.
srs_utime_t session_timeout;
@ -109,22 +171,23 @@ private:
// The ip and port of client.
std::string ip_;
int port_;
SrsRtspStack *rtsp_;
ISrsRtspStack *rtsp_;
std::string session_id_;
SrsSharedPtr<SrsRtspSource> source_;
SrsEphemeralDelta *delta_;
ISrsEphemeralDelta *delta_;
ISrsProtocolReadWriter *skt_;
SrsSecurity *security_;
ISrsSecurity *security_;
iovec *cache_iov_;
SrsBuffer *cache_buffer_;
// key: ssrc
std::map<uint32_t, SrsRtcTrackDescription *> tracks_;
// key: ssrc
std::map<uint32_t, ISrsStreamWriter *> networks_;
SrsRtspPlayStream *player_;
ISrsRtspPlayStream *player_;
public:
SrsRtspConnection(ISrsResourceManager *cm, ISrsProtocolReadWriter *skt, std::string cip, int port);
void assemble(); // Construct object, to avoid call function in constructor.
virtual ~SrsRtspConnection();
// interface ISrsDisposingHandler
public:
@ -137,7 +200,8 @@ public:
public:
ISrsKbpsDelta *delta();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_describe(SrsRtspRequest *req, std::string &sdp);
virtual srs_error_t do_setup(SrsRtspRequest *req, uint32_t *ssrc);
virtual srs_error_t do_play(SrsRtspRequest *req, SrsRtspConnection *conn);
@ -162,6 +226,12 @@ public:
// Interface ISrsCoroutineHandler
public:
virtual srs_error_t cycle();
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t do_cycle();
srs_error_t on_rtsp_request(SrsRtspRequest *req_raw);
// Interface ISrsExpire.
public:
virtual void expire();
@ -174,17 +244,16 @@ public:
bool is_alive();
void alive();
private:
srs_error_t do_cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t http_hooks_on_play(ISrsRequest *req);
srs_error_t get_ssrc_by_stream_id(uint32_t stream_id, uint32_t *ssrc);
};
class SrsRtspTcpNetwork : public ISrsStreamWriter
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsProtocolReadWriter *skt_;
int channel_;

View File

@ -250,6 +250,9 @@ SrsRtspSource::SrsRtspSource()
req_ = NULL;
stream_die_at_ = 0;
stat_ = _srs_stat;
circuit_breaker_ = _srs_circuit_breaker;
}
SrsRtspSource::~SrsRtspSource()
@ -266,6 +269,9 @@ SrsRtspSource::~SrsRtspSource()
if (cid.empty())
cid = _pre_source_id;
srs_trace("free rtc source id=[%s]", cid.c_str());
stat_ = NULL;
circuit_breaker_ = NULL;
}
// CRITICAL: This method is called AFTER the source has been added to the source pool
@ -437,8 +443,7 @@ srs_error_t SrsRtspSource::on_publish()
return srs_error_wrap(err, "source id change");
}
SrsStatistic *stat = _srs_stat;
stat->on_stream_publish(req_, _source_id.c_str());
stat_->on_stream_publish(req_, _source_id.c_str());
return err;
}
@ -457,8 +462,7 @@ void SrsRtspSource::on_unpublish()
}
_source_id = SrsContextId();
SrsStatistic *stat = _srs_stat;
stat->on_stream_close(req_);
stat_->on_stream_close(req_);
// Destroy and cleanup source when no publishers and consumers.
if (consumers_.empty()) {
@ -475,7 +479,7 @@ srs_error_t SrsRtspSource::on_rtp(SrsRtpPacket *pkt)
srs_error_t err = srs_success;
// If circuit-breaker is dying, drop packet.
if (_srs_circuit_breaker->hybrid_dying_water_level()) {
if (circuit_breaker_->hybrid_dying_water_level()) {
_srs_pps_aloss2->sugar_ += (int64_t)consumers_.size();
return err;
}
@ -531,6 +535,8 @@ SrsRtspRtpBuilder::SrsRtspRtpBuilder(ISrsRtpTarget *target, SrsSharedPtr<SrsRtsp
// Lazy initialization flags
audio_initialized_ = false;
video_initialized_ = false;
config_ = _srs_config;
}
SrsRtspRtpBuilder::~SrsRtspRtpBuilder()
@ -538,6 +544,8 @@ SrsRtspRtpBuilder::~SrsRtspRtpBuilder()
srs_freep(format_);
srs_freep(meta_);
srs_freep(video_builder_);
config_ = NULL;
}
srs_error_t SrsRtspRtpBuilder::initialize_audio_track(SrsAudioCodecId codec)
@ -679,7 +687,7 @@ srs_error_t SrsRtspRtpBuilder::initialize(ISrsRequest *r)
}
// Setup the SPS/PPS parsing strategy.
format_->try_annexb_first_ = _srs_config->try_annexb_first(r->vhost_);
format_->try_annexb_first_ = config_->try_annexb_first(r->vhost_);
srs_trace("RTSP bridge from RTMP, try_annexb_first=%d", format_->try_annexb_first_);
@ -997,7 +1005,15 @@ srs_error_t SrsRtspRtpBuilder::consume_packets(vector<SrsRtpPacket *> &pkts)
return err;
}
SrsRtspSendTrack::SrsRtspSendTrack(SrsRtspConnection *session, SrsRtcTrackDescription *track_desc, bool is_audio)
ISrsRtspSendTrack::ISrsRtspSendTrack()
{
}
ISrsRtspSendTrack::~ISrsRtspSendTrack()
{
}
SrsRtspSendTrack::SrsRtspSendTrack(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc, bool is_audio)
{
session_ = session;
track_desc_ = track_desc->copy();
@ -1031,7 +1047,12 @@ std::string SrsRtspSendTrack::get_track_id()
return track_desc_->id_;
}
SrsRtspAudioSendTrack::SrsRtspAudioSendTrack(SrsRtspConnection *session, SrsRtcTrackDescription *track_desc)
SrsRtcTrackDescription *SrsRtspSendTrack::track_desc()
{
return track_desc_;
}
SrsRtspAudioSendTrack::SrsRtspAudioSendTrack(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc)
: SrsRtspSendTrack(session, track_desc, true)
{
}
@ -1071,7 +1092,7 @@ srs_error_t SrsRtspAudioSendTrack::on_rtp(SrsRtpPacket *pkt)
return err;
}
SrsRtspVideoSendTrack::SrsRtspVideoSendTrack(SrsRtspConnection *session, SrsRtcTrackDescription *track_desc)
SrsRtspVideoSendTrack::SrsRtspVideoSendTrack(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc)
: SrsRtspSendTrack(session, track_desc, false)
{
}

View File

@ -26,15 +26,21 @@ class SrsRtcSourceDescription;
class SrsResourceManager;
class SrsRtspConnection;
class SrsRtpVideoBuilder;
class ISrsStatistic;
class ISrsCircuitBreaker;
class ISrsAppConfig;
class ISrsRtspConnection;
// The RTSP stream consumer, consume packets from RTSP stream source.
class SrsRtspConsumer
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Because source references to this object, so we should directly use the source ptr.
SrsRtspSource *source_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::vector<SrsRtpPacket *> queue_;
// when source id changed, notice all consumers
bool should_update_source_id_;
@ -43,7 +49,8 @@ private:
bool mw_waiting_;
int mw_min_msgs_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The callback for stream change event.
ISrsRtcSourceChangeCallback *handler_;
@ -83,7 +90,8 @@ public:
// The RTSP source manager.
class SrsRtspSourceManager : public ISrsHourGlassHandler, public ISrsRtspSourceManager
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_mutex_t lock_;
std::map<std::string, SrsSharedPtr<SrsRtspSource> > pool_;
SrsHourGlass *timer_;
@ -95,7 +103,8 @@ public:
public:
virtual srs_error_t initialize();
// interface ISrsHourGlassHandler
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t setup_ticks();
virtual srs_error_t notify(int event, srs_utime_t interval, srs_utime_t tick);
@ -118,7 +127,13 @@ extern SrsResourceManager *_srs_rtsp_manager;
// A Source is a stream, to publish and to play with, binding to SrsRtspPlayStream.
class SrsRtspSource : public ISrsRtpTarget
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
ISrsCircuitBreaker *circuit_breaker_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// For publish, it's the publish client id.
// For edge, it's the edge ingest id.
// when source id changed, for example, the edge reconnect,
@ -131,15 +146,18 @@ private:
SrsRtcTrackDescription *audio_desc_;
SrsRtcTrackDescription *video_desc_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// To delivery stream to clients.
std::vector<SrsRtspConsumer *> consumers_;
std::vector<SrsRtspConsumer *>
consumers_;
// Whether stream is created, that is, SDP is done.
bool is_created_;
// Whether stream is delivering data, that is, DTLS is done.
bool is_delivering_packets_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The last die time, while die means neither publishers nor players.
srs_utime_t stream_die_at_;
@ -158,9 +176,11 @@ public:
// Update the authentication information in request.
virtual void update_auth(ISrsRequest *r);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The stream source changed.
virtual srs_error_t on_source_changed();
virtual srs_error_t
on_source_changed();
public:
// Get current source id.
@ -201,7 +221,12 @@ public:
// Convert AV frame to RTSP RTP packets.
class SrsRtspRtpBuilder
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
ISrsRtpTarget *rtp_target_;
// The format, codec information.
@ -211,13 +236,15 @@ private:
// The video builder, convert frame to RTP packets.
SrsRtpVideoBuilder *video_builder_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
uint16_t audio_sequence_;
uint32_t audio_ssrc_;
uint8_t audio_payload_type_;
int audio_sample_rate_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsSharedPtr<SrsRtspSource> source_;
// Lazy initialization flags
bool audio_initialized_;
@ -227,9 +254,11 @@ public:
SrsRtspRtpBuilder(ISrsRtpTarget *target, SrsSharedPtr<SrsRtspSource> source);
virtual ~SrsRtspRtpBuilder();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Lazy initialization methods
srs_error_t initialize_audio_track(SrsAudioCodecId codec);
srs_error_t
initialize_audio_track(SrsAudioCodecId codec);
srs_error_t initialize_video_track(SrsVideoCodecId codec);
public:
@ -238,16 +267,20 @@ public:
virtual void on_unpublish();
virtual srs_error_t on_frame(SrsMediaPacket *frame);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t on_audio(SrsMediaPacket *msg);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t package_aac(SrsParsedAudioPacket *audio, SrsRtpPacket *pkt);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t on_video(SrsMediaPacket *msg);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t filter(SrsMediaPacket *msg, SrsFormat *format, bool &has_idr, std::vector<SrsNaluSample *> &samples);
srs_error_t package_stap_a(SrsMediaPacket *msg, SrsRtpPacket *pkt);
srs_error_t package_nalus(SrsMediaPacket *msg, const std::vector<SrsNaluSample *> &samples, std::vector<SrsRtpPacket *> &pkts);
@ -256,18 +289,32 @@ private:
srs_error_t consume_packets(std::vector<SrsRtpPacket *> &pkts);
};
class SrsRtspSendTrack
class ISrsRtspSendTrack
{
public:
ISrsRtspSendTrack();
virtual ~ISrsRtspSendTrack();
public:
virtual bool set_track_status(bool active) = 0;
virtual std::string get_track_id() = 0;
virtual SrsRtcTrackDescription *track_desc() = 0;
virtual srs_error_t on_rtp(SrsRtpPacket *pkt) = 0;
};
class SrsRtspSendTrack : public ISrsRtspSendTrack
{
public:
// send track description
SrsRtcTrackDescription *track_desc_;
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
// The owner connection for this track.
SrsRtspConnection *session_;
ISrsRtspConnection *session_;
public:
SrsRtspSendTrack(SrsRtspConnection *session, SrsRtcTrackDescription *track_desc, bool is_audio);
SrsRtspSendTrack(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc, bool is_audio);
virtual ~SrsRtspSendTrack();
public:
@ -276,15 +323,13 @@ public:
bool set_track_status(bool active);
bool get_track_status();
std::string get_track_id();
public:
virtual srs_error_t on_rtp(SrsRtpPacket *pkt) = 0;
virtual SrsRtcTrackDescription *track_desc();
};
class SrsRtspAudioSendTrack : public SrsRtspSendTrack
{
public:
SrsRtspAudioSendTrack(SrsRtspConnection *session, SrsRtcTrackDescription *track_desc);
SrsRtspAudioSendTrack(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc);
virtual ~SrsRtspAudioSendTrack();
public:
@ -294,7 +339,7 @@ public:
class SrsRtspVideoSendTrack : public SrsRtspSendTrack
{
public:
SrsRtspVideoSendTrack(SrsRtspConnection *session, SrsRtcTrackDescription *track_desc);
SrsRtspVideoSendTrack(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc);
virtual ~SrsRtspVideoSendTrack();
public:

View File

@ -41,7 +41,8 @@ public:
// @param req the request object of client.
virtual srs_error_t check(SrsRtmpConnType type, std::string ip, ISrsRequest *req);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_check(SrsConfDirective *rules, SrsRtmpConnType type, std::string ip, ISrsRequest *req);
virtual srs_error_t allow_check(SrsConfDirective *rules, SrsRtmpConnType type, std::string ip);
virtual srs_error_t deny_check(SrsConfDirective *rules, SrsRtmpConnType type, std::string ip);

View File

@ -78,15 +78,11 @@ extern std::string _srs_reload_id;
extern SrsRtcBlackhole *_srs_blackhole;
extern SrsDtlsCertificate *_srs_rtc_dtls_certificate;
bool _srs_global_initialized = false;
srs_error_t srs_global_initialize()
{
srs_error_t err = srs_success;
// Root global objects.
_srs_log = new SrsFileLog();
_srs_context = new SrsThreadContext();
_srs_config = new SrsConfig();
// Initialize the global kbps statistics variables
if ((err = srs_global_kbps_initialize()) != srs_success) {
return srs_error_wrap(err, "global kbps initialize");
@ -108,6 +104,10 @@ srs_error_t srs_global_initialize()
_srs_stages = new SrsStageManager();
_srs_sources = new SrsLiveSourceManager();
_srs_circuit_breaker = new SrsCircuitBreaker();
// Initialize global statistic instance before _srs_hooks, as SrsHttpHooks depends on it.
_srs_stat = new SrsStatistic();
_srs_hooks = new SrsHttpHooks();
_srs_srt_sources = new SrsSrtSourceManager();
@ -136,12 +136,36 @@ srs_error_t srs_global_initialize()
SrsRand rand;
_srs_reload_id = rand.gen_str(7);
// Initialize global statistic instance.
_srs_stat = new SrsStatistic();
// Global initialization done
_srs_global_initialized = true;
return err;
}
ISrsSignalHandler::ISrsSignalHandler()
{
}
ISrsSignalHandler::~ISrsSignalHandler()
{
}
ISrsApiServerOwner::ISrsApiServerOwner()
{
}
ISrsApiServerOwner::~ISrsApiServerOwner()
{
}
ISrsRtcApiServer::ISrsRtcApiServer()
{
}
ISrsRtcApiServer::~ISrsRtcApiServer()
{
}
SrsServer::SrsServer()
{
signal_reload_ = false;
@ -262,7 +286,9 @@ SrsServer::~SrsServer()
circuit_breaker_ = NULL;
srt_sources_ = NULL;
rtc_sources_ = NULL;
#ifdef SRS_RTSP
rtsp_sources_ = NULL;
#endif
#ifdef SRS_GB28181
gb_manager_ = NULL;
#endif
@ -355,7 +381,7 @@ void SrsServer::gracefully_dispose()
srs_trace("final wait for %dms", srsu2msi(config_->get_grace_final_wait()));
}
ISrsHttpServeMux *SrsServer::api_server()
ISrsCommonHttpHandler *SrsServer::api_server()
{
return http_api_mux_;
}
@ -674,7 +700,8 @@ srs_error_t SrsServer::listen()
// Create exporter server listener.
if (config_->get_exporter_enabled()) {
exporter_listener_->set_endpoint(config_->get_exporter_listen())->set_label("Exporter-Server");
exporter_listener_->set_endpoint(config_->get_exporter_listen());
exporter_listener_->set_label("Exporter-Server");
if ((err = exporter_listener_->listen()) != srs_success) {
return srs_error_wrap(err, "exporter server listen");
}
@ -758,9 +785,13 @@ srs_error_t SrsServer::http_handle()
if ((err = http_api_mux_->handle("/api/v1/clients/", new SrsGoApiClients())) != srs_success) {
return srs_error_wrap(err, "handle clients");
}
if ((err = http_api_mux_->handle("/api/v1/raw", new SrsGoApiRaw(this))) != srs_success) {
SrsGoApiRaw *raw_api = new SrsGoApiRaw(this);
raw_api->assemble();
if ((err = http_api_mux_->handle("/api/v1/raw", raw_api)) != srs_success) {
return srs_error_wrap(err, "handle raw");
}
if ((err = http_api_mux_->handle("/api/v1/clusters", new SrsGoApiClusters())) != srs_success) {
return srs_error_wrap(err, "handle clusters");
}
@ -805,7 +836,9 @@ srs_error_t SrsServer::http_handle()
#endif
// metrics by prometheus
if ((err = http_api_mux_->handle("/metrics", new SrsGoApiMetrics())) != srs_success) {
SrsGoApiMetrics *metrics = new SrsGoApiMetrics();
metrics->assemble();
if ((err = http_api_mux_->handle("/metrics", metrics)) != srs_success) {
return srs_error_wrap(err, "handle tests errors");
}
@ -1038,6 +1071,12 @@ srs_error_t SrsServer::do_cycle()
return srs_error_wrap(err, "cycle");
}
// Break the loop when quit signals are set, otherwise we loop forever
// printing "cleanup for quit signal" every second.
if (signal_fast_quit_ || signal_gracefully_quit_) {
break;
}
srs_usleep(1 * SRS_UTIME_SECONDS);
}
@ -1337,7 +1376,7 @@ srs_error_t SrsServer::listen_rtc_udp()
return err;
}
srs_error_t SrsServer::on_udp_packet(SrsUdpMuxSocket *skt)
srs_error_t SrsServer::on_udp_packet(ISrsUdpMuxSocket *skt)
{
return rtc_session_manager_->on_udp_packet(skt);
}
@ -1378,12 +1417,12 @@ srs_error_t SrsServer::listen_rtc_api()
return err;
}
SrsRtcConnection *SrsServer::find_rtc_session_by_username(const std::string &username)
ISrsRtcConnection *SrsServer::find_rtc_session_by_username(const std::string &username)
{
return rtc_session_manager_->find_rtc_session_by_username(username);
}
srs_error_t SrsServer::create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, SrsRtcConnection **psession)
srs_error_t SrsServer::create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, ISrsRtcConnection **psession)
{
srs_error_t err = srs_success;
@ -1527,7 +1566,9 @@ srs_error_t SrsServer::do_on_tcp_client(ISrsListener *listener, srs_netfd_t &stf
resource = new SrsRtcTcpConn(new SrsTcpConnection(stfd2), ip, port);
#ifdef SRS_RTSP
} else if (listener == rtsp_listener_) {
resource = new SrsRtspConnection(conn_manager_, new SrsTcpConnection(stfd2), ip, port);
SrsRtspConnection *conn = new SrsRtspConnection(conn_manager_, new SrsTcpConnection(stfd2), ip, port);
conn->assemble();
resource = conn;
#endif
} else if (listener == exporter_listener_) {
// TODO: FIXME: Maybe should support https metrics.
@ -1542,7 +1583,7 @@ srs_error_t SrsServer::do_on_tcp_client(ISrsListener *listener, srs_netfd_t &stf
// For RTC TCP connection, use resource executor to manage the resource.
SrsRtcTcpConn *raw_conn = dynamic_cast<SrsRtcTcpConn *>(resource);
if (raw_conn) {
SrsSharedResource<SrsRtcTcpConn> *conn = new SrsSharedResource<SrsRtcTcpConn>(raw_conn);
SrsSharedResource<ISrsRtcTcpConn> *conn = new SrsSharedResource<ISrsRtcTcpConn>(raw_conn);
SrsExecutorCoroutine *executor = new SrsExecutorCoroutine(conn_manager_, conn, raw_conn, raw_conn);
raw_conn->setup_owner(conn, executor, executor);
if ((err = executor->start()) != srs_success) {

View File

@ -33,7 +33,7 @@ class SrsRtcConnection;
class ISrsAsyncCallTask;
class SrsSignalManager;
class SrsServer;
class ISrsHttpServeMux;
class ISrsCommonHttpHandler;
class SrsHttpServer;
class SrsIngester;
class SrsHttpHeartbeat;
@ -68,11 +68,47 @@ class ISrsRtspSourceManager;
class ISrsLog;
class ISrsStatistic;
class ISrsHourGlass;
class SrsAppFactory;
class ISrsAppFactory;
class ISrsUdpMuxSocket;
class ISrsRtcConnection;
// Initialize global shared variables cross all threads.
extern srs_error_t srs_global_initialize();
// The signal handler interface.
class ISrsSignalHandler
{
public:
ISrsSignalHandler();
virtual ~ISrsSignalHandler();
public:
virtual void on_signal(int signo) = 0;
};
// The API server owner interface.
class ISrsApiServerOwner
{
public:
ISrsApiServerOwner();
virtual ~ISrsApiServerOwner();
public:
virtual ISrsCommonHttpHandler *api_server() = 0;
};
// The RTC API server owner interface.
class ISrsRtcApiServer
{
public:
ISrsRtcApiServer();
virtual ~ISrsRtcApiServer();
public:
virtual srs_error_t create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, ISrsRtcConnection **psession) = 0;
virtual ISrsRtcConnection *find_rtc_session_by_username(const std::string &ufrag) = 0;
};
// SrsServer is the main server class of SRS (Simple Realtime Server) that provides comprehensive
// streaming media server functionality. It serves as the central orchestrator for all streaming
// protocols and services in a single-threaded, coroutine-based architecture.
@ -81,9 +117,13 @@ class SrsServer : public ISrsReloadHandler, // Reload framework for permormance
public ISrsTcpHandler,
public ISrsHourGlassHandler,
public ISrsSrtClientHandler,
public ISrsUdpMuxHandler
public ISrsUdpMuxHandler,
public ISrsSignalHandler,
public ISrsApiServerOwner,
public ISrsRtcApiServer
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
ISrsLiveSourceManager *live_sources_;
ISrsResourceManager *conn_manager_;
@ -92,28 +132,34 @@ private:
ISrsCircuitBreaker *circuit_breaker_;
ISrsSrtSourceManager *srt_sources_;
ISrsRtcSourceManager *rtc_sources_;
#ifdef SRS_RTSP
ISrsRtspSourceManager *rtsp_sources_;
#endif
#ifdef SRS_GB28181
ISrsResourceManager *gb_manager_;
#endif
ISrsLog *log_;
ISrsStatistic *stat_;
SrsAppFactory *app_factory_;
ISrsAppFactory *app_factory_;
private:
ISrsHttpServeMux *http_api_mux_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsCommonHttpHandler *http_api_mux_;
SrsHttpServer *http_server_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsHttpHeartbeat *http_heartbeat_;
SrsIngester *ingester_;
ISrsHourGlass *timer_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// PID file manager for process identification and locking.
SrsPidFileLocker *pid_file_locker_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// If reusing, HTTP API use the same port of HTTP server.
bool reuse_api_over_server_;
// If reusing, WebRTC TCP use the same port of HTTP server.
@ -150,17 +196,22 @@ private:
SrsGbListener *stream_caster_gb28181_;
#endif
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// SRT acceptors for MPEG-TS over SRT.
std::vector<SrsSrtAcceptor *> srt_acceptors_;
std::vector<SrsSrtAcceptor *>
srt_acceptors_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// WebRTC UDP listeners for RTC server functionality.
std::vector<SrsUdpMuxListener *> rtc_listeners_;
std::vector<SrsUdpMuxListener *>
rtc_listeners_;
// WebRTC session manager.
SrsRtcSessionManager *rtc_session_manager_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Signal manager which convert gignal to io message.
SrsSignalManager *signal_manager_;
// To query the latest available version of SRS.
@ -178,17 +229,19 @@ public:
SrsServer();
virtual ~SrsServer();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// When SIGTERM, SRS should do cleanup, for example,
// to stop all ingesters, cleanup HLS and dvr.
virtual void dispose();
virtual void
dispose();
// Close listener to stop accepting new connections,
// then wait and quit when all connections finished.
virtual void gracefully_dispose();
public:
// Get the HTTP API server mux.
ISrsHttpServeMux *api_server();
ISrsCommonHttpHandler *api_server();
// server startup workflow, @see run_master()
public:
@ -199,7 +252,8 @@ public:
public:
srs_error_t run();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t initialize_st();
virtual srs_error_t initialize_signal();
virtual srs_error_t listen();
@ -211,7 +265,8 @@ public:
void stop();
// interface ISrsCoroutineHandler
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t cycle();
// server utilities.
@ -231,21 +286,26 @@ public:
// @remark, maybe the HTTP RAW API will trigger the on_signal() also.
virtual void on_signal(int signo);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The server thread main cycle,
// update the global static data, for instance, the current time,
// the cpu/mem/network statistic.
virtual srs_error_t do_cycle();
virtual srs_error_t
do_cycle();
virtual srs_error_t do2_cycle();
// interface ISrsHourGlassHandler
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t setup_ticks();
virtual srs_error_t notify(int event, srs_utime_t interval, srs_utime_t tick);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Resample the server kbs.
virtual void resample_kbps();
virtual void
resample_kbps();
// SRT-related methods
virtual srs_error_t listen_srt_mpegts();
@ -253,29 +313,34 @@ private:
virtual srs_error_t accept_srt_client(srs_srt_t srt_fd);
virtual srs_error_t srt_fd_to_resource(srs_srt_t srt_fd, ISrsResource **pr);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// WebRTC-related methods
virtual srs_error_t listen_rtc_udp();
virtual srs_error_t
listen_rtc_udp();
// Interface ISrsUdpMuxHandler
public:
virtual srs_error_t on_udp_packet(SrsUdpMuxSocket *skt);
virtual srs_error_t on_udp_packet(ISrsUdpMuxSocket *skt);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t listen_rtc_api();
public:
virtual SrsRtcConnection *find_rtc_session_by_username(const std::string &ufrag);
virtual srs_error_t create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, SrsRtcConnection **psession);
virtual ISrsRtcConnection *find_rtc_session_by_username(const std::string &ufrag);
virtual srs_error_t create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, ISrsRtcConnection **psession);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t srs_update_server_statistics();
// Interface ISrsTcpHandler
public:
virtual srs_error_t on_tcp_client(ISrsListener *listener, srs_netfd_t stfd);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t do_on_tcp_client(ISrsListener *listener, srs_netfd_t &stfd);
virtual srs_error_t on_before_connection(const char *label, int fd, const std::string &ip, int port);
@ -292,13 +357,15 @@ extern SrsServer *_srs_server;
// @see: st-1.9/docs/notes.html
class SrsSignalManager : public ISrsCoroutineHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Per-process pipe which is used as a signal queue.
// Up to PIPE_BUF/sizeof(int) signals can be queued up.
int sig_pipe_[2];
srs_netfd_t signal_read_stfd_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsServer *server_;
ISrsCoroutine *trd_;
@ -313,7 +380,8 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Global singleton instance
static SrsSignalManager *instance;
// Signal catching function.
@ -325,10 +393,12 @@ private:
// @see https://github.com/ossrs/srs/issues/1635
class SrsInotifyWorker : public ISrsCoroutineHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsServer *server_;
ISrsCoroutine *trd_;
srs_netfd_t inotify_fd_;
@ -347,10 +417,12 @@ public:
// PID file manager for process identification and locking.
class SrsPidFileLocker
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsAppConfig *config_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
int pid_fd_;
std::string pid_file_;
@ -362,9 +434,11 @@ public:
// Acquire the PID file for the whole process.
virtual srs_error_t acquire();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Close the PID file descriptor.
virtual void close();
virtual void
close();
};
#endif

View File

@ -92,7 +92,15 @@ srs_error_t SrsSrtConnection::writev(const iovec *iov, int iov_size, ssize_t *nw
return srs_error_new(ERROR_SRT_CONN, "unsupport method");
}
SrsSrtRecvThread::SrsSrtRecvThread(SrsSrtConnection *srt_conn)
ISrsSrtRecvThread::ISrsSrtRecvThread()
{
}
ISrsSrtRecvThread::~ISrsSrtRecvThread()
{
}
SrsSrtRecvThread::SrsSrtRecvThread(ISrsProtocolReadWriter *srt_conn)
{
srt_conn_ = srt_conn;
trd_ = new SrsSTCoroutine("srt-recv", this, _srs_context->get_id());
@ -153,6 +161,14 @@ srs_error_t SrsSrtRecvThread::get_recv_err()
return srs_error_copy(recv_err_);
}
ISrsMpegtsSrtConnection::ISrsMpegtsSrtConnection()
{
}
ISrsMpegtsSrtConnection::~ISrsMpegtsSrtConnection()
{
}
SrsMpegtsSrtConn::SrsMpegtsSrtConn(ISrsResourceManager *resource_manager, srs_srt_t srt_fd, std::string ip, int port) : srt_source_(new SrsSrtSource())
{
// Create a identify for this client.
@ -176,6 +192,14 @@ SrsMpegtsSrtConn::SrsMpegtsSrtConn(ISrsResourceManager *resource_manager, srs_sr
req_->ip_ = ip;
security_ = new SrsSecurity();
stat_ = _srs_stat;
config_ = _srs_config;
stream_publish_tokens_ = _srs_stream_publish_tokens;
srt_sources_ = _srs_srt_sources;
live_sources_ = _srs_sources;
rtc_sources_ = _srs_rtc_sources;
hooks_ = _srs_hooks;
}
SrsMpegtsSrtConn::~SrsMpegtsSrtConn()
@ -187,6 +211,14 @@ SrsMpegtsSrtConn::~SrsMpegtsSrtConn()
srs_freep(srt_conn_);
srs_freep(req_);
srs_freep(security_);
stat_ = NULL;
config_ = NULL;
stream_publish_tokens_ = NULL;
srt_sources_ = NULL;
live_sources_ = NULL;
rtc_sources_ = NULL;
hooks_ = NULL;
}
std::string SrsMpegtsSrtConn::desc()
@ -230,9 +262,8 @@ srs_error_t SrsMpegtsSrtConn::cycle()
srs_error_t err = do_cycle();
// Update statistic when done.
SrsStatistic *stat = _srs_stat;
stat->kbps_add_delta(get_id().c_str(), delta_);
stat->on_disconnect(get_id().c_str(), err);
stat_->kbps_add_delta(get_id().c_str(), delta_);
stat_->on_disconnect(get_id().c_str(), err);
// Notify manager to remove it.
// Note that we create this object, so we use manager to remove it.
@ -262,7 +293,7 @@ srs_error_t SrsMpegtsSrtConn::do_cycle()
// If streamid empty, using default streamid instead.
if (streamid.empty()) {
streamid = _srs_config->get_srt_default_streamid();
streamid = config_->get_srt_default_streamid();
srs_warn("srt get empty streamid, using default streamid %s instead", streamid.c_str());
}
@ -273,13 +304,13 @@ srs_error_t SrsMpegtsSrtConn::do_cycle()
}
// discovery vhost, resolve the vhost from config
SrsConfDirective *parsed_vhost = _srs_config->get_vhost(req_->vhost_);
SrsConfDirective *parsed_vhost = config_->get_vhost(req_->vhost_);
if (parsed_vhost) {
req_->vhost_ = parsed_vhost->arg0();
}
bool srt_enabled = _srs_config->get_srt_enabled(req_->vhost_);
bool edge = _srs_config->get_vhost_is_edge(req_->vhost_);
bool srt_enabled = config_->get_srt_enabled(req_->vhost_);
bool edge = config_->get_vhost_is_edge(req_->vhost_);
if (srt_enabled && edge) {
srt_enabled = false;
@ -295,7 +326,7 @@ srs_error_t SrsMpegtsSrtConn::do_cycle()
// Acquire stream publish token to prevent race conditions across all protocols.
SrsStreamPublishToken *publish_token_raw = NULL;
if (mode == SrtModePush && (err = _srs_stream_publish_tokens->acquire_token(req_, publish_token_raw)) != srs_success) {
if (mode == SrtModePush && (err = stream_publish_tokens_->acquire_token(req_, publish_token_raw)) != srs_success) {
return srs_error_wrap(err, "acquire stream publish token");
}
SrsUniquePtr<SrsStreamPublishToken> publish_token(publish_token_raw);
@ -303,7 +334,7 @@ srs_error_t SrsMpegtsSrtConn::do_cycle()
srs_trace("stream publish token acquired, type=srt, url=%s", req_->get_stream_url().c_str());
}
if ((err = _srs_srt_sources->fetch_or_create(req_, srt_source_)) != srs_success) {
if ((err = srt_sources_->fetch_or_create(req_, srt_source_)) != srs_success) {
return srs_error_wrap(err, "fetch srt source");
}
@ -327,8 +358,7 @@ srs_error_t SrsMpegtsSrtConn::publishing()
srs_error_t err = srs_success;
// We must do stat the client before hooks, because hooks depends on it.
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");
}
@ -356,8 +386,7 @@ srs_error_t SrsMpegtsSrtConn::playing()
srs_error_t err = srs_success;
// We must do stat the client before hooks, because hooks depends on it.
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");
}
@ -387,19 +416,19 @@ srs_error_t SrsMpegtsSrtConn::acquire_publish()
}
// Check rtmp stream is busy.
SrsSharedPtr<SrsLiveSource> live_source = _srs_sources->fetch(req_);
SrsSharedPtr<SrsLiveSource> live_source = live_sources_->fetch(req_);
if (live_source.get() && !live_source->can_publish(false)) {
return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "live_source stream %s busy", req_->get_stream_url().c_str());
}
if ((err = _srs_sources->fetch_or_create(req_, live_source)) != srs_success) {
if ((err = live_sources_->fetch_or_create(req_, live_source)) != srs_success) {
return srs_error_wrap(err, "create source");
}
srs_assert(live_source.get() != NULL);
bool enabled_cache = _srs_config->get_gop_cache(req_->vhost_);
int gcmf = _srs_config->get_gop_cache_max_frames(req_->vhost_);
bool enabled_cache = config_->get_gop_cache(req_->vhost_);
int gcmf = config_->get_gop_cache_max_frames(req_->vhost_);
live_source->set_cache(enabled_cache);
live_source->set_gop_cache_max_frames(gcmf);
@ -408,9 +437,9 @@ srs_error_t SrsMpegtsSrtConn::acquire_publish()
// Check whether RTC stream is busy.
SrsSharedPtr<SrsRtcSource> rtc;
bool rtc_server_enabled = _srs_config->get_rtc_server_enabled();
bool rtc_enabled = _srs_config->get_rtc_enabled(req_->vhost_);
bool edge = _srs_config->get_vhost_is_edge(req_->vhost_);
bool rtc_server_enabled = config_->get_rtc_server_enabled();
bool rtc_enabled = config_->get_rtc_enabled(req_->vhost_);
bool edge = config_->get_vhost_is_edge(req_->vhost_);
if (rtc_enabled && edge) {
rtc_enabled = false;
@ -418,7 +447,7 @@ srs_error_t SrsMpegtsSrtConn::acquire_publish()
}
if (rtc_server_enabled && rtc_enabled) {
if ((err = _srs_rtc_sources->fetch_or_create(req_, rtc)) != srs_success) {
if ((err = rtc_sources_->fetch_or_create(req_, rtc)) != srs_success) {
return srs_error_wrap(err, "create source");
}
@ -430,7 +459,7 @@ srs_error_t SrsMpegtsSrtConn::acquire_publish()
// Bridge to RTMP and RTC streaming.
SrsSrtBridge *bridge = new SrsSrtBridge();
bool srt_to_rtmp = _srs_config->get_srt_to_rtmp(req_->vhost_);
bool srt_to_rtmp = config_->get_srt_to_rtmp(req_->vhost_);
if (srt_to_rtmp && edge) {
srt_to_rtmp = false;
srs_warn("disable SRT to RTMP for edge vhost=%s", req_->vhost_.c_str());
@ -440,7 +469,7 @@ srs_error_t SrsMpegtsSrtConn::acquire_publish()
bridge->enable_srt2rtmp(live_source);
}
bool rtmp_to_rtc = _srs_config->get_rtc_from_rtmp(req_->vhost_);
bool rtmp_to_rtc = config_->get_rtc_from_rtmp(req_->vhost_);
if (rtmp_to_rtc && edge) {
rtmp_to_rtc = false;
srs_warn("disable RTMP to WebRTC for edge vhost=%s", req_->vhost_.c_str());
@ -524,13 +553,13 @@ srs_error_t SrsMpegtsSrtConn::do_playing()
{
srs_error_t err = srs_success;
SrsSrtConsumer *consumer_raw = NULL;
ISrsSrtConsumer *consumer_raw = NULL;
if ((err = srt_source_->create_consumer(consumer_raw)) != srs_success) {
return srs_error_wrap(err, "create consumer, ts source=%s", req_->get_stream_url().c_str());
}
srs_assert(consumer_raw);
SrsUniquePtr<SrsSrtConsumer> consumer(consumer_raw);
SrsUniquePtr<ISrsSrtConsumer> consumer(consumer_raw);
// TODO: FIXME: Dumps the SPS/PPS from gop cache, without other frames.
if ((err = srt_source_->consumer_dumps(consumer.get())) != srs_success) {
@ -632,7 +661,7 @@ srs_error_t SrsMpegtsSrtConn::http_hooks_on_connect()
{
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;
}
@ -642,7 +671,7 @@ srs_error_t SrsMpegtsSrtConn::http_hooks_on_connect()
vector<string> hooks;
if (true) {
SrsConfDirective *conf = _srs_config->get_vhost_on_connect(req_->vhost_);
SrsConfDirective *conf = config_->get_vhost_on_connect(req_->vhost_);
if (!conf) {
return err;
@ -653,7 +682,7 @@ srs_error_t SrsMpegtsSrtConn::http_hooks_on_connect()
for (int i = 0; i < (int)hooks.size(); i++) {
std::string url = hooks.at(i);
if ((err = _srs_hooks->on_connect(url, req_)) != srs_success) {
if ((err = hooks_->on_connect(url, req_)) != srs_success) {
return srs_error_wrap(err, "srt on_connect %s", url.c_str());
}
}
@ -663,7 +692,7 @@ srs_error_t SrsMpegtsSrtConn::http_hooks_on_connect()
void SrsMpegtsSrtConn::http_hooks_on_close()
{
if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost_)) {
if (!config_->get_vhost_http_hooks_enabled(req_->vhost_)) {
return;
}
@ -673,7 +702,7 @@ void SrsMpegtsSrtConn::http_hooks_on_close()
vector<string> hooks;
if (true) {
SrsConfDirective *conf = _srs_config->get_vhost_on_close(req_->vhost_);
SrsConfDirective *conf = config_->get_vhost_on_close(req_->vhost_);
if (!conf) {
return;
@ -684,7 +713,7 @@ void SrsMpegtsSrtConn::http_hooks_on_close()
for (int i = 0; i < (int)hooks.size(); i++) {
std::string url = hooks.at(i);
_srs_hooks->on_close(url, req_, srt_conn_->get_send_bytes(), srt_conn_->get_recv_bytes());
hooks_->on_close(url, req_, srt_conn_->get_send_bytes(), srt_conn_->get_recv_bytes());
}
}
@ -692,7 +721,7 @@ srs_error_t SrsMpegtsSrtConn::http_hooks_on_publish()
{
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;
}
@ -702,7 +731,7 @@ srs_error_t SrsMpegtsSrtConn::http_hooks_on_publish()
vector<string> hooks;
if (true) {
SrsConfDirective *conf = _srs_config->get_vhost_on_publish(req_->vhost_);
SrsConfDirective *conf = config_->get_vhost_on_publish(req_->vhost_);
if (!conf) {
return err;
@ -713,7 +742,7 @@ srs_error_t SrsMpegtsSrtConn::http_hooks_on_publish()
for (int i = 0; i < (int)hooks.size(); i++) {
std::string url = hooks.at(i);
if ((err = _srs_hooks->on_publish(url, req_)) != srs_success) {
if ((err = hooks_->on_publish(url, req_)) != srs_success) {
return srs_error_wrap(err, "srt on_publish %s", url.c_str());
}
}
@ -723,7 +752,7 @@ srs_error_t SrsMpegtsSrtConn::http_hooks_on_publish()
void SrsMpegtsSrtConn::http_hooks_on_unpublish()
{
if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost_)) {
if (!config_->get_vhost_http_hooks_enabled(req_->vhost_)) {
return;
}
@ -733,7 +762,7 @@ void SrsMpegtsSrtConn::http_hooks_on_unpublish()
vector<string> hooks;
if (true) {
SrsConfDirective *conf = _srs_config->get_vhost_on_unpublish(req_->vhost_);
SrsConfDirective *conf = config_->get_vhost_on_unpublish(req_->vhost_);
if (!conf) {
return;
@ -744,7 +773,7 @@ void SrsMpegtsSrtConn::http_hooks_on_unpublish()
for (int i = 0; i < (int)hooks.size(); i++) {
std::string url = hooks.at(i);
_srs_hooks->on_unpublish(url, req_);
hooks_->on_unpublish(url, req_);
}
}
@ -752,7 +781,7 @@ srs_error_t SrsMpegtsSrtConn::http_hooks_on_play()
{
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;
}
@ -762,7 +791,7 @@ srs_error_t SrsMpegtsSrtConn::http_hooks_on_play()
vector<string> hooks;
if (true) {
SrsConfDirective *conf = _srs_config->get_vhost_on_play(req_->vhost_);
SrsConfDirective *conf = config_->get_vhost_on_play(req_->vhost_);
if (!conf) {
return err;
@ -773,7 +802,7 @@ srs_error_t SrsMpegtsSrtConn::http_hooks_on_play()
for (int i = 0; i < (int)hooks.size(); i++) {
std::string url = hooks.at(i);
if ((err = _srs_hooks->on_play(url, req_)) != srs_success) {
if ((err = hooks_->on_play(url, req_)) != srs_success) {
return srs_error_wrap(err, "srt on_play %s", url.c_str());
}
}
@ -783,7 +812,7 @@ srs_error_t SrsMpegtsSrtConn::http_hooks_on_play()
void SrsMpegtsSrtConn::http_hooks_on_stop()
{
if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost_)) {
if (!config_->get_vhost_http_hooks_enabled(req_->vhost_)) {
return;
}
@ -793,7 +822,7 @@ void SrsMpegtsSrtConn::http_hooks_on_stop()
vector<string> hooks;
if (true) {
SrsConfDirective *conf = _srs_config->get_vhost_on_stop(req_->vhost_);
SrsConfDirective *conf = config_->get_vhost_on_stop(req_->vhost_);
if (!conf) {
return;
@ -804,7 +833,7 @@ void SrsMpegtsSrtConn::http_hooks_on_stop()
for (int i = 0; i < (int)hooks.size(); i++) {
std::string url = hooks.at(i);
_srs_hooks->on_stop(url, req_);
hooks_->on_stop(url, req_);
}
return;

View File

@ -23,6 +23,17 @@ class SrsLiveSource;
class SrsSrtSource;
class SrsSrtServer;
class SrsNetworkDelta;
class ISrsNetworkDelta;
class ISrsSrtSocket;
class SrsNetworkKbps;
class ISrsSecurity;
class ISrsStatistic;
class ISrsAppConfig;
class ISrsStreamPublishTokenManager;
class ISrsSrtSourceManager;
class ISrsLiveSourceManager;
class ISrsRtcSourceManager;
class ISrsHttpHooks;
// The basic connection of SRS, for SRT based protocols,
// all srt connections accept from srt listener must extends from this base class,
@ -48,37 +59,75 @@ public:
virtual srs_error_t write(void *buf, size_t size, ssize_t *nwrite);
virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t *nwrite);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// The underlayer srt fd handler.
srs_srt_t srt_fd_;
// The underlayer srt socket.
SrsSrtSocket *srt_skt_;
ISrsSrtSocket *srt_skt_;
};
class SrsSrtRecvThread : public ISrsCoroutineHandler
// The recv thread for SRT connection.
class ISrsSrtRecvThread : public ISrsCoroutineHandler
{
public:
SrsSrtRecvThread(SrsSrtConnection *srt_conn);
ISrsSrtRecvThread();
virtual ~ISrsSrtRecvThread();
public:
};
// The recv thread for SRT connection.
class SrsSrtRecvThread : public ISrsSrtRecvThread
{
public:
SrsSrtRecvThread(ISrsProtocolReadWriter *srt_conn);
~SrsSrtRecvThread();
// Interface ISrsCoroutineHandler
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t do_cycle();
public:
srs_error_t start();
srs_error_t get_recv_err();
private:
SrsSrtConnection *srt_conn_;
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsProtocolReadWriter *srt_conn_;
ISrsCoroutine *trd_;
srs_error_t recv_err_;
};
class SrsMpegtsSrtConn : public ISrsConnection, public ISrsStartable, public ISrsCoroutineHandler, public ISrsExpire
// The SRT connection, for client to publish or play stream.
class ISrsMpegtsSrtConnection : public ISrsConnection, // It's a resource.
public ISrsStartable,
public ISrsCoroutineHandler,
public ISrsExpire
{
public:
ISrsMpegtsSrtConnection();
virtual ~ISrsMpegtsSrtConnection();
public:
};
// The SRT connection, for client to publish or play stream.
class SrsMpegtsSrtConn : public ISrsMpegtsSrtConnection
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
ISrsAppConfig *config_;
ISrsStreamPublishTokenManager *stream_publish_tokens_;
ISrsSrtSourceManager *srt_sources_;
ISrsLiveSourceManager *live_sources_;
ISrsRtcSourceManager *rtc_sources_;
ISrsHttpHooks *hooks_;
public:
SrsMpegtsSrtConn(ISrsResourceManager *resource_manager, srs_srt_t srt_fd, std::string ip, int port);
virtual ~SrsMpegtsSrtConn();
@ -102,10 +151,12 @@ public:
public:
virtual srs_error_t cycle();
protected:
// clang-format off
SRS_DECLARE_PROTECTED: // clang-format on
virtual srs_error_t do_cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t publishing();
srs_error_t playing();
srs_error_t acquire_publish();
@ -113,10 +164,12 @@ private:
srs_error_t do_publishing();
srs_error_t do_playing();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t on_srt_packet(char *buf, int nb_buf);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t http_hooks_on_connect();
void http_hooks_on_close();
srs_error_t http_hooks_on_publish();
@ -124,11 +177,12 @@ private:
srs_error_t http_hooks_on_play();
void http_hooks_on_stop();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsResourceManager *resource_manager_;
srs_srt_t srt_fd_;
SrsSrtConnection *srt_conn_;
SrsNetworkDelta *delta_;
ISrsProtocolReadWriter *srt_conn_;
ISrsNetworkDelta *delta_;
SrsNetworkKbps *kbps_;
std::string ip_;
int port_;
@ -136,7 +190,7 @@ private:
ISrsRequest *req_;
SrsSharedPtr<SrsSrtSource> srt_source_;
SrsSecurity *security_;
ISrsSecurity *security_;
};
#endif

View File

@ -28,12 +28,14 @@ public:
// Bind and listen SRT(udp) port, use handler to process the client.
class SrsSrtListener : public ISrsCoroutineHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_srt_t lfd_;
SrsSrtSocket *srt_skt_;
ISrsCoroutine *trd_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsSrtHandler *handler_;
std::string ip_;
int port_;

View File

@ -30,12 +30,14 @@ public:
// A common srt acceptor, for SRT server.
class SrsSrtAcceptor : public ISrsSrtHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string ip_;
int port_;
ISrsSrtClientHandler *srt_handler_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsSrtListener *listener_;
public:
@ -45,7 +47,8 @@ public:
public:
virtual srs_error_t listen(std::string ip, int port);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t set_srt_opt();
// Interface ISrsSrtHandler
public:
@ -69,7 +72,8 @@ public:
public:
virtual srs_error_t cycle();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsSrtPoller *srt_poller_;
ISrsCoroutine *trd_;
};

View File

@ -220,7 +220,15 @@ SrsSharedPtr<SrsSrtSource> SrsSrtSourceManager::fetch(ISrsRequest *r)
SrsSrtSourceManager *_srs_srt_sources = NULL;
SrsSrtConsumer::SrsSrtConsumer(SrsSrtSource *s)
ISrsSrtConsumer::ISrsSrtConsumer()
{
}
ISrsSrtConsumer::~ISrsSrtConsumer()
{
}
SrsSrtConsumer::SrsSrtConsumer(ISrsSrtSource *s)
{
source_ = s;
should_update_source_id_ = false;
@ -916,12 +924,22 @@ srs_error_t SrsSrtFrameBuilder::on_aac_frame(SrsTsMessage *msg, uint32_t pts, ch
return err;
}
ISrsSrtSource::ISrsSrtSource()
{
}
ISrsSrtSource::~ISrsSrtSource()
{
}
SrsSrtSource::SrsSrtSource()
{
req_ = NULL;
can_publish_ = true;
srt_bridge_ = NULL;
stream_die_at_ = 0;
stat_ = _srs_stat;
}
SrsSrtSource::~SrsSrtSource()
@ -937,6 +955,8 @@ SrsSrtSource::~SrsSrtSource()
if (cid.empty())
cid = _pre_source_id;
srs_trace("free srt source id=[%s]", cid.c_str());
stat_ = NULL;
}
// CRITICAL: This method is called AFTER the source has been added to the source pool
@ -995,10 +1015,13 @@ srs_error_t SrsSrtSource::on_source_id_changed(SrsContextId id)
_source_id = id;
// notice all consumer
std::vector<SrsSrtConsumer *>::iterator it;
std::vector<ISrsSrtConsumer *>::iterator it;
for (it = consumers_.begin(); it != consumers_.end(); ++it) {
SrsSrtConsumer *consumer = *it;
consumer->update_source_id();
ISrsSrtConsumer *consumer = *it;
SrsSrtConsumer *consumer_impl = dynamic_cast<SrsSrtConsumer *>(consumer);
if (consumer_impl) {
consumer_impl->update_source_id();
}
}
return err;
@ -1025,7 +1048,7 @@ void SrsSrtSource::set_bridge(ISrsSrtBridge *bridge)
srt_bridge_ = bridge;
}
srs_error_t SrsSrtSource::create_consumer(SrsSrtConsumer *&consumer)
srs_error_t SrsSrtSource::create_consumer(ISrsSrtConsumer *&consumer)
{
srs_error_t err = srs_success;
@ -1037,7 +1060,7 @@ srs_error_t SrsSrtSource::create_consumer(SrsSrtConsumer *&consumer)
return err;
}
srs_error_t SrsSrtSource::consumer_dumps(SrsSrtConsumer *consumer)
srs_error_t SrsSrtSource::consumer_dumps(ISrsSrtConsumer *consumer)
{
srs_error_t err = srs_success;
@ -1047,9 +1070,9 @@ srs_error_t SrsSrtSource::consumer_dumps(SrsSrtConsumer *consumer)
return err;
}
void SrsSrtSource::on_consumer_destroy(SrsSrtConsumer *consumer)
void SrsSrtSource::on_consumer_destroy(ISrsSrtConsumer *consumer)
{
std::vector<SrsSrtConsumer *>::iterator it;
std::vector<ISrsSrtConsumer *>::iterator it;
it = std::find(consumers_.begin(), consumers_.end(), consumer);
if (it != consumers_.end()) {
it = consumers_.erase(it);
@ -1080,8 +1103,7 @@ srs_error_t SrsSrtSource::on_publish()
return srs_error_wrap(err, "bridge on publish");
}
SrsStatistic *stat = _srs_stat;
stat->on_stream_publish(req_, _source_id.c_str());
stat_->on_stream_publish(req_, _source_id.c_str());
return err;
}
@ -1093,8 +1115,7 @@ void SrsSrtSource::on_unpublish()
return;
}
SrsStatistic *stat = _srs_stat;
stat->on_stream_close(req_);
stat_->on_stream_close(req_);
if (srt_bridge_) {
srt_bridge_->on_unpublish();
@ -1115,7 +1136,7 @@ srs_error_t SrsSrtSource::on_packet(SrsSrtPacket *packet)
srs_error_t err = srs_success;
for (int i = 0; i < (int)consumers_.size(); i++) {
SrsSrtConsumer *consumer = consumers_.at(i);
ISrsSrtConsumer *consumer = consumers_.at(i);
if ((err = consumer->enqueue(packet->copy())) != srs_success) {
return srs_error_wrap(err, "consume ts packet");
}

View File

@ -24,6 +24,9 @@ class SrsLiveSource;
class SrsSrtSource;
class SrsAlonePithyPrint;
class SrsSrtFrameBuilder;
class ISrsStatistic;
class ISrsSrtConsumer;
class ISrsSrtSource;
// The SRT packet with shared message.
class SrsSrtPacket
@ -45,7 +48,8 @@ public:
char *data();
int size();
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsMediaPacket *shared_buffer_;
// The size of SRT packet or SRT payload.
int actual_buffer_size_;
@ -67,7 +71,8 @@ public:
// The SRT source manager.
class SrsSrtSourceManager : public ISrsHourGlassHandler, public ISrsSrtSourceManager
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_mutex_t lock_;
std::map<std::string, SrsSharedPtr<SrsSrtSource> > pool_;
SrsHourGlass *timer_;
@ -79,7 +84,8 @@ public:
public:
virtual srs_error_t initialize();
// interface ISrsHourGlassHandler
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
virtual srs_error_t setup_ticks();
virtual srs_error_t notify(int event, srs_utime_t interval, srs_utime_t tick);
@ -97,17 +103,33 @@ public:
// Global singleton instance.
extern SrsSrtSourceManager *_srs_srt_sources;
class SrsSrtConsumer
// The SRT consumer interface.
class ISrsSrtConsumer
{
public:
SrsSrtConsumer(SrsSrtSource *source);
ISrsSrtConsumer();
virtual ~ISrsSrtConsumer();
public:
virtual srs_error_t enqueue(SrsSrtPacket *packet) = 0;
virtual srs_error_t dump_packet(SrsSrtPacket **ppkt) = 0;
virtual void wait(int nb_msgs, srs_utime_t timeout) = 0;
};
// The SRT consumer, consume packets from SRT stream source.
class SrsSrtConsumer : public ISrsSrtConsumer
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Because source references to this object, so we should directly use the source ptr.
ISrsSrtSource *source_;
public:
SrsSrtConsumer(ISrsSrtSource *source);
virtual ~SrsSrtConsumer();
private:
// Because source references to this object, so we should directly use the source ptr.
SrsSrtSource *source_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::vector<SrsSrtPacket *> queue_;
// when source id changed, notice all consumers
bool should_update_source_id_;
@ -145,7 +167,8 @@ public:
public:
virtual srs_error_t on_ts_message(SrsTsMessage *msg);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t on_ts_video_avc(SrsTsMessage *msg, SrsBuffer *avs);
srs_error_t on_ts_audio(SrsTsMessage *msg, SrsBuffer *avs);
srs_error_t check_sps_pps_change(SrsTsMessage *msg);
@ -156,10 +179,12 @@ private:
srs_error_t check_vps_sps_pps_change(SrsTsMessage *msg);
srs_error_t on_hevc_frame(SrsTsMessage *msg, std::vector<std::pair<char *, int> > &ipb_frames);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsFrameTarget *frame_target_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsTsContext *ts_ctx_;
// Record sps/pps had changed, if change, need to generate new video sh frame.
bool sps_pps_change_;
@ -173,10 +198,12 @@ private:
bool audio_sh_change_;
std::string audio_sh_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsRequest *req_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// SRT to rtmp, video stream id.
int video_streamid_;
// SRT to rtmp, audio stream id.
@ -185,9 +212,26 @@ private:
SrsAlonePithyPrint *pp_audio_duration_;
};
// A SRT source is a stream, to publish and to play with.
class SrsSrtSource : public ISrsSrtTarget
// The SRT source interface.
class ISrsSrtSource : public ISrsSrtTarget
{
public:
ISrsSrtSource();
virtual ~ISrsSrtSource();
public:
virtual SrsContextId source_id() = 0;
virtual SrsContextId pre_source_id() = 0;
virtual void on_consumer_destroy(ISrsSrtConsumer *consumer) = 0;
};
// A SRT source is a stream, to publish and to play with.
class SrsSrtSource : public ISrsSrtSource
{
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsStatistic *stat_;
public:
SrsSrtSource();
virtual ~SrsSrtSource();
@ -214,10 +258,10 @@ public:
public:
// Create consumer
// @param consumer, output the create consumer.
virtual srs_error_t create_consumer(SrsSrtConsumer *&consumer);
virtual srs_error_t create_consumer(ISrsSrtConsumer *&consumer);
// Dumps packets in cache to consumer.
virtual srs_error_t consumer_dumps(SrsSrtConsumer *consumer);
virtual void on_consumer_destroy(SrsSrtConsumer *consumer);
virtual srs_error_t consumer_dumps(ISrsSrtConsumer *consumer);
virtual void on_consumer_destroy(ISrsSrtConsumer *consumer);
// Whether we can publish stream to the source, return false if it exists.
virtual bool can_publish();
// When start publish stream.
@ -228,19 +272,21 @@ public:
public:
srs_error_t on_packet(SrsSrtPacket *packet);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Source id.
SrsContextId _source_id;
// previous source id.
SrsContextId _pre_source_id;
ISrsRequest *req_;
// To delivery packets to clients.
std::vector<SrsSrtConsumer *> consumers_;
std::vector<ISrsSrtConsumer *> consumers_;
bool can_publish_;
// The last die time, while die means neither publishers nor players.
srs_utime_t stream_die_at_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsSrtBridge *srt_bridge_;
};

View File

@ -25,7 +25,8 @@ class SrsExecutorCoroutine;
// @see https://github.com/ossrs/srs/pull/908
class SrsDummyCoroutine : public ISrsCoroutine
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsContextId cid_;
public:
@ -55,7 +56,8 @@ public:
// Please read https://github.com/ossrs/srs/issues/78
class SrsSTCoroutine : public ISrsCoroutine
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
SrsFastCoroutine *impl_;
public:
@ -96,24 +98,28 @@ public:
// High performance coroutine.
class SrsFastCoroutine : public ISrsCoroutine
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
std::string name_;
int stack_size_;
ISrsCoroutineHandler *handler_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_thread_t trd_;
SrsContextId cid_;
srs_error_t trd_err_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
bool started_;
bool interrupted_;
bool disposed_;
// Cycle done, no need to interrupt it.
bool cycle_done_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
// Sub state in disposed, we need to wait for thread to quit.
bool stopping_;
SrsContextId stopping_cid_;
@ -140,7 +146,8 @@ public:
const SrsContextId &cid();
virtual void set_cid(const SrsContextId &cid);
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
srs_error_t cycle();
static void *pfn(void *arg);
};
@ -148,7 +155,8 @@ private:
// Like goroutine sync.WaitGroup.
class SrsWaitGroup
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
int nn_;
srs_cond_t done_;
@ -196,15 +204,22 @@ public:
// srs_freep(executor);
// return err;
// }
class SrsExecutorCoroutine : public ISrsResource, public ISrsStartable, public ISrsInterruptable, public ISrsContextIdSetter, public ISrsContextIdGetter, public ISrsCoroutineHandler
class SrsExecutorCoroutine : public ISrsResource, // It's a resource.
public ISrsStartable,
public ISrsInterruptable,
public ISrsContextIdSetter,
public ISrsContextIdGetter,
public ISrsCoroutineHandler
{
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsResourceManager *manager_;
ISrsResource *resource_;
ISrsCoroutineHandler *handler_;
ISrsExecutorHandler *callback_;
private:
// clang-format off
SRS_DECLARE_PRIVATE: // clang-format on
ISrsCoroutine *trd_;
public:

Some files were not shown because too many files have changed in this diff Show More