├── Makefile ├── README.md ├── VS2017 ├── rtsp.sln ├── rtsp.vcxproj ├── rtsp.vcxproj.filters ├── rtsp.vcxproj.user └── x64 │ ├── Debug │ ├── rtsp.Build.CppClean.log │ ├── rtsp.log │ └── rtsp.vcxproj.FileListAbsolute.txt │ └── Release │ ├── rtsp.Build.CppClean.log │ ├── rtsp.log │ └── rtsp.vcxproj.FileListAbsolute.txt ├── example ├── rtsp_h264_file.cpp ├── rtsp_h265.cpp ├── rtsp_pusher.cpp └── rtsp_server.cpp ├── pic └── 1.pic.JPG ├── src ├── 3rdpart │ └── md5 │ │ ├── COPYING │ │ └── md5.hpp ├── net │ ├── Acceptor.cpp │ ├── Acceptor.h │ ├── BufferReader.cpp │ ├── BufferReader.h │ ├── BufferWriter.cpp │ ├── BufferWriter.h │ ├── Channel.h │ ├── EpollTaskScheduler.cpp │ ├── EpollTaskScheduler.h │ ├── EventLoop.cpp │ ├── EventLoop.h │ ├── Logger.cpp │ ├── Logger.h │ ├── MemoryManager.cpp │ ├── MemoryManager.h │ ├── NetInterface.cpp │ ├── NetInterface.h │ ├── Pipe.cpp │ ├── Pipe.h │ ├── RingBuffer.h │ ├── SelectTaskScheduler.cpp │ ├── SelectTaskScheduler.h │ ├── Socket.h │ ├── SocketUtil.cpp │ ├── SocketUtil.h │ ├── TaskScheduler.cpp │ ├── TaskScheduler.h │ ├── TcpConnection.cpp │ ├── TcpConnection.h │ ├── TcpServer.cpp │ ├── TcpServer.h │ ├── TcpSocket.cpp │ ├── TcpSocket.h │ ├── ThreadSafeQueue.h │ ├── Timer.cpp │ ├── Timer.h │ ├── Timestamp.cpp │ ├── Timestamp.h │ └── log.h └── xop │ ├── AACSource.cpp │ ├── AACSource.h │ ├── DigestAuthentication.cpp │ ├── DigestAuthentication.h │ ├── G711ASource.cpp │ ├── G711ASource.h │ ├── H264Parser.cpp │ ├── H264Parser.h │ ├── H264Source.cpp │ ├── H264Source.h │ ├── H265Source.cpp │ ├── H265Source.h │ ├── MediaSession.cpp │ ├── MediaSession.h │ ├── MediaSource.h │ ├── RtpConnection.cpp │ ├── RtpConnection.h │ ├── RtspConnection.cpp │ ├── RtspConnection.h │ ├── RtspMessage.cpp │ ├── RtspMessage.h │ ├── RtspPusher.cpp │ ├── RtspPusher.h │ ├── RtspServer.cpp │ ├── RtspServer.h │ ├── media.h │ ├── rtp.h │ └── rtsp.h └── test.h265 /Makefile: -------------------------------------------------------------------------------- 1 | DEUBG = -D_DEBUG 2 | 3 | TARGET1 = rtsp_server 4 | TARGET2 = rtsp_pusher 5 | TARGET3 = rtsp_h264_file 6 | 7 | OBJS_PATH = objs 8 | 9 | CROSS_COMPILE = 10 | CXX = $(CROSS_COMPILE)g++ 11 | CC = $(CROSS_COMPILE)gcc 12 | STRIP = $(CROSS_COMPILE)strip 13 | 14 | INC = -I$(shell pwd)/src/ -I$(shell pwd)/src/net -I$(shell pwd)/src/xop -I$(shell pwd)/src/3rdpart 15 | LIB = 16 | 17 | LD_FLAGS = -lrt -pthread -lpthread -ldl -lm $(DEBUG) 18 | CXX_FLAGS = -std=c++11 19 | 20 | O_FLAG = -O2 21 | 22 | SRC1 = $(notdir $(wildcard ./src/net/*.cpp)) 23 | OBJS1 = $(patsubst %.cpp,$(OBJS_PATH)/%.o,$(SRC1)) 24 | 25 | SRC2 = $(notdir $(wildcard ./src/xop/*.cpp)) 26 | OBJS2 = $(patsubst %.cpp,$(OBJS_PATH)/%.o,$(SRC2)) 27 | 28 | SRC3 = $(notdir $(wildcard ./example/rtsp_server.cpp)) 29 | OBJS3 = $(patsubst %.cpp,$(OBJS_PATH)/%.o,$(SRC3)) 30 | 31 | SRC4 = $(notdir $(wildcard ./example/rtsp_pusher.cpp)) 32 | OBJS4 = $(patsubst %.cpp,$(OBJS_PATH)/%.o,$(SRC4)) 33 | 34 | SRC5 = $(notdir $(wildcard ./example/rtsp_h264_file.cpp)) 35 | OBJS5 = $(patsubst %.cpp,$(OBJS_PATH)/%.o,$(SRC5)) 36 | 37 | all: BUILD_DIR $(TARGET1) $(TARGET2) $(TARGET3) 38 | 39 | BUILD_DIR: 40 | @-mkdir -p $(OBJS_PATH) 41 | 42 | $(TARGET1) : $(OBJS1) $(OBJS2) $(OBJS3) 43 | $(CXX) $^ -o $@ $(CFLAGS) $(LD_FLAGS) $(CXX_FLAGS) 44 | 45 | $(TARGET2) : $(OBJS1) $(OBJS2) $(OBJS4) 46 | $(CXX) $^ -o $@ $(CFLAGS) $(LD_FLAGS) $(CXX_FLAGS) 47 | 48 | $(TARGET3) : $(OBJS1) $(OBJS2) $(OBJS5) 49 | $(CXX) $^ -o $@ $(CFLAGS) $(LD_FLAGS) $(CXX_FLAGS) 50 | 51 | $(OBJS_PATH)/%.o : ./example/%.cpp 52 | $(CXX) -c $< -o $@ $(CXX_FLAGS) $(INC) 53 | $(OBJS_PATH)/%.o : ./src/net/%.cpp 54 | $(CXX) -c $< -o $@ $(CXX_FLAGS) $(INC) 55 | $(OBJS_PATH)/%.o : ./src/xop/%.cpp 56 | $(CXX) -c $< -o $@ $(CXX_FLAGS) $(INC) 57 | 58 | clean: 59 | -rm -rf $(OBJS_PATH) $(TARGET1) $(TARGET2) $(TARGET3) 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rtspServerH265 2 | Use rtsp protocol to push local H265 video encoding files 3 | 项目介绍 4 | - 5 | * C++11实现的RTSP服务器和推流器。主要完成对H265视频编码文件的RTSP推流 6 | 7 | 使用说明 8 | - 9 | * 1.编译并运行程序; 10 | * 2.打开VLC软件,在媒体-->打开网络串流输入:rtsp://127.0.0.1:554/codec2021 ,点VLC的播放按钮 11 | * 3.即可在VLC软件看到本地H265码流文件的画面 12 | 13 | 编译环境 14 | - 15 | * Linux: gcc 4.8 16 | * Windows: vs2017以上 17 | 18 | 感谢 19 | - 20 | * https://github.com/PHZ76/RtspServer 21 | 22 | 23 | 联系方式 24 | - 25 | * 21510025@zju.edu.cn 26 | -------------------------------------------------------------------------------- /VS2017/rtsp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.645 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rtsp", "rtsp.vcxproj", "{EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Debug|x64.ActiveCfg = Debug|x64 17 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Debug|x64.Build.0 = Debug|x64 18 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Debug|x86.ActiveCfg = Debug|Win32 19 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Debug|x86.Build.0 = Debug|Win32 20 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Release|x64.ActiveCfg = Release|x64 21 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Release|x64.Build.0 = Release|x64 22 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Release|x86.ActiveCfg = Release|Win32 23 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {6644BEFC-17EF-4D94-9620-AC36DCD57B40} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /VS2017/rtsp.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {EC47BBA1-2E43-41D0-9120-DCCFF31BB8E3} 24 | rtsp 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v142 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v142 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v142 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v142 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | Disabled 77 | true 78 | true 79 | $(ProjectDir)..\src;$(ProjectDir)..\src\3rdpart;%(AdditionalIncludeDirectories) 80 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 81 | 82 | 83 | 84 | 85 | Level3 86 | Disabled 87 | true 88 | true 89 | $(ProjectDir)..\src;$(ProjectDir)..\src\3rdpart;%(AdditionalIncludeDirectories) 90 | _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;%(PreprocessorDefinitions) 91 | 92 | 93 | %(AdditionalDependencies) 94 | 95 | 96 | 97 | 98 | 99 | 100 | Level3 101 | MaxSpeed 102 | true 103 | true 104 | true 105 | true 106 | $(ProjectDir)..\src;$(ProjectDir)..\src\3rdpart;%(AdditionalIncludeDirectories) 107 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 108 | 109 | 110 | true 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | MaxSpeed 118 | true 119 | true 120 | true 121 | true 122 | $(ProjectDir)..\src;$(ProjectDir)..\src\3rdpart;%(AdditionalIncludeDirectories) 123 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 124 | 125 | 126 | true 127 | true 128 | 129 | 130 | %(AdditionalDependencies) 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /VS2017/rtsp.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {93fd1892-c18d-4be0-8936-a01a836e79c7} 18 | 19 | 20 | {f0200b67-2e3e-4d18-92fb-6a9ef1d1d4d3} 21 | 22 | 23 | {dcb79e29-beb4-4205-a5a7-9e8b373ac709} 24 | 25 | 26 | {bd328520-ced7-4f34-a7db-68df5cb07909} 27 | 28 | 29 | 30 | 31 | 源文件\xop 32 | 33 | 34 | 源文件\xop 35 | 36 | 37 | 源文件\xop 38 | 39 | 40 | 源文件\xop 41 | 42 | 43 | 源文件\xop 44 | 45 | 46 | 源文件\xop 47 | 48 | 49 | 源文件\xop 50 | 51 | 52 | 源文件\xop 53 | 54 | 55 | 源文件\xop 56 | 57 | 58 | 源文件\xop 59 | 60 | 61 | 源文件\xop 62 | 63 | 64 | 源文件\net 65 | 66 | 67 | 源文件\net 68 | 69 | 70 | 源文件\net 71 | 72 | 73 | 源文件\net 74 | 75 | 76 | 源文件\net 77 | 78 | 79 | 源文件\net 80 | 81 | 82 | 源文件\net 83 | 84 | 85 | 源文件\net 86 | 87 | 88 | 源文件\net 89 | 90 | 91 | 源文件\net 92 | 93 | 94 | 源文件\net 95 | 96 | 97 | 源文件\net 98 | 99 | 100 | 源文件\net 101 | 102 | 103 | 源文件\net 104 | 105 | 106 | 源文件\net 107 | 108 | 109 | 源文件\net 110 | 111 | 112 | 源文件\net 113 | 114 | 115 | 源文件\xop 116 | 117 | 118 | 源文件 119 | 120 | 121 | 122 | 123 | 源文件\xop 124 | 125 | 126 | 源文件\xop 127 | 128 | 129 | 源文件\xop 130 | 131 | 132 | 源文件\xop 133 | 134 | 135 | 源文件\xop 136 | 137 | 138 | 源文件\xop 139 | 140 | 141 | 源文件\xop 142 | 143 | 144 | 源文件\xop 145 | 146 | 147 | 源文件\xop 148 | 149 | 150 | 源文件\xop 151 | 152 | 153 | 源文件\xop 154 | 155 | 156 | 源文件\xop 157 | 158 | 159 | 源文件\xop 160 | 161 | 162 | 源文件\xop 163 | 164 | 165 | 源文件\xop 166 | 167 | 168 | 源文件\net 169 | 170 | 171 | 源文件\net 172 | 173 | 174 | 源文件\net 175 | 176 | 177 | 源文件\net 178 | 179 | 180 | 源文件\net 181 | 182 | 183 | 源文件\net 184 | 185 | 186 | 源文件\net 187 | 188 | 189 | 源文件\net 190 | 191 | 192 | 源文件\net 193 | 194 | 195 | 源文件\net 196 | 197 | 198 | 源文件\net 199 | 200 | 201 | 源文件\net 202 | 203 | 204 | 源文件\net 205 | 206 | 207 | 源文件\net 208 | 209 | 210 | 源文件\net 211 | 212 | 213 | 源文件\net 214 | 215 | 216 | 源文件\net 217 | 218 | 219 | 源文件\net 220 | 221 | 222 | 源文件\net 223 | 224 | 225 | 源文件\net 226 | 227 | 228 | 源文件\net 229 | 230 | 231 | 源文件\net 232 | 233 | 234 | 源文件\xop 235 | 236 | 237 | 源文件\3rdpart\md5 238 | 239 | 240 | -------------------------------------------------------------------------------- /VS2017/rtsp.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(ProjectDir)..\ 5 | WindowsLocalDebugger 6 | test.h264 7 | 8 | 9 | $(ProjectDir)..\ 10 | WindowsLocalDebugger 11 | test.h264 12 | 13 | 14 | $(ProjectDir)..\ 15 | WindowsLocalDebugger 16 | test.h265 17 | 18 | 19 | $(ProjectDir)..\ 20 | WindowsLocalDebugger 21 | test.h265 22 | 23 | -------------------------------------------------------------------------------- /VS2017/x64/Debug/rtsp.Build.CppClean.log: -------------------------------------------------------------------------------- 1 | f:\rtspserver-master\vs2017\x64\debug\vc142.pdb 2 | f:\rtspserver-master\vs2017\x64\debug\vc142.idb 3 | f:\rtspserver-master\vs2017\x64\debug\digestauthentication.obj 4 | f:\rtspserver-master\vs2017\x64\debug\aacsource.obj 5 | f:\rtspserver-master\vs2017\x64\debug\timestamp.obj 6 | f:\rtspserver-master\vs2017\x64\debug\timer.obj 7 | f:\rtspserver-master\vs2017\x64\debug\tcpsocket.obj 8 | f:\rtspserver-master\vs2017\x64\debug\tcpserver.obj 9 | f:\rtspserver-master\vs2017\x64\debug\tcpconnection.obj 10 | f:\rtspserver-master\vs2017\x64\debug\taskscheduler.obj 11 | f:\rtspserver-master\vs2017\x64\debug\socketutil.obj 12 | f:\rtspserver-master\vs2017\x64\debug\selecttaskscheduler.obj 13 | f:\rtspserver-master\vs2017\x64\debug\pipe.obj 14 | f:\rtspserver-master\vs2017\x64\debug\netinterface.obj 15 | f:\rtspserver-master\vs2017\x64\debug\memorymanager.obj 16 | f:\rtspserver-master\vs2017\x64\debug\logger.obj 17 | f:\rtspserver-master\vs2017\x64\debug\eventloop.obj 18 | f:\rtspserver-master\vs2017\x64\debug\epolltaskscheduler.obj 19 | f:\rtspserver-master\vs2017\x64\debug\bufferwriter.obj 20 | f:\rtspserver-master\vs2017\x64\debug\bufferreader.obj 21 | f:\rtspserver-master\vs2017\x64\debug\acceptor.obj 22 | f:\rtspserver-master\vs2017\x64\debug\rtsp_h265.obj 23 | f:\rtspserver-master\vs2017\x64\debug\rtspserver.obj 24 | f:\rtspserver-master\vs2017\x64\debug\rtsppusher.obj 25 | f:\rtspserver-master\vs2017\x64\debug\rtspmessage.obj 26 | f:\rtspserver-master\vs2017\x64\debug\rtspconnection.obj 27 | f:\rtspserver-master\vs2017\x64\debug\rtpconnection.obj 28 | f:\rtspserver-master\vs2017\x64\debug\mediasession.obj 29 | f:\rtspserver-master\vs2017\x64\debug\h265source.obj 30 | f:\rtspserver-master\vs2017\x64\debug\h264source.obj 31 | f:\rtspserver-master\vs2017\x64\debug\h264parser.obj 32 | f:\rtspserver-master\vs2017\x64\debug\g711asource.obj 33 | f:\rtspserver-master\vs2017\x64\debug\rtsp.exe 34 | f:\rtspserver-master\vs2017\x64\debug\rtsp.ilk 35 | f:\rtspserver-master\vs2017\x64\debug\rtsp.pdb 36 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\aacsource.obj 37 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\acceptor.obj 38 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\bufferreader.obj 39 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\bufferwriter.obj 40 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\digestauthentication.obj 41 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\epolltaskscheduler.obj 42 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\eventloop.obj 43 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\g711asource.obj 44 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\h264parser.obj 45 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\h264source.obj 46 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\h265source.obj 47 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\logger.obj 48 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\mediasession.obj 49 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\memorymanager.obj 50 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\netinterface.obj 51 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\pipe.obj 52 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtpconnection.obj 53 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtspconnection.obj 54 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtspmessage.obj 55 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsppusher.obj 56 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtspserver.obj 57 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp_h265.obj 58 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\selecttaskscheduler.obj 59 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\socketutil.obj 60 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\taskscheduler.obj 61 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\tcpconnection.obj 62 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\tcpserver.obj 63 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\tcpsocket.obj 64 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\timer.obj 65 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\timestamp.obj 66 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.ilk 67 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\vc142.idb 68 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.pdb 69 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\vc142.pdb 70 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.exe 71 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.tlog\cl.command.1.tlog 72 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.tlog\cl.read.1.tlog 73 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.tlog\cl.write.1.tlog 74 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.tlog\link.command.1.tlog 75 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.tlog\link.read.1.tlog 76 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\debug\rtsp.tlog\link.write.1.tlog 77 | -------------------------------------------------------------------------------- /VS2017/x64/Debug/rtsp.log: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /VS2017/x64/Debug/rtsp.vcxproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | C:\Users\84038\Desktop\RtspServer-master\VS2017\x64\Debug\rtsp.exe 2 | C:\Users\84038\Desktop\RtspServer-master\VS2017\x64\Debug\rtsp.pdb 3 | D:\fxx\桌面\FAN\7月\RtspServer-master\VS2017\x64\Debug\rtsp.exe 4 | D:\fxx\桌面\FAN\7月\RtspServer-master\VS2017\x64\Debug\rtsp.pdb 5 | F:\RtspServer-master\VS2017\x64\Debug\rtsp.exe 6 | F:\RtspServer-master\VS2017\x64\Debug\rtsp.pdb 7 | -------------------------------------------------------------------------------- /VS2017/x64/Release/rtsp.Build.CppClean.log: -------------------------------------------------------------------------------- 1 | f:\rtspserver-master\vs2017\x64\release\vc142.pdb 2 | f:\rtspserver-master\vs2017\x64\release\x265_encode.obj 3 | f:\rtspserver-master\vs2017\x64\release\rtsp_h265.obj 4 | f:\rtspserver-master\vs2017\x64\release\digestauthentication.obj 5 | f:\rtspserver-master\vs2017\x64\release\aacsource.obj 6 | f:\rtspserver-master\vs2017\x64\release\timestamp.obj 7 | f:\rtspserver-master\vs2017\x64\release\timer.obj 8 | f:\rtspserver-master\vs2017\x64\release\tcpsocket.obj 9 | f:\rtspserver-master\vs2017\x64\release\tcpserver.obj 10 | f:\rtspserver-master\vs2017\x64\release\tcpconnection.obj 11 | f:\rtspserver-master\vs2017\x64\release\taskscheduler.obj 12 | f:\rtspserver-master\vs2017\x64\release\socketutil.obj 13 | f:\rtspserver-master\vs2017\x64\release\selecttaskscheduler.obj 14 | f:\rtspserver-master\vs2017\x64\release\pipe.obj 15 | f:\rtspserver-master\vs2017\x64\release\netinterface.obj 16 | f:\rtspserver-master\vs2017\x64\release\memorymanager.obj 17 | f:\rtspserver-master\vs2017\x64\release\logger.obj 18 | f:\rtspserver-master\vs2017\x64\release\eventloop.obj 19 | f:\rtspserver-master\vs2017\x64\release\epolltaskscheduler.obj 20 | f:\rtspserver-master\vs2017\x64\release\bufferwriter.obj 21 | f:\rtspserver-master\vs2017\x64\release\bufferreader.obj 22 | f:\rtspserver-master\vs2017\x64\release\acceptor.obj 23 | f:\rtspserver-master\vs2017\x64\release\rtspserver.obj 24 | f:\rtspserver-master\vs2017\x64\release\rtsppusher.obj 25 | f:\rtspserver-master\vs2017\x64\release\rtspmessage.obj 26 | f:\rtspserver-master\vs2017\x64\release\rtspconnection.obj 27 | f:\rtspserver-master\vs2017\x64\release\rtpconnection.obj 28 | f:\rtspserver-master\vs2017\x64\release\mediasession.obj 29 | f:\rtspserver-master\vs2017\x64\release\h265source.obj 30 | f:\rtspserver-master\vs2017\x64\release\h264source.obj 31 | f:\rtspserver-master\vs2017\x64\release\h264parser.obj 32 | f:\rtspserver-master\vs2017\x64\release\g711asource.obj 33 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\vc142.pdb 34 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\digestauthentication.obj 35 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\aacsource.obj 36 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\timestamp.obj 37 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\timer.obj 38 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\tcpsocket.obj 39 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\tcpserver.obj 40 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\tcpconnection.obj 41 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\taskscheduler.obj 42 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\socketutil.obj 43 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\selecttaskscheduler.obj 44 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\pipe.obj 45 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\netinterface.obj 46 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\memorymanager.obj 47 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\logger.obj 48 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\eventloop.obj 49 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\epolltaskscheduler.obj 50 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\bufferwriter.obj 51 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\bufferreader.obj 52 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\acceptor.obj 53 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp_h265.obj 54 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtspserver.obj 55 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsppusher.obj 56 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtspmessage.obj 57 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtspconnection.obj 58 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtpconnection.obj 59 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\mediasession.obj 60 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\h265source.obj 61 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\h264source.obj 62 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\h264parser.obj 63 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\g711asource.obj 64 | f:\rtspserver-master\vs2017\x64\release\rtsp.exe 65 | f:\rtspserver-master\vs2017\x64\release\rtsp.pdb 66 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.exe 67 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.pdb 68 | f:\rtspserver-master\vs2017\x64\release\rtsp.ipdb 69 | f:\rtspserver-master\vs2017\x64\release\rtsp.iobj 70 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.ipdb 71 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.iobj 72 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\x265_encode.obj 73 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.tlog\cl.command.1.tlog 74 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.tlog\cl.read.1.tlog 75 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.tlog\cl.write.1.tlog 76 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.tlog\link.command.1.tlog 77 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.tlog\link.read.1.tlog 78 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.tlog\link.write.1.tlog 79 | c:\users\84038\desktop\rtspserverh265\vs2017\x64\release\rtsp.tlog\rtsp.write.1u.tlog 80 | -------------------------------------------------------------------------------- /VS2017/x64/Release/rtsp.log: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /VS2017/x64/Release/rtsp.vcxproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- 1 | F:\RtspServer-master\VS2017\x64\Release\rtsp.exe 2 | -------------------------------------------------------------------------------- /example/rtsp_h264_file.cpp: -------------------------------------------------------------------------------- 1 | // RTSP Server 2 | 3 | #include "xop/RtspServer.h" 4 | #include "net/Timer.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class H264File 11 | { 12 | public: 13 | H264File(int buf_size=500000); 14 | ~H264File(); 15 | 16 | bool Open(const char *path); 17 | void Close(); 18 | 19 | bool IsOpened() const 20 | { return (m_file != NULL); } 21 | 22 | int ReadFrame(char* in_buf, int in_buf_size, bool* end); 23 | 24 | private: 25 | FILE *m_file = NULL; 26 | char *m_buf = NULL; 27 | int m_buf_size = 0; 28 | int m_bytes_used = 0; 29 | int m_count = 0; 30 | }; 31 | 32 | void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, H264File* h264_file); 33 | 34 | #if 0 35 | int main(int argc, char **argv) 36 | { 37 | if(argc != 2) { 38 | printf("Usage: %s test.h264\n", argv[0]); 39 | return 0; 40 | } 41 | 42 | H264File h264_file; 43 | if(!h264_file.Open(argv[1])) { 44 | printf("Open %s failed.\n", argv[1]); 45 | return 0; 46 | } 47 | 48 | std::string suffix = "live"; 49 | std::string ip = "127.0.0.1"; 50 | std::string port = "554"; 51 | std::string rtsp_url = "rtsp://" + ip + ":" + port + "/" + suffix; 52 | 53 | std::shared_ptr event_loop(new xop::EventLoop()); 54 | std::shared_ptr server = xop::RtspServer::Create(event_loop.get()); 55 | 56 | if (!server->Start("0.0.0.0", atoi(port.c_str()))) { 57 | printf("RTSP Server listen on %s failed.\n", port.c_str()); 58 | return 0; 59 | } 60 | 61 | #ifdef AUTH_CONFIG 62 | server->SetAuthConfig("-_-", "admin", "12345"); 63 | #endif 64 | 65 | xop::MediaSession *session = xop::MediaSession::CreateNew("live"); 66 | session->AddSource(xop::channel_0, xop::H264Source::CreateNew()); 67 | //session->StartMulticast(); 68 | session->SetNotifyCallback([] (xop::MediaSessionId session_id, uint32_t clients){ 69 | std::cout << "The number of rtsp clients: " << clients << std::endl; 70 | }); 71 | 72 | xop::MediaSessionId session_id = server->AddSession(session); 73 | 74 | std::thread t1(SendFrameThread, server.get(), session_id, &h264_file); 75 | t1.detach(); 76 | 77 | std::cout << "Play URL: " << rtsp_url << std::endl; 78 | 79 | while (1) { 80 | xop::Timer::Sleep(100); 81 | } 82 | 83 | getchar(); 84 | return 0; 85 | } 86 | #endif 87 | 88 | void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, H264File* h264_file) 89 | { 90 | int buf_size = 2000000; 91 | std::unique_ptr frame_buf(new uint8_t[buf_size]); 92 | 93 | while(1) { 94 | bool end_of_frame = false; 95 | int frame_size = h264_file->ReadFrame((char*)frame_buf.get(), buf_size, &end_of_frame); 96 | if(frame_size > 0) { 97 | xop::AVFrame videoFrame = {0}; 98 | videoFrame.type = 0; 99 | videoFrame.size = frame_size; 100 | videoFrame.timestamp = xop::H264Source::GetTimestamp(); 101 | videoFrame.buffer.reset(new uint8_t[videoFrame.size]); 102 | memcpy(videoFrame.buffer.get(), frame_buf.get(), videoFrame.size); 103 | rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame); 104 | } 105 | else { 106 | break; 107 | } 108 | 109 | xop::Timer::Sleep(40); 110 | }; 111 | } 112 | 113 | H264File::H264File(int buf_size) 114 | : m_buf_size(buf_size) 115 | { 116 | m_buf = new char[m_buf_size]; 117 | } 118 | 119 | H264File::~H264File() 120 | { 121 | delete m_buf; 122 | } 123 | 124 | bool H264File::Open(const char *path) 125 | { 126 | m_file = fopen(path, "rb"); 127 | if(m_file == NULL) 128 | { 129 | return false; 130 | } 131 | 132 | return true; 133 | } 134 | 135 | void H264File::Close() 136 | { 137 | if(m_file) { 138 | fclose(m_file); 139 | m_file = NULL; 140 | m_count = 0; 141 | m_bytes_used = 0; 142 | } 143 | } 144 | 145 | int H264File::ReadFrame(char* in_buf, int in_buf_size, bool* end) 146 | { 147 | if(m_file == NULL) { 148 | return -1; 149 | } 150 | 151 | int bytes_read = (int)fread(m_buf, 1, m_buf_size, m_file); 152 | if(bytes_read == 0) 153 | { 154 | fseek(m_file, 0, SEEK_SET); 155 | m_count = 0; 156 | m_bytes_used = 0; 157 | bytes_read = (int)fread(m_buf, 1, m_buf_size, m_file); 158 | if(bytes_read == 0) 159 | { 160 | this->Close(); 161 | return -1; 162 | } 163 | } 164 | 165 | bool is_find_start = false, is_find_end = false; 166 | int i = 0, start_code = 3; 167 | *end = false; 168 | 169 | for (i=0; i0) { 211 | flag = is_find_end = true; 212 | i = bytes_read; 213 | *end = true; 214 | } 215 | 216 | if(!is_find_start || !is_find_end) { 217 | this->Close(); 218 | return -1; 219 | } 220 | 221 | int size = (i<=in_buf_size ? i : in_buf_size); 222 | memcpy(in_buf, m_buf, size); 223 | 224 | if(!flag) { 225 | m_count += 1; 226 | m_bytes_used += i; 227 | } 228 | else { 229 | m_count = 0; 230 | m_bytes_used = 0; 231 | } 232 | 233 | fseek(m_file, m_bytes_used, SEEK_SET); 234 | return size; 235 | } 236 | 237 | 238 | -------------------------------------------------------------------------------- /example/rtsp_h265.cpp: -------------------------------------------------------------------------------- 1 | // RTSP Server 2 | #include "xop/RtspServer.h" 3 | #include "net/Timer.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define MAX_FRAME_SIZE 500000 10 | 11 | class H265File 12 | { 13 | public: 14 | H265File(int buf_size = MAX_FRAME_SIZE); 15 | ~H265File(); 16 | 17 | bool Open(const char *path); 18 | void Close(); 19 | 20 | bool IsOpened() const 21 | { 22 | return (m_file != NULL); 23 | } 24 | 25 | int ReadFrame(char* in_buf, int in_buf_size, bool* end); 26 | 27 | private: 28 | FILE *m_file = NULL; 29 | char *m_buf = NULL; 30 | int m_buf_size = 0; 31 | int m_bytes_used = 0; 32 | int m_count = 0; 33 | }; 34 | 35 | 36 | void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, H265File* h265_file) 37 | { 38 | int buf_size = MAX_FRAME_SIZE; 39 | std::unique_ptr frame_buf(new uint8_t[buf_size]); 40 | 41 | while(1) 42 | { 43 | bool end_of_frame = false; 44 | int frame_size = h265_file->ReadFrame((char*)frame_buf.get(), buf_size, &end_of_frame); 45 | //fprintf(stderr,"send stream %d bits\n", frame_size << 3); 46 | 47 | if(frame_size > 0) 48 | { 49 | xop::AVFrame videoFrame = {0}; 50 | videoFrame.type = 0; 51 | videoFrame.size = frame_size; 52 | videoFrame.timestamp = xop::H265Source::GetTimestamp(); 53 | videoFrame.buffer.reset(new uint8_t[videoFrame.size]); 54 | memcpy(videoFrame.buffer.get(), frame_buf.get(), videoFrame.size); 55 | rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame); 56 | } 57 | else 58 | { 59 | fprintf(stderr, "send stream size is %d\n", frame_size); 60 | break; 61 | } 62 | xop::Timer::Sleep(40); 63 | }; 64 | 65 | return; 66 | } 67 | 68 | 69 | H265File::H265File(int buf_size) 70 | : m_buf_size(buf_size) 71 | { 72 | m_buf = new char[m_buf_size]; 73 | } 74 | 75 | H265File::~H265File() 76 | { 77 | delete m_buf; 78 | } 79 | 80 | bool H265File::Open(const char *path) 81 | { 82 | m_file = fopen(path, "rb"); 83 | if(m_file == NULL) 84 | { 85 | return false; 86 | } 87 | return true; 88 | } 89 | 90 | void H265File::Close() 91 | { 92 | if(m_file) 93 | { 94 | fclose(m_file); 95 | m_file = NULL; 96 | m_count = 0; 97 | m_bytes_used = 0; 98 | } 99 | } 100 | 101 | int H265File::ReadFrame(char* in_buf, int in_buf_size, bool* end) 102 | { 103 | if(m_file == NULL) 104 | { 105 | return -1; 106 | } 107 | 108 | int bytes_read = (int)fread(m_buf, 1, m_buf_size, m_file); 109 | if(bytes_read == 0) 110 | { 111 | fseek(m_file, 0, SEEK_SET); 112 | m_count = 0; 113 | m_bytes_used = 0; 114 | bytes_read = (int)fread(m_buf, 1, m_buf_size, m_file); 115 | if(bytes_read == 0) 116 | { 117 | this->Close(); 118 | return -1; 119 | } 120 | } 121 | 122 | bool is_find_start = false; 123 | bool is_find_end = false; 124 | int i = 0, start_code = 3; 125 | *end = false; 126 | 127 | int code = 0; 128 | for (i = 0; i < bytes_read - 5; i++) 129 | { 130 | if(m_buf[i] == 0 && m_buf[i + 1] == 0 && m_buf[i + 2] == 1) 131 | { 132 | start_code = 3; 133 | } 134 | else if(m_buf[i] == 0 && m_buf[i + 1] == 0 && m_buf[i + 2] == 0 && m_buf[i + 3] == 1) 135 | { 136 | start_code = 4; 137 | } 138 | else 139 | { 140 | continue; 141 | } 142 | 143 | code = m_buf[i + start_code]; 144 | if (((code & 0x7E) >> 1 == 32) || ((code & 0x7E) >> 1 == 33) || 145 | ((code & 0x7E) >> 1 == 34) || ((code & 0x7E) >> 1 == 19) || 146 | ((code & 0x7E) >> 1 == 1) || ((code & 0x7E) >> 1 == 20) || 147 | ((code & 0x7E) >> 1 == 39)) 148 | { 149 | is_find_start = true; 150 | i += start_code; 151 | break; 152 | } 153 | } 154 | 155 | for (; i < bytes_read - 5; i++) 156 | { 157 | if(m_buf[i] == 0 && m_buf[i + 1] == 0 && m_buf[i + 2] == 1) 158 | { 159 | start_code = 3; 160 | } 161 | else if(m_buf[i] == 0 && m_buf[i + 1] == 0 && m_buf[i + 2] == 0 && m_buf[i + 3] == 1) 162 | { 163 | start_code = 4; 164 | } 165 | else 166 | { 167 | continue; 168 | } 169 | 170 | code = m_buf[i + start_code]; 171 | if(((code & 0x7E) >> 1 == 32) || ((code & 0x7E) >> 1 == 33) || 172 | ((code & 0x7E) >> 1 == 34) || ((code & 0x7E) >> 1 == 19) || 173 | ((code & 0x7E) >> 1 == 1) || ((code & 0x7E) >> 1 == 20) || 174 | ((code & 0x7E) >> 1 == 39)) 175 | { 176 | is_find_end = true; 177 | break; 178 | } 179 | } 180 | 181 | bool flag = false; 182 | if(is_find_start && !is_find_end && m_count > 0) 183 | { 184 | flag = is_find_end = true; 185 | i = bytes_read; 186 | *end = true; 187 | } 188 | 189 | if(!is_find_start || !is_find_end) 190 | { 191 | this->Close(); 192 | return -1; 193 | } 194 | int size = (i <= in_buf_size ? i : in_buf_size); 195 | memcpy(in_buf, m_buf, size); 196 | 197 | if(!flag) 198 | { 199 | m_count += 1; 200 | m_bytes_used += i; 201 | } 202 | else 203 | { 204 | m_count = 0; 205 | m_bytes_used = 0; 206 | } 207 | 208 | fseek(m_file, m_bytes_used, SEEK_SET); 209 | return size; 210 | } 211 | 212 | 213 | int test_rtsp_h265(void) 214 | { 215 | std::shared_ptr h265_server; 216 | xop::MediaSessionId h265_session_id; 217 | 218 | H265File h265_file; 219 | if (!h265_file.Open("test.h265")) 220 | { 221 | return 0; 222 | } 223 | 224 | std::string suffix = "codec2021"; 225 | std::string ip = "127.0.0.1"; 226 | std::string port = "554"; 227 | std::string rtsp_url = "rtsp://" + ip + ":" + port + "/" + suffix; 228 | 229 | std::shared_ptr event_loop(new xop::EventLoop()); 230 | h265_server = xop::RtspServer::Create(event_loop.get()); 231 | 232 | if (!h265_server->Start("0.0.0.0", atoi(port.c_str()))) { 233 | printf("RTSP Server listen on %s failed.\n", port.c_str()); 234 | return 0; 235 | } 236 | 237 | #ifdef AUTH_CONFIG 238 | server->SetAuthConfig("-_-", "admin", "12345"); 239 | #endif 240 | 241 | xop::MediaSession* session = xop::MediaSession::CreateNew("codec2021"); 242 | session->AddSource(xop::channel_0, xop::H265Source::CreateNew()); 243 | //session->StartMulticast(); 244 | session->SetNotifyCallback([](xop::MediaSessionId session_id, uint32_t clients) { 245 | std::cout << "The number of rtsp clients: " << clients << std::endl; 246 | }); 247 | 248 | h265_session_id = h265_server->AddSession(session); 249 | 250 | std::cout << "Play URL: " << rtsp_url << std::endl; 251 | 252 | std::thread t1(SendFrameThread, h265_server.get(), h265_session_id, &h265_file); 253 | 254 | while (1) 255 | { 256 | xop::Timer::Sleep(100); 257 | } 258 | 259 | return 0; 260 | } 261 | 262 | 263 | int main(int argc, char** argv) 264 | { 265 | if(argc != 2) 266 | { 267 | printf("Usage: %s test.h265\n", argv[0]); 268 | return 0; 269 | } 270 | 271 | 272 | test_rtsp_h265(); 273 | 274 | return 0; 275 | } 276 | -------------------------------------------------------------------------------- /example/rtsp_pusher.cpp: -------------------------------------------------------------------------------- 1 | // RTSP Pusher 2 | 3 | #include "xop/RtspPusher.h" 4 | #include "net/Timer.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define PUSH_TEST "rtsp://10.11.165.203:554/test" 11 | 12 | void snedFrameThread(xop::RtspPusher* rtspPusher); 13 | 14 | int main(int argc, char **argv) 15 | { 16 | std::shared_ptr event_loop(new xop::EventLoop()); 17 | std::shared_ptr rtsp_pusher = xop::RtspPusher::Create(event_loop.get()); 18 | 19 | xop::MediaSession *session = xop::MediaSession::CreateNew(); 20 | session->AddSource(xop::channel_0, xop::H264Source::CreateNew()); 21 | session->AddSource(xop::channel_1, xop::AACSource::CreateNew(44100, 2, false)); 22 | rtsp_pusher->AddSession(session); 23 | 24 | if (rtsp_pusher->OpenUrl(PUSH_TEST, 3000) < 0) { 25 | std::cout << "Open " << PUSH_TEST << " failed." << std::endl; 26 | getchar(); 27 | return 0; 28 | } 29 | 30 | std::cout << "Push stream to " << PUSH_TEST << " ..." << std::endl; 31 | 32 | std::thread thread(snedFrameThread, rtsp_pusher.get()); 33 | thread.detach(); 34 | 35 | while (1) { 36 | xop::Timer::Sleep(100); 37 | } 38 | 39 | getchar(); 40 | return 0; 41 | } 42 | 43 | void snedFrameThread(xop::RtspPusher* rtsp_pusher) 44 | { 45 | while(rtsp_pusher->IsConnected()) 46 | { 47 | { 48 | /* 49 | //获取一帧 H264, 打包 50 | xop::AVFrame videoFrame = {0}; 51 | //videoFrame.size = video frame size; // 视频帧大小 52 | videoFrame.timestamp = xop::H264Source::GetTimestamp(); // 时间戳, 建议使用编码器提供的时间戳 53 | videoFrame.buffer.reset(new uint8_t[videoFrame.size]); 54 | //memcpy(videoFrame.buffer.get(), video frame data, videoFrame.size); 55 | 56 | rtsp_pusher->PushFrame(xop::channel_0, videoFrame); //推流到服务器, 接口线程安全 57 | */ 58 | } 59 | 60 | { 61 | /* 62 | //获取一帧 AAC, 打包 63 | xop::AVFrame audioFrame = {0}; 64 | //audioFrame.size = audio frame size; // 音频帧大小 65 | audioFrame.timestamp = xop::AACSource::GetTimestamp(44100); // 时间戳 66 | audioFrame.buffer.reset(new uint8_t[audioFrame.size]); 67 | //memcpy(audioFrame.buffer.get(), audio frame data, audioFrame.size); 68 | 69 | rtsp_pusher->PushFrame(xop::channel_1, audioFrame); //推流到服务器, 接口线程安全 70 | */ 71 | } 72 | 73 | xop::Timer::Sleep(1); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /example/rtsp_server.cpp: -------------------------------------------------------------------------------- 1 | // RTSP Server 2 | 3 | #include "xop/RtspServer.h" 4 | #include "net/Timer.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, int& clients); 11 | 12 | int main(int argc, char **argv) 13 | { 14 | int clients = 0; 15 | std::string ip = "0.0.0.0"; 16 | std::string rtsp_url = "rtsp://127.0.0.1:554/live"; 17 | 18 | std::shared_ptr event_loop(new xop::EventLoop()); 19 | std::shared_ptr server = xop::RtspServer::Create(event_loop.get()); 20 | if (!server->Start(ip, 554)) { 21 | return -1; 22 | } 23 | 24 | #ifdef AUTH_CONFIG 25 | server->SetAuthConfig("-_-", "admin", "12345"); 26 | #endif 27 | 28 | xop::MediaSession *session = xop::MediaSession::CreateNew("live"); // url: rtsp://ip/live 29 | session->AddSource(xop::channel_0, xop::H264Source::CreateNew()); 30 | session->AddSource(xop::channel_1, xop::AACSource::CreateNew(44100,2)); 31 | // session->startMulticast(); /* 开启组播(ip,端口随机生成), 默认使用 RTP_OVER_UDP, RTP_OVER_RTSP */ 32 | 33 | session->SetNotifyCallback([&clients, &rtsp_url](xop::MediaSessionId session_id, uint32_t num_clients) { 34 | clients = num_clients; 35 | std::cout << "[" << rtsp_url << "]" << " Online: " << clients << std::endl; 36 | }); 37 | 38 | std::cout << "URL: " << rtsp_url << std::endl; 39 | 40 | xop::MediaSessionId session_id = server->AddSession(session); 41 | //server->removeMeidaSession(session_id); /* 取消会话, 接口线程安全 */ 42 | 43 | std::thread thread(SendFrameThread, server.get(), session_id, std::ref(clients)); 44 | thread.detach(); 45 | 46 | while(1) { 47 | xop::Timer::Sleep(100); 48 | } 49 | 50 | getchar(); 51 | return 0; 52 | } 53 | 54 | void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, int& clients) 55 | { 56 | while(1) 57 | { 58 | if(clients > 0) /* 会话有客户端在线, 发送音视频数据 */ 59 | { 60 | { 61 | /* 62 | //获取一帧 H264, 打包 63 | xop::AVFrame videoFrame = {0}; 64 | videoFrame.type = 0; // 建议确定帧类型。I帧(xop::VIDEO_FRAME_I) P帧(xop::VIDEO_FRAME_P) 65 | videoFrame.size = video frame size; // 视频帧大小 66 | videoFrame.timestamp = xop::H264Source::GetTimestamp(); // 时间戳, 建议使用编码器提供的时间戳 67 | videoFrame.buffer.reset(new uint8_t[videoFrame.size]); 68 | memcpy(videoFrame.buffer.get(), video frame data, videoFrame.size); 69 | 70 | rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame); //送到服务器进行转发, 接口线程安全 71 | */ 72 | } 73 | 74 | { 75 | /* 76 | //获取一帧 AAC, 打包 77 | xop::AVFrame audioFrame = {0}; 78 | audioFrame.type = xop::AUDIO_FRAME; 79 | audioFrame.size = audio frame size; /* 音频帧大小 80 | audioFrame.timestamp = xop::AACSource::GetTimestamp(44100); // 时间戳 81 | audioFrame.buffer.reset(new uint8_t[audioFrame.size]); 82 | memcpy(audioFrame.buffer.get(), audio frame data, audioFrame.size); 83 | 84 | rtsp_server->PushFrame(session_id, xop::channel_1, audioFrame); // 送到服务器进行转发, 接口线程安全 85 | */ 86 | } 87 | } 88 | 89 | xop::Timer::Sleep(1); /* 实际使用需要根据帧率计算延时! */ 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /pic/1.pic.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codec2021/rtspServerH265/1a3d7928bc3d84cb458e34f63d49565d4a8b6f74/pic/1.pic.JPG -------------------------------------------------------------------------------- /src/3rdpart/md5/COPYING: -------------------------------------------------------------------------------- 1 | Main Library: 2 | 3 | Copyright (c) 2014, Peter Thorson. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of the WebSocket++ Project nor the 13 | names of its contributors may be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | Bundled Libraries: 28 | 29 | ****** Base 64 Library (base64/base64.hpp) ****** 30 | base64.hpp is a repackaging of the base64.cpp and base64.h files into a 31 | single header suitable for use as a header only library. This conversion was 32 | done by Peter Thorson (webmaster@zaphoyd.com) in 2012. All modifications to 33 | the code are redistributed under the same license as the original, which is 34 | listed below. 35 | 36 | base64.cpp and base64.h 37 | 38 | Copyright (C) 2004-2008 René Nyffenegger 39 | 40 | This source code is provided 'as-is', without any express or implied 41 | warranty. In no event will the author be held liable for any damages 42 | arising from the use of this software. 43 | 44 | Permission is granted to anyone to use this software for any purpose, 45 | including commercial applications, and to alter it and redistribute it 46 | freely, subject to the following restrictions: 47 | 48 | 1. The origin of this source code must not be misrepresented; you must not 49 | claim that you wrote the original source code. If you use this source code 50 | in a product, an acknowledgment in the product documentation would be 51 | appreciated but is not required. 52 | 53 | 2. Altered source versions must be plainly marked as such, and must not be 54 | misrepresented as being the original source code. 55 | 56 | 3. This notice may not be removed or altered from any source distribution. 57 | 58 | René Nyffenegger rene.nyffenegger@adp-gmbh.ch 59 | 60 | ****** SHA1 Library (sha1/sha1.hpp) ****** 61 | sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the shallsha1 62 | library (http://code.google.com/p/smallsha1/) into a single header suitable for 63 | use as a header only library. This conversion was done by Peter Thorson 64 | (webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed 65 | under the same license as the original, which is listed below. 66 | 67 | Copyright (c) 2011, Micael Hildenborg 68 | All rights reserved. 69 | 70 | Redistribution and use in source and binary forms, with or without 71 | modification, are permitted provided that the following conditions are met: 72 | * Redistributions of source code must retain the above copyright 73 | notice, this list of conditions and the following disclaimer. 74 | * Redistributions in binary form must reproduce the above copyright 75 | notice, this list of conditions and the following disclaimer in the 76 | documentation and/or other materials provided with the distribution. 77 | * Neither the name of Micael Hildenborg nor the 78 | names of its contributors may be used to endorse or promote products 79 | derived from this software without specific prior written permission. 80 | 81 | THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY 82 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 83 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 84 | DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY 85 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 86 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 87 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 88 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 89 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 90 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 91 | 92 | ****** MD5 Library (common/md5.hpp) ****** 93 | md5.hpp is a reformulation of the md5.h and md5.c code from 94 | http://www.opensource.apple.com/source/cups/cups-59/cups/md5.c to allow it to 95 | function as a component of a header only library. This conversion was done by 96 | Peter Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The 97 | changes are released under the same license as the original (listed below) 98 | 99 | Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. 100 | 101 | This software is provided 'as-is', without any express or implied 102 | warranty. In no event will the authors be held liable for any damages 103 | arising from the use of this software. 104 | 105 | Permission is granted to anyone to use this software for any purpose, 106 | including commercial applications, and to alter it and redistribute it 107 | freely, subject to the following restrictions: 108 | 109 | 1. The origin of this software must not be misrepresented; you must not 110 | claim that you wrote the original software. If you use this software 111 | in a product, an acknowledgment in the product documentation would be 112 | appreciated but is not required. 113 | 2. Altered source versions must be plainly marked as such, and must not be 114 | misrepresented as being the original software. 115 | 3. This notice may not be removed or altered from any source distribution. 116 | 117 | L. Peter Deutsch 118 | ghost@aladdin.com 119 | 120 | ****** UTF8 Validation logic (utf8_validation.hpp) ****** 121 | utf8_validation.hpp is adapted from code originally written by Bjoern Hoehrmann 122 | . See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for 123 | details. 124 | 125 | The original license: 126 | 127 | Copyright (c) 2008-2009 Bjoern Hoehrmann 128 | 129 | Permission is hereby granted, free of charge, to any person obtaining a copy 130 | of this software and associated documentation files (the "Software"), to deal 131 | in the Software without restriction, including without limitation the rights 132 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 133 | copies of the Software, and to permit persons to whom the Software is 134 | furnished to do so, subject to the following conditions: 135 | 136 | The above copyright notice and this permission notice shall be included in 137 | all copies or substantial portions of the Software. 138 | 139 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 140 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 141 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 142 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 143 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 144 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 145 | SOFTWARE. 146 | -------------------------------------------------------------------------------- /src/net/Acceptor.cpp: -------------------------------------------------------------------------------- 1 | #include "Acceptor.h" 2 | #include "EventLoop.h" 3 | #include "SocketUtil.h" 4 | #include "Logger.h" 5 | 6 | using namespace xop; 7 | 8 | Acceptor::Acceptor(EventLoop* eventLoop) 9 | : event_loop_(eventLoop) 10 | , tcp_socket_(new TcpSocket) 11 | { 12 | 13 | } 14 | 15 | Acceptor::~Acceptor() 16 | { 17 | 18 | } 19 | 20 | int Acceptor::Listen(std::string ip, uint16_t port) 21 | { 22 | std::lock_guard locker(mutex_); 23 | 24 | if (tcp_socket_->GetSocket() > 0) { 25 | tcp_socket_->Close(); 26 | } 27 | 28 | SOCKET sockfd = tcp_socket_->Create(); 29 | channel_ptr_.reset(new Channel(sockfd)); 30 | SocketUtil::SetReuseAddr(sockfd); 31 | SocketUtil::SetReusePort(sockfd); 32 | SocketUtil::SetNonBlock(sockfd); 33 | 34 | if (!tcp_socket_->Bind(ip, port)) { 35 | return -1; 36 | } 37 | 38 | if (!tcp_socket_->Listen(1024)) { 39 | return -1; 40 | } 41 | 42 | channel_ptr_->SetReadCallback([this]() { this->OnAccept(); }); 43 | channel_ptr_->EnableReading(); 44 | event_loop_->UpdateChannel(channel_ptr_); 45 | return 0; 46 | } 47 | 48 | void Acceptor::Close() 49 | { 50 | std::lock_guard locker(mutex_); 51 | 52 | if (tcp_socket_->GetSocket() > 0) { 53 | event_loop_->RemoveChannel(channel_ptr_); 54 | tcp_socket_->Close(); 55 | } 56 | } 57 | 58 | void Acceptor::OnAccept() 59 | { 60 | std::lock_guard locker(mutex_); 61 | 62 | SOCKET connfd = tcp_socket_->Accept(); 63 | if (connfd > 0) { 64 | if (new_connection_callback_) { 65 | new_connection_callback_(connfd); 66 | } 67 | else { 68 | SocketUtil::Close(connfd); 69 | } 70 | } 71 | } 72 | 73 | -------------------------------------------------------------------------------- /src/net/Acceptor.h: -------------------------------------------------------------------------------- 1 | #ifndef XOP_ACCEPTOR_H 2 | #define XOP_ACCEPTOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "Channel.h" 8 | #include "TcpSocket.h" 9 | 10 | namespace xop 11 | { 12 | 13 | typedef std::function NewConnectionCallback; 14 | 15 | class EventLoop; 16 | 17 | class Acceptor 18 | { 19 | public: 20 | Acceptor(EventLoop* eventLoop); 21 | ~Acceptor(); 22 | 23 | void SetNewConnectionCallback(const NewConnectionCallback& cb) 24 | { new_connection_callback_ = cb; } 25 | 26 | int Listen(std::string ip, uint16_t port); 27 | void Close(); 28 | 29 | private: 30 | void OnAccept(); 31 | 32 | EventLoop* event_loop_ = nullptr; 33 | std::mutex mutex_; 34 | std::unique_ptr tcp_socket_; 35 | ChannelPtr channel_ptr_; 36 | NewConnectionCallback new_connection_callback_; 37 | }; 38 | 39 | } 40 | 41 | #endif 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/net/BufferReader.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #include "BufferReader.h" 5 | #include "Socket.h" 6 | #include 7 | 8 | using namespace xop; 9 | uint32_t xop::ReadUint32BE(char* data) 10 | { 11 | uint8_t* p = (uint8_t*)data; 12 | uint32_t value = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 13 | return value; 14 | } 15 | 16 | uint32_t xop::ReadUint32LE(char* data) 17 | { 18 | uint8_t* p = (uint8_t*)data; 19 | uint32_t value = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; 20 | return value; 21 | } 22 | 23 | uint32_t xop::ReadUint24BE(char* data) 24 | { 25 | uint8_t* p = (uint8_t*)data; 26 | uint32_t value = (p[0] << 16) | (p[1] << 8) | p[2]; 27 | return value; 28 | } 29 | 30 | uint32_t xop::ReadUint24LE(char* data) 31 | { 32 | uint8_t* p = (uint8_t*)data; 33 | uint32_t value = (p[2] << 16) | (p[1] << 8) | p[0]; 34 | return value; 35 | } 36 | 37 | uint16_t xop::ReadUint16BE(char* data) 38 | { 39 | uint8_t* p = (uint8_t*)data; 40 | uint16_t value = (p[0] << 8) | p[1]; 41 | return value; 42 | } 43 | 44 | uint16_t xop::ReadUint16LE(char* data) 45 | { 46 | uint8_t* p = (uint8_t*)data; 47 | uint16_t value = (p[1] << 8) | p[0]; 48 | return value; 49 | } 50 | 51 | const char BufferReader::kCRLF[] = "\r\n"; 52 | 53 | BufferReader::BufferReader(uint32_t initialSize) 54 | : buffer_(new std::vector(initialSize)) 55 | { 56 | buffer_->resize(initialSize); 57 | } 58 | 59 | BufferReader::~BufferReader() 60 | { 61 | 62 | } 63 | 64 | int BufferReader::Read(SOCKET sockfd) 65 | { 66 | uint32_t size = WritableBytes(); 67 | if(size < MAX_BYTES_PER_READ) { 68 | uint32_t bufferReaderSize = (uint32_t)buffer_->size(); 69 | if(bufferReaderSize > MAX_BUFFER_SIZE) { 70 | return 0; 71 | } 72 | 73 | buffer_->resize(bufferReaderSize + MAX_BYTES_PER_READ); 74 | } 75 | 76 | int bytes_read = ::recv(sockfd, beginWrite(), MAX_BYTES_PER_READ, 0); 77 | if(bytes_read > 0) { 78 | writer_index_ += bytes_read; 79 | } 80 | 81 | return bytes_read; 82 | } 83 | 84 | 85 | uint32_t BufferReader::ReadAll(std::string& data) 86 | { 87 | uint32_t size = ReadableBytes(); 88 | if(size > 0) { 89 | data.assign(Peek(), size); 90 | writer_index_ = 0; 91 | reader_index_ = 0; 92 | } 93 | 94 | return size; 95 | } 96 | 97 | uint32_t BufferReader::ReadUntilCrlf(std::string& data) 98 | { 99 | const char* crlf = FindLastCrlf(); 100 | if(crlf == nullptr) { 101 | return 0; 102 | } 103 | 104 | uint32_t size = (uint32_t)(crlf - Peek() + 2); 105 | data.assign(Peek(), size); 106 | Retrieve(size); 107 | return size; 108 | } 109 | 110 | -------------------------------------------------------------------------------- /src/net/BufferReader.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef XOP_BUFFER_READER_H 5 | #define XOP_BUFFER_READER_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "Socket.h" 13 | 14 | namespace xop 15 | { 16 | 17 | uint32_t ReadUint32BE(char* data); 18 | uint32_t ReadUint32LE(char* data); 19 | uint32_t ReadUint24BE(char* data); 20 | uint32_t ReadUint24LE(char* data); 21 | uint16_t ReadUint16BE(char* data); 22 | uint16_t ReadUint16LE(char* data); 23 | 24 | class BufferReader 25 | { 26 | public: 27 | static const uint32_t kInitialSize = 2048; 28 | BufferReader(uint32_t initialSize = kInitialSize); 29 | virtual ~BufferReader(); 30 | 31 | uint32_t ReadableBytes() const 32 | { return (uint32_t)(writer_index_ - reader_index_); } 33 | 34 | uint32_t WritableBytes() const 35 | { return (uint32_t)(buffer_->size() - writer_index_); } 36 | 37 | char* Peek() 38 | { return Begin() + reader_index_; } 39 | 40 | const char* Peek() const 41 | { return Begin() + reader_index_; } 42 | 43 | const char* FindFirstCrlf() const { 44 | const char* crlf = std::search(Peek(), BeginWrite(), kCRLF, kCRLF+2); 45 | return crlf == BeginWrite() ? nullptr : crlf; 46 | } 47 | 48 | const char* FindLastCrlf() const { 49 | const char* crlf = std::find_end(Peek(), BeginWrite(), kCRLF, kCRLF+2); 50 | return crlf == BeginWrite() ? nullptr : crlf; 51 | } 52 | 53 | const char* FindLastCrlfCrlf() const { 54 | char crlfCrlf[] = "\r\n\r\n"; 55 | const char* crlf = std::find_end(Peek(), BeginWrite(), crlfCrlf, crlfCrlf + 4); 56 | return crlf == BeginWrite() ? nullptr : crlf; 57 | } 58 | 59 | void RetrieveAll() { 60 | writer_index_ = 0; 61 | reader_index_ = 0; 62 | } 63 | 64 | void Retrieve(size_t len) { 65 | if (len <= ReadableBytes()) { 66 | reader_index_ += len; 67 | if(reader_index_ == writer_index_) { 68 | reader_index_ = 0; 69 | writer_index_ = 0; 70 | } 71 | } 72 | else { 73 | RetrieveAll(); 74 | } 75 | } 76 | 77 | void RetrieveUntil(const char* end) 78 | { Retrieve(end - Peek()); } 79 | 80 | int Read(SOCKET sockfd); 81 | uint32_t ReadAll(std::string& data); 82 | uint32_t ReadUntilCrlf(std::string& data); 83 | 84 | uint32_t Size() const 85 | { return (uint32_t)buffer_->size(); } 86 | 87 | private: 88 | char* Begin() 89 | { return &*buffer_->begin(); } 90 | 91 | const char* Begin() const 92 | { return &*buffer_->begin(); } 93 | 94 | char* beginWrite() 95 | { return Begin() + writer_index_; } 96 | 97 | const char* BeginWrite() const 98 | { return Begin() + writer_index_; } 99 | 100 | std::shared_ptr> buffer_; 101 | size_t reader_index_ = 0; 102 | size_t writer_index_ = 0; 103 | 104 | static const char kCRLF[]; 105 | static const uint32_t MAX_BYTES_PER_READ = 4096; 106 | static const uint32_t MAX_BUFFER_SIZE = 1024 * 100000; 107 | }; 108 | 109 | } 110 | 111 | #endif 112 | 113 | 114 | -------------------------------------------------------------------------------- /src/net/BufferWriter.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #include "BufferWriter.h" 5 | #include "Socket.h" 6 | #include "SocketUtil.h" 7 | 8 | using namespace xop; 9 | 10 | void xop::WriteUint32BE(char* p, uint32_t value) 11 | { 12 | p[0] = value >> 24; 13 | p[1] = value >> 16; 14 | p[2] = value >> 8; 15 | p[3] = value & 0xff; 16 | } 17 | 18 | void xop::WriteUint32LE(char* p, uint32_t value) 19 | { 20 | p[0] = value & 0xff; 21 | p[1] = value >> 8; 22 | p[2] = value >> 16; 23 | p[3] = value >> 24; 24 | } 25 | 26 | void xop::WriteUint24BE(char* p, uint32_t value) 27 | { 28 | p[0] = value >> 16; 29 | p[1] = value >> 8; 30 | p[2] = value & 0xff; 31 | } 32 | 33 | void xop::WriteUint24LE(char* p, uint32_t value) 34 | { 35 | p[0] = value & 0xff; 36 | p[1] = value >> 8; 37 | p[2] = value >> 16; 38 | } 39 | 40 | void xop::WriteUint16BE(char* p, uint16_t value) 41 | { 42 | p[0] = value >> 8; 43 | p[1] = value & 0xff; 44 | } 45 | 46 | void xop::WriteUint16LE(char* p, uint16_t value) 47 | { 48 | p[0] = value & 0xff; 49 | p[1] = value >> 8; 50 | } 51 | 52 | BufferWriter::BufferWriter(int capacity) 53 | : max_queue_length_(capacity) 54 | , buffer_(new std::queue) 55 | { 56 | 57 | } 58 | 59 | bool BufferWriter::Append(std::shared_ptr data, uint32_t size, uint32_t index) 60 | { 61 | if (size <= index) { 62 | return false; 63 | } 64 | 65 | if ((int)buffer_->size() >= max_queue_length_) { 66 | return false; 67 | } 68 | 69 | Packet pkt = {data, size, index}; 70 | buffer_->emplace(std::move(pkt)); 71 | return true; 72 | } 73 | 74 | bool BufferWriter::Append(const char* data, uint32_t size, uint32_t index) 75 | { 76 | if (size <= index) { 77 | return false; 78 | } 79 | 80 | if ((int)buffer_->size() >= max_queue_length_) { 81 | return false; 82 | } 83 | 84 | Packet pkt; 85 | pkt.data.reset(new char[size+512]); 86 | memcpy(pkt.data.get(), data, size); 87 | pkt.size = size; 88 | pkt.writeIndex = index; 89 | buffer_->emplace(std::move(pkt)); 90 | return true; 91 | } 92 | 93 | int BufferWriter::Send(SOCKET sockfd, int timeout) 94 | { 95 | if (timeout > 0) { 96 | SocketUtil::SetBlock(sockfd, timeout); 97 | } 98 | 99 | int ret = 0; 100 | int count = 1; 101 | 102 | do 103 | { 104 | if (buffer_->empty()) { 105 | return 0; 106 | } 107 | 108 | count -= 1; 109 | Packet &pkt = buffer_->front(); 110 | ret = ::send(sockfd, pkt.data.get() + pkt.writeIndex, pkt.size - pkt.writeIndex, 0); 111 | if (ret > 0) { 112 | pkt.writeIndex += ret; 113 | if (pkt.size == pkt.writeIndex) { 114 | count += 1; 115 | buffer_->pop(); 116 | } 117 | } 118 | else if (ret < 0) { 119 | #if defined(__linux) || defined(__linux__) 120 | if (errno == EINTR || errno == EAGAIN) 121 | #elif defined(WIN32) || defined(_WIN32) 122 | int error = WSAGetLastError(); 123 | if (error == WSAEWOULDBLOCK || error == WSAEINPROGRESS || error == 0) 124 | #endif 125 | { 126 | ret = 0; 127 | } 128 | } 129 | } while (count > 0); 130 | 131 | if (timeout > 0) { 132 | SocketUtil::SetNonBlock(sockfd); 133 | } 134 | 135 | return ret; 136 | } 137 | 138 | 139 | -------------------------------------------------------------------------------- /src/net/BufferWriter.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef XOP_BUFFER_WRITER_H 5 | #define XOP_BUFFER_WRITER_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "Socket.h" 12 | 13 | namespace xop 14 | { 15 | 16 | void WriteUint32BE(char* p, uint32_t value); 17 | void WriteUint32LE(char* p, uint32_t value); 18 | void WriteUint24BE(char* p, uint32_t value); 19 | void WriteUint24LE(char* p, uint32_t value); 20 | void WriteUint16BE(char* p, uint16_t value); 21 | void WriteUint16LE(char* p, uint16_t value); 22 | 23 | class BufferWriter 24 | { 25 | public: 26 | BufferWriter(int capacity = kMaxQueueLength); 27 | ~BufferWriter() {} 28 | 29 | bool Append(std::shared_ptr data, uint32_t size, uint32_t index=0); 30 | bool Append(const char* data, uint32_t size, uint32_t index=0); 31 | int Send(SOCKET sockfd, int timeout=0); 32 | 33 | bool IsEmpty() const 34 | { return buffer_->empty(); } 35 | 36 | bool IsFull() const 37 | { return ((int)buffer_->size() >= max_queue_length_ ? true : false); } 38 | 39 | uint32_t Size() const 40 | { return (uint32_t)buffer_->size(); } 41 | 42 | private: 43 | typedef struct 44 | { 45 | std::shared_ptr data; 46 | uint32_t size; 47 | uint32_t writeIndex; 48 | } Packet; 49 | 50 | std::shared_ptr> buffer_; 51 | int max_queue_length_ = 0; 52 | 53 | static const int kMaxQueueLength = 10000; 54 | }; 55 | 56 | } 57 | 58 | #endif 59 | 60 | -------------------------------------------------------------------------------- /src/net/Channel.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef XOP_CHANNEL_H 5 | #define XOP_CHANNEL_H 6 | 7 | #include 8 | #include 9 | #include "Socket.h" 10 | 11 | namespace xop 12 | { 13 | 14 | enum EventType 15 | { 16 | EVENT_NONE = 0, 17 | EVENT_IN = 1, 18 | EVENT_PRI = 2, 19 | EVENT_OUT = 4, 20 | EVENT_ERR = 8, 21 | EVENT_HUP = 16, 22 | EVENT_RDHUP = 8192 23 | }; 24 | 25 | class Channel 26 | { 27 | public: 28 | typedef std::function EventCallback; 29 | 30 | Channel() = delete; 31 | Channel(SOCKET sockfd) : sockfd_(sockfd) {}; 32 | virtual ~Channel() {}; 33 | 34 | void SetReadCallback(const EventCallback& cb) 35 | { read_callback_ = cb; } 36 | 37 | void SetWriteCallback(const EventCallback& cb) 38 | { write_callback_ = cb; } 39 | 40 | void SetCloseCallback(const EventCallback& cb) 41 | { close_callback_ = cb; } 42 | 43 | void SetErrorCallback(const EventCallback& cb) 44 | { error_callback_ = cb; } 45 | 46 | SOCKET GetSocket() const { return sockfd_; } 47 | 48 | int GetEvents() const { return events_; } 49 | void SetEvents(int events) { events_ = events; } 50 | 51 | void EnableReading() 52 | { events_ |= EVENT_IN; } 53 | 54 | void EnableWriting() 55 | { events_ |= EVENT_OUT; } 56 | 57 | void DisableReading() 58 | { events_ &= ~EVENT_IN; } 59 | 60 | void DisableWriting() 61 | { events_ &= ~EVENT_OUT; } 62 | 63 | bool IsNoneEvent() const { return events_ == EVENT_NONE; } 64 | bool IsWriting() const { return (events_ & EVENT_OUT) != 0; } 65 | bool IsReading() const { return (events_ & EVENT_IN) != 0; } 66 | 67 | void HandleEvent(int events) 68 | { 69 | if (events & (EVENT_PRI | EVENT_IN)) { 70 | read_callback_(); 71 | } 72 | 73 | if (events & EVENT_OUT) { 74 | write_callback_(); 75 | } 76 | 77 | if (events & EVENT_HUP) { 78 | close_callback_(); 79 | return ; 80 | } 81 | 82 | if (events & (EVENT_ERR)) { 83 | error_callback_(); 84 | } 85 | } 86 | 87 | private: 88 | EventCallback read_callback_ = []{}; 89 | EventCallback write_callback_ = []{}; 90 | EventCallback close_callback_ = []{}; 91 | EventCallback error_callback_ = []{}; 92 | 93 | SOCKET sockfd_ = 0; 94 | int events_ = 0; 95 | }; 96 | 97 | typedef std::shared_ptr ChannelPtr; 98 | 99 | } 100 | 101 | #endif 102 | 103 | -------------------------------------------------------------------------------- /src/net/EpollTaskScheduler.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #include "EpollTaskScheduler.h" 5 | 6 | #if defined(__linux) || defined(__linux__) 7 | #include 8 | #include 9 | #endif 10 | 11 | using namespace xop; 12 | 13 | EpollTaskScheduler::EpollTaskScheduler(int id) 14 | : TaskScheduler(id) 15 | { 16 | #if defined(__linux) || defined(__linux__) 17 | epollfd_ = epoll_create1(0); 18 | #endif 19 | this->UpdateChannel(wakeup_channel_); 20 | } 21 | 22 | EpollTaskScheduler::~EpollTaskScheduler() 23 | { 24 | 25 | } 26 | 27 | void EpollTaskScheduler::UpdateChannel(ChannelPtr channel) 28 | { 29 | std::lock_guard lock(mutex_); 30 | #if defined(__linux) || defined(__linux__) 31 | int fd = channel->GetSocket(); 32 | if(channels_.find(fd) != channels_.end()) { 33 | if(channel->IsNoneEvent()) { 34 | Update(EPOLL_CTL_DEL, channel); 35 | channels_.erase(fd); 36 | } 37 | else { 38 | Update(EPOLL_CTL_MOD, channel); 39 | } 40 | } 41 | else { 42 | if(!channel->IsNoneEvent()) { 43 | channels_.emplace(fd, channel); 44 | Update(EPOLL_CTL_ADD, channel); 45 | } 46 | } 47 | #endif 48 | } 49 | 50 | void EpollTaskScheduler::Update(int operation, ChannelPtr& channel) 51 | { 52 | #if defined(__linux) || defined(__linux__) 53 | struct epoll_event event = {0}; 54 | 55 | if(operation != EPOLL_CTL_DEL) { 56 | event.data.ptr = channel.get(); 57 | event.events = channel->GetEvents(); 58 | } 59 | 60 | if(::epoll_ctl(epollfd_, operation, channel->GetSocket(), &event) < 0) { 61 | 62 | } 63 | #endif 64 | } 65 | 66 | void EpollTaskScheduler::RemoveChannel(ChannelPtr& channel) 67 | { 68 | std::lock_guard lock(mutex_); 69 | #if defined(__linux) || defined(__linux__) 70 | int fd = channel->GetSocket(); 71 | 72 | if(channels_.find(fd) != channels_.end()) { 73 | Update(EPOLL_CTL_DEL, channel); 74 | channels_.erase(fd); 75 | } 76 | #endif 77 | } 78 | 79 | bool EpollTaskScheduler::HandleEvent(int timeout) 80 | { 81 | #if defined(__linux) || defined(__linux__) 82 | struct epoll_event events[512] = {0}; 83 | int num_events = -1; 84 | 85 | num_events = epoll_wait(epollfd_, events, 512, timeout); 86 | if(num_events < 0) { 87 | if(errno != EINTR) { 88 | return false; 89 | } 90 | } 91 | 92 | for(int n=0; nHandleEvent(events[n].events); 95 | } 96 | } 97 | return true; 98 | #else 99 | return false; 100 | #endif 101 | } 102 | 103 | 104 | -------------------------------------------------------------------------------- /src/net/EpollTaskScheduler.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef XOP_EPOLL_TASK_SCHEDULER_H 5 | #define XOP_EPOLL_TASK_SCHEDULER_H 6 | 7 | #include "TaskScheduler.h" 8 | #include 9 | #include 10 | 11 | namespace xop 12 | { 13 | class EpollTaskScheduler : public TaskScheduler 14 | { 15 | public: 16 | EpollTaskScheduler(int id = 0); 17 | virtual ~EpollTaskScheduler(); 18 | 19 | void UpdateChannel(ChannelPtr channel); 20 | void RemoveChannel(ChannelPtr& channel); 21 | 22 | // timeout: ms 23 | bool HandleEvent(int timeout); 24 | 25 | private: 26 | void Update(int operation, ChannelPtr& channel); 27 | 28 | int epollfd_ = -1; 29 | std::mutex mutex_; 30 | std::unordered_map channels_; 31 | }; 32 | 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/net/EventLoop.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2019-10-18 3 | 4 | #include "EventLoop.h" 5 | 6 | #if defined(WIN32) || defined(_WIN32) 7 | #include 8 | #endif 9 | 10 | #if defined(WIN32) || defined(_WIN32) 11 | #pragma comment(lib, "Ws2_32.lib") 12 | #pragma comment(lib,"Iphlpapi.lib") 13 | #endif 14 | 15 | using namespace xop; 16 | 17 | EventLoop::EventLoop(uint32_t num_threads) 18 | : index_(1) 19 | { 20 | num_threads_ = 1; 21 | if (num_threads > 0) { 22 | num_threads_ = num_threads; 23 | } 24 | 25 | this->Loop(); 26 | } 27 | 28 | EventLoop::~EventLoop() 29 | { 30 | this->Quit(); 31 | } 32 | 33 | std::shared_ptr EventLoop::GetTaskScheduler() 34 | { 35 | std::lock_guard locker(mutex_); 36 | if (task_schedulers_.size() == 1) { 37 | return task_schedulers_.at(0); 38 | } 39 | else { 40 | auto task_scheduler = task_schedulers_.at(index_); 41 | index_++; 42 | if (index_ >= task_schedulers_.size()) { 43 | index_ = 1; 44 | } 45 | return task_scheduler; 46 | } 47 | 48 | return nullptr; 49 | } 50 | 51 | void EventLoop::Loop() 52 | { 53 | std::lock_guard locker(mutex_); 54 | 55 | if (!task_schedulers_.empty()) { 56 | return ; 57 | } 58 | 59 | for (uint32_t n = 0; n < num_threads_; n++) 60 | { 61 | #if defined(__linux) || defined(__linux__) 62 | std::shared_ptr task_scheduler_ptr(new EpollTaskScheduler(n)); 63 | #elif defined(WIN32) || defined(_WIN32) 64 | std::shared_ptr task_scheduler_ptr(new SelectTaskScheduler(n)); 65 | #endif 66 | task_schedulers_.push_back(task_scheduler_ptr); 67 | std::shared_ptr thread(new std::thread(&TaskScheduler::Start, task_scheduler_ptr.get())); 68 | thread->native_handle(); 69 | threads_.push_back(thread); 70 | } 71 | 72 | int priority = TASK_SCHEDULER_PRIORITY_REALTIME; 73 | 74 | for (auto iter : threads_) 75 | { 76 | #if defined(__linux) || defined(__linux__) 77 | 78 | #elif defined(WIN32) || defined(_WIN32) 79 | switch (priority) 80 | { 81 | case TASK_SCHEDULER_PRIORITY_LOW: 82 | SetThreadPriority(iter->native_handle(), THREAD_PRIORITY_BELOW_NORMAL); 83 | break; 84 | case TASK_SCHEDULER_PRIORITY_NORMAL: 85 | SetThreadPriority(iter->native_handle(), THREAD_PRIORITY_NORMAL); 86 | break; 87 | case TASK_SCHEDULER_PRIORITYO_HIGH: 88 | SetThreadPriority(iter->native_handle(), THREAD_PRIORITY_ABOVE_NORMAL); 89 | break; 90 | case TASK_SCHEDULER_PRIORITY_HIGHEST: 91 | SetThreadPriority(iter->native_handle(), THREAD_PRIORITY_HIGHEST); 92 | break; 93 | case TASK_SCHEDULER_PRIORITY_REALTIME: 94 | SetThreadPriority(iter->native_handle(), THREAD_PRIORITY_TIME_CRITICAL); 95 | break; 96 | } 97 | #endif 98 | } 99 | } 100 | 101 | void EventLoop::Quit() 102 | { 103 | std::lock_guard locker(mutex_); 104 | 105 | for (auto iter : task_schedulers_) { 106 | iter->Stop(); 107 | } 108 | 109 | for (auto iter : threads_) { 110 | iter->join(); 111 | } 112 | 113 | task_schedulers_.clear(); 114 | threads_.clear(); 115 | } 116 | 117 | void EventLoop::UpdateChannel(ChannelPtr channel) 118 | { 119 | std::lock_guard locker(mutex_); 120 | if (task_schedulers_.size() > 0) { 121 | task_schedulers_[0]->UpdateChannel(channel); 122 | } 123 | } 124 | 125 | void EventLoop::RemoveChannel(ChannelPtr& channel) 126 | { 127 | std::lock_guard locker(mutex_); 128 | if (task_schedulers_.size() > 0) { 129 | task_schedulers_[0]->RemoveChannel(channel); 130 | } 131 | } 132 | 133 | TimerId EventLoop::AddTimer(TimerEvent timerEvent, uint32_t msec) 134 | { 135 | std::lock_guard locker(mutex_); 136 | if (task_schedulers_.size() > 0) { 137 | return task_schedulers_[0]->AddTimer(timerEvent, msec); 138 | } 139 | return 0; 140 | } 141 | 142 | void EventLoop::RemoveTimer(TimerId timerId) 143 | { 144 | std::lock_guard locker(mutex_); 145 | if (task_schedulers_.size() > 0) { 146 | task_schedulers_[0]->RemoveTimer(timerId); 147 | } 148 | } 149 | 150 | bool EventLoop::AddTriggerEvent(TriggerEvent callback) 151 | { 152 | std::lock_guard locker(mutex_); 153 | if (task_schedulers_.size() > 0) { 154 | return task_schedulers_[0]->AddTriggerEvent(callback); 155 | } 156 | return false; 157 | } 158 | -------------------------------------------------------------------------------- /src/net/EventLoop.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef XOP_EVENT_LOOP_H 5 | #define XOP_EVENT_LOOP_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "SelectTaskScheduler.h" 16 | #include "EpollTaskScheduler.h" 17 | #include "Pipe.h" 18 | #include "Timer.h" 19 | #include "RingBuffer.h" 20 | 21 | #define TASK_SCHEDULER_PRIORITY_LOW 0 22 | #define TASK_SCHEDULER_PRIORITY_NORMAL 1 23 | #define TASK_SCHEDULER_PRIORITYO_HIGH 2 24 | #define TASK_SCHEDULER_PRIORITY_HIGHEST 3 25 | #define TASK_SCHEDULER_PRIORITY_REALTIME 4 26 | 27 | namespace xop 28 | { 29 | 30 | class EventLoop 31 | { 32 | public: 33 | EventLoop(const EventLoop&) = delete; 34 | EventLoop &operator = (const EventLoop&) = delete; 35 | EventLoop(uint32_t num_threads =1); //std::thread::hardware_concurrency() 36 | virtual ~EventLoop(); 37 | 38 | std::shared_ptr GetTaskScheduler(); 39 | 40 | bool AddTriggerEvent(TriggerEvent callback); 41 | TimerId AddTimer(TimerEvent timerEvent, uint32_t msec); 42 | void RemoveTimer(TimerId timerId); 43 | void UpdateChannel(ChannelPtr channel); 44 | void RemoveChannel(ChannelPtr& channel); 45 | 46 | void Loop(); 47 | void Quit(); 48 | 49 | private: 50 | std::mutex mutex_; 51 | uint32_t num_threads_ = 1; 52 | uint32_t index_ = 1; 53 | std::vector> task_schedulers_; 54 | std::vector> threads_; 55 | }; 56 | 57 | } 58 | 59 | #endif 60 | 61 | -------------------------------------------------------------------------------- /src/net/Logger.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #if defined(WIN32) || defined(_WIN32) 5 | #ifndef _CRT_SECURE_NO_WARNINGS 6 | #define _CRT_SECURE_NO_WARNINGS 7 | #endif 8 | #endif 9 | 10 | #include "Logger.h" 11 | #include 12 | #include 13 | #include "Timestamp.h" 14 | 15 | using namespace xop; 16 | 17 | const char* Priority_To_String[] = 18 | { 19 | "DEBUG", 20 | "CONFIG", 21 | "INFO", 22 | "WARNING", 23 | "ERROR" 24 | }; 25 | 26 | Logger::Logger() 27 | { 28 | 29 | } 30 | 31 | Logger& Logger::instance() 32 | { 33 | static Logger s_logger; 34 | return s_logger; 35 | } 36 | 37 | Logger::~Logger() 38 | { 39 | 40 | } 41 | 42 | void Logger::init(char *pathname) 43 | { 44 | std::unique_lock lock(_mutex); 45 | 46 | if (pathname != nullptr) 47 | { 48 | _ofs.open(pathname, std::ios::out | std::ios::binary); 49 | if (_ofs.fail()) 50 | { 51 | std::cerr << "Failed to open logfile." << std::endl; 52 | } 53 | } 54 | } 55 | 56 | void Logger::exit() 57 | { 58 | std::unique_lock lock(_mutex); 59 | 60 | if (_ofs.is_open()) 61 | { 62 | _ofs.close(); 63 | } 64 | } 65 | 66 | void Logger::log(Priority priority, const char* __file, const char* __func, int __line, const char *fmt, ...) 67 | { 68 | std::unique_lock lock(_mutex); 69 | 70 | char buf[2048] = {0}; 71 | sprintf(buf, "[%s][%s:%s:%d] ", Priority_To_String[priority], __file, __func, __line); 72 | va_list args; 73 | va_start(args, fmt); 74 | vsprintf(buf + strlen(buf), fmt, args); 75 | va_end(args); 76 | 77 | write(std::string(buf)); 78 | } 79 | 80 | void Logger::log2(Priority priority, const char *fmt, ...) 81 | { 82 | std::unique_lock lock(_mutex); 83 | 84 | char buf[4096] = { 0 }; 85 | sprintf(buf, "[%s] ", Priority_To_String[priority]); 86 | va_list args; 87 | va_start(args, fmt); 88 | vsprintf(buf + strlen(buf), fmt, args); 89 | va_end(args); 90 | 91 | write(std::string(buf)); 92 | } 93 | 94 | void Logger::write(std::string info) 95 | { 96 | if (_ofs.is_open()) 97 | { 98 | _ofs << "[" << Timestamp::localtime() << "]" 99 | << info << std::endl; 100 | } 101 | 102 | std::cout << "[" << Timestamp::localtime() << "]" 103 | << info << std::endl; 104 | } 105 | -------------------------------------------------------------------------------- /src/net/Logger.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2020-5-15 3 | 4 | #ifndef XOP_LOGGER_H 5 | #define XOP_LOGGER_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace xop { 16 | 17 | 18 | enum Priority 19 | { 20 | LOG_DEBUG, LOG_STATE, LOG_INFO, LOG_WARNING, LOG_ERROR, 21 | }; 22 | 23 | class Logger 24 | { 25 | public: 26 | Logger &operator=(const Logger &) = delete; 27 | Logger(const Logger &) = delete; 28 | static Logger& instance(); 29 | ~Logger(); 30 | 31 | void init(char *pathname = nullptr); 32 | void exit(); 33 | 34 | void log(Priority priority, const char* __file, const char* __func, int __line, const char *fmt, ...); 35 | void log2(Priority priority, const char *fmt, ...); 36 | 37 | private: 38 | void write(std::string buf); 39 | Logger(); 40 | 41 | std::mutex _mutex; 42 | std::ofstream _ofs; 43 | }; 44 | 45 | } 46 | 47 | #ifdef _DEBUG 48 | #define LOG_DEBUG(fmt, ...) xop::Logger::instance().log(LOG_DEBUG, __FILE__, __FUNCTION__,__LINE__, fmt, ##__VA_ARGS__) 49 | #else 50 | #define LOG_DEBUG(fmt, ...) 51 | #endif 52 | #define LOG_INFO(fmt, ...) xop::Logger::instance().log2(LOG_INFO, fmt, ##__VA_ARGS__) 53 | #define LOG_ERROR(fmt, ...) xop::Logger::instance().log(LOG_ERROR, __FILE__, __FUNCTION__,__LINE__, fmt, ##__VA_ARGS__) 54 | 55 | #endif 56 | 57 | -------------------------------------------------------------------------------- /src/net/MemoryManager.cpp: -------------------------------------------------------------------------------- 1 | #include "MemoryManager.h" 2 | 3 | using namespace xop; 4 | 5 | void* xop::Alloc(uint32_t size) 6 | { 7 | return MemoryManager::Instance().Alloc(size); 8 | } 9 | 10 | void xop::Free(void *ptr) 11 | { 12 | return MemoryManager::Instance().Free(ptr); 13 | } 14 | 15 | MemoryPool::MemoryPool() 16 | { 17 | 18 | } 19 | 20 | MemoryPool::~MemoryPool() 21 | { 22 | if (memory_) { 23 | free(memory_); 24 | } 25 | } 26 | 27 | void MemoryPool::Init(uint32_t size, uint32_t n) 28 | { 29 | if (memory_) { 30 | return; 31 | } 32 | 33 | block_size_ = size; 34 | num_blocks_ = n; 35 | memory_ = (char*)malloc(num_blocks_ * (block_size_ + sizeof(MemoryBlock))); 36 | head_ = (MemoryBlock*)memory_; 37 | head_->blockId = 1; 38 | head_->pool = this; 39 | head_->next = nullptr; 40 | 41 | MemoryBlock* current = head_; 42 | for (uint32_t n = 1; n < num_blocks_; n++) { 43 | MemoryBlock* next = (MemoryBlock*)(memory_ + (n * (block_size_ + sizeof(MemoryBlock)))); 44 | next->blockId = n + 1; 45 | next->pool = this; 46 | next->next = nullptr; 47 | 48 | current->next = next; 49 | current = next; 50 | } 51 | } 52 | 53 | void* MemoryPool::Alloc(uint32_t size) 54 | { 55 | MemoryBlock* block = nullptr; 56 | 57 | std::lock_guard locker(mutex_); 58 | if (head_ != nullptr) { 59 | MemoryBlock* block = head_; 60 | head_ = head_->next; 61 | return ((char*)block + sizeof(MemoryBlock)); 62 | } 63 | 64 | return nullptr; 65 | } 66 | 67 | void MemoryPool::Free(void* ptr) 68 | { 69 | MemoryBlock *block = (MemoryBlock*)((char*)ptr - sizeof(MemoryBlock)); 70 | if (block->blockId != 0) { 71 | std::lock_guard locker(mutex_); 72 | block->next = head_; 73 | head_ = block; 74 | } 75 | } 76 | 77 | MemoryManager::MemoryManager() 78 | { 79 | memory_pools_[0].Init(4096, 50); 80 | memory_pools_[1].Init(40960, 10); 81 | memory_pools_[2].Init(102400, 5); 82 | //memory_pools_[3].Init(204800, 2); 83 | } 84 | 85 | MemoryManager::~MemoryManager() 86 | { 87 | 88 | } 89 | 90 | MemoryManager& MemoryManager::Instance() 91 | { 92 | static MemoryManager s_mgr; 93 | return s_mgr; 94 | } 95 | 96 | void* MemoryManager::Alloc(uint32_t size) 97 | { 98 | for (int n = 0; n < kMaxMemoryPool; n++) { 99 | if (size <= memory_pools_[n].BolckSize()) { 100 | void* ptr = memory_pools_[n].Alloc(size); 101 | if (ptr != nullptr) { 102 | return ptr; 103 | } 104 | else { 105 | break; 106 | } 107 | } 108 | } 109 | 110 | MemoryBlock *block = (MemoryBlock*)malloc(size + sizeof(MemoryBlock)); 111 | block->blockId = 0; 112 | block->pool = nullptr; 113 | block->next = nullptr; 114 | return ((char*)block + sizeof(MemoryBlock)); 115 | } 116 | 117 | void MemoryManager::Free(void* ptr) 118 | { 119 | MemoryBlock *block = (MemoryBlock*)((char*)ptr - sizeof(MemoryBlock)); 120 | MemoryPool *pool = block->pool; 121 | 122 | if (pool != nullptr && block->blockId > 0) { 123 | pool->Free(ptr); 124 | } 125 | else { 126 | ::free(block); 127 | } 128 | } -------------------------------------------------------------------------------- /src/net/MemoryManager.h: -------------------------------------------------------------------------------- 1 | #ifndef XOP_MEMMORY_MANAGER_H 2 | #define XOP_MEMMORY_MANAGER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace xop 10 | { 11 | 12 | void* Alloc(uint32_t size); 13 | void Free(void *ptr); 14 | 15 | class MemoryPool; 16 | 17 | struct MemoryBlock 18 | { 19 | uint32_t blockId = 0; 20 | MemoryPool *pool = nullptr; 21 | MemoryBlock *next = nullptr; 22 | }; 23 | 24 | class MemoryPool 25 | { 26 | public: 27 | MemoryPool(); 28 | ~MemoryPool(); 29 | 30 | void Init(uint32_t size, uint32_t n); 31 | void* Alloc(uint32_t size); 32 | void Free(void* ptr); 33 | 34 | size_t BolckSize() const 35 | { return block_size_; } 36 | 37 | //private: 38 | char* memory_ = nullptr; 39 | uint32_t block_size_ = 0; 40 | uint32_t num_blocks_ = 0; 41 | MemoryBlock* head_ = nullptr; 42 | std::mutex mutex_; 43 | }; 44 | 45 | class MemoryManager 46 | { 47 | public: 48 | static MemoryManager& Instance(); 49 | ~MemoryManager(); 50 | 51 | void* Alloc(uint32_t size); 52 | void Free(void* ptr); 53 | 54 | private: 55 | MemoryManager(); 56 | 57 | static const int kMaxMemoryPool = 3; 58 | MemoryPool memory_pools_[kMaxMemoryPool]; 59 | }; 60 | 61 | } 62 | #endif 63 | -------------------------------------------------------------------------------- /src/net/NetInterface.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #include "NetInterface.h" 5 | #include "Socket.h" 6 | 7 | using namespace xop; 8 | 9 | std::string NetInterface::GetLocalIPAddress() 10 | { 11 | #if defined(__linux) || defined(__linux__) 12 | SOCKET sockfd = 0; 13 | char buf[512] = { 0 }; 14 | struct ifconf ifconf; 15 | struct ifreq *ifreq; 16 | sockfd = socket(AF_INET, SOCK_DGRAM, 0); 17 | if (sockfd == INVALID_SOCKET) 18 | { 19 | close(sockfd); 20 | return "0.0.0.0"; 21 | } 22 | 23 | ifconf.ifc_len = 512; 24 | ifconf.ifc_buf = buf; 25 | if (ioctl(sockfd, SIOCGIFCONF, &ifconf) < 0) 26 | { 27 | close(sockfd); 28 | return "0.0.0.0"; 29 | } 30 | 31 | close(sockfd); 32 | 33 | ifreq = (struct ifreq*)ifconf.ifc_buf; 34 | for (int i = (ifconf.ifc_len / sizeof(struct ifreq)); i>0; i--) 35 | { 36 | if (ifreq->ifr_flags == AF_INET) 37 | { 38 | if (strcmp(ifreq->ifr_name, "lo") != 0) 39 | { 40 | return inet_ntoa(((struct sockaddr_in*)&(ifreq->ifr_addr))->sin_addr); 41 | } 42 | ifreq++; 43 | } 44 | } 45 | return "0.0.0.0"; 46 | #elif defined(WIN32) || defined(_WIN32) 47 | PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO(); 48 | unsigned long size = sizeof(IP_ADAPTER_INFO); 49 | 50 | int ret = GetAdaptersInfo(pIpAdapterInfo, &size); 51 | if (ret == ERROR_BUFFER_OVERFLOW) 52 | { 53 | delete pIpAdapterInfo; 54 | pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[size]; 55 | ret = GetAdaptersInfo(pIpAdapterInfo, &size); 56 | } 57 | 58 | if (ret != ERROR_SUCCESS) 59 | { 60 | delete pIpAdapterInfo; 61 | return "0.0.0.0"; 62 | } 63 | 64 | while (pIpAdapterInfo) 65 | { 66 | IP_ADDR_STRING *pIpAddrString = &(pIpAdapterInfo->IpAddressList); 67 | while(pIpAddrString) 68 | { 69 | if (strcmp(pIpAddrString->IpAddress.String, "127.0.0.1")!=0 70 | && strcmp(pIpAddrString->IpAddress.String, "0.0.0.0")!=0) 71 | { 72 | // pIpAddrString->IpMask.String 73 | //pIpAdapterInfo->GatewayList.IpAddress.String 74 | std::string ip(pIpAddrString->IpAddress.String); 75 | //delete pIpAdapterInfo; 76 | return ip; 77 | } 78 | pIpAddrString = pIpAddrString->Next; 79 | } while (pIpAddrString); 80 | pIpAdapterInfo = pIpAdapterInfo->Next; 81 | } 82 | 83 | delete pIpAdapterInfo; 84 | return "0.0.0.0"; 85 | #else 86 | return "0.0.0.0"; 87 | #endif 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/net/NetInterface.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef XOP_NET_INTERFACE_H 5 | #define XOP_NET_INTERFACE_H 6 | 7 | #include 8 | 9 | namespace xop { 10 | 11 | class NetInterface 12 | { 13 | public: 14 | static std::string GetLocalIPAddress(); 15 | }; 16 | 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/net/Pipe.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #include "Pipe.h" 5 | #include "SocketUtil.h" 6 | #include 7 | 8 | using namespace xop; 9 | 10 | Pipe::Pipe() 11 | { 12 | 13 | } 14 | 15 | bool Pipe::Create() 16 | { 17 | #if defined(WIN32) || defined(_WIN32) 18 | TcpSocket rp(socket(AF_INET, SOCK_STREAM, 0)), wp(socket(AF_INET, SOCK_STREAM, 0)); 19 | std::random_device rd; 20 | 21 | pipe_fd_[0] = rp.GetSocket(); 22 | pipe_fd_[1] = wp.GetSocket(); 23 | uint16_t port = 0; 24 | int again = 5; 25 | 26 | while(again--) { 27 | port = rd(); // random 28 | if (rp.Bind("127.0.0.1", port)) { 29 | break; 30 | } 31 | } 32 | 33 | if (again == 0) { 34 | return false; 35 | } 36 | 37 | if (!rp.Listen(1)) { 38 | return false; 39 | } 40 | 41 | if (!wp.Connect("127.0.0.1", port)) { 42 | return false; 43 | } 44 | 45 | if ((pipe_fd_[0] = rp.Accept()) < 0) { 46 | return false; 47 | } 48 | 49 | SocketUtil::SetNonBlock(pipe_fd_[0]); 50 | SocketUtil::SetNonBlock(pipe_fd_[1]); 51 | #elif defined(__linux) || defined(__linux__) 52 | if (pipe2(pipe_fd_, O_NONBLOCK | O_CLOEXEC) < 0) { 53 | return false; 54 | } 55 | #endif 56 | return true; 57 | } 58 | 59 | int Pipe::Write(void *buf, int len) 60 | { 61 | #if defined(WIN32) || defined(_WIN32) 62 | return ::send(pipe_fd_[1], (char *)buf, len, 0); 63 | #elif defined(__linux) || defined(__linux__) 64 | return ::write(pipe_fd_[1], buf, len); 65 | #endif 66 | } 67 | 68 | int Pipe::Read(void *buf, int len) 69 | { 70 | #if defined(WIN32) || defined(_WIN32) 71 | return recv(pipe_fd_[0], (char *)buf, len, 0); 72 | #elif defined(__linux) || defined(__linux__) 73 | return ::read(pipe_fd_[0], buf, len); 74 | #endif 75 | } 76 | 77 | void Pipe::Close() 78 | { 79 | #if defined(WIN32) || defined(_WIN32) 80 | closesocket(pipe_fd_[0]); 81 | closesocket(pipe_fd_[1]); 82 | #elif defined(__linux) || defined(__linux__) 83 | ::close(pipe_fd_[0]); 84 | ::close(pipe_fd_[1]); 85 | #endif 86 | 87 | } 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/net/Pipe.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef XOP_PIPE_H 5 | #define XOP_PIPE_H 6 | 7 | #include "TcpSocket.h" 8 | 9 | namespace xop 10 | { 11 | 12 | class Pipe 13 | { 14 | public: 15 | Pipe(); 16 | bool Create(); 17 | int Write(void *buf, int len); 18 | int Read(void *buf, int len); 19 | void Close(); 20 | 21 | SOCKET Read() const { return pipe_fd_[0]; } 22 | SOCKET Write() const { return pipe_fd_[1]; } 23 | 24 | private: 25 | SOCKET pipe_fd_[2]; 26 | }; 27 | 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/net/RingBuffer.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef XOP_RING_BUFFER_H 5 | #define XOP_RING_BUFFER_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace xop 13 | { 14 | 15 | template 16 | class RingBuffer 17 | { 18 | public: 19 | RingBuffer(unsigned capacity=60) 20 | : _buffer(capacity) 21 | , _capacity(capacity) 22 | , _numDatas(0) 23 | { } 24 | 25 | ~RingBuffer() { } 26 | 27 | bool push(const T& data) { return pushData(std::forward(data)); } 28 | bool push(T&& data) { return pushData(data); } 29 | 30 | bool pop(T& data) 31 | { 32 | if(_numDatas > 0) 33 | { 34 | data = std::move(_buffer[_getPos]); 35 | add(_getPos); 36 | _numDatas--; 37 | return true; 38 | } 39 | 40 | return false; 41 | } 42 | 43 | bool isFull() const { return ((_numDatas==_capacity)?true:false); } 44 | bool isEmpty() const { return ((_numDatas==0)?true:false); } 45 | int size() const { return _numDatas; } 46 | 47 | private: 48 | template 49 | bool pushData(F&& data) 50 | { 51 | if (_numDatas < _capacity) 52 | { 53 | _buffer[_putPos] = std::forward(data); 54 | add(_putPos); 55 | _numDatas++; 56 | return true; 57 | } 58 | 59 | return false; 60 | } 61 | 62 | void add(int& pos) 63 | { 64 | pos = (((pos+1)==_capacity) ? 0 : (pos+1)); 65 | } 66 | 67 | int _capacity = 0; 68 | int _putPos = 0; 69 | int _getPos = 0; 70 | 71 | std::atomic_int _numDatas; 72 | std::vector _buffer; 73 | }; 74 | 75 | } 76 | 77 | #endif 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/net/SelectTaskScheduler.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #include "SelectTaskScheduler.h" 5 | #include "Logger.h" 6 | #include "Timer.h" 7 | #include 8 | #include 9 | 10 | using namespace xop; 11 | 12 | #define SELECT_CTL_ADD 0 13 | #define SELECT_CTL_MOD 1 14 | #define SELECT_CTL_DEL 2 15 | 16 | SelectTaskScheduler::SelectTaskScheduler(int id) 17 | : TaskScheduler(id) 18 | { 19 | FD_ZERO(&fd_read_backup_); 20 | FD_ZERO(&fd_write_backup_); 21 | FD_ZERO(&fd_exp_backup_); 22 | 23 | this->UpdateChannel(wakeup_channel_); 24 | } 25 | 26 | SelectTaskScheduler::~SelectTaskScheduler() 27 | { 28 | 29 | } 30 | 31 | void SelectTaskScheduler::UpdateChannel(ChannelPtr channel) 32 | { 33 | std::lock_guard lock(mutex_); 34 | 35 | SOCKET socket = channel->GetSocket(); 36 | 37 | if(channels_.find(socket) != channels_.end()) { 38 | if(channel->IsNoneEvent()) { 39 | is_fd_read_reset_ = true; 40 | is_fd_write_reset_ = true; 41 | is_fd_exp_reset_ = true; 42 | channels_.erase(socket); 43 | } 44 | else { 45 | //is_fd_read_reset_ = true; 46 | is_fd_write_reset_ = true; 47 | } 48 | } 49 | else { 50 | if(!channel->IsNoneEvent()) { 51 | channels_.emplace(socket, channel); 52 | is_fd_read_reset_ = true; 53 | is_fd_write_reset_ = true; 54 | is_fd_exp_reset_ = true; 55 | } 56 | } 57 | } 58 | 59 | void SelectTaskScheduler::RemoveChannel(ChannelPtr& channel) 60 | { 61 | std::lock_guard lock(mutex_); 62 | 63 | SOCKET fd = channel->GetSocket(); 64 | 65 | if(channels_.find(fd) != channels_.end()) { 66 | is_fd_read_reset_ = true; 67 | is_fd_write_reset_ = true; 68 | is_fd_exp_reset_ = true; 69 | channels_.erase(fd); 70 | } 71 | } 72 | 73 | bool SelectTaskScheduler::HandleEvent(int timeout) 74 | { 75 | if(channels_.empty()) { 76 | if (timeout <= 0) { 77 | timeout = 10; 78 | } 79 | 80 | Timer::Sleep(timeout); 81 | return true; 82 | } 83 | 84 | fd_set fd_read; 85 | fd_set fd_write; 86 | fd_set fd_exp; 87 | FD_ZERO(&fd_read); 88 | FD_ZERO(&fd_write); 89 | FD_ZERO(&fd_exp); 90 | bool fd_read_reset = false; 91 | bool fd_write_reset = false; 92 | bool fd_exp_reset = false; 93 | 94 | if(is_fd_read_reset_ || is_fd_write_reset_ || is_fd_exp_reset_) { 95 | if (is_fd_exp_reset_) { 96 | maxfd_ = 0; 97 | } 98 | 99 | std::lock_guard lock(mutex_); 100 | for(auto iter : channels_) { 101 | int events = iter.second->GetEvents(); 102 | SOCKET fd = iter.second->GetSocket(); 103 | 104 | if (is_fd_read_reset_ && (events&EVENT_IN)) { 105 | FD_SET(fd, &fd_read); 106 | } 107 | 108 | if(is_fd_write_reset_ && (events&EVENT_OUT)) { 109 | FD_SET(fd, &fd_write); 110 | } 111 | 112 | if(is_fd_exp_reset_) { 113 | FD_SET(fd, &fd_exp); 114 | if(fd > maxfd_) { 115 | maxfd_ = fd; 116 | } 117 | } 118 | } 119 | 120 | fd_read_reset = is_fd_read_reset_; 121 | fd_write_reset = is_fd_write_reset_; 122 | fd_exp_reset = is_fd_exp_reset_; 123 | is_fd_read_reset_ = false; 124 | is_fd_write_reset_ = false; 125 | is_fd_exp_reset_ = false; 126 | } 127 | 128 | if(fd_read_reset) { 129 | FD_ZERO(&fd_read_backup_); 130 | memcpy(&fd_read_backup_, &fd_read, sizeof(fd_set)); 131 | } 132 | else { 133 | memcpy(&fd_read, &fd_read_backup_, sizeof(fd_set)); 134 | } 135 | 136 | 137 | if(fd_write_reset) { 138 | FD_ZERO(&fd_write_backup_); 139 | memcpy(&fd_write_backup_, &fd_write, sizeof(fd_set)); 140 | } 141 | else { 142 | memcpy(&fd_write, &fd_write_backup_, sizeof(fd_set)); 143 | } 144 | 145 | 146 | if(fd_exp_reset) { 147 | FD_ZERO(&fd_exp_backup_); 148 | memcpy(&fd_exp_backup_, &fd_exp, sizeof(fd_set)); 149 | } 150 | else { 151 | memcpy(&fd_exp, &fd_exp_backup_, sizeof(fd_set)); 152 | } 153 | 154 | if(timeout <= 0) { 155 | timeout = 10; 156 | } 157 | 158 | struct timeval tv = { timeout/1000, timeout%1000*1000 }; 159 | int ret = select((int)maxfd_+1, &fd_read, &fd_write, &fd_exp, &tv); 160 | if (ret < 0) { 161 | #if defined(__linux) || defined(__linux__) 162 | if(errno == EINTR) { 163 | return true; 164 | } 165 | #endif 166 | return false; 167 | } 168 | 169 | std::forward_list> event_list; 170 | if(ret > 0) { 171 | std::lock_guard lock(mutex_); 172 | for(auto iter : channels_) { 173 | int events = 0; 174 | SOCKET socket = iter.second->GetSocket(); 175 | 176 | if (FD_ISSET(socket, &fd_read)) { 177 | events |= EVENT_IN; 178 | } 179 | 180 | if (FD_ISSET(socket, &fd_write)) { 181 | events |= EVENT_OUT; 182 | } 183 | 184 | if (FD_ISSET(socket, &fd_exp)) { 185 | events |= (EVENT_HUP); // close 186 | } 187 | 188 | if(events != 0) { 189 | event_list.emplace_front(iter.second, events); 190 | } 191 | } 192 | } 193 | 194 | for(auto& iter: event_list) { 195 | iter.first->HandleEvent(iter.second); 196 | } 197 | 198 | return true; 199 | } 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /src/net/SelectTaskScheduler.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef XOP_SELECT_TASK_SCHEDULER_H 5 | #define XOP_SELECT_TASK_SCHEDULER_H 6 | 7 | #include "TaskScheduler.h" 8 | #include "Socket.h" 9 | #include 10 | #include 11 | 12 | #if defined(__linux) || defined(__linux__) 13 | #include 14 | #include 15 | #include 16 | #include 17 | #endif 18 | 19 | namespace xop 20 | { 21 | 22 | class SelectTaskScheduler : public TaskScheduler 23 | { 24 | public: 25 | SelectTaskScheduler(int id = 0); 26 | virtual ~SelectTaskScheduler(); 27 | 28 | void UpdateChannel(ChannelPtr channel); 29 | void RemoveChannel(ChannelPtr& channel); 30 | bool HandleEvent(int timeout); 31 | 32 | private: 33 | fd_set fd_read_backup_; 34 | fd_set fd_write_backup_; 35 | fd_set fd_exp_backup_; 36 | SOCKET maxfd_ = 0; 37 | 38 | bool is_fd_read_reset_ = false; 39 | bool is_fd_write_reset_ = false; 40 | bool is_fd_exp_reset_ = false; 41 | 42 | std::mutex mutex_; 43 | std::unordered_map channels_; 44 | }; 45 | 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/net/Socket.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef XOP_SOCKET_H 5 | #define XOP_SOCKET_H 6 | 7 | #if defined(__linux) || defined(__linux__) 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #define SOCKET int 25 | #define INVALID_SOCKET (-1) 26 | #define SOCKET_ERROR (-1) 27 | 28 | #elif defined(WIN32) || defined(_WIN32) 29 | #define FD_SETSIZE 1024 30 | #define WIN32_LEAN_AND_MEAN 31 | #define _WINSOCK_DEPRECATED_NO_WARNINGS 32 | #include 33 | #include 34 | #include 35 | #include 36 | #define SHUT_RD 0 37 | #define SHUT_WR 1 38 | #define SHUT_RDWR 2 39 | 40 | #else 41 | 42 | #endif 43 | 44 | #include 45 | #include 46 | 47 | #endif // _XOP_SOCKET_H 48 | -------------------------------------------------------------------------------- /src/net/SocketUtil.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #include "SocketUtil.h" 5 | #include "Socket.h" 6 | #include 7 | 8 | using namespace xop; 9 | 10 | bool SocketUtil::Bind(SOCKET sockfd, std::string ip, uint16_t port) 11 | { 12 | struct sockaddr_in addr = {0}; 13 | addr.sin_family = AF_INET; 14 | addr.sin_addr.s_addr = inet_addr(ip.c_str()); 15 | addr.sin_port = htons(port); 16 | 17 | if(::bind(sockfd, (struct sockaddr*)&addr, sizeof addr) == SOCKET_ERROR) { 18 | return false; 19 | } 20 | 21 | return true; 22 | } 23 | 24 | void SocketUtil::SetNonBlock(SOCKET fd) 25 | { 26 | #if defined(__linux) || defined(__linux__) 27 | int flags = fcntl(fd, F_GETFL, 0); 28 | fcntl(fd, F_SETFL, flags | O_NONBLOCK); 29 | #else 30 | unsigned long on = 1; 31 | ioctlsocket(fd, FIONBIO, &on); 32 | #endif 33 | } 34 | 35 | void SocketUtil::SetBlock(SOCKET fd, int writeTimeout) 36 | { 37 | #if defined(__linux) || defined(__linux__) 38 | int flags = fcntl(fd, F_GETFL, 0); 39 | fcntl(fd, F_SETFL, flags&(~O_NONBLOCK)); 40 | #elif defined(WIN32) || defined(_WIN32) 41 | unsigned long on = 0; 42 | ioctlsocket(fd, FIONBIO, &on); 43 | #else 44 | #endif 45 | if(writeTimeout > 0) 46 | { 47 | #ifdef SO_SNDTIMEO 48 | #if defined(__linux) || defined(__linux__) 49 | struct timeval tv = {writeTimeout/1000, (writeTimeout%1000)*1000}; 50 | setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof tv); 51 | #elif defined(WIN32) || defined(_WIN32) 52 | unsigned long ms = (unsigned long)writeTimeout; 53 | setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&ms, sizeof(unsigned long)); 54 | #else 55 | #endif 56 | #endif 57 | } 58 | } 59 | 60 | void SocketUtil::SetReuseAddr(SOCKET sockfd) 61 | { 62 | int on = 1; 63 | setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof on); 64 | } 65 | 66 | void SocketUtil::SetReusePort(SOCKET sockfd) 67 | { 68 | #ifdef SO_REUSEPORT 69 | int on = 1; 70 | setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const char*)&on, sizeof(on)); 71 | #endif 72 | } 73 | 74 | void SocketUtil::SetNoDelay(SOCKET sockfd) 75 | { 76 | #ifdef TCP_NODELAY 77 | int on = 1; 78 | int ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&on, sizeof(on)); 79 | #endif 80 | } 81 | 82 | void SocketUtil::SetKeepAlive(SOCKET sockfd) 83 | { 84 | int on = 1; 85 | setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on)); 86 | } 87 | 88 | void SocketUtil::SetNoSigpipe(SOCKET sockfd) 89 | { 90 | #ifdef SO_NOSIGPIPE 91 | int on = 1; 92 | setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (char *)&on, sizeof(on)); 93 | #endif 94 | } 95 | 96 | void SocketUtil::SetSendBufSize(SOCKET sockfd, int size) 97 | { 98 | setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size)); 99 | } 100 | 101 | void SocketUtil::SetRecvBufSize(SOCKET sockfd, int size) 102 | { 103 | setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size)); 104 | } 105 | 106 | std::string SocketUtil::GetPeerIp(SOCKET sockfd) 107 | { 108 | struct sockaddr_in addr = { 0 }; 109 | socklen_t addrlen = sizeof(struct sockaddr_in); 110 | if (getpeername(sockfd, (struct sockaddr *)&addr, &addrlen) == 0) 111 | { 112 | return inet_ntoa(addr.sin_addr); 113 | } 114 | 115 | return "0.0.0.0"; 116 | } 117 | 118 | uint16_t SocketUtil::GetPeerPort(SOCKET sockfd) 119 | { 120 | struct sockaddr_in addr = { 0 }; 121 | socklen_t addrlen = sizeof(struct sockaddr_in); 122 | if (getpeername(sockfd, (struct sockaddr *)&addr, &addrlen) == 0) 123 | { 124 | return ntohs(addr.sin_port); 125 | } 126 | 127 | return 0; 128 | } 129 | 130 | int SocketUtil::GetPeerAddr(SOCKET sockfd, struct sockaddr_in *addr) 131 | { 132 | socklen_t addrlen = sizeof(struct sockaddr_in); 133 | return getpeername(sockfd, (struct sockaddr *)addr, &addrlen); 134 | } 135 | 136 | void SocketUtil::Close(SOCKET sockfd) 137 | { 138 | #if defined(__linux) || defined(__linux__) 139 | ::close(sockfd); 140 | #elif defined(WIN32) || defined(_WIN32) 141 | ::closesocket(sockfd); 142 | #endif 143 | } 144 | 145 | bool SocketUtil::Connect(SOCKET sockfd, std::string ip, uint16_t port, int timeout) 146 | { 147 | bool isConnected = true; 148 | if (timeout > 0) 149 | { 150 | SocketUtil::SetNonBlock(sockfd); 151 | } 152 | 153 | struct sockaddr_in addr = { 0 }; 154 | socklen_t addrlen = sizeof(addr); 155 | addr.sin_family = AF_INET; 156 | addr.sin_port = htons(port); 157 | addr.sin_addr.s_addr = inet_addr(ip.c_str()); 158 | if (::connect(sockfd, (struct sockaddr*)&addr, addrlen) == SOCKET_ERROR) 159 | { 160 | if (timeout > 0) 161 | { 162 | isConnected = false; 163 | fd_set fdWrite; 164 | FD_ZERO(&fdWrite); 165 | FD_SET(sockfd, &fdWrite); 166 | struct timeval tv = { timeout / 1000, timeout % 1000 * 1000 }; 167 | select((int)sockfd + 1, NULL, &fdWrite, NULL, &tv); 168 | if (FD_ISSET(sockfd, &fdWrite)) 169 | { 170 | isConnected = true; 171 | } 172 | SocketUtil::SetBlock(sockfd); 173 | } 174 | else 175 | { 176 | isConnected = false; 177 | } 178 | } 179 | 180 | return isConnected; 181 | } 182 | 183 | -------------------------------------------------------------------------------- /src/net/SocketUtil.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef XOP_SOCKET_UTIL_H 5 | #define XOP_SOCKET_UTIL_H 6 | 7 | #include "Socket.h" 8 | #include 9 | 10 | namespace xop 11 | { 12 | 13 | class SocketUtil 14 | { 15 | public: 16 | static bool Bind(SOCKET sockfd, std::string ip, uint16_t port); 17 | static void SetNonBlock(SOCKET fd); 18 | static void SetBlock(SOCKET fd, int write_timeout=0); 19 | static void SetReuseAddr(SOCKET fd); 20 | static void SetReusePort(SOCKET sockfd); 21 | static void SetNoDelay(SOCKET sockfd); 22 | static void SetKeepAlive(SOCKET sockfd); 23 | static void SetNoSigpipe(SOCKET sockfd); 24 | static void SetSendBufSize(SOCKET sockfd, int size); 25 | static void SetRecvBufSize(SOCKET sockfd, int size); 26 | static std::string GetPeerIp(SOCKET sockfd); 27 | static uint16_t GetPeerPort(SOCKET sockfd); 28 | static int GetPeerAddr(SOCKET sockfd, struct sockaddr_in *addr); 29 | static void Close(SOCKET sockfd); 30 | static bool Connect(SOCKET sockfd, std::string ip, uint16_t port, int timeout=0); 31 | }; 32 | 33 | } 34 | 35 | #endif // _SOCKET_UTIL_H 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/net/TaskScheduler.cpp: -------------------------------------------------------------------------------- 1 | #include "TaskScheduler.h" 2 | #if defined(__linux) || defined(__linux__) 3 | #include 4 | #endif 5 | 6 | using namespace xop; 7 | 8 | TaskScheduler::TaskScheduler(int id) 9 | : id_(id) 10 | , is_shutdown_(false) 11 | , wakeup_pipe_(new Pipe()) 12 | , trigger_events_(new xop::RingBuffer(kMaxTriggetEvents)) 13 | { 14 | static std::once_flag flag; 15 | std::call_once(flag, [] { 16 | #if defined(WIN32) || defined(_WIN32) 17 | WSADATA wsa_data; 18 | if (WSAStartup(MAKEWORD(2, 2), &wsa_data)) { 19 | WSACleanup(); 20 | } 21 | #endif 22 | }); 23 | 24 | if (wakeup_pipe_->Create()) { 25 | wakeup_channel_.reset(new Channel(wakeup_pipe_->Read())); 26 | wakeup_channel_->EnableReading(); 27 | wakeup_channel_->SetReadCallback([this]() { this->Wake(); }); 28 | } 29 | } 30 | 31 | TaskScheduler::~TaskScheduler() 32 | { 33 | 34 | } 35 | 36 | void TaskScheduler::Start() 37 | { 38 | #if defined(__linux) || defined(__linux__) 39 | signal(SIGPIPE, SIG_IGN); 40 | signal(SIGQUIT, SIG_IGN); 41 | signal(SIGUSR1, SIG_IGN); 42 | signal(SIGTERM, SIG_IGN); 43 | signal(SIGKILL, SIG_IGN); 44 | #endif 45 | is_shutdown_ = false; 46 | while (!is_shutdown_) { 47 | this->HandleTriggerEvent(); 48 | this->timer_queue_.HandleTimerEvent(); 49 | int64_t timeout = this->timer_queue_.GetTimeRemaining(); 50 | this->HandleEvent((int)timeout); 51 | } 52 | } 53 | 54 | void TaskScheduler::Stop() 55 | { 56 | is_shutdown_ = true; 57 | char event = kTriggetEvent; 58 | wakeup_pipe_->Write(&event, 1); 59 | } 60 | 61 | TimerId TaskScheduler::AddTimer(TimerEvent timerEvent, uint32_t msec) 62 | { 63 | TimerId id = timer_queue_.AddTimer(timerEvent, msec); 64 | return id; 65 | } 66 | 67 | void TaskScheduler::RemoveTimer(TimerId timerId) 68 | { 69 | timer_queue_.RemoveTimer(timerId); 70 | } 71 | 72 | bool TaskScheduler::AddTriggerEvent(TriggerEvent callback) 73 | { 74 | if (trigger_events_->size() < kMaxTriggetEvents) { 75 | std::lock_guard lock(mutex_); 76 | char event = kTriggetEvent; 77 | trigger_events_->push(std::move(callback)); 78 | wakeup_pipe_->Write(&event, 1); 79 | return true; 80 | } 81 | 82 | return false; 83 | } 84 | 85 | void TaskScheduler::Wake() 86 | { 87 | char event[10] = { 0 }; 88 | while (wakeup_pipe_->Read(event, 10) > 0); 89 | } 90 | 91 | void TaskScheduler::HandleTriggerEvent() 92 | { 93 | do 94 | { 95 | TriggerEvent callback; 96 | if (trigger_events_->pop(callback)) { 97 | callback(); 98 | } 99 | } while (trigger_events_->size() > 0); 100 | } -------------------------------------------------------------------------------- /src/net/TaskScheduler.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef XOP_TASK_SCHEDULER_H 5 | #define XOP_TASK_SCHEDULER_H 6 | 7 | #include "Channel.h" 8 | #include "Pipe.h" 9 | #include "Timer.h" 10 | #include "RingBuffer.h" 11 | 12 | namespace xop 13 | { 14 | 15 | typedef std::function TriggerEvent; 16 | 17 | class TaskScheduler 18 | { 19 | public: 20 | TaskScheduler(int id=1); 21 | virtual ~TaskScheduler(); 22 | 23 | void Start(); 24 | void Stop(); 25 | TimerId AddTimer(TimerEvent timerEvent, uint32_t msec); 26 | void RemoveTimer(TimerId timerId); 27 | bool AddTriggerEvent(TriggerEvent callback); 28 | 29 | virtual void UpdateChannel(ChannelPtr channel) { }; 30 | virtual void RemoveChannel(ChannelPtr& channel) { }; 31 | virtual bool HandleEvent(int timeout) { return false; }; 32 | 33 | int GetId() const 34 | { return id_; } 35 | 36 | protected: 37 | void Wake(); 38 | void HandleTriggerEvent(); 39 | 40 | int id_ = 0; 41 | std::atomic_bool is_shutdown_; 42 | std::unique_ptr wakeup_pipe_; 43 | std::shared_ptr wakeup_channel_; 44 | std::unique_ptr> trigger_events_; 45 | 46 | std::mutex mutex_; 47 | TimerQueue timer_queue_; 48 | 49 | static const char kTriggetEvent = 1; 50 | static const char kTimerEvent = 2; 51 | static const int kMaxTriggetEvents = 50000; 52 | }; 53 | 54 | } 55 | #endif 56 | 57 | -------------------------------------------------------------------------------- /src/net/TcpConnection.cpp: -------------------------------------------------------------------------------- 1 | #include "TcpConnection.h" 2 | #include "SocketUtil.h" 3 | 4 | using namespace xop; 5 | 6 | TcpConnection::TcpConnection(TaskScheduler *task_scheduler, SOCKET sockfd) 7 | : task_scheduler_(task_scheduler) 8 | , read_buffer_(new BufferReader) 9 | , write_buffer_(new BufferWriter(500)) 10 | , channel_(new Channel(sockfd)) 11 | { 12 | is_closed_ = false; 13 | 14 | channel_->SetReadCallback([this]() { this->HandleRead(); }); 15 | channel_->SetWriteCallback([this]() { this->HandleWrite(); }); 16 | channel_->SetCloseCallback([this]() { this->HandleClose(); }); 17 | channel_->SetErrorCallback([this]() { this->HandleError(); }); 18 | 19 | SocketUtil::SetNonBlock(sockfd); 20 | SocketUtil::SetSendBufSize(sockfd, 100 * 1024); 21 | SocketUtil::SetKeepAlive(sockfd); 22 | 23 | channel_->EnableReading(); 24 | task_scheduler_->UpdateChannel(channel_); 25 | } 26 | 27 | TcpConnection::~TcpConnection() 28 | { 29 | SOCKET fd = channel_->GetSocket(); 30 | if (fd > 0) { 31 | SocketUtil::Close(fd); 32 | } 33 | } 34 | 35 | void TcpConnection::Send(std::shared_ptr data, uint32_t size) 36 | { 37 | if (!is_closed_) { 38 | mutex_.lock(); 39 | write_buffer_->Append(data, size); 40 | mutex_.unlock(); 41 | 42 | this->HandleWrite(); 43 | } 44 | } 45 | 46 | void TcpConnection::Send(const char *data, uint32_t size) 47 | { 48 | if (!is_closed_) { 49 | mutex_.lock(); 50 | write_buffer_->Append(data, size); 51 | mutex_.unlock(); 52 | 53 | this->HandleWrite(); 54 | } 55 | } 56 | 57 | void TcpConnection::Disconnect() 58 | { 59 | std::lock_guard lock(mutex_); 60 | auto conn = shared_from_this(); 61 | task_scheduler_->AddTriggerEvent([conn]() { 62 | conn->Close(); 63 | }); 64 | } 65 | 66 | void TcpConnection::HandleRead() 67 | { 68 | { 69 | std::lock_guard lock(mutex_); 70 | 71 | if (is_closed_) { 72 | return; 73 | } 74 | 75 | int ret = read_buffer_->Read(channel_->GetSocket()); 76 | if (ret <= 0) { 77 | this->Close(); 78 | return; 79 | } 80 | } 81 | 82 | if (read_cb_) { 83 | bool ret = read_cb_(shared_from_this(), *read_buffer_); 84 | if (false == ret) { 85 | std::lock_guard lock(mutex_); 86 | this->Close(); 87 | } 88 | } 89 | } 90 | 91 | void TcpConnection::HandleWrite() 92 | { 93 | if (is_closed_) { 94 | return; 95 | } 96 | 97 | //std::lock_guard lock(mutex_); 98 | if (!mutex_.try_lock()) { 99 | return; 100 | } 101 | 102 | int ret = 0; 103 | bool empty = false; 104 | do 105 | { 106 | ret = write_buffer_->Send(channel_->GetSocket()); 107 | if (ret < 0) { 108 | this->Close(); 109 | mutex_.unlock(); 110 | return; 111 | } 112 | empty = write_buffer_->IsEmpty(); 113 | } while (0); 114 | 115 | if (empty) { 116 | if (channel_->IsWriting()) { 117 | channel_->DisableWriting(); 118 | task_scheduler_->UpdateChannel(channel_); 119 | } 120 | } 121 | else if(!channel_->IsWriting()) { 122 | channel_->EnableWriting(); 123 | task_scheduler_->UpdateChannel(channel_); 124 | } 125 | 126 | mutex_.unlock(); 127 | } 128 | 129 | void TcpConnection::Close() 130 | { 131 | if (!is_closed_) { 132 | is_closed_ = true; 133 | task_scheduler_->RemoveChannel(channel_); 134 | 135 | if (close_cb_) { 136 | close_cb_(shared_from_this()); 137 | } 138 | 139 | if (disconnect_cb_) { 140 | disconnect_cb_(shared_from_this()); 141 | } 142 | } 143 | } 144 | 145 | void TcpConnection::HandleClose() 146 | { 147 | std::lock_guard lock(mutex_); 148 | this->Close(); 149 | } 150 | 151 | void TcpConnection::HandleError() 152 | { 153 | std::lock_guard lock(mutex_); 154 | this->Close(); 155 | } 156 | -------------------------------------------------------------------------------- /src/net/TcpConnection.h: -------------------------------------------------------------------------------- 1 | #ifndef XOP_TCP_CONNECTION_H 2 | #define XOP_TCP_CONNECTION_H 3 | 4 | #include 5 | #include 6 | #include "TaskScheduler.h" 7 | #include "BufferReader.h" 8 | #include "BufferWriter.h" 9 | #include "Channel.h" 10 | 11 | namespace xop 12 | { 13 | 14 | class TcpConnection : public std::enable_shared_from_this 15 | { 16 | public: 17 | using Ptr = std::shared_ptr; 18 | using DisconnectCallback = std::function conn)> ; 19 | using CloseCallback = std::function conn)>; 20 | using ReadCallback = std::function conn, xop::BufferReader& buffer)>; 21 | 22 | TcpConnection(TaskScheduler *task_scheduler, SOCKET sockfd); 23 | virtual ~TcpConnection(); 24 | 25 | TaskScheduler* GetTaskScheduler() const 26 | { return task_scheduler_; } 27 | 28 | void SetReadCallback(const ReadCallback& cb) 29 | { read_cb_ = cb; } 30 | 31 | void SetCloseCallback(const CloseCallback& cb) 32 | { close_cb_ = cb; } 33 | 34 | void Send(std::shared_ptr data, uint32_t size); 35 | void Send(const char *data, uint32_t size); 36 | 37 | void Disconnect(); 38 | 39 | bool IsClosed() const 40 | { return is_closed_; } 41 | 42 | SOCKET GetSocket() const 43 | { return channel_->GetSocket(); } 44 | 45 | protected: 46 | friend class TcpServer; 47 | 48 | virtual void HandleRead(); 49 | virtual void HandleWrite(); 50 | virtual void HandleClose(); 51 | virtual void HandleError(); 52 | 53 | void SetDisconnectCallback(const DisconnectCallback& cb) 54 | { disconnect_cb_ = cb; } 55 | 56 | TaskScheduler* task_scheduler_; 57 | std::unique_ptr read_buffer_; 58 | std::unique_ptr write_buffer_; 59 | std::atomic_bool is_closed_; 60 | 61 | private: 62 | void Close(); 63 | 64 | std::shared_ptr channel_; 65 | std::mutex mutex_; 66 | DisconnectCallback disconnect_cb_; 67 | CloseCallback close_cb_; 68 | ReadCallback read_cb_; 69 | }; 70 | 71 | } 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/net/TcpServer.cpp: -------------------------------------------------------------------------------- 1 | #include "TcpServer.h" 2 | #include "Acceptor.h" 3 | #include "EventLoop.h" 4 | #include "Logger.h" 5 | #include 6 | 7 | using namespace xop; 8 | using namespace std; 9 | 10 | TcpServer::TcpServer(EventLoop* event_loop) 11 | : event_loop_(event_loop) 12 | , port_(0) 13 | , acceptor_(new Acceptor(event_loop_)) 14 | , is_started_(false) 15 | { 16 | acceptor_->SetNewConnectionCallback([this](SOCKET sockfd) { 17 | TcpConnection::Ptr conn = this->OnConnect(sockfd); 18 | if (conn) { 19 | this->AddConnection(sockfd, conn); 20 | conn->SetDisconnectCallback([this](TcpConnection::Ptr conn) { 21 | auto scheduler = conn->GetTaskScheduler(); 22 | SOCKET sockfd = conn->GetSocket(); 23 | if (!scheduler->AddTriggerEvent([this, sockfd] {this->RemoveConnection(sockfd); })) { 24 | scheduler->AddTimer([this, sockfd]() {this->RemoveConnection(sockfd); return false; }, 100); 25 | } 26 | }); 27 | } 28 | }); 29 | } 30 | 31 | TcpServer::~TcpServer() 32 | { 33 | Stop(); 34 | } 35 | 36 | bool TcpServer::Start(std::string ip, uint16_t port) 37 | { 38 | Stop(); 39 | 40 | if (!is_started_) { 41 | if (acceptor_->Listen(ip, port) < 0) { 42 | return false; 43 | } 44 | 45 | port_ = port; 46 | ip_ = ip; 47 | is_started_ = true; 48 | return true; 49 | } 50 | 51 | return false; 52 | } 53 | 54 | void TcpServer::Stop() 55 | { 56 | if (is_started_) { 57 | 58 | mutex_.lock(); 59 | for (auto iter : connections_) { 60 | iter.second->Disconnect(); 61 | } 62 | mutex_.unlock(); 63 | 64 | acceptor_->Close(); 65 | is_started_ = false; 66 | 67 | while (1) { 68 | Timer::Sleep(1); 69 | if (connections_.empty()) { 70 | break; 71 | } 72 | } 73 | } 74 | } 75 | 76 | TcpConnection::Ptr TcpServer::OnConnect(SOCKET sockfd) 77 | { 78 | return std::make_shared(event_loop_->GetTaskScheduler().get(), sockfd); 79 | } 80 | 81 | void TcpServer::AddConnection(SOCKET sockfd, TcpConnection::Ptr tcpConn) 82 | { 83 | std::lock_guard locker(mutex_); 84 | connections_.emplace(sockfd, tcpConn); 85 | } 86 | 87 | void TcpServer::RemoveConnection(SOCKET sockfd) 88 | { 89 | std::lock_guard locker(mutex_); 90 | connections_.erase(sockfd); 91 | } 92 | -------------------------------------------------------------------------------- /src/net/TcpServer.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-11-10 3 | 4 | #ifndef XOP_TCPSERVER_H 5 | #define XOP_TCPSERVER_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "Socket.h" 12 | #include "TcpConnection.h" 13 | 14 | namespace xop 15 | { 16 | 17 | class Acceptor; 18 | class EventLoop; 19 | 20 | class TcpServer 21 | { 22 | public: 23 | TcpServer(EventLoop* event_loop); 24 | virtual ~TcpServer(); 25 | 26 | virtual bool Start(std::string ip, uint16_t port); 27 | virtual void Stop(); 28 | 29 | std::string GetIPAddress() const 30 | { return ip_; } 31 | 32 | uint16_t GetPort() const 33 | { return port_; } 34 | 35 | protected: 36 | virtual TcpConnection::Ptr OnConnect(SOCKET sockfd); 37 | virtual void AddConnection(SOCKET sockfd, TcpConnection::Ptr tcpConn); 38 | virtual void RemoveConnection(SOCKET sockfd); 39 | 40 | EventLoop* event_loop_; 41 | uint16_t port_; 42 | std::string ip_; 43 | std::unique_ptr acceptor_; 44 | bool is_started_; 45 | std::mutex mutex_; 46 | std::unordered_map> connections_; 47 | }; 48 | 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/net/TcpSocket.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #include "TcpSocket.h" 5 | #include "Socket.h" 6 | #include "SocketUtil.h" 7 | #include "Logger.h" 8 | 9 | using namespace xop; 10 | 11 | TcpSocket::TcpSocket(SOCKET sockfd) 12 | : sockfd_(sockfd) 13 | { 14 | 15 | } 16 | 17 | TcpSocket::~TcpSocket() 18 | { 19 | 20 | } 21 | 22 | SOCKET TcpSocket::Create() 23 | { 24 | sockfd_ = ::socket(AF_INET, SOCK_STREAM, 0); 25 | return sockfd_; 26 | } 27 | 28 | bool TcpSocket::Bind(std::string ip, uint16_t port) 29 | { 30 | struct sockaddr_in addr = {0}; 31 | addr.sin_family = AF_INET; 32 | addr.sin_addr.s_addr = inet_addr(ip.c_str()); 33 | addr.sin_port = htons(port); 34 | 35 | if(::bind(sockfd_, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) 36 | { 37 | LOG_DEBUG(" bind <%s:%u> failed.\n", sockfd_, ip.c_str(), port); 38 | return false; 39 | } 40 | 41 | return true; 42 | } 43 | 44 | bool TcpSocket::Listen(int backlog) 45 | { 46 | if(::listen(sockfd_, backlog) == SOCKET_ERROR) 47 | { 48 | LOG_DEBUG(" listen failed.\n", sockfd_); 49 | return false; 50 | } 51 | 52 | return true; 53 | } 54 | 55 | SOCKET TcpSocket::Accept() 56 | { 57 | struct sockaddr_in addr = {0}; 58 | socklen_t addrlen = sizeof addr; 59 | 60 | SOCKET clientfd = ::accept(sockfd_, (struct sockaddr*)&addr, &addrlen); 61 | 62 | return clientfd; 63 | } 64 | 65 | bool TcpSocket::Connect(std::string ip, uint16_t port, int timeout) 66 | { 67 | if(!SocketUtil::Connect(sockfd_, ip, port, timeout)) 68 | { 69 | LOG_DEBUG(" connect failed.\n", sockfd_); 70 | return false; 71 | } 72 | 73 | return true; 74 | } 75 | 76 | void TcpSocket::Close() 77 | { 78 | #if defined(__linux) || defined(__linux__) 79 | ::close(sockfd_); 80 | #elif defined(WIN32) || defined(_WIN32) 81 | closesocket(sockfd_); 82 | #else 83 | 84 | #endif 85 | sockfd_ = 0; 86 | } 87 | 88 | void TcpSocket::ShutdownWrite() 89 | { 90 | shutdown(sockfd_, SHUT_WR); 91 | sockfd_ = 0; 92 | } 93 | -------------------------------------------------------------------------------- /src/net/TcpSocket.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef XOP_TCP_SOCKET_H 5 | #define XOP_TCP_SOCKET_H 6 | 7 | #include 8 | #include 9 | #include "Socket.h" 10 | 11 | namespace xop 12 | { 13 | 14 | class TcpSocket 15 | { 16 | public: 17 | TcpSocket(SOCKET sockfd=-1); 18 | virtual ~TcpSocket(); 19 | 20 | SOCKET Create(); 21 | bool Bind(std::string ip, uint16_t port); 22 | bool Listen(int backlog); 23 | SOCKET Accept(); 24 | bool Connect(std::string ip, uint16_t port, int timeout = 0); 25 | void Close(); 26 | void ShutdownWrite(); 27 | 28 | SOCKET GetSocket() const { return sockfd_; } 29 | 30 | private: 31 | SOCKET sockfd_ = -1; 32 | }; 33 | 34 | } 35 | 36 | #endif 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/net/ThreadSafeQueue.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_SAFE_QUEUE_H 2 | #define THREAD_SAFE_QUEUE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace xop 9 | { 10 | 11 | template 12 | class ThreadSafeQueue 13 | { 14 | public: 15 | ThreadSafeQueue() 16 | { 17 | 18 | } 19 | 20 | ThreadSafeQueue(ThreadSafeQueue const& other) 21 | { 22 | std::lock_guard lock(other._mutex); 23 | _dataQueue = other._dataQueue; 24 | } 25 | 26 | ~ThreadSafeQueue() 27 | { 28 | 29 | } 30 | 31 | void push(T value) 32 | { 33 | std::lock_guard lock(_mutex); 34 | _dataQueue.push(value); 35 | _dataCond.notify_one(); 36 | } 37 | 38 | bool waitAndPop(T& value) 39 | { 40 | std::unique_lock lock(_mutex); 41 | _dataCond.wait(lock); 42 | if (_dataQueue.empty()) 43 | { 44 | return false; 45 | } 46 | value = _dataQueue.front(); 47 | _dataQueue.pop(); 48 | return true; 49 | } 50 | 51 | std::shared_ptr waitAndPop() 52 | { 53 | std::unique_lock lock(_mutex); 54 | _dataCond.wait(lock); 55 | if (_dataQueue.empty()) 56 | { 57 | return nullptr; 58 | } 59 | std::shared_ptr res(std::make_shared(_dataQueue.front())); 60 | _dataQueue.pop(); 61 | return res; 62 | } 63 | 64 | bool tryPop(T& value) 65 | { 66 | std::lock_guard lock(_mutex); 67 | if(_dataQueue.empty()) 68 | return false; 69 | 70 | value = _dataQueue.front(); 71 | _dataQueue.pop(); 72 | 73 | return true; 74 | } 75 | 76 | std::shared_ptr tryPop() 77 | { 78 | std::lock_guard lock(_mutex); 79 | if(_dataQueue.empty()) 80 | return std::shared_ptr(); 81 | std::shared_ptr res(std::make_shared(_dataQueue.front())); 82 | _dataQueue.pop(); 83 | return res; 84 | } 85 | 86 | size_t size() const 87 | { 88 | std::lock_guard lock(_mutex); 89 | return _dataQueue.size(); 90 | } 91 | 92 | bool empty() const 93 | { 94 | std::lock_guard lock(_mutex); 95 | return _dataQueue.empty(); 96 | } 97 | 98 | void clear() 99 | { 100 | std::lock_guard lock(_mutex); 101 | std::queue empty; 102 | _dataQueue.swap(empty); 103 | } 104 | 105 | void wake() 106 | { 107 | _dataCond.notify_one(); 108 | } 109 | 110 | private: 111 | mutable std::mutex _mutex; 112 | std::queue _dataQueue; 113 | std::condition_variable _dataCond; 114 | }; 115 | 116 | } 117 | 118 | #endif 119 | 120 | -------------------------------------------------------------------------------- /src/net/Timer.cpp: -------------------------------------------------------------------------------- 1 | #include "Timer.h" 2 | #include 3 | 4 | using namespace xop; 5 | using namespace std; 6 | using namespace std::chrono; 7 | 8 | TimerId TimerQueue::AddTimer(const TimerEvent& event, uint32_t ms) 9 | { 10 | std::lock_guard locker(mutex_); 11 | int64_t timeout = GetTimeNow(); 12 | TimerId timer_id = ++last_timer_id_; 13 | 14 | auto timer = make_shared(event, ms); 15 | timer->SetNextTimeout(timeout); 16 | timers_.emplace(timer_id, timer); 17 | events_.emplace(std::pair(timeout + ms, timer_id), std::move(timer)); 18 | return timer_id; 19 | } 20 | 21 | void TimerQueue::RemoveTimer(TimerId timerId) 22 | { 23 | std::lock_guard locker(mutex_); 24 | auto iter = timers_.find(timerId); 25 | if (iter != timers_.end()) { 26 | int64_t timeout = iter->second->getNextTimeout(); 27 | events_.erase(std::pair(timeout, timerId)); 28 | timers_.erase(timerId); 29 | } 30 | } 31 | 32 | int64_t TimerQueue::GetTimeNow() 33 | { 34 | auto time_point = steady_clock::now(); 35 | return duration_cast(time_point.time_since_epoch()).count(); 36 | } 37 | 38 | int64_t TimerQueue::GetTimeRemaining() 39 | { 40 | std::lock_guard locker(mutex_); 41 | 42 | if (timers_.empty()) { 43 | return -1; 44 | } 45 | 46 | int64_t msec = events_.begin()->first.first - GetTimeNow(); 47 | if (msec < 0) { 48 | msec = 0; 49 | } 50 | 51 | return msec; 52 | } 53 | 54 | void TimerQueue::HandleTimerEvent() 55 | { 56 | if(!timers_.empty()) { 57 | std::lock_guard locker(mutex_); 58 | int64_t timePoint = GetTimeNow(); 59 | while(!timers_.empty() && events_.begin()->first.first<=timePoint) 60 | { 61 | TimerId timerId = events_.begin()->first.second; 62 | bool flag = events_.begin()->second->event_callback_(); 63 | if(flag == true) { 64 | events_.begin()->second->SetNextTimeout(timePoint); 65 | auto timerPtr = std::move(events_.begin()->second); 66 | events_.erase(events_.begin()); 67 | events_.emplace(std::pair(timerPtr->getNextTimeout(), timerId), timerPtr); 68 | } 69 | else { 70 | events_.erase(events_.begin()); 71 | timers_.erase(timerId); 72 | } 73 | } 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/net/Timer.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef _XOP_TIMER_H 5 | #define _XOP_TIMER_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace xop 18 | { 19 | 20 | typedef std::function TimerEvent; 21 | typedef uint32_t TimerId; 22 | 23 | class Timer 24 | { 25 | public: 26 | Timer(const TimerEvent& event, uint32_t msec) 27 | : event_callback_(event) 28 | , interval_(msec) 29 | { 30 | if (interval_ == 0) { 31 | interval_ = 1; 32 | } 33 | } 34 | 35 | Timer() { } 36 | 37 | static void Sleep(uint32_t msec) 38 | { 39 | std::this_thread::sleep_for(std::chrono::milliseconds(msec)); 40 | } 41 | 42 | void SetEventCallback(const TimerEvent& event) 43 | { 44 | event_callback_ = event; 45 | } 46 | 47 | void Start(int64_t microseconds, bool repeat = false) 48 | { 49 | is_repeat_ = repeat; 50 | auto time_begin = std::chrono::high_resolution_clock::now(); 51 | int64_t elapsed = 0; 52 | 53 | do 54 | { 55 | std::this_thread::sleep_for(std::chrono::microseconds(microseconds - elapsed)); 56 | time_begin = std::chrono::high_resolution_clock::now(); 57 | event_callback_(); 58 | elapsed = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - time_begin).count(); 59 | if (elapsed < 0) { 60 | elapsed = 0; 61 | } 62 | 63 | } while (is_repeat_); 64 | } 65 | 66 | void stop() 67 | { 68 | is_repeat_ = false; 69 | } 70 | 71 | private: 72 | friend class TimerQueue; 73 | 74 | void SetNextTimeout(int64_t time_point) 75 | { 76 | next_timeout_ = time_point + interval_; 77 | } 78 | 79 | int64_t getNextTimeout() const 80 | { 81 | return next_timeout_; 82 | } 83 | 84 | bool is_repeat_ = false; 85 | TimerEvent event_callback_ = [] { return false; }; 86 | uint32_t interval_ = 0; 87 | int64_t next_timeout_ = 0; 88 | }; 89 | 90 | class TimerQueue 91 | { 92 | public: 93 | TimerId AddTimer(const TimerEvent& event, uint32_t msec); 94 | void RemoveTimer(TimerId timerId); 95 | 96 | int64_t GetTimeRemaining(); 97 | void HandleTimerEvent(); 98 | 99 | private: 100 | int64_t GetTimeNow(); 101 | 102 | std::mutex mutex_; 103 | std::unordered_map> timers_; 104 | std::map, std::shared_ptr> events_; 105 | uint32_t last_timer_id_ = 0; 106 | uint32_t time_remaining_ = 0; 107 | }; 108 | 109 | } 110 | 111 | #endif 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /src/net/Timestamp.cpp: -------------------------------------------------------------------------------- 1 | #include "Timestamp.h" 2 | #include 3 | #include // std::put_time 4 | #include 5 | 6 | using namespace xop; 7 | using namespace std; 8 | using namespace std::chrono; 9 | 10 | std::string Timestamp::localtime() 11 | { 12 | std::ostringstream stream; 13 | auto now = system_clock::now(); 14 | time_t tt = system_clock::to_time_t(now); 15 | 16 | #if defined(WIN32) || defined(_WIN32) 17 | struct tm tm; 18 | localtime_s(&tm, &tt); 19 | stream << std::put_time(&tm, "%F %T"); 20 | #elif defined(__linux) || defined(__linux__) 21 | char buffer[200] = {0}; 22 | std::string timeString; 23 | std::strftime(buffer, 200, "%F %T", std::localtime(&tt)); 24 | stream << buffer; 25 | #endif 26 | return stream.str(); 27 | } -------------------------------------------------------------------------------- /src/net/Timestamp.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-15 3 | 4 | #ifndef XOP_TIMESTAMP_H 5 | #define XOP_TIMESTAMP_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace xop 15 | { 16 | 17 | class Timestamp 18 | { 19 | public: 20 | Timestamp() 21 | : _beginTimePoint(std::chrono::high_resolution_clock::now()) 22 | { } 23 | 24 | void reset() 25 | { 26 | _beginTimePoint = std::chrono::high_resolution_clock::now(); 27 | } 28 | 29 | int64_t elapsed() 30 | { 31 | return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - _beginTimePoint).count(); 32 | } 33 | 34 | static std::string localtime(); 35 | 36 | private: 37 | std::chrono::time_point _beginTimePoint; 38 | }; 39 | 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/net/log.h: -------------------------------------------------------------------------------- 1 | #ifndef _XOP_LOG_H 2 | #define _XOP_LOG_H 3 | 4 | #include 5 | 6 | //#ifdef HI_DEBUG 7 | #define LOG(format, ...) \ 8 | { \ 9 | fprintf(stderr, "[DEBUG] [%s:%s:%d] " format "", \ 10 | __FILE__, __FUNCTION__ , __LINE__, ##__VA_ARGS__); \ 11 | } 12 | //#else 13 | //#define LOG(format, ...) 14 | //#endif 15 | 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/xop/AACSource.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-16 3 | 4 | #if defined(WIN32) || defined(_WIN32) 5 | #ifndef _CRT_SECURE_NO_WARNINGS 6 | #define _CRT_SECURE_NO_WARNINGS 7 | #endif 8 | #endif 9 | #include "AACSource.h" 10 | #include 11 | #include 12 | #include 13 | #if defined(__linux) || defined(__linux__) 14 | #include 15 | #endif 16 | 17 | using namespace xop; 18 | using namespace std; 19 | 20 | AACSource::AACSource(uint32_t samplerate, uint32_t channels, bool has_adts) 21 | : samplerate_(samplerate) 22 | , channels_(channels) 23 | , has_adts_(has_adts) 24 | { 25 | payload_ = 97; 26 | media_type_ = AAC; 27 | clock_rate_ = samplerate; 28 | } 29 | 30 | AACSource* AACSource::CreateNew(uint32_t samplerate, uint32_t channels, bool has_adts) 31 | { 32 | return new AACSource(samplerate, channels, has_adts); 33 | } 34 | 35 | AACSource::~AACSource() 36 | { 37 | 38 | } 39 | 40 | string AACSource::GetMediaDescription(uint16_t port) 41 | { 42 | char buf[100] = { 0 }; 43 | sprintf(buf, "m=audio %hu RTP/AVP 97", port); // \r\nb=AS:64 44 | 45 | return string(buf); 46 | } 47 | 48 | static uint32_t AACSampleRate[16] = 49 | { 50 | 97000, 88200, 64000, 48000, 51 | 44100, 32000, 24000, 22050, 52 | 16000, 12000, 11025, 8000, 53 | 7350, 0, 0, 0 /*reserved */ 54 | }; 55 | 56 | string AACSource::GetAttribute() // RFC 3640 57 | { 58 | char buf[500] = { 0 }; 59 | sprintf(buf, "a=rtpmap:97 MPEG4-GENERIC/%u/%u\r\n", samplerate_, channels_); 60 | 61 | uint8_t index = 0; 62 | for (index = 0; index < 16; index++) { 63 | if (AACSampleRate[index] == samplerate_) { 64 | break; 65 | } 66 | } 67 | 68 | if (index == 16) { 69 | return ""; // error 70 | } 71 | 72 | uint8_t profile = 1; 73 | char config[10] = {0}; 74 | 75 | sprintf(config, "%02x%02x", (uint8_t)((profile+1) << 3)|(index >> 1), (uint8_t)((index << 7)|(channels_<< 3))); 76 | sprintf(buf+strlen(buf), 77 | "a=fmtp:97 profile-level-id=1;" 78 | "mode=AAC-hbr;" 79 | "sizelength=13;indexlength=3;indexdeltalength=3;" 80 | "config=%04u", 81 | atoi(config)); 82 | 83 | return string(buf); 84 | } 85 | 86 | 87 | 88 | bool AACSource::HandleFrame(MediaChannelId channel_id, AVFrame frame) 89 | { 90 | if (frame.size > (MAX_RTP_PAYLOAD_SIZE-AU_SIZE)) { 91 | return false; 92 | } 93 | 94 | int adts_size = 0; 95 | if (has_adts_) { 96 | adts_size = ADTS_SIZE; 97 | } 98 | 99 | uint8_t *frame_buf = frame.buffer.get() + adts_size; 100 | uint32_t frame_size = frame.size - adts_size; 101 | 102 | char AU[AU_SIZE] = { 0 }; 103 | AU[0] = 0x00; 104 | AU[1] = 0x10; 105 | AU[2] = (frame_size & 0x1fe0) >> 5; 106 | AU[3] = (frame_size & 0x1f) << 3; 107 | 108 | RtpPacket rtpPkt; 109 | rtpPkt.type = frame.type; 110 | rtpPkt.timestamp = frame.timestamp; 111 | rtpPkt.size = frame_size + 4 + RTP_HEADER_SIZE + AU_SIZE; 112 | rtpPkt.last = 1; 113 | 114 | rtpPkt.data.get()[4 + RTP_HEADER_SIZE + 0] = AU[0]; 115 | rtpPkt.data.get()[4 + RTP_HEADER_SIZE + 1] = AU[1]; 116 | rtpPkt.data.get()[4 + RTP_HEADER_SIZE + 2] = AU[2]; 117 | rtpPkt.data.get()[4 + RTP_HEADER_SIZE + 3] = AU[3]; 118 | 119 | memcpy(rtpPkt.data.get()+4+RTP_HEADER_SIZE+AU_SIZE, frame_buf, frame_size); 120 | 121 | if (send_frame_callback_) { 122 | send_frame_callback_(channel_id, rtpPkt); 123 | } 124 | 125 | return true; 126 | } 127 | 128 | uint32_t AACSource::GetTimestamp(uint32_t sampleRate) 129 | { 130 | //auto time_point = chrono::time_point_cast(chrono::high_resolution_clock::now()); 131 | //return (uint32_t)(time_point.time_since_epoch().count() * sampleRate / 1000); 132 | 133 | auto time_point = chrono::time_point_cast(chrono::steady_clock::now()); 134 | return (uint32_t)((time_point.time_since_epoch().count()+500) / 1000 * sampleRate / 1000); 135 | } 136 | -------------------------------------------------------------------------------- /src/xop/AACSource.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-16 3 | 4 | #ifndef XOP_AAC_SOURCE_H 5 | #define XOP_AAC_SOURCE_H 6 | 7 | #include "MediaSource.h" 8 | #include "rtp.h" 9 | 10 | namespace xop 11 | { 12 | 13 | class AACSource : public MediaSource 14 | { 15 | public: 16 | static AACSource* CreateNew(uint32_t samplerate=44100, uint32_t channels=2, bool has_adts=true); 17 | virtual ~AACSource(); 18 | 19 | uint32_t GetSamplerate() const 20 | { return samplerate_; } 21 | 22 | uint32_t GetChannels() const 23 | { return channels_; } 24 | 25 | virtual std::string GetMediaDescription(uint16_t port=0); 26 | 27 | virtual std::string GetAttribute(); 28 | 29 | bool HandleFrame(MediaChannelId channel_id, AVFrame frame); 30 | 31 | static uint32_t GetTimestamp(uint32_t samplerate =44100); 32 | 33 | private: 34 | AACSource(uint32_t samplerate, uint32_t channels, bool has_adts); 35 | 36 | uint32_t samplerate_ = 44100; 37 | uint32_t channels_ = 2; 38 | bool has_adts_ = true; 39 | 40 | static const int ADTS_SIZE = 7; 41 | static const int AU_SIZE = 4; 42 | }; 43 | 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/xop/DigestAuthentication.cpp: -------------------------------------------------------------------------------- 1 | #include "DigestAuthentication.h" 2 | #include "md5/md5.hpp" 3 | 4 | using namespace xop; 5 | 6 | DigestAuthentication::DigestAuthentication(std::string realm, std::string username, std::string password) 7 | : m_realm(realm) 8 | , m_username(username) 9 | , m_password(password) 10 | { 11 | 12 | } 13 | 14 | DigestAuthentication::~DigestAuthentication() 15 | { 16 | 17 | } 18 | 19 | std::string DigestAuthentication::GetNonce() 20 | { 21 | return md5::generate_nonce(); 22 | } 23 | 24 | std::string DigestAuthentication::GetResponse(std::string nonce, std::string cmd, std::string url) 25 | { 26 | //md5(md5(: : ) : : md5(:)) 27 | 28 | auto hex1 = md5::md5_hash_hex(m_username + ":" + m_realm + ":" + m_password); 29 | auto hex2 = md5::md5_hash_hex(cmd + ":" + url); 30 | auto response = md5::md5_hash_hex(hex1 + ":" + nonce + ":" + hex2); 31 | return response; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/xop/DigestAuthentication.h: -------------------------------------------------------------------------------- 1 | //PHZ 2 | //2019-10-6 3 | 4 | #ifndef RTSP_DIGEST_AUTHENTICATION_H 5 | #define RTSP_DIGEST_AUTHENTICATION_H 6 | 7 | #include 8 | #include 9 | 10 | namespace xop 11 | { 12 | 13 | class DigestAuthentication 14 | { 15 | public: 16 | DigestAuthentication(std::string realm, std::string username, std::string password); 17 | virtual ~DigestAuthentication(); 18 | 19 | std::string GetRealm() const 20 | { return m_realm; } 21 | 22 | std::string GetUsername() const 23 | { return m_username; } 24 | 25 | std::string GetPassword() const 26 | { return m_password; } 27 | 28 | std::string GetNonce(); 29 | std::string GetResponse(std::string nonce, std::string cmd, std::string url); 30 | 31 | private: 32 | std::string m_realm; 33 | std::string m_username; 34 | std::string m_password; 35 | 36 | }; 37 | 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/xop/G711ASource.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-16 3 | 4 | #if defined(WIN32) || defined(_WIN32) 5 | #ifndef _CRT_SECURE_NO_WARNINGS 6 | #define _CRT_SECURE_NO_WARNINGS 7 | #endif 8 | #endif 9 | #include "G711ASource.h" 10 | #include 11 | #include 12 | #if defined(__linux) || defined(__linux__) 13 | #include 14 | #endif 15 | 16 | using namespace xop; 17 | using namespace std; 18 | 19 | G711ASource::G711ASource() 20 | { 21 | payload_ = 8; 22 | media_type_ = PCMA; 23 | clock_rate_ = 8000; 24 | } 25 | 26 | G711ASource* G711ASource::CreateNew() 27 | { 28 | return new G711ASource(); 29 | } 30 | 31 | G711ASource::~G711ASource() 32 | { 33 | 34 | } 35 | 36 | string G711ASource::GetMediaDescription(uint16_t port) 37 | { 38 | char buf[100] = {0}; 39 | sprintf(buf, "m=audio %hu RTP/AVP 8", port); 40 | 41 | return string(buf); 42 | } 43 | 44 | string G711ASource::GetAttribute() 45 | { 46 | return string("a=rtpmap:8 PCMA/8000/1"); 47 | } 48 | 49 | bool G711ASource::HandleFrame(MediaChannelId channel_id, AVFrame frame) 50 | { 51 | if (frame.size > MAX_RTP_PAYLOAD_SIZE) { 52 | return false; 53 | } 54 | 55 | uint8_t *frame_buf = frame.buffer.get(); 56 | uint32_t frame_size = frame.size; 57 | 58 | RtpPacket rtpPkt; 59 | rtpPkt.type = frame.type; 60 | rtpPkt.timestamp = frame.timestamp; 61 | rtpPkt.size = frame_size + 4 + RTP_HEADER_SIZE; 62 | rtpPkt.last = 1; 63 | 64 | memcpy(rtpPkt.data.get()+4+RTP_HEADER_SIZE, frame_buf, frame_size); 65 | 66 | if (send_frame_callback_) { 67 | send_frame_callback_(channel_id, rtpPkt); 68 | } 69 | 70 | return true; 71 | } 72 | 73 | uint32_t G711ASource::GetTimestamp() 74 | { 75 | auto time_point = chrono::time_point_cast(chrono::steady_clock::now()); 76 | return (uint32_t)((time_point.time_since_epoch().count()+500)/1000*8); 77 | } 78 | 79 | -------------------------------------------------------------------------------- /src/xop/G711ASource.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-16 3 | 4 | #ifndef XOP_G711A_SOURCE_H 5 | #define XOP_G711A_SOURCE_H 6 | 7 | #include "MediaSource.h" 8 | #include "rtp.h" 9 | 10 | namespace xop 11 | { 12 | 13 | class G711ASource : public MediaSource 14 | { 15 | public: 16 | static G711ASource* CreateNew(); 17 | virtual ~G711ASource(); 18 | 19 | uint32_t GetSampleRate() const 20 | { return samplerate_; } 21 | 22 | uint32_t GetChannels() const 23 | { return channels_; } 24 | 25 | virtual std::string GetMediaDescription(uint16_t port=0); 26 | 27 | virtual std::string GetAttribute(); 28 | 29 | bool HandleFrame(MediaChannelId channel_id, AVFrame frame); 30 | 31 | static uint32_t GetTimestamp(); 32 | 33 | private: 34 | G711ASource(); 35 | 36 | uint32_t samplerate_ = 8000; 37 | uint32_t channels_ = 1; 38 | }; 39 | 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/xop/H264Parser.cpp: -------------------------------------------------------------------------------- 1 | #include "H264Parser.h" 2 | #include 3 | 4 | using namespace xop; 5 | 6 | Nal H264Parser::findNal(const uint8_t *data, uint32_t size) 7 | { 8 | Nal nal(nullptr, nullptr); 9 | 10 | if(size < 5) 11 | { 12 | return nal; 13 | } 14 | 15 | nal.second = const_cast(data) + (size-1); 16 | 17 | uint32_t startCode = 0; 18 | uint32_t pos = 0; 19 | uint8_t prefix[3] = {0}; 20 | memcpy(prefix, data, 3); 21 | size -= 3; 22 | data += 2; 23 | 24 | while(size--) 25 | { 26 | if ((prefix[pos % 3] == 0) && (prefix[(pos + 1) % 3] == 0) && (prefix[(pos + 2) % 3] == 1)) 27 | { 28 | if(nal.first == nullptr) // 00 00 01 29 | { 30 | nal.first = const_cast(data) + 1; 31 | startCode = 3; 32 | } 33 | else if(startCode == 3) 34 | { 35 | nal.second = const_cast(data) - 3; 36 | break; 37 | } 38 | } 39 | else if ((prefix[pos % 3] == 0) && (prefix[(pos + 1) % 3] == 0) && (prefix[(pos + 2) % 3] == 0)) 40 | { 41 | if (*(data+1) == 0x01) // 00 00 00 01 42 | { 43 | if(nal.first == nullptr) 44 | { 45 | if(size >= 1) 46 | { 47 | nal.first = const_cast(data) + 2; 48 | } 49 | else 50 | { 51 | break; 52 | } 53 | startCode = 4; 54 | } 55 | else if(startCode == 4) 56 | { 57 | nal.second = const_cast(data) - 3; 58 | break; 59 | } 60 | } 61 | } 62 | 63 | prefix[(pos++) % 3] = *(++data); 64 | } 65 | 66 | if(nal.first == nullptr) 67 | nal.second = nullptr; 68 | 69 | return nal; 70 | } 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/xop/H264Parser.h: -------------------------------------------------------------------------------- 1 | #ifndef XOP_H264_PARSER_H 2 | #define XOP_H264_PARSER_H 3 | 4 | #include 5 | #include 6 | 7 | namespace xop 8 | { 9 | 10 | typedef std::pair Nal; // 11 | 12 | class H264Parser 13 | { 14 | public: 15 | static Nal findNal(const uint8_t *data, uint32_t size); 16 | 17 | private: 18 | 19 | }; 20 | 21 | } 22 | 23 | #endif 24 | 25 | -------------------------------------------------------------------------------- /src/xop/H264Source.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-16 3 | 4 | #if defined(WIN32) || defined(_WIN32) 5 | #ifndef _CRT_SECURE_NO_WARNINGS 6 | #define _CRT_SECURE_NO_WARNINGS 7 | #endif 8 | #endif 9 | 10 | #include "H264Source.h" 11 | #include 12 | #include 13 | #if defined(__linux) || defined(__linux__) 14 | #include 15 | #endif 16 | 17 | using namespace xop; 18 | using namespace std; 19 | 20 | H264Source::H264Source(uint32_t framerate) 21 | : framerate_(framerate) 22 | { 23 | payload_ = 96; 24 | media_type_ = H264; 25 | clock_rate_ = 90000; 26 | } 27 | 28 | H264Source* H264Source::CreateNew(uint32_t framerate) 29 | { 30 | return new H264Source(framerate); 31 | } 32 | 33 | H264Source::~H264Source() 34 | { 35 | 36 | } 37 | 38 | string H264Source::GetMediaDescription(uint16_t port) 39 | { 40 | char buf[100] = {0}; 41 | sprintf(buf, "m=video %hu RTP/AVP 96", port); // \r\nb=AS:2000 42 | 43 | return string(buf); 44 | } 45 | 46 | string H264Source::GetAttribute() 47 | { 48 | return string("a=rtpmap:96 H264/90000"); 49 | } 50 | 51 | bool H264Source::HandleFrame(MediaChannelId channel_id, AVFrame frame) 52 | { 53 | uint8_t* frame_buf = frame.buffer.get(); 54 | uint32_t frame_size = frame.size; 55 | 56 | if (frame.timestamp == 0) { 57 | frame.timestamp = GetTimestamp(); 58 | } 59 | 60 | if (frame_size <= MAX_RTP_PAYLOAD_SIZE) { 61 | RtpPacket rtp_pkt; 62 | rtp_pkt.type = frame.type; 63 | rtp_pkt.timestamp = frame.timestamp; 64 | rtp_pkt.size = frame_size + 4 + RTP_HEADER_SIZE; 65 | rtp_pkt.last = 1; 66 | memcpy(rtp_pkt.data.get()+4+RTP_HEADER_SIZE, frame_buf, frame_size); 67 | 68 | if (send_frame_callback_) { 69 | if (!send_frame_callback_(channel_id, rtp_pkt)) { 70 | return false; 71 | } 72 | } 73 | } 74 | else { 75 | char FU_A[2] = {0}; 76 | 77 | FU_A[0] = (frame_buf[0] & 0xE0) | 28; 78 | FU_A[1] = 0x80 | (frame_buf[0] & 0x1f); 79 | 80 | frame_buf += 1; 81 | frame_size -= 1; 82 | 83 | while (frame_size + 2 > MAX_RTP_PAYLOAD_SIZE) { 84 | RtpPacket rtp_pkt; 85 | rtp_pkt.type = frame.type; 86 | rtp_pkt.timestamp = frame.timestamp; 87 | rtp_pkt.size = 4 + RTP_HEADER_SIZE + MAX_RTP_PAYLOAD_SIZE; 88 | rtp_pkt.last = 0; 89 | 90 | rtp_pkt.data.get()[RTP_HEADER_SIZE+4] = FU_A[0]; 91 | rtp_pkt.data.get()[RTP_HEADER_SIZE+5] = FU_A[1]; 92 | memcpy(rtp_pkt.data.get()+4+RTP_HEADER_SIZE+2, frame_buf, MAX_RTP_PAYLOAD_SIZE-2); 93 | 94 | if (send_frame_callback_) { 95 | if (!send_frame_callback_(channel_id, rtp_pkt)) 96 | return false; 97 | } 98 | 99 | frame_buf += MAX_RTP_PAYLOAD_SIZE - 2; 100 | frame_size -= MAX_RTP_PAYLOAD_SIZE - 2; 101 | 102 | FU_A[1] &= ~0x80; 103 | } 104 | 105 | { 106 | RtpPacket rtp_pkt; 107 | rtp_pkt.type = frame.type; 108 | rtp_pkt.timestamp = frame.timestamp; 109 | rtp_pkt.size = 4 + RTP_HEADER_SIZE + 2 + frame_size; 110 | rtp_pkt.last = 1; 111 | 112 | FU_A[1] |= 0x40; 113 | rtp_pkt.data.get()[RTP_HEADER_SIZE+4] = FU_A[0]; 114 | rtp_pkt.data.get()[RTP_HEADER_SIZE+5] = FU_A[1]; 115 | memcpy(rtp_pkt.data.get()+4+RTP_HEADER_SIZE+2, frame_buf, frame_size); 116 | 117 | if (send_frame_callback_) { 118 | if (!send_frame_callback_(channel_id, rtp_pkt)) { 119 | return false; 120 | } 121 | } 122 | } 123 | } 124 | 125 | return true; 126 | } 127 | 128 | uint32_t H264Source::GetTimestamp() 129 | { 130 | /* #if defined(__linux) || defined(__linux__) 131 | struct timeval tv = {0}; 132 | gettimeofday(&tv, NULL); 133 | uint32_t ts = ((tv.tv_sec*1000)+((tv.tv_usec+500)/1000))*90; // 90: _clockRate/1000; 134 | return ts; 135 | #else */ 136 | auto time_point = chrono::time_point_cast(chrono::steady_clock::now()); 137 | return (uint32_t)((time_point.time_since_epoch().count() + 500) / 1000 * 90 ); 138 | //#endif 139 | } 140 | -------------------------------------------------------------------------------- /src/xop/H264Source.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-16 3 | 4 | #ifndef XOP_H264_SOURCE_H 5 | #define XOP_H264_SOURCE_H 6 | 7 | #include "MediaSource.h" 8 | #include "rtp.h" 9 | 10 | namespace xop 11 | { 12 | 13 | class H264Source : public MediaSource 14 | { 15 | public: 16 | static H264Source* CreateNew(uint32_t framerate=25); 17 | ~H264Source(); 18 | 19 | void SetFramerate(uint32_t framerate) 20 | { framerate_ = framerate; } 21 | 22 | uint32_t GetFramerate() const 23 | { return framerate_; } 24 | 25 | virtual std::string GetMediaDescription(uint16_t port); 26 | 27 | virtual std::string GetAttribute(); 28 | 29 | bool HandleFrame(MediaChannelId channel_id, AVFrame frame); 30 | 31 | static uint32_t GetTimestamp(); 32 | 33 | private: 34 | H264Source(uint32_t framerate); 35 | 36 | uint32_t framerate_ = 25; 37 | }; 38 | 39 | } 40 | 41 | #endif 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/xop/H265Source.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-6-7 3 | 4 | #if defined(WIN32) || defined(_WIN32) 5 | #ifndef _CRT_SECURE_NO_WARNINGS 6 | #define _CRT_SECURE_NO_WARNINGS 7 | #endif 8 | #endif 9 | 10 | #include "H265Source.h" 11 | #include 12 | #include 13 | #if defined(__linux) || defined(__linux__) 14 | #include 15 | #endif 16 | 17 | using namespace xop; 18 | using namespace std; 19 | 20 | H265Source::H265Source(uint32_t framerate) 21 | : framerate_(framerate) 22 | { 23 | payload_ = 96; 24 | media_type_ = H265; 25 | clock_rate_ = 90000; 26 | } 27 | 28 | H265Source* H265Source::CreateNew(uint32_t framerate) 29 | { 30 | return new H265Source(framerate); 31 | } 32 | 33 | H265Source::~H265Source() 34 | { 35 | 36 | } 37 | 38 | string H265Source::GetMediaDescription(uint16_t port) 39 | { 40 | char buf[100] = {0}; 41 | sprintf(buf, "m=video %hu RTP/AVP 96", port); 42 | 43 | return string(buf); 44 | } 45 | 46 | string H265Source::GetAttribute() 47 | { 48 | return string("a=rtpmap:96 H265/90000"); 49 | } 50 | 51 | bool H265Source::HandleFrame(MediaChannelId channelId, AVFrame frame) 52 | { 53 | uint8_t *frame_buf = frame.buffer.get(); 54 | uint32_t frame_size = frame.size; 55 | 56 | if (frame.timestamp == 0) { 57 | frame.timestamp = GetTimestamp(); 58 | } 59 | 60 | if (frame_size <= MAX_RTP_PAYLOAD_SIZE) { 61 | RtpPacket rtp_pkt; 62 | rtp_pkt.type = frame.type; 63 | rtp_pkt.timestamp = frame.timestamp; 64 | rtp_pkt.size = frame_size + 4 + RTP_HEADER_SIZE; 65 | rtp_pkt.last = 1; 66 | 67 | memcpy(rtp_pkt.data.get()+4+RTP_HEADER_SIZE, frame_buf, frame_size); 68 | 69 | if (send_frame_callback_) { 70 | if (!send_frame_callback_(channelId, rtp_pkt)) { 71 | return false; 72 | } 73 | } 74 | } 75 | else { 76 | char FU[3] = {0}; 77 | char nalUnitType = (frame_buf[0] & 0x7E) >> 1; 78 | FU[0] = (frame_buf[0] & 0x81) | (49<<1); 79 | FU[1] = frame_buf[1]; 80 | FU[2] = (0x80 | nalUnitType); 81 | 82 | frame_buf += 2; 83 | frame_size -= 2; 84 | 85 | while (frame_size + 3 > MAX_RTP_PAYLOAD_SIZE) { 86 | RtpPacket rtp_pkt; 87 | rtp_pkt.type = frame.type; 88 | rtp_pkt.timestamp = frame.timestamp; 89 | rtp_pkt.size = 4 + RTP_HEADER_SIZE + MAX_RTP_PAYLOAD_SIZE; 90 | rtp_pkt.last = 0; 91 | 92 | rtp_pkt.data.get()[RTP_HEADER_SIZE+4] = FU[0]; 93 | rtp_pkt.data.get()[RTP_HEADER_SIZE+5] = FU[1]; 94 | rtp_pkt.data.get()[RTP_HEADER_SIZE+6] = FU[2]; 95 | memcpy(rtp_pkt.data.get()+4+RTP_HEADER_SIZE+3, frame_buf, MAX_RTP_PAYLOAD_SIZE-3); 96 | 97 | if (send_frame_callback_) { 98 | if (!send_frame_callback_(channelId, rtp_pkt)) { 99 | return false; 100 | } 101 | } 102 | 103 | frame_buf += (MAX_RTP_PAYLOAD_SIZE - 3); 104 | frame_size -= (MAX_RTP_PAYLOAD_SIZE - 3); 105 | 106 | FU[2] &= ~0x80; 107 | } 108 | 109 | { 110 | RtpPacket rtp_pkt; 111 | rtp_pkt.type = frame.type; 112 | rtp_pkt.timestamp = frame.timestamp; 113 | rtp_pkt.size = 4 + RTP_HEADER_SIZE + 3 + frame_size; 114 | rtp_pkt.last = 1; 115 | 116 | FU[2] |= 0x40; 117 | rtp_pkt.data.get()[RTP_HEADER_SIZE+4] = FU[0]; 118 | rtp_pkt.data.get()[RTP_HEADER_SIZE+5] = FU[1]; 119 | rtp_pkt.data.get()[RTP_HEADER_SIZE+6] = FU[2]; 120 | memcpy(rtp_pkt.data.get()+4+RTP_HEADER_SIZE+3, frame_buf, frame_size); 121 | 122 | if (send_frame_callback_) { 123 | if (!send_frame_callback_(channelId, rtp_pkt)) { 124 | return false; 125 | } 126 | } 127 | } 128 | } 129 | 130 | return true; 131 | } 132 | 133 | 134 | uint32_t H265Source::GetTimestamp() 135 | { 136 | /* #if defined(__linux) || defined(__linux__) 137 | struct timeval tv = {0}; 138 | gettimeofday(&tv, NULL); 139 | uint32_t ts = ((tv.tv_sec*1000)+((tv.tv_usec+500)/1000))*90; // 90: _clockRate/1000; 140 | return ts; 141 | #else */ 142 | //auto time_point = chrono::time_point_cast(chrono::system_clock::now()); 143 | //auto time_point = chrono::time_point_cast(chrono::steady_clock::now()); 144 | auto time_point = chrono::time_point_cast(chrono::steady_clock::now()); 145 | return (uint32_t)((time_point.time_since_epoch().count() + 500) / 1000 * 90); 146 | //#endif 147 | } 148 | -------------------------------------------------------------------------------- /src/xop/H265Source.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-16 3 | 4 | #ifndef XOP_H265_SOURCE_H 5 | #define XOP_H265_SOURCE_H 6 | 7 | #include "MediaSource.h" 8 | #include "rtp.h" 9 | 10 | namespace xop 11 | { 12 | 13 | class H265Source : public MediaSource 14 | { 15 | public: 16 | static H265Source* CreateNew(uint32_t framerate=25); 17 | ~H265Source(); 18 | 19 | void Setframerate(uint32_t framerate) 20 | { framerate_ = framerate; } 21 | 22 | uint32_t GetFramerate() const 23 | { return framerate_; } 24 | 25 | virtual std::string GetMediaDescription(uint16_t port=0); 26 | 27 | virtual std::string GetAttribute(); 28 | 29 | bool HandleFrame(MediaChannelId channelId, AVFrame frame); 30 | 31 | static uint32_t GetTimestamp(); 32 | 33 | private: 34 | H265Source(uint32_t framerate); 35 | 36 | uint32_t framerate_ = 25; 37 | }; 38 | 39 | } 40 | 41 | #endif 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/xop/MediaSession.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-9-30 3 | 4 | #include "MediaSession.h" 5 | #include "RtpConnection.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "net/Logger.h" 11 | #include "net/NetInterface.h" 12 | #include "net/SocketUtil.h" 13 | 14 | using namespace xop; 15 | using namespace std; 16 | 17 | std::atomic_uint MediaSession::last_session_id_(1); 18 | 19 | MediaSession::MediaSession(std::string url_suffxx) 20 | : suffix_(url_suffxx) 21 | , media_sources_(2) 22 | , _buffer(2) 23 | { 24 | has_new_client_ = false; 25 | session_id_ = ++last_session_id_; 26 | 27 | for(int n=0; nSetSendFrameCallback([this](MediaChannelId channelId, RtpPacket pkt) { 47 | std::forward_list> clients; 48 | std::map packets; 49 | { 50 | std::lock_guard lock(map_mutex_); 51 | for (auto iter = clients_.begin(); iter != clients_.end();) { 52 | auto conn = iter->second.lock(); 53 | if (conn == nullptr) { 54 | clients_.erase(iter++); 55 | } 56 | else { 57 | int id = conn->GetId(); 58 | if (id >= 0) { 59 | if (packets.find(id) == packets.end()) { 60 | RtpPacket tmpPkt; 61 | memcpy(tmpPkt.data.get(), pkt.data.get(), pkt.size); 62 | tmpPkt.size = pkt.size; 63 | tmpPkt.last = pkt.last; 64 | tmpPkt.timestamp = pkt.timestamp; 65 | tmpPkt.type = pkt.type; 66 | packets.emplace(id, tmpPkt); 67 | } 68 | clients.emplace_front(conn); 69 | } 70 | iter++; 71 | } 72 | } 73 | } 74 | 75 | int count = 0; 76 | for(auto iter : clients) { 77 | int ret = 0; 78 | int id = iter->GetId(); 79 | if (id >= 0) { 80 | auto iter2 = packets.find(id); 81 | if (iter2 != packets.end()) { 82 | count++; 83 | ret = iter->SendRtpPacket(channelId, iter2->second); 84 | if (is_multicast_ && ret == 0) { 85 | break; 86 | } 87 | } 88 | } 89 | } 90 | return true; 91 | }); 92 | 93 | media_sources_[channelId].reset(source); 94 | return true; 95 | } 96 | 97 | bool MediaSession::RemoveSource(MediaChannelId channelId) 98 | { 99 | media_sources_[channelId] = nullptr; 100 | return true; 101 | } 102 | 103 | bool MediaSession::StartMulticast() 104 | { 105 | if (is_multicast_) { 106 | return true; 107 | } 108 | 109 | multicast_ip_ = MulticastAddr::instance().GetAddr(); 110 | if (multicast_ip_ == "") { 111 | return false; 112 | } 113 | 114 | std::random_device rd; 115 | multicast_port_[channel_0] = htons(rd() & 0xfffe); 116 | multicast_port_[channel_1] = htons(rd() & 0xfffe); 117 | 118 | is_multicast_ = true; 119 | return true; 120 | } 121 | 122 | std::string MediaSession::GetSdpMessage(std::string sessionName) 123 | { 124 | if (sdp_ != "") { 125 | return sdp_; 126 | } 127 | 128 | if (media_sources_.empty()) { 129 | return ""; 130 | } 131 | 132 | std::string ip = NetInterface::GetLocalIPAddress(); 133 | char buf[2048] = {0}; 134 | 135 | snprintf(buf, sizeof(buf), 136 | "v=0\r\n" 137 | "o=- 9%ld 1 IN IP4 %s\r\n" 138 | "t=0 0\r\n" 139 | "a=control:*\r\n" , 140 | (long)std::time(NULL), ip.c_str()); 141 | 142 | if(sessionName != "") { 143 | snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), 144 | "s=%s\r\n", 145 | sessionName.c_str()); 146 | } 147 | 148 | if(is_multicast_) { 149 | snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), 150 | "a=type:broadcast\r\n" 151 | "a=rtcp-unicast: reflection\r\n"); 152 | } 153 | 154 | for (uint32_t chn=0; chnGetMediaDescription(multicast_port_[chn]).c_str()); 160 | 161 | snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), 162 | "c=IN IP4 %s/255\r\n", 163 | multicast_ip_.c_str()); 164 | } 165 | else { 166 | snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), 167 | "%s\r\n", 168 | media_sources_[chn]->GetMediaDescription(0).c_str()); 169 | } 170 | 171 | snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), 172 | "%s\r\n", 173 | media_sources_[chn]->GetAttribute().c_str()); 174 | 175 | snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), 176 | "a=control:track%d\r\n", chn); 177 | } 178 | } 179 | 180 | sdp_ = buf; 181 | return sdp_; 182 | } 183 | 184 | MediaSource* MediaSession::GetMediaSource(MediaChannelId channelId) 185 | { 186 | if (media_sources_[channelId]) { 187 | return media_sources_[channelId].get(); 188 | } 189 | 190 | return nullptr; 191 | } 192 | 193 | bool MediaSession::HandleFrame(MediaChannelId channelId, AVFrame frame) 194 | { 195 | std::lock_guard lock(mutex_); 196 | 197 | if(media_sources_[channelId]) { 198 | media_sources_[channelId]->HandleFrame(channelId, frame); 199 | } 200 | else { 201 | return false; 202 | } 203 | 204 | return true; 205 | } 206 | 207 | bool MediaSession::AddClient(SOCKET rtspfd, std::shared_ptr rtp_conn) 208 | { 209 | std::lock_guard lock(map_mutex_); 210 | 211 | auto iter = clients_.find (rtspfd); 212 | if(iter == clients_.end()) { 213 | std::weak_ptr rtp_conn_weak_ptr = rtp_conn; 214 | clients_.emplace(rtspfd, rtp_conn_weak_ptr); 215 | if (notify_callback_) { 216 | notify_callback_(session_id_, (uint32_t)clients_.size()); /* 回调通知当前客户端数量 */ 217 | } 218 | 219 | has_new_client_ = true; 220 | return true; 221 | } 222 | 223 | return false; 224 | } 225 | 226 | void MediaSession::RemoveClient(SOCKET rtspfd) 227 | { 228 | std::lock_guard lock(map_mutex_); 229 | 230 | if (clients_.find(rtspfd) != clients_.end()) { 231 | clients_.erase(rtspfd); 232 | if (notify_callback_) { 233 | notify_callback_(session_id_, (uint32_t)clients_.size()); /* 回调通知当前客户端数量 */ 234 | } 235 | } 236 | } 237 | 238 | -------------------------------------------------------------------------------- /src/xop/MediaSession.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-6-8 3 | 4 | #ifndef XOP_MEDIA_SESSION_H 5 | #define XOP_MEDIA_SESSION_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "media.h" 16 | #include "H264Source.h" 17 | #include "H265Source.h" 18 | #include "G711ASource.h" 19 | #include "AACSource.h" 20 | #include "MediaSource.h" 21 | #include "net/Socket.h" 22 | #include "net/RingBuffer.h" 23 | 24 | namespace xop 25 | { 26 | 27 | class RtpConnection; 28 | 29 | class MediaSession 30 | { 31 | public: 32 | typedef std::function NotifyCallback; 33 | 34 | static MediaSession* CreateNew(std::string url_suffxx="live"); 35 | ~MediaSession(); 36 | 37 | bool AddSource(MediaChannelId channel_id, MediaSource* source); 38 | bool RemoveSource(MediaChannelId channel_id); 39 | 40 | bool StartMulticast(); 41 | 42 | void SetNotifyCallback(const NotifyCallback& cb) 43 | { notify_callback_ = cb; } 44 | 45 | std::string GetRtspUrlSuffix() const 46 | { return suffix_; } 47 | 48 | void SetRtspUrlSuffix(std::string& suffix) 49 | { suffix_ = suffix; } 50 | 51 | std::string GetSdpMessage(std::string sessionName=""); 52 | 53 | MediaSource* GetMediaSource(MediaChannelId channel_id); 54 | 55 | bool HandleFrame(MediaChannelId channel_id, AVFrame frame); 56 | 57 | bool AddClient(SOCKET rtspfd, std::shared_ptr rtpConnPtr); 58 | void RemoveClient(SOCKET rtspfd); 59 | 60 | MediaSessionId GetMediaSessionId() 61 | { return session_id_; } 62 | 63 | uint32_t GetNumClient() const 64 | { return (uint32_t)clients_.size(); } 65 | 66 | bool IsMulticast() const 67 | { return is_multicast_; } 68 | 69 | std::string GetMulticastIp() const 70 | { return multicast_ip_; } 71 | 72 | uint16_t GetMulticastPort(MediaChannelId channel_id) const 73 | { 74 | if (channel_id >= MAX_MEDIA_CHANNEL) { 75 | return 0; 76 | } 77 | return multicast_port_[channel_id]; 78 | } 79 | 80 | private: 81 | friend class MediaSource; 82 | friend class RtspServer; 83 | MediaSession(std::string url_suffxx); 84 | 85 | MediaSessionId session_id_ = 0; 86 | std::string suffix_; 87 | std::string sdp_; 88 | 89 | std::vector> media_sources_; 90 | std::vector> _buffer; 91 | 92 | NotifyCallback notify_callback_; 93 | std::mutex mutex_; 94 | std::mutex map_mutex_; 95 | std::map> clients_; 96 | 97 | bool is_multicast_ = false; 98 | uint16_t multicast_port_[MAX_MEDIA_CHANNEL]; 99 | std::string multicast_ip_; 100 | std::atomic_bool has_new_client_; 101 | 102 | static std::atomic_uint last_session_id_; 103 | }; 104 | 105 | typedef std::shared_ptr MediaSessionPtr; 106 | 107 | class MulticastAddr 108 | { 109 | public: 110 | static MulticastAddr& instance() 111 | { 112 | static MulticastAddr s_multi_addr; 113 | return s_multi_addr; 114 | } 115 | 116 | std::string GetAddr() 117 | { 118 | std::lock_guard lock(m_mutex); 119 | std::string addr_str; 120 | struct sockaddr_in addr = { 0 }; 121 | std::random_device rd; 122 | 123 | for (int n = 0; n <= 10; n++) { 124 | uint32_t range = 0xE8FFFFFF - 0xE8000100; 125 | addr.sin_addr.s_addr = htonl(0xE8000100 + (rd()) % range); 126 | addr_str = inet_ntoa(addr.sin_addr); 127 | 128 | if (m_addrs.find(addr_str) != m_addrs.end()) { 129 | addr_str.clear(); 130 | } 131 | else { 132 | m_addrs.insert(addr_str); 133 | break; 134 | } 135 | } 136 | 137 | return addr_str; 138 | } 139 | 140 | void Release(std::string addr) { 141 | std::lock_guard lock(m_mutex); 142 | m_addrs.erase(addr); 143 | } 144 | 145 | private: 146 | std::mutex m_mutex; 147 | std::unordered_set m_addrs; 148 | }; 149 | 150 | } 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /src/xop/MediaSource.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-6-8 3 | 4 | #ifndef XOP_MEDIA_SOURCE_H 5 | #define XOP_MEDIA_SOURCE_H 6 | 7 | #include "media.h" 8 | #include "rtp.h" 9 | #include "net/Socket.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace xop 17 | { 18 | 19 | class MediaSource 20 | { 21 | public: 22 | typedef std::function SendFrameCallback; 23 | 24 | MediaSource() {} 25 | virtual ~MediaSource() {} 26 | 27 | virtual MediaType GetMediaType() const 28 | { return media_type_; } 29 | 30 | virtual std::string GetMediaDescription(uint16_t port=0) = 0; 31 | 32 | virtual std::string GetAttribute() = 0; 33 | 34 | virtual bool HandleFrame(MediaChannelId channelId, AVFrame frame) = 0; 35 | virtual void SetSendFrameCallback(const SendFrameCallback cb) 36 | { send_frame_callback_ = cb; } 37 | 38 | virtual uint32_t GetPayloadType() const 39 | { return payload_; } 40 | 41 | virtual uint32_t GetClockRate() const 42 | { return clock_rate_; } 43 | 44 | protected: 45 | MediaType media_type_ = NONE; 46 | uint32_t payload_ = 0; 47 | uint32_t clock_rate_ = 0; 48 | SendFrameCallback send_frame_callback_; 49 | }; 50 | 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/xop/RtpConnection.cpp: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-9-30 3 | 4 | #include "RtpConnection.h" 5 | #include "RtspConnection.h" 6 | #include "net/SocketUtil.h" 7 | 8 | using namespace std; 9 | using namespace xop; 10 | 11 | RtpConnection::RtpConnection(std::weak_ptr rtsp_connection) 12 | : rtsp_connection_(rtsp_connection) 13 | { 14 | std::random_device rd; 15 | 16 | for(int chn=0; chn 0) { 32 | SocketUtil::Close(rtpfd_[chn]); 33 | } 34 | 35 | if(rtcpfd_[chn] > 0) { 36 | SocketUtil::Close(rtcpfd_[chn]); 37 | } 38 | } 39 | } 40 | 41 | int RtpConnection::GetId() const 42 | { 43 | auto conn = rtsp_connection_.lock(); 44 | if (!conn) { 45 | return -1; 46 | } 47 | RtspConnection *rtspConn = (RtspConnection *)conn.get(); 48 | return rtspConn->GetId(); 49 | } 50 | 51 | bool RtpConnection::SetupRtpOverTcp(MediaChannelId channel_id, uint16_t rtp_channel, uint16_t rtcp_channel) 52 | { 53 | auto conn = rtsp_connection_.lock(); 54 | if (!conn) { 55 | return false; 56 | } 57 | 58 | media_channel_info_[channel_id].rtp_channel = rtp_channel; 59 | media_channel_info_[channel_id].rtcp_channel = rtcp_channel; 60 | rtpfd_[channel_id] = conn->GetSocket(); 61 | rtcpfd_[channel_id] = conn->GetSocket(); 62 | media_channel_info_[channel_id].is_setup = true; 63 | transport_mode_ = RTP_OVER_TCP; 64 | 65 | return true; 66 | } 67 | 68 | bool RtpConnection::SetupRtpOverUdp(MediaChannelId channel_id, uint16_t rtp_port, uint16_t rtcp_port) 69 | { 70 | auto conn = rtsp_connection_.lock(); 71 | if (!conn) { 72 | return false; 73 | } 74 | 75 | if(SocketUtil::GetPeerAddr(conn->GetSocket(), &peer_addr_) < 0) { 76 | return false; 77 | } 78 | 79 | media_channel_info_[channel_id].rtp_port = rtp_port; 80 | media_channel_info_[channel_id].rtcp_port = rtcp_port; 81 | 82 | std::random_device rd; 83 | for (int n = 0; n <= 10; n++) { 84 | if (n == 10) { 85 | return false; 86 | } 87 | 88 | local_rtp_port_[channel_id] = rd() & 0xfffe; 89 | local_rtcp_port_[channel_id] =local_rtp_port_[channel_id] + 1; 90 | 91 | rtpfd_[channel_id] = ::socket(AF_INET, SOCK_DGRAM, 0); 92 | if(!SocketUtil::Bind(rtpfd_[channel_id], "0.0.0.0", local_rtp_port_[channel_id])) { 93 | SocketUtil::Close(rtpfd_[channel_id]); 94 | continue; 95 | } 96 | 97 | rtcpfd_[channel_id] = ::socket(AF_INET, SOCK_DGRAM, 0); 98 | if(!SocketUtil::Bind(rtcpfd_[channel_id], "0.0.0.0", local_rtcp_port_[channel_id])) { 99 | SocketUtil::Close(rtpfd_[channel_id]); 100 | SocketUtil::Close(rtcpfd_[channel_id]); 101 | continue; 102 | } 103 | 104 | break; 105 | } 106 | 107 | SocketUtil::SetSendBufSize(rtpfd_[channel_id], 50*1024); 108 | 109 | peer_rtp_addr_[channel_id].sin_family = AF_INET; 110 | peer_rtp_addr_[channel_id].sin_addr.s_addr = peer_addr_.sin_addr.s_addr; 111 | peer_rtp_addr_[channel_id].sin_port = htons(media_channel_info_[channel_id].rtp_port); 112 | 113 | peer_rtcp_sddr_[channel_id].sin_family = AF_INET; 114 | peer_rtcp_sddr_[channel_id].sin_addr.s_addr = peer_addr_.sin_addr.s_addr; 115 | peer_rtcp_sddr_[channel_id].sin_port = htons(media_channel_info_[channel_id].rtcp_port); 116 | 117 | media_channel_info_[channel_id].is_setup = true; 118 | transport_mode_ = RTP_OVER_UDP; 119 | 120 | return true; 121 | } 122 | 123 | bool RtpConnection::SetupRtpOverMulticast(MediaChannelId channel_id, std::string ip, uint16_t port) 124 | { 125 | std::random_device rd; 126 | for (int n = 0; n <= 10; n++) { 127 | if (n == 10) { 128 | return false; 129 | } 130 | 131 | local_rtp_port_[channel_id] = rd() & 0xfffe; 132 | rtpfd_[channel_id] = ::socket(AF_INET, SOCK_DGRAM, 0); 133 | if (!SocketUtil::Bind(rtpfd_[channel_id], "0.0.0.0", local_rtp_port_[channel_id])) { 134 | SocketUtil::Close(rtpfd_[channel_id]); 135 | continue; 136 | } 137 | 138 | break; 139 | } 140 | 141 | media_channel_info_[channel_id].rtp_port = port; 142 | 143 | peer_rtp_addr_[channel_id].sin_family = AF_INET; 144 | peer_rtp_addr_[channel_id].sin_addr.s_addr = inet_addr(ip.c_str()); 145 | peer_rtp_addr_[channel_id].sin_port = htons(port); 146 | 147 | media_channel_info_[channel_id].is_setup = true; 148 | transport_mode_ = RTP_OVER_MULTICAST; 149 | is_multicast_ = true; 150 | return true; 151 | } 152 | 153 | void RtpConnection::Play() 154 | { 155 | for(int chn=0; chn(chrono::steady_clock::now()); 196 | auto ts = time_point.time_since_epoch().count(); 197 | for (int chn = 0; chntask_scheduler_->AddTriggerEvent([this, channel_id, pkt] { 244 | this->SetFrameType(pkt.type); 245 | this->SetRtpHeader(channel_id, pkt); 246 | if((media_channel_info_[channel_id].is_play || media_channel_info_[channel_id].is_record) && has_key_frame_ ) { 247 | if(transport_mode_ == RTP_OVER_TCP) { 248 | SendRtpOverTcp(channel_id, pkt); 249 | } 250 | else { 251 | SendRtpOverUdp(channel_id, pkt); 252 | } 253 | 254 | //media_channel_info_[channel_id].octetCount += pkt.size; 255 | //media_channel_info_[channel_id].packetCount += 1; 256 | } 257 | }); 258 | 259 | return ret ? 0 : -1; 260 | } 261 | 262 | int RtpConnection::SendRtpOverTcp(MediaChannelId channel_id, RtpPacket pkt) 263 | { 264 | auto conn = rtsp_connection_.lock(); 265 | if (!conn) { 266 | return -1; 267 | } 268 | 269 | uint8_t* rtpPktPtr = pkt.data.get(); 270 | rtpPktPtr[0] = '$'; 271 | rtpPktPtr[1] = (char)media_channel_info_[channel_id].rtp_channel; 272 | rtpPktPtr[2] = (char)(((pkt.size-4)&0xFF00)>>8); 273 | rtpPktPtr[3] = (char)((pkt.size -4)&0xFF); 274 | 275 | conn->Send((char*)rtpPktPtr, pkt.size); 276 | return pkt.size; 277 | } 278 | 279 | int RtpConnection::SendRtpOverUdp(MediaChannelId channel_id, RtpPacket pkt) 280 | { 281 | //media_channel_info_[channel_id].octetCount += pktSize; 282 | //media_channel_info_[channel_id].packetCount += 1; 283 | 284 | int ret = sendto(rtpfd_[channel_id], (const char*)pkt.data.get()+4, pkt.size-4, 0, 285 | (struct sockaddr *)&(peer_rtp_addr_[channel_id]), 286 | sizeof(struct sockaddr_in)); 287 | 288 | if(ret < 0) { 289 | Teardown(); 290 | return -1; 291 | } 292 | 293 | return ret; 294 | } 295 | -------------------------------------------------------------------------------- /src/xop/RtpConnection.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-6-8 3 | 4 | #ifndef XOP_RTP_CONNECTION_H 5 | #define XOP_RTP_CONNECTION_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "rtp.h" 13 | #include "media.h" 14 | #include "net/Socket.h" 15 | #include "net/TcpConnection.h" 16 | 17 | namespace xop 18 | { 19 | 20 | class RtspConnection; 21 | 22 | class RtpConnection 23 | { 24 | public: 25 | RtpConnection(std::weak_ptr rtsp_connection); 26 | virtual ~RtpConnection(); 27 | 28 | void SetClockRate(MediaChannelId channel_id, uint32_t clock_rate) 29 | { media_channel_info_[channel_id].clock_rate = clock_rate; } 30 | 31 | void SetPayloadType(MediaChannelId channel_id, uint32_t payload) 32 | { media_channel_info_[channel_id].rtp_header.payload = payload; } 33 | 34 | bool SetupRtpOverTcp(MediaChannelId channel_id, uint16_t rtp_channel, uint16_t rtcp_channel); 35 | bool SetupRtpOverUdp(MediaChannelId channel_id, uint16_t rtp_port, uint16_t rtcp_port); 36 | bool SetupRtpOverMulticast(MediaChannelId channel_id, std::string ip, uint16_t port); 37 | 38 | uint32_t GetRtpSessionId() const 39 | { return (uint32_t)((size_t)(this)); } 40 | 41 | uint16_t GetRtpPort(MediaChannelId channel_id) const 42 | { return local_rtp_port_[channel_id]; } 43 | 44 | uint16_t GetRtcpPort(MediaChannelId channel_id) const 45 | { return local_rtcp_port_[channel_id]; } 46 | 47 | SOCKET GetRtcpfd(MediaChannelId channel_id) 48 | { return rtcpfd_[channel_id]; } 49 | 50 | bool IsMulticast() const 51 | { return is_multicast_; } 52 | 53 | bool IsSetup(MediaChannelId channel_id) const 54 | { return media_channel_info_[channel_id].is_setup; } 55 | 56 | std::string GetMulticastIp(MediaChannelId channel_id) const; 57 | 58 | void Play(); 59 | void Record(); 60 | void Teardown(); 61 | 62 | std::string GetRtpInfo(const std::string& rtsp_url); 63 | int SendRtpPacket(MediaChannelId channel_id, RtpPacket pkt); 64 | 65 | bool IsClosed() const 66 | { return is_closed_; } 67 | 68 | int GetId() const; 69 | 70 | bool HasKeyFrame() const 71 | { return has_key_frame_; } 72 | 73 | private: 74 | friend class RtspConnection; 75 | friend class MediaSession; 76 | void SetFrameType(uint8_t frameType = 0); 77 | void SetRtpHeader(MediaChannelId channel_id, RtpPacket pkt); 78 | int SendRtpOverTcp(MediaChannelId channel_id, RtpPacket pkt); 79 | int SendRtpOverUdp(MediaChannelId channel_id, RtpPacket pkt); 80 | 81 | std::weak_ptr rtsp_connection_; 82 | 83 | TransportMode transport_mode_; 84 | bool is_multicast_ = false; 85 | 86 | bool is_closed_ = false; 87 | bool has_key_frame_ = false; 88 | 89 | uint8_t frame_type_ = 0; 90 | uint16_t local_rtp_port_[MAX_MEDIA_CHANNEL]; 91 | uint16_t local_rtcp_port_[MAX_MEDIA_CHANNEL]; 92 | SOCKET rtpfd_[MAX_MEDIA_CHANNEL]; 93 | SOCKET rtcpfd_[MAX_MEDIA_CHANNEL]; 94 | 95 | struct sockaddr_in peer_addr_; 96 | struct sockaddr_in peer_rtp_addr_[MAX_MEDIA_CHANNEL]; 97 | struct sockaddr_in peer_rtcp_sddr_[MAX_MEDIA_CHANNEL]; 98 | MediaChannelInfo media_channel_info_[MAX_MEDIA_CHANNEL]; 99 | }; 100 | 101 | } 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /src/xop/RtspConnection.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-6-8 3 | 4 | #ifndef _RTSP_CONNECTION_H 5 | #define _RTSP_CONNECTION_H 6 | 7 | #include "net/EventLoop.h" 8 | #include "net/TcpConnection.h" 9 | #include "RtpConnection.h" 10 | #include "RtspMessage.h" 11 | #include "DigestAuthentication.h" 12 | #include "rtsp.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace xop 20 | { 21 | 22 | class RtspServer; 23 | class MediaSession; 24 | 25 | class RtspConnection : public TcpConnection 26 | { 27 | public: 28 | typedef std::function CloseCallback; 29 | 30 | enum ConnectionMode 31 | { 32 | RTSP_SERVER, 33 | RTSP_PUSHER, 34 | //RTSP_CLIENT, 35 | }; 36 | 37 | enum ConnectionState 38 | { 39 | START_CONNECT, 40 | START_PLAY, 41 | START_PUSH 42 | }; 43 | 44 | RtspConnection() = delete; 45 | RtspConnection(std::shared_ptr rtsp_server, TaskScheduler *task_scheduler, SOCKET sockfd); 46 | ~RtspConnection(); 47 | 48 | MediaSessionId GetMediaSessionId() 49 | { return session_id_; } 50 | 51 | TaskScheduler *GetTaskScheduler() const 52 | { return task_scheduler_; } 53 | 54 | void KeepAlive() 55 | { alive_count_++; } 56 | 57 | bool IsAlive() const 58 | { 59 | if (IsClosed()) { 60 | return false; 61 | } 62 | 63 | if(rtp_conn_ != nullptr) { 64 | if (rtp_conn_->IsMulticast()) { 65 | return true; 66 | } 67 | } 68 | 69 | return (alive_count_ > 0); 70 | } 71 | 72 | void ResetAliveCount() 73 | { alive_count_ = 0; } 74 | 75 | int GetId() const 76 | { return task_scheduler_->GetId(); } 77 | 78 | bool IsPlay() const 79 | { return conn_state_ == START_PLAY; } 80 | 81 | bool IsRecord() const 82 | { return conn_state_ == START_PUSH; } 83 | 84 | private: 85 | friend class RtpConnection; 86 | friend class MediaSession; 87 | friend class RtspServer; 88 | friend class RtspPusher; 89 | 90 | bool OnRead(BufferReader& buffer); 91 | void OnClose(); 92 | void HandleRtcp(SOCKET sockfd); 93 | void HandleRtcp(BufferReader& buffer); 94 | bool HandleRtspRequest(BufferReader& buffer); 95 | bool HandleRtspResponse(BufferReader& buffer); 96 | 97 | void SendRtspMessage(std::shared_ptr buf, uint32_t size); 98 | 99 | void HandleCmdOption(); 100 | void HandleCmdDescribe(); 101 | void HandleCmdSetup(); 102 | void HandleCmdPlay(); 103 | void HandleCmdTeardown(); 104 | void HandleCmdGetParamter(); 105 | bool HandleAuthentication(); 106 | 107 | void SendOptions(ConnectionMode mode= RTSP_SERVER); 108 | void SendDescribe(); 109 | void SendAnnounce(); 110 | void SendSetup(); 111 | void HandleRecord(); 112 | 113 | std::atomic_int alive_count_; 114 | std::weak_ptr rtsp_; 115 | xop::TaskScheduler *task_scheduler_ = nullptr; 116 | 117 | ConnectionMode conn_mode_ = RTSP_SERVER; 118 | ConnectionState conn_state_ = START_CONNECT; 119 | MediaSessionId session_id_ = 0; 120 | 121 | bool has_auth_ = true; 122 | std::string _nonce; 123 | std::unique_ptr auth_info_; 124 | 125 | std::shared_ptr rtp_channel_; 126 | std::shared_ptr rtcp_channels_[MAX_MEDIA_CHANNEL]; 127 | std::unique_ptr rtsp_request_; 128 | std::unique_ptr rtsp_response_; 129 | std::shared_ptr rtp_conn_; 130 | }; 131 | 132 | } 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /src/xop/RtspMessage.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-6-8 3 | 4 | #ifndef XOP_RTSP_MESSAGE_H 5 | #define XOP_RTSP_MESSAGE_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "rtp.h" 12 | #include "media.h" 13 | #include "net/BufferReader.h" 14 | 15 | namespace xop 16 | { 17 | 18 | class RtspRequest 19 | { 20 | public: 21 | enum Method 22 | { 23 | OPTIONS=0, DESCRIBE, SETUP, PLAY, TEARDOWN, GET_PARAMETER, 24 | RTCP, NONE, 25 | }; 26 | 27 | const char* MethodToString[8] = 28 | { 29 | "OPTIONS", "DESCRIBE", "SETUP", "PLAY", "TEARDOWN", "GET_PARAMETER", 30 | "RTCP", "NONE" 31 | }; 32 | 33 | enum RtspRequestParseState 34 | { 35 | kParseRequestLine, 36 | kParseHeadersLine, 37 | //kParseBody, 38 | kGotAll, 39 | }; 40 | 41 | bool ParseRequest(xop::BufferReader *buffer); 42 | 43 | bool GotAll() const 44 | { return state_ == kGotAll; } 45 | 46 | void Reset() 47 | { 48 | state_ = kParseRequestLine; 49 | request_line_param_.clear(); 50 | header_line_param_.clear(); 51 | } 52 | 53 | Method GetMethod() const 54 | { return method_; } 55 | 56 | uint32_t GetCSeq() const; 57 | 58 | std::string GetRtspUrl() const; 59 | 60 | std::string GetRtspUrlSuffix() const; 61 | 62 | std::string GetIp() const; 63 | 64 | std::string GetAuthResponse() const; 65 | 66 | TransportMode GetTransportMode() const 67 | { return transport_; } 68 | 69 | MediaChannelId GetChannelId() const 70 | { return channel_id_; } 71 | 72 | uint8_t GetRtpChannel() const; 73 | uint8_t GetRtcpChannel() const; 74 | uint16_t GetRtpPort() const; 75 | uint16_t GetRtcpPort() const; 76 | 77 | int BuildOptionRes(const char* buf, int buf_size); 78 | int BuildDescribeRes(const char* buf, int buf_size, const char* sdp); 79 | int BuildSetupMulticastRes(const char* buf, int buf_size, const char* multicast_ip, uint16_t port, uint32_t session_id); 80 | int BuildSetupTcpRes(const char* buf, int buf_size, uint16_t rtp_chn, uint16_t rtcp_chn, uint32_t session_id); 81 | int BuildSetupUdpRes(const char* buf, int buf_size, uint16_t rtp_chn, uint16_t rtcp_chn, uint32_t session_id); 82 | int BuildPlayRes(const char* buf, int buf_size, const char* rtp_info, uint32_t session_id); 83 | int BuildTeardownRes(const char* buf, int buf_size, uint32_t session_id); 84 | int BuildGetParamterRes(const char* buf, int buf_size, uint32_t session_id); 85 | int BuildNotFoundRes(const char* buf, int buf_size); 86 | int BuildServerErrorRes(const char* buf, int buf_size); 87 | int BuildUnsupportedRes(const char* buf, int buf_size); 88 | int BuildUnauthorizedRes(const char* buf, int buf_size, const char* realm, const char* nonce); 89 | 90 | private: 91 | bool ParseRequestLine(const char* begin, const char* end); 92 | bool ParseHeadersLine(const char* begin, const char* end); 93 | bool ParseCSeq(std::string& message); 94 | bool ParseAccept(std::string& message); 95 | bool ParseTransport(std::string& message); 96 | bool ParseSessionId(std::string& message); 97 | bool ParseMediaChannel(std::string& message); 98 | bool ParseAuthorization(std::string& message); 99 | 100 | Method method_; 101 | MediaChannelId channel_id_; 102 | TransportMode transport_; 103 | std::string auth_response_; 104 | std::unordered_map> request_line_param_; 105 | std::unordered_map> header_line_param_; 106 | 107 | RtspRequestParseState state_ = kParseRequestLine; 108 | }; 109 | 110 | class RtspResponse 111 | { 112 | public: 113 | enum Method 114 | { 115 | OPTIONS=0, DESCRIBE, ANNOUNCE, SETUP, RECORD, RTCP, 116 | NONE, 117 | }; 118 | 119 | bool ParseResponse(xop::BufferReader *buffer); 120 | 121 | Method GetMethod() const 122 | { return method_; } 123 | 124 | uint32_t GetCSeq() const 125 | { return cseq_; } 126 | 127 | std::string GetSession() const 128 | { return session_; } 129 | 130 | void SetUserAgent(const char *user_agent) 131 | { user_agent_ = std::string(user_agent); } 132 | 133 | void SetRtspUrl(const char *url) 134 | { rtsp_url_ = std::string(url); } 135 | 136 | int BuildOptionReq(const char* buf, int buf_size); 137 | int BuildDescribeReq(const char* buf, int buf_size); 138 | int BuildAnnounceReq(const char* buf, int buf_size, const char *sdp); 139 | int BuildSetupTcpReq(const char* buf, int buf_size, int channel); 140 | int BuildRecordReq(const char* buf, int buf_size); 141 | 142 | private: 143 | Method method_; 144 | uint32_t cseq_ = 0; 145 | std::string user_agent_; 146 | std::string rtsp_url_; 147 | std::string session_; 148 | }; 149 | 150 | } 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /src/xop/RtspPusher.cpp: -------------------------------------------------------------------------------- 1 | #include "RtspPusher.h" 2 | #include "RtspConnection.h" 3 | #include "net/Logger.h" 4 | #include "net/TcpSocket.h" 5 | #include "net/Timestamp.h" 6 | #include 7 | 8 | using namespace xop; 9 | 10 | RtspPusher::RtspPusher(xop::EventLoop *event_loop) 11 | : event_loop_(event_loop) 12 | { 13 | 14 | } 15 | 16 | RtspPusher::~RtspPusher() 17 | { 18 | this->Close(); 19 | } 20 | 21 | std::shared_ptr RtspPusher::Create(xop::EventLoop* loop) 22 | { 23 | std::shared_ptr pusher(new RtspPusher(loop)); 24 | return pusher; 25 | } 26 | 27 | void RtspPusher::AddSession(MediaSession* session) 28 | { 29 | std::lock_guard locker(mutex_); 30 | media_session_.reset(session); 31 | } 32 | 33 | void RtspPusher::RemoveSession(MediaSessionId sessionId) 34 | { 35 | std::lock_guard locker(mutex_); 36 | media_session_ = nullptr; 37 | } 38 | 39 | MediaSessionPtr RtspPusher::LookMediaSession(MediaSessionId sessionId) 40 | { 41 | return media_session_; 42 | } 43 | 44 | int RtspPusher::OpenUrl(std::string url, int msec) 45 | { 46 | std::lock_guard lock(mutex_); 47 | 48 | static xop::Timestamp tp; 49 | int timeout = msec; 50 | if (timeout <= 0) { 51 | timeout = 10000; 52 | } 53 | 54 | tp.reset(); 55 | 56 | if (!this->parseRtspUrl(url)) { 57 | LOG_ERROR("rtsp url(%s) was illegal.\n", url.c_str()); 58 | return -1; 59 | } 60 | 61 | if (rtsp_conn_ != nullptr) { 62 | std::shared_ptr rtspConn = rtsp_conn_; 63 | SOCKET sockfd = rtspConn->GetSocket(); 64 | task_scheduler_->AddTriggerEvent([sockfd, rtspConn]() { 65 | rtspConn->Disconnect(); 66 | }); 67 | rtsp_conn_ = nullptr; 68 | } 69 | 70 | TcpSocket tcpSocket; 71 | tcpSocket.Create(); 72 | if (!tcpSocket.Connect(rtsp_url_info_.ip, rtsp_url_info_.port, timeout)) 73 | { 74 | tcpSocket.Close(); 75 | return -1; 76 | } 77 | 78 | task_scheduler_ = event_loop_->GetTaskScheduler().get(); 79 | rtsp_conn_.reset(new RtspConnection(shared_from_this(), task_scheduler_, tcpSocket.GetSocket())); 80 | event_loop_->AddTriggerEvent([this]() { 81 | rtsp_conn_->SendOptions(RtspConnection::RTSP_PUSHER); 82 | }); 83 | 84 | timeout -= (int)tp.elapsed(); 85 | if (timeout < 0) { 86 | timeout = 1000; 87 | } 88 | 89 | do 90 | { 91 | xop::Timer::Sleep(100); 92 | timeout -= 100; 93 | } while (!rtsp_conn_->IsRecord() && timeout > 0); 94 | 95 | if (!rtsp_conn_->IsRecord()) { 96 | std::shared_ptr rtspConn = rtsp_conn_; 97 | SOCKET sockfd = rtspConn->GetSocket(); 98 | task_scheduler_->AddTriggerEvent([sockfd, rtspConn]() { 99 | rtspConn->Disconnect(); 100 | }); 101 | rtsp_conn_ = nullptr; 102 | return -1; 103 | } 104 | 105 | return 0; 106 | } 107 | 108 | void RtspPusher::Close() 109 | { 110 | std::lock_guard lock(mutex_); 111 | 112 | if (rtsp_conn_ != nullptr) { 113 | std::shared_ptr rtsp_conn = rtsp_conn_; 114 | SOCKET sockfd = rtsp_conn->GetSocket(); 115 | task_scheduler_->AddTriggerEvent([sockfd, rtsp_conn]() { 116 | rtsp_conn->Disconnect(); 117 | }); 118 | rtsp_conn_ = nullptr; 119 | } 120 | } 121 | 122 | bool RtspPusher::IsConnected() 123 | { 124 | std::lock_guard lock(mutex_); 125 | 126 | if (rtsp_conn_ != nullptr) { 127 | return (!rtsp_conn_->IsClosed()); 128 | } 129 | return false; 130 | } 131 | 132 | bool RtspPusher::PushFrame(MediaChannelId channelId, AVFrame frame) 133 | { 134 | std::lock_guard locker(mutex_); 135 | if (!media_session_ || !rtsp_conn_) { 136 | return false; 137 | } 138 | 139 | return media_session_->HandleFrame(channelId, frame); 140 | } -------------------------------------------------------------------------------- /src/xop/RtspPusher.h: -------------------------------------------------------------------------------- 1 | #ifndef XOP_RTSP_PUSHER_H 2 | #define XOP_RTSP_PUSHER_H 3 | 4 | #include 5 | #include 6 | #include "rtsp.h" 7 | 8 | namespace xop 9 | { 10 | 11 | class RtspConnection; 12 | 13 | class RtspPusher : public Rtsp 14 | { 15 | public: 16 | static std::shared_ptr Create(xop::EventLoop* loop); 17 | ~RtspPusher(); 18 | 19 | void AddSession(MediaSession* session); 20 | void RemoveSession(MediaSessionId session_id); 21 | 22 | int OpenUrl(std::string url, int msec = 3000); 23 | void Close(); 24 | bool IsConnected(); 25 | 26 | bool PushFrame(MediaChannelId channelId, AVFrame frame); 27 | 28 | private: 29 | friend class RtspConnection; 30 | 31 | RtspPusher(xop::EventLoop *event_loop); 32 | MediaSessionPtr LookMediaSession(MediaSessionId session_id); 33 | 34 | xop::EventLoop* event_loop_ = nullptr; 35 | xop::TaskScheduler* task_scheduler_ = nullptr; 36 | std::mutex mutex_; 37 | std::shared_ptr rtsp_conn_; 38 | std::shared_ptr media_session_; 39 | }; 40 | 41 | } 42 | 43 | #endif -------------------------------------------------------------------------------- /src/xop/RtspServer.cpp: -------------------------------------------------------------------------------- 1 | #include "RtspServer.h" 2 | #include "RtspConnection.h" 3 | #include "net/SocketUtil.h" 4 | #include "net/Logger.h" 5 | 6 | using namespace xop; 7 | using namespace std; 8 | 9 | RtspServer::RtspServer(EventLoop* loop) 10 | : TcpServer(loop) 11 | { 12 | 13 | } 14 | 15 | RtspServer::~RtspServer() 16 | { 17 | 18 | } 19 | 20 | std::shared_ptr RtspServer::Create(xop::EventLoop* loop) 21 | { 22 | std::shared_ptr server(new RtspServer(loop)); 23 | return server; 24 | } 25 | 26 | MediaSessionId RtspServer::AddSession(MediaSession* session) 27 | { 28 | std::lock_guard locker(mutex_); 29 | 30 | if (rtsp_suffix_map_.find(session->GetRtspUrlSuffix()) != rtsp_suffix_map_.end()) { 31 | return 0; 32 | } 33 | 34 | std::shared_ptr media_session(session); 35 | MediaSessionId sessionId = media_session->GetMediaSessionId(); 36 | rtsp_suffix_map_.emplace(std::move(media_session->GetRtspUrlSuffix()), sessionId); 37 | media_sessions_.emplace(sessionId, std::move(media_session)); 38 | 39 | return sessionId; 40 | } 41 | 42 | void RtspServer::RemoveSession(MediaSessionId sessionId) 43 | { 44 | std::lock_guard locker(mutex_); 45 | 46 | auto iter = media_sessions_.find(sessionId); 47 | if(iter != media_sessions_.end()) { 48 | rtsp_suffix_map_.erase(iter->second->GetRtspUrlSuffix()); 49 | media_sessions_.erase(sessionId); 50 | } 51 | } 52 | 53 | MediaSessionPtr RtspServer::LookMediaSession(const std::string& suffix) 54 | { 55 | std::lock_guard locker(mutex_); 56 | 57 | auto iter = rtsp_suffix_map_.find(suffix); 58 | if(iter != rtsp_suffix_map_.end()) { 59 | MediaSessionId id = iter->second; 60 | return media_sessions_[id]; 61 | } 62 | 63 | return nullptr; 64 | } 65 | 66 | MediaSessionPtr RtspServer::LookMediaSession(MediaSessionId sessionId) 67 | { 68 | std::lock_guard locker(mutex_); 69 | 70 | auto iter = media_sessions_.find(sessionId); 71 | if(iter != media_sessions_.end()) { 72 | return iter->second; 73 | } 74 | 75 | return nullptr; 76 | } 77 | 78 | bool RtspServer::PushFrame(MediaSessionId sessionId, MediaChannelId channelId, AVFrame frame) 79 | { 80 | std::shared_ptr sessionPtr = nullptr; 81 | 82 | { 83 | std::lock_guard locker(mutex_); 84 | auto iter = media_sessions_.find(sessionId); 85 | if (iter != media_sessions_.end()) { 86 | sessionPtr = iter->second; 87 | } 88 | else { 89 | return false; 90 | } 91 | } 92 | 93 | if (sessionPtr!=nullptr && sessionPtr->GetNumClient()!=0) { 94 | return sessionPtr->HandleFrame(channelId, frame); 95 | } 96 | 97 | return false; 98 | } 99 | 100 | TcpConnection::Ptr RtspServer::OnConnect(SOCKET sockfd) 101 | { 102 | return std::make_shared(shared_from_this(), event_loop_->GetTaskScheduler().get(), sockfd); 103 | } 104 | 105 | -------------------------------------------------------------------------------- /src/xop/RtspServer.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2020-4-2 3 | 4 | #ifndef XOP_RTSP_SERVER_H 5 | #define XOP_RTSP_SERVER_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "net/TcpServer.h" 12 | #include "rtsp.h" 13 | 14 | namespace xop 15 | { 16 | 17 | class RtspConnection; 18 | 19 | class RtspServer : public Rtsp, public TcpServer 20 | { 21 | public: 22 | static std::shared_ptr Create(xop::EventLoop* loop); 23 | ~RtspServer(); 24 | 25 | MediaSessionId AddSession(MediaSession* session); 26 | void RemoveSession(MediaSessionId sessionId); 27 | 28 | bool PushFrame(MediaSessionId sessionId, MediaChannelId channelId, AVFrame frame); 29 | 30 | private: 31 | friend class RtspConnection; 32 | 33 | RtspServer(xop::EventLoop* loop); 34 | MediaSessionPtr LookMediaSession(const std::string& suffix); 35 | MediaSessionPtr LookMediaSession(MediaSessionId sessionId); 36 | virtual TcpConnection::Ptr OnConnect(SOCKET sockfd); 37 | 38 | std::mutex mutex_; 39 | std::unordered_map> media_sessions_; 40 | std::unordered_map rtsp_suffix_map_; 41 | }; 42 | 43 | } 44 | 45 | #endif 46 | 47 | -------------------------------------------------------------------------------- /src/xop/media.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-5-16 3 | 4 | #ifndef XOP_MEDIA_H 5 | #define XOP_MEDIA_H 6 | 7 | #include 8 | 9 | namespace xop 10 | { 11 | 12 | /* RTSP服务支持的媒体类型 */ 13 | enum MediaType 14 | { 15 | //PCMU = 0, 16 | PCMA = 8, 17 | H264 = 96, 18 | AAC = 37, 19 | H265 = 265, 20 | NONE 21 | }; 22 | 23 | enum FrameType 24 | { 25 | VIDEO_FRAME_I = 0x01, 26 | VIDEO_FRAME_P = 0x02, 27 | VIDEO_FRAME_B = 0x03, 28 | AUDIO_FRAME = 0x11, 29 | }; 30 | 31 | struct AVFrame 32 | { 33 | AVFrame(uint32_t size = 0) 34 | :buffer(new uint8_t[size + 1]) 35 | { 36 | this->size = size; 37 | type = 0; 38 | timestamp = 0; 39 | } 40 | 41 | std::shared_ptr buffer; /* 帧数据 */ 42 | uint32_t size; /* 帧大小 */ 43 | uint8_t type; /* 帧类型 */ 44 | uint32_t timestamp; /* 时间戳 */ 45 | }; 46 | 47 | #define MAX_MEDIA_CHANNEL 2 48 | 49 | enum MediaChannelId 50 | { 51 | channel_0, 52 | channel_1 53 | }; 54 | 55 | typedef uint32_t MediaSessionId; 56 | 57 | } 58 | 59 | #endif 60 | 61 | -------------------------------------------------------------------------------- /src/xop/rtp.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-6-11 3 | 4 | #ifndef XOP_RTP_H 5 | #define XOP_RTP_H 6 | 7 | #include 8 | #include 9 | 10 | #define RTP_HEADER_SIZE 12 11 | #define MAX_RTP_PAYLOAD_SIZE 1420 //1460 1500-20-12-8 12 | #define RTP_VERSION 2 13 | #define RTP_TCP_HEAD_SIZE 4 14 | 15 | namespace xop 16 | { 17 | 18 | enum TransportMode 19 | { 20 | RTP_OVER_TCP = 1, 21 | RTP_OVER_UDP = 2, 22 | RTP_OVER_MULTICAST = 3, 23 | }; 24 | 25 | typedef struct _RTP_header 26 | { 27 | /* 小端序 */ 28 | unsigned char csrc:4; 29 | unsigned char extension:1; 30 | unsigned char padding:1; 31 | unsigned char version:2; 32 | unsigned char payload:7; 33 | unsigned char marker:1; 34 | 35 | unsigned short seq; 36 | unsigned int ts; 37 | unsigned int ssrc; 38 | } RtpHeader; 39 | 40 | struct MediaChannelInfo 41 | { 42 | RtpHeader rtp_header; 43 | 44 | // tcp 45 | uint16_t rtp_channel; 46 | uint16_t rtcp_channel; 47 | 48 | // udp 49 | uint16_t rtp_port; 50 | uint16_t rtcp_port; 51 | uint16_t packet_seq; 52 | uint32_t clock_rate; 53 | 54 | // rtcp 55 | uint64_t packet_count; 56 | uint64_t octet_count; 57 | uint64_t last_rtcp_ntp_time; 58 | 59 | bool is_setup; 60 | bool is_play; 61 | bool is_record; 62 | }; 63 | 64 | struct RtpPacket 65 | { 66 | RtpPacket() 67 | : data(new uint8_t[1600]) 68 | { 69 | type = 0; 70 | } 71 | 72 | std::shared_ptr data; 73 | uint32_t size; 74 | uint32_t timestamp; 75 | uint8_t type; 76 | uint8_t last; 77 | }; 78 | 79 | } 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /src/xop/rtsp.h: -------------------------------------------------------------------------------- 1 | // PHZ 2 | // 2018-6-8 3 | 4 | #ifndef XOP_RTSP_H 5 | #define XOP_RTSP_H 6 | 7 | #include 8 | #include 9 | #include "MediaSession.h" 10 | #include "net/Acceptor.h" 11 | #include "net/EventLoop.h" 12 | #include "net/Socket.h" 13 | #include "net/Timer.h" 14 | 15 | namespace xop 16 | { 17 | 18 | struct RtspUrlInfo 19 | { 20 | std::string url; 21 | std::string ip; 22 | uint16_t port; 23 | std::string suffix; 24 | }; 25 | 26 | class Rtsp : public std::enable_shared_from_this 27 | { 28 | public: 29 | Rtsp() : has_auth_info_(false) {} 30 | virtual ~Rtsp() {} 31 | 32 | virtual void SetAuthConfig(std::string realm, std::string username, std::string password) 33 | { 34 | realm_ = realm; 35 | username_ = username; 36 | password_ = password; 37 | has_auth_info_ = true; 38 | 39 | if (realm_=="" || username=="") { 40 | has_auth_info_ = false; 41 | } 42 | } 43 | 44 | virtual void SetVersion(std::string version) // SDP Session Name 45 | { version_ = std::move(version); } 46 | 47 | virtual std::string GetVersion() 48 | { return version_; } 49 | 50 | virtual std::string GetRtspUrl() 51 | { return rtsp_url_info_.url; } 52 | 53 | bool parseRtspUrl(std::string url) 54 | { 55 | char ip[100] = { 0 }; 56 | char suffix[100] = { 0 }; 57 | uint16_t port = 0; 58 | #if defined(__linux) || defined(__linux__) 59 | if (sscanf(url.c_str() + 7, "%[^:]:%hu/%s", ip, &port, suffix) == 3) 60 | #elif defined(WIN32) || defined(_WIN32) 61 | if (sscanf_s(url.c_str() + 7, "%[^:]:%hu/%s", ip, 100, &port, suffix, 100) == 3) 62 | #endif 63 | { 64 | rtsp_url_info_.port = port; 65 | } 66 | #if defined(__linux) || defined(__linux__) 67 | else if (sscanf(url.c_str() + 7, "%[^/]/%s", ip, suffix) == 2) 68 | #elif defined(WIN32) || defined(_WIN32) 69 | else if (sscanf_s(url.c_str() + 7, "%[^/]/%s", ip, 100, suffix, 100) == 2) 70 | #endif 71 | { 72 | rtsp_url_info_.port = 554; 73 | } 74 | else 75 | { 76 | //LOG("%s was illegal.\n", url.c_str()); 77 | return false; 78 | } 79 | 80 | rtsp_url_info_.ip = ip; 81 | rtsp_url_info_.suffix = suffix; 82 | rtsp_url_info_.url = url; 83 | return true; 84 | } 85 | 86 | protected: 87 | friend class RtspConnection; 88 | virtual MediaSessionPtr LookMediaSession(const std::string& suffix) 89 | { return nullptr; } 90 | 91 | virtual MediaSessionPtr LookMediaSession(MediaSessionId sessionId) 92 | { return nullptr; } 93 | 94 | bool has_auth_info_ = false; 95 | std::string realm_; 96 | std::string username_; 97 | std::string password_; 98 | std::string version_; 99 | struct RtspUrlInfo rtsp_url_info_; 100 | }; 101 | 102 | } 103 | 104 | #endif 105 | 106 | 107 | -------------------------------------------------------------------------------- /test.h265: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codec2021/rtspServerH265/1a3d7928bc3d84cb458e34f63d49565d4a8b6f74/test.h265 --------------------------------------------------------------------------------