类
UDP:
ISrsUdpHandler
SrsUdpListener
TCP:
ISrsTCPHandler
SrsTCPListener
app/srs_app_listener.hpp
app/srs_app_listener.cpp
/** * the udp packet handler. */ class ISrsUdpHandler { public: ISrsUdpHandler(); virtual ~ISrsUdpHandler(); public: /** * when fd changed, for instance, reload the listen port, * notify the handler and user can do something. */ virtual int on_stfd_change(st_netfd_t fd); public: /** * when udp listener got a udp packet, notice server to process it. * @param type, the client type, used to create concrete connection, * for instance RTMP connection to serve client. * @param from, the udp packet from address. * @param buf, the udp packet bytes, user should copy if need to use. * @param nb_buf, the size of udp packet bytes. * @remark user should never use the buf, for it's a shared memory bytes. */ virtual int on_udp_packet(sockaddr_in* from, char* buf, int nb_buf) = 0; };
ISrsUdpHandler用来处理UDP数据包
SrsMpegtsOverUdp类
app/srs_app_mpegts_udp.h
app/srs_app_mpegts_udp.cpp
/** * the mpegts over udp stream caster. */ class SrsMpegtsOverUdp : virtual public ISrsTsHandler , virtual public ISrsUdpHandler { private: SrsBuffer* stream; SrsTsContext* context; SrsSimpleStream* buffer; std::string output; private: SrsSimpleRtmpClient* sdk; private: SrsRawH264Stream* avc; std::string h264_sps; bool h264_sps_changed; std::string h264_pps; bool h264_pps_changed; bool h264_sps_pps_sent; private: SrsRawAacStream* aac; std::string aac_specific_config; private: SrsMpegtsQueue* queue; SrsPithyPrint* pprint; public: SrsMpegtsOverUdp(SrsConfDirective* c); virtual ~SrsMpegtsOverUdp(); // interface ISrsUdpHandler public: virtual int on_udp_packet(sockaddr_in* from, char* buf, int nb_buf); private: virtual int on_udp_bytes(std::string host, int port, char* buf, int nb_buf); // interface ISrsTsHandler public: virtual int on_ts_message(SrsTsMessage* msg); private: virtual int on_ts_video(SrsTsMessage* msg, SrsBuffer* avs); virtual int write_h264_sps_pps(uint32_t dts, uint32_t pts); virtual int write_h264_ipb_frame(char* frame, int frame_size, uint32_t dts, uint32_t pts); virtual int on_ts_audio(SrsTsMessage* msg, SrsBuffer* avs); virtual int write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, uint32_t dts); private: virtual int rtmp_write_packet(char type, uint32_t timestamp, char* data, int size); private: // Connect to RTMP server. virtual int connect(); // Close the connection to RTMP server. virtual void close(); };
udp用作 mpegts over udp stream caster
/** * the tcp connection handler. */ class ISrsTcpHandler { public: ISrsTcpHandler(); virtual ~ISrsTcpHandler(); public: /** * when got tcp client. */ virtual int on_tcp_client(st_netfd_t stfd) = 0; };
/** * bind and listen tcp port, use handler to process the client. */ class SrsTcpListener : public ISrsReusableThreadHandler { private: int _fd; st_netfd_t _stfd; SrsReusableThread* pthread; private: ISrsTcpHandler* handler; std::string ip; int port; public: SrsTcpListener(ISrsTcpHandler* h, std::string i, int p); virtual ~SrsTcpListener(); public: virtual int fd(); public: virtual int listen(); // interface ISrsReusableThreadHandler. public: virtual int cycle(); };
int SrsUdpListener::listen() { int ret = ERROR_SUCCESS; if ((_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { ret = ERROR_SOCKET_CREATE; srs_error("create linux socket error. ip=%s, port=%d, ret=%d", ip.c_str(), port, ret); return ret; } srs_verbose("create linux socket success. ip=%s, port=%d, fd=%d", ip.c_str(), port, _fd); int reuse_socket = 1; if (setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1) { ret = ERROR_SOCKET_SETREUSE; srs_error("setsockopt reuse-addr error. ip=%s, port=%d, ret=%d", ip.c_str(), port, ret); return ret; } srs_verbose("setsockopt reuse-addr success. ip=%s, port=%d, fd=%d", ip.c_str(), port, _fd); sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip.c_str()); if (bind(_fd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { ret = ERROR_SOCKET_BIND; srs_error("bind socket error. ep=%s:%d, ret=%d", ip.c_str(), port, ret); return ret; } srs_verbose("bind socket success. ep=%s:%d, fd=%d", ip.c_str(), port, _fd); if ((_stfd = st_netfd_open_socket(_fd)) == NULL){ ret = ERROR_ST_OPEN_SOCKET; srs_error("st_netfd_open_socket open socket failed. ep=%s:%d, ret=%d", ip.c_str(), port, ret); return ret; } srs_verbose("st open socket success. ep=%s:%d, fd=%d", ip.c_str(), port, _fd); if ((ret = pthread->start()) != ERROR_SUCCESS) { srs_error("st_thread_create listen thread error. ep=%s:%d, ret=%d", ip.c_str(), port, ret); return ret; } srs_verbose("create st listen thread success, ep=%s:%d", ip.c_str(), port); return ret; }
SrsUdpListener::listen函数
1. 创建udp套接字,绑定设置成员 _fd
2. call _stfd = st_netfd_open_socket(_fd)
3. call pthread->start()启动coroutine,在 cycle函数里 call st_recvfrom接收数据,call handler->on_udp_packet处理数据
SrsTcpListener的listen函数和SrsUdpListener一样
SrsTcpListener的cycle函数
int SrsTcpListener::cycle() { int ret = ERROR_SUCCESS; st_netfd_t client_stfd = st_accept(_stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT); if(client_stfd == NULL){ // ignore error. if (errno != EINTR) { srs_error("ignore accept thread stoppped for accept client error"); } return ret; } srs_verbose("get a client. fd=%d", st_netfd_fileno(client_stfd)); if ((ret = handler->on_tcp_client(client_stfd)) != ERROR_SUCCESS) { srs_warn("accept client error. ret=%d", ret); return ret; } return ret; }
call st_accept接收连接,call handler->on_tcp_client处理连接
-------------------------------- 分割线 -------------------------------------------------------------------------------
文件
app/srs_app_server.h app/srs_app_server.cpp
// listener type for server to identify the connection, // that is, use different type to process the connection. enum SrsListenerType { // RTMP client, SrsListenerRtmpStream = 0, // HTTP api, SrsListenerHttpApi = 1, // HTTP stream, HDS/HLS/DASH SrsListenerHttpStream = 2, // UDP stream, MPEG-TS over udp. SrsListenerMpegTsOverUdp = 3, // TCP stream, RTSP stream. SrsListenerRtsp = 4, // TCP stream, FLV stream over HTTP. SrsListenerFlv = 5, };
/** * 通用 listener */ class SrsListener { protected: SrsListenerType type; protected: std::string ip; int port; SrsServer* server; public: SrsListener(SrsServer* svr, SrsListenerType t); virtual ~SrsListener(); public: virtual SrsListenerType listen_type(); virtual int listen(std::string i, int p) = 0; };
/** * tcp listener.
* SrsBufferListener类在一下位置被调用
* 1. SrsBufferListener 用于 SrsListenerRtmpStream 类型,用于处理RTMP连接
* 在SrsServer::listen_rtmp函数里构造
*
* 2. SrsBufferListener 用于SrsListenerHttpApi类型,用于处理http api的连接
* 在 SrsServer::listen_http_api函数里构造
*
* 3. SrsBufferListener 用于 SrsListenerHttpStream类型,用于处理 http stream连接
* 用于 http flv,http mp4,hls等
* 在 SrsServer::listen_http_stream函数里构造 */ class SrsBufferListener : virtual public SrsListener, virtual public ISrsTcpHandler { private: SrsTcpListener* listener; public: SrsBufferListener(SrsServer* server, SrsListenerType type); virtual ~SrsBufferListener(); public: virtual int listen(std::string ip, int port); // ISrsTcpHandler public: virtual int on_tcp_client(st_netfd_t stfd); };
int SrsBufferListener::listen(string i, int p) { int ret = ERROR_SUCCESS; ip = i; port = p; srs_freep(listener); listener = new SrsTcpListener(this, ip, port); if ((ret = listener->listen()) != ERROR_SUCCESS) { srs_error("tcp listen failed. ret=%d", ret); return ret; } srs_info("listen thread current_cid=%d, " "listen at port=%d, type=%d, fd=%d started success, ep=%s:%d", _srs_context->get_id(), p, type, listener->fd(), i.c_str(), p); srs_trace("%s listen at tcp://%s:%d, fd=%d", srs_listener_type2string(type).c_str(), ip.c_str(), port, listener->fd()); return ret; } int SrsBufferListener::on_tcp_client(st_netfd_t stfd) { int ret = ERROR_SUCCESS; if ((ret = server->accept_client(type, stfd)) != ERROR_SUCCESS) { srs_warn("accept client error. ret=%d", ret); return ret; } return ret; }
接收的客户端连接都通过SrsServer的accept_client函数处理,
int SrsServer::accept_client(SrsListenerType type, st_netfd_t stfd) { int ret = ERROR_SUCCESS; SrsConnection* conn = fd2conn(type, stfd); if (conn == NULL) { srs_close_stfd(stfd); return ERROR_SUCCESS; } srs_assert(conn); // directly enqueue, the cycle thread will remove the client. conns.push_back(conn); srs_verbose("add conn to vector."); // cycle will start process thread and when finished remove the client. // @remark never use the conn, for it maybe destroyed. if ((ret = conn->start()) != ERROR_SUCCESS) { return ret; } srs_verbose("accept client finished. conns=%d, ret=%d", (int)conns.size(), ret); return ret; }
1. 调用 fd2conn函数得到 SrsConnection对象,存到
std::vector<SrsConnection*> conns;
2. call conn->start(),启动coroutine,在单独的协程里处理一个特定客户的请求
SrsConnection* SrsServer::fd2conn(SrsListenerType type, st_netfd_t stfd) { int ret = ERROR_SUCCESS; int fd = st_netfd_fileno(stfd); string ip = srs_get_peer_ip(fd); // for some keep alive application, for example, the keepalived, // will send some tcp packet which we cann't got the ip, // we just ignore it. if (ip.empty()) { srs_info("ignore empty ip client, fd=%d.", fd); return NULL; } // check connection limitation. int max_connections = _srs_config->get_max_connections(); if (handler && (ret = handler->on_accept_client(max_connections, (int)conns.size()) != ERROR_SUCCESS)) { srs_error("handle accept client failed, drop client: clients=%d, max=%d, fd=%d. ret=%d", (int)conns.size(), max_connections, fd, ret); return NULL; } if ((int)conns.size() >= max_connections) { srs_error("exceed the max connections, drop client: clients=%d, max=%d, fd=%d", (int)conns.size(), max_connections, fd); return NULL; } // avoid fd leak when fork. // @see https://github.com/ossrs/srs/issues/518 if (true) { int val; if ((val = fcntl(fd, F_GETFD, 0)) < 0) { ret = ERROR_SYSTEM_PID_GET_FILE_INFO; srs_error("fnctl F_GETFD error! fd=%d. ret=%#x", fd, ret); return NULL; } val |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, val) < 0) { ret = ERROR_SYSTEM_PID_SET_FILE_INFO; srs_error("fcntl F_SETFD error! fd=%d ret=%#x", fd, ret); return NULL; } } SrsConnection* conn = NULL; if (type == SrsListenerRtmpStream) { conn = new SrsRtmpConn(this, stfd, ip); } else if (type == SrsListenerHttpApi) { conn = new SrsHttpApi(this, stfd, http_api_mux, ip); } else if (type == SrsListenerHttpStream) { conn = new SrsResponseOnlyHttpConn(this, stfd, http_server, ip); } else { srs_warn("close for no service handler. fd=%d, ip=%s", fd, ip.c_str()); srs_close_stfd(stfd); return NULL; } return conn; }
1. type == SrsListenerRtmpStream ==> new SrsRtmpConn(this, stfd, ip);
2. type == SrsListenerHttpApi ==> new SrsHttpApi(this, stfd, http_api_mux, ip);3. type == SrsListenerHttpStream ==> new SrsResponseOnlyHttpConn(this, stfd, http_server, ip);
class SrsRtmpConn : public virtual SrsConnection, public virtual ISrsReloadHandler
SrsRtmpConn(SrsServer* svr, st_netfd_t c, std::string cip);
class SrsHttpApi : virtual public SrsConnection, virtual public ISrsReloadHandler
SrsHttpApi(IConnectionManager* cm, st_netfd_t fd, SrsHttpServeMux* m, std::string cip);
/** * drop body of request, only process the response. */ class SrsResponseOnlyHttpConn : public SrsHttpConn { public: SrsResponseOnlyHttpConn(IConnectionManager* cm, st_netfd_t fd, ISrsHttpServeMux* m, std::string cip); virtual ~SrsResponseOnlyHttpConn(); public: // Directly read a HTTP request message. // It's exported for HTTP stream, such as HTTP FLV, only need to write to client when // serving it, but we need to start a thread to read message to detect whether FD is closed. // @see https://github.com/ossrs/srs/issues/636#issuecomment-298208427 // @remark Should only used in HTTP-FLV streaming connection. virtual int pop_message(ISrsHttpMessage** preq); public: virtual int on_got_http_message(ISrsHttpMessage* msg); };
/** * The http connection which request the static or stream content. */ class SrsHttpConn : public SrsConnection
/** * the basic connection of SRS, * all connections accept from listener must extends from this base class, * server will add the connection to manager, and delete it when remove. */ class SrsConnection : virtual public ISrsConnection, virtual public ISrsOneCycleThreadHandler , virtual public IKbpsDelta, virtual public ISrsReloadHandler { private: /** * each connection start a green thread, * when thread stop, the connection will be delete by server. */ SrsOneCycleThread* pthread; /** * the id of connection. */ int id;
可见生成的是SrsConnection的子类,下一篇分析SrsConnection类及其子类
/** * the tcp listener, for rtsp server. */ class SrsRtspListener : virtual public SrsListener, virtual public ISrsTcpHandler { private: SrsTcpListener* listener; ISrsTcpHandler* caster; public: SrsRtspListener(SrsServer* svr, SrsListenerType t, SrsConfDirective* c); virtual ~SrsRtspListener(); public: virtual int listen(std::string i, int p); // ISrsTcpHandler public: virtual int on_tcp_client(st_netfd_t stfd); };
SrsRtspListener 接收 rtsp推流,由caster将rtsp stream变换成rtmp stream后推送到 rtmp server
SrsRtspListener::SrsRtspListener(SrsServer* svr, SrsListenerType t, SrsConfDirective* c) : SrsListener(svr, t) { listener = NULL; // the caller already ensure the type is ok, // we just assert here for unknown stream caster. srs_assert(type == SrsListenerRtsp); if (type == SrsListenerRtsp) { caster = new SrsRtspCaster(c); } } SrsRtspListener::~SrsRtspListener() { srs_freep(caster); srs_freep(listener); } int SrsRtspListener::listen(string i, int p) { int ret = ERROR_SUCCESS; // the caller already ensure the type is ok, // we just assert here for unknown stream caster. srs_assert(type == SrsListenerRtsp); ip = i; port = p; srs_freep(listener); listener = new SrsTcpListener(this, ip, port); if ((ret = listener->listen()) != ERROR_SUCCESS) { srs_error("rtsp caster listen failed. ret=%d", ret); return ret; } srs_info("listen thread listen at port=%d, type=%d, fd=%d started success, ep=%s:%d", port, type, listener->fd(), ip.c_str(), port); srs_trace("%s listen at tcp://%s:%d, fd=%d", srs_listener_type2string(type).c_str(), ip.c_str(), port, listener->fd()); return ret; } int SrsRtspListener::on_tcp_client(st_netfd_t stfd) { int ret = ERROR_SUCCESS; if ((ret = caster->on_tcp_client(stfd)) != ERROR_SUCCESS) { srs_warn("accept client error. ret=%d", ret); return ret; } return ret; }
SrsRtspCaster
文件app/srs_app_rtsp.hpp
app/srs_app_rtsp.cpp
/** * the caster for rtsp. */ class SrsRtspCaster : public ISrsTcpHandler { private: std::string output; int local_port_min; int local_port_max; // key: port, value: whether used. std::map<int, bool> used_ports; private: std::vector<SrsRtspConn*> clients; public: SrsRtspCaster(SrsConfDirective* c); virtual ~SrsRtspCaster(); public: /** * alloc a rtp port from local ports pool. * @param pport output the rtp port. */ virtual int alloc_port(int* pport); /** * free the alloced rtp port. */ virtual void free_port(int lpmin, int lpmax); // interface ISrsTcpHandler public: virtual int on_tcp_client(st_netfd_t stfd); // internal methods. public: virtual void remove(SrsRtspConn* conn); };
int SrsRtspCaster::on_tcp_client(st_netfd_t stfd) { int ret = ERROR_SUCCESS; // output 是要输出的目标 RTMP推流地址 SrsRtspConn* conn = new SrsRtspConn(this, stfd, output); if ((ret = conn->serve()) != ERROR_SUCCESS) { srs_error("rtsp: serve client failed. ret=%d", ret); srs_freep(conn); return ret; } clients.push_back(conn); srs_info("rtsp: start thread to serve client."); return ret; }
class SrsRtspConn : public ISrsOneCycleThreadHandler
int SrsRtspConn::serve() { int ret = ERROR_SUCCESS;
if ((ret = skt->initialize(stfd)) != ERROR_SUCCESS) {
return ret; } return trd->start(); }
成员变量
SrsStSocket* skt;
int SrsRtspConn::do_cycle() { int ret = ERROR_SUCCESS; // retrieve ip of client. std::string ip = srs_get_peer_ip(st_netfd_fileno(stfd)); srs_trace("rtsp: serve %s", ip.c_str()); // consume all rtsp messages. for (;;) { SrsRtspRequest* req = NULL;
// rtsp类型 SrsRtspStack,构造参数skt if ((ret = rtsp->recv_message(&req)) != ERROR_SUCCESS) { if (!srs_is_client_gracefully_close(ret)) { srs_error("rtsp: recv request failed. ret=%d", ret); } return ret; } SrsAutoFree(SrsRtspRequest, req); srs_info("rtsp: got rtsp request"); if (req->is_options()) { SrsRtspOptionsResponse* res = new SrsRtspOptionsResponse((int)req->seq); res->session = session; if ((ret = rtsp->send_message(res)) != ERROR_SUCCESS) { if (!srs_is_client_gracefully_close(ret)) { srs_error("rtsp: send OPTIONS response failed. ret=%d", ret); } return ret; } } else if (req->is_announce()) { if (rtsp_tcUrl.empty()) { rtsp_tcUrl = req->uri; } size_t pos = string::npos; if ((pos = rtsp_tcUrl.rfind(".sdp")) != string::npos) { rtsp_tcUrl = rtsp_tcUrl.substr(0, pos); } srs_parse_rtmp_url(rtsp_tcUrl, rtsp_tcUrl, rtsp_stream); srs_assert(req->sdp); video_id = ::atoi(req->sdp->video_stream_id.c_str()); audio_id = ::atoi(req->sdp->audio_stream_id.c_str()); video_codec = req->sdp->video_codec; audio_codec = req->sdp->audio_codec; audio_sample_rate = ::atoi(req->sdp->audio_sample_rate.c_str()); audio_channel = ::atoi(req->sdp->audio_channel.c_str()); h264_sps = req->sdp->video_sps; h264_pps = req->sdp->video_pps; aac_specific_config = req->sdp->audio_sh; srs_trace("rtsp: video(#%d, %s, %s/%s), audio(#%d, %s, %s/%s, %dHZ %dchannels), %s/%s", video_id, video_codec.c_str(), req->sdp->video_protocol.c_str(), req->sdp->video_transport_format.c_str(), audio_id, audio_codec.c_str(), req->sdp->audio_protocol.c_str(), req->sdp->audio_transport_format.c_str(), audio_sample_rate, audio_channel, rtsp_tcUrl.c_str(), rtsp_stream.c_str() ); SrsRtspResponse* res = new SrsRtspResponse((int)req->seq); res->session = session; if ((ret = rtsp->send_message(res)) != ERROR_SUCCESS) { if (!srs_is_client_gracefully_close(ret)) { srs_error("rtsp: send ANNOUNCE response failed. ret=%d", ret); } return ret; } } else if (req->is_setup()) { srs_assert(req->transport); int lpm = 0; if ((ret = caster->alloc_port(&lpm)) != ERROR_SUCCESS) { srs_error("rtsp: alloc port failed. ret=%d", ret); return ret; } SrsRtpConn* rtp = NULL; if (req->stream_id == video_id) { srs_freep(video_rtp); rtp = video_rtp = new SrsRtpConn(this, lpm, video_id); } else { srs_freep(audio_rtp); rtp = audio_rtp = new SrsRtpConn(this, lpm, audio_id); } if ((ret = rtp->listen()) != ERROR_SUCCESS) { srs_error("rtsp: rtp listen at port=%d failed. ret=%d", lpm, ret); return ret; } srs_trace("rtsp: #%d %s over %s/%s/%s %s client-port=%d-%d, server-port=%d-%d", req->stream_id, (req->stream_id == video_id)? "Video":"Audio", req->transport->transport.c_str(), req->transport->profile.c_str(), req->transport->lower_transport.c_str(), req->transport->cast_type.c_str(), req->transport->client_port_min, req->transport->client_port_max, lpm, lpm + 1 ); // create session. if (session.empty()) { session = "O9EaZ4bf"; // TODO: FIXME: generate session id. } SrsRtspSetupResponse* res = new SrsRtspSetupResponse((int)req->seq); res->client_port_min = req->transport->client_port_min; res->client_port_max = req->transport->client_port_max; res->local_port_min = lpm; res->local_port_max = lpm + 1; res->session = session; if ((ret = rtsp->send_message(res)) != ERROR_SUCCESS) { if (!srs_is_client_gracefully_close(ret)) { srs_error("rtsp: send SETUP response failed. ret=%d", ret); } return ret; } } else if (req->is_record()) { SrsRtspResponse* res = new SrsRtspResponse((int)req->seq); res->session = session; if ((ret = rtsp->send_message(res)) != ERROR_SUCCESS) { if (!srs_is_client_gracefully_close(ret)) { srs_error("rtsp: send SETUP response failed. ret=%d", ret); } return ret; } } } return ret; }