// // Copyright (c) 2013-2025 The SRS Authors // // SPDX-License-Identifier: MIT // #ifndef SRS_APP_SRT_SOURCE_HPP #define SRS_APP_SRT_SOURCE_HPP #include #include #include #include #include #include #include #include class SrsMediaPacket; class ISrsRequest; class SrsLiveSource; class SrsSrtSource; class SrsAlonePithyPrint; class SrsSrtFrameBuilder; // The SRT packet with shared message. class SrsSrtPacket { public: SrsSrtPacket(); virtual ~SrsSrtPacket(); public: // Wrap buffer to shared_message, which is managed by us. char *wrap(int size); char *wrap(char *data, int size); // Wrap the shared message, we copy it. char *wrap(SrsMediaPacket *msg); // Copy the SRT packet. virtual SrsSrtPacket *copy(); public: char *data(); int size(); private: SrsMediaPacket *shared_buffer_; // The size of SRT packet or SRT payload. int actual_buffer_size_; }; class SrsSrtSourceManager : public ISrsHourGlass { private: srs_mutex_t lock_; std::map > pool_; SrsHourGlass *timer_; public: SrsSrtSourceManager(); virtual ~SrsSrtSourceManager(); public: virtual srs_error_t initialize(); // interface ISrsHourGlass private: virtual srs_error_t setup_ticks(); virtual srs_error_t notify(int event, srs_utime_t interval, srs_utime_t tick); public: // create source when fetch from cache failed. // @param r the client request. // @param pps the matched source, if success never be NULL. virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr &pps); public: // Get the exists source, NULL when not exists. virtual SrsSharedPtr fetch(ISrsRequest *r); }; // Global singleton instance. extern SrsSrtSourceManager *_srs_srt_sources; class SrsSrtConsumer { public: SrsSrtConsumer(SrsSrtSource *source); virtual ~SrsSrtConsumer(); private: // Because source references to this object, so we should directly use the source ptr. SrsSrtSource *source_; private: std::vector queue_; // when source id changed, notice all consumers bool should_update_source_id_; // The cond wait for mw. srs_cond_t mw_wait_; bool mw_waiting_; int mw_min_msgs_; public: // When source id changed, notice client to print. void update_source_id(); // Put SRT packet into queue. srs_error_t enqueue(SrsSrtPacket *packet); // For SRT, we only got one packet, because there is not many packets in queue. virtual srs_error_t dump_packet(SrsSrtPacket **ppkt); // Wait for at-least some messages incoming in queue. virtual void wait(int nb_msgs, srs_utime_t timeout); }; // Collect and build SRT TS packet to AV frames. class SrsSrtFrameBuilder : public ISrsTsHandler { public: SrsSrtFrameBuilder(ISrsStreamBridge *bridge); virtual ~SrsSrtFrameBuilder(); public: srs_error_t initialize(ISrsRequest *r); public: virtual srs_error_t on_publish(); virtual srs_error_t on_packet(SrsSrtPacket *pkt); virtual void on_unpublish(); // Interface ISrsTsHandler public: virtual srs_error_t on_ts_message(SrsTsMessage *msg); private: srs_error_t on_ts_video_avc(SrsTsMessage *msg, SrsBuffer *avs); srs_error_t on_ts_audio(SrsTsMessage *msg, SrsBuffer *avs); srs_error_t check_sps_pps_change(SrsTsMessage *msg); srs_error_t on_h264_frame(SrsTsMessage *msg, std::vector > &ipb_frames); srs_error_t check_audio_sh_change(SrsTsMessage *msg, uint32_t pts); srs_error_t on_aac_frame(SrsTsMessage *msg, uint32_t pts, char *frame, int frame_size); srs_error_t on_ts_video_hevc(SrsTsMessage *msg, SrsBuffer *avs); srs_error_t check_vps_sps_pps_change(SrsTsMessage *msg); srs_error_t on_hevc_frame(SrsTsMessage *msg, std::vector > &ipb_frames); private: ISrsStreamBridge *bridge_; private: SrsTsContext *ts_ctx_; // Record sps/pps had changed, if change, need to generate new video sh frame. bool sps_pps_change_; std::string sps_; std::string pps_; bool vps_sps_pps_change_; std::string hevc_vps_; std::string hevc_sps_; std::vector hevc_pps_; // Record audio sepcific config had changed, if change, need to generate new audio sh frame. bool audio_sh_change_; std::string audio_sh_; private: ISrsRequest *req_; private: // SRT to rtmp, video stream id. int video_streamid_; // SRT to rtmp, audio stream id. int audio_streamid_; // Cycle print when audio duration too large because mpegts may merge multi audio frame in one pes packet. SrsAlonePithyPrint *pp_audio_duration_; }; class SrsSrtSource { public: SrsSrtSource(); virtual ~SrsSrtSource(); public: virtual srs_error_t initialize(ISrsRequest *r); public: // Whether stream is dead, which is no publisher or player. virtual bool stream_is_dead(); public: // The source id changed. virtual srs_error_t on_source_id_changed(SrsContextId id); // Get current source id. virtual SrsContextId source_id(); virtual SrsContextId pre_source_id(); // Update the authentication information in request. virtual void update_auth(ISrsRequest *r); public: void set_bridge(ISrsStreamBridge *bridge); public: // Create consumer // @param consumer, output the create consumer. virtual srs_error_t create_consumer(SrsSrtConsumer *&consumer); // Dumps packets in cache to consumer. virtual srs_error_t consumer_dumps(SrsSrtConsumer *consumer); virtual void on_consumer_destroy(SrsSrtConsumer *consumer); // Whether we can publish stream to the source, return false if it exists. virtual bool can_publish(); // When start publish stream. virtual srs_error_t on_publish(); // When stop publish stream. virtual void on_unpublish(); public: srs_error_t on_packet(SrsSrtPacket *packet); private: // Source id. SrsContextId _source_id; // previous source id. SrsContextId _pre_source_id; ISrsRequest *req_; // To delivery packets to clients. std::vector consumers_; bool can_publish_; // The last die time, while die means neither publishers nor players. srs_utime_t stream_die_at_; private: SrsSrtFrameBuilder *frame_builder_; ISrsStreamBridge *bridge_; }; #endif