ronantakizawa/codereview-bench huggingface dataset:
Repository: ossrs/srs
File: trunk/src/app/srs_app_source.cpp (C++)

Code before:
        if (!SrsFlvVideo::h264(msg->payload, msg->size)) {
            return err;
        }
        
        cached_video_count++;
        audio_after_last_video_count = 0;
    }
    
    // no acceptable video or pure audio, disable the cache.
    if (pure_audio()) {
        return err;
    }
    
    // ok, gop cache enabled, and got an audio.
    if (msg->is_audio()) {
        audio_after_last_video_count++;
    }
    
    // clear gop cache when pure audio count overflow
    if (audio_after_last_video_count > SRS_PURE_AUDIO_GUESS_COUNT) {
        srs_warn("clear gop cache for guess pure audio overflow");
        clear();
        return err;
    }
    
    if (cached_video_count > gop_cache_max_frames_){
        srs_warn("too much frames in the gop cache");
        clear();
    }

    // clear gop cache when got key frame
    if (msg->is_video() && SrsFlvVideo::keyframe(msg->payload, msg->size)) {
        clear();
        
        // curent msg is video frame, so we set to 1.
        cached_video_count = 1;
    }
    
    // cache the frame.
    gop_cache.push_back(msg->copy());
    
    return err;
}

void SrsGopCache::clear()
{
    std::vector<SrsSharedPtrMessage*>::iterator it;
    for (it = gop_cache.begin(); it != gop_cache.end(); ++it) {
        SrsSharedPtrMessage* msg = *it;
        srs_freep(msg);
    }

Review comment (performance):
The length of the queue `gop_cache.size()` should be used instead of the variable `cached_video_count`, as it only represents video frames.

This situation usually occurs as an exception, and continuously sending data messages can also cause OOM (Out of Memory).

`TRANS_BY_GPT3`

Code after:
    }
    
    // no acceptable video or pure audio, disable the cache.
    if (pure_audio()) {
        return err;
    }
    
    // ok, gop cache enabled, and got an audio.
    if (msg->is_audio()) {
        audio_after_last_video_count++;
    }
    
    // clear gop cache when pure audio count overflow
    if (audio_after_last_video_count > SRS_PURE_AUDIO_GUESS_COUNT) {
        srs_warn("clear gop cache for guess pure audio overflow");
        clear();
        return err;
    }
    
    // clear gop cache when got key frame
    if (msg->is_video() && SrsFlvVideo::keyframe(msg->payload, msg->size)) {
        clear();
        
        // curent msg is video frame, so we set to 1.
        cached_video_count = 1;
    }

    // cache the frame.
    gop_cache.push_back(msg->copy());

    // Clear gop cache if exceed the max frames.
    if (gop_cache.size() > (size_t)gop_cache_max_frames_) {
        srs_warn("Gop cache exceed max frames=%d, total=%d, videos=%d, aalvc=%d",
            gop_cache_max_frames_, (int)gop_cache.size(), cached_video_count, audio_after_last_video_count);
        clear();
    }

    return err;
}

void SrsGopCache::clear()
{
    std::vector<SrsSharedPtrMessage*>::iterator it;
    for (it = gop_cache.begin(); it != gop_cache.end(); ++it) {
        SrsSharedPtrMessage* msg = *it;
        srs_freep(msg);
    }
    gop_cache.clear();
    
    cached_video_count = 0;
    audio_after_last_video_count = 0;
Repository: ossrs/srs
File: trunk/src/kernel/srs_kernel_file.hpp (C++)

Code before:
#include <string>

// for srs-librtmp, @see https://github.com/ossrs/srs/issues/213
#ifndef _WIN32
#include <sys/uio.h>
#endif

class SrsFileReader;

/**
 * file writer, to write to file.
 */
class SrsFileWriter : public ISrsWriteSeeker
{
private:
    std::string path_;
    FILE *fd_;
    char *buf_;
public:
    SrsFileWriter();
    virtual ~SrsFileWriter();
public:
    /**
     * set io buf size
    */
   virtual srs_error_t srs_set_iobuf_size(int size);

    /**
     * open file writer, in truncate mode.
     * @param p a string indicates the path of file to open.
     */
    virtual srs_error_t open(std::string p);
    /**
     * open file writer, in append mode.
     * @param p a string indicates the path of file to open.
     */
    virtual srs_error_t open_append(std::string p);
    /**
     * close current writer.
     * @remark user can reopen again.
     */
    virtual void close();
public:
    virtual bool is_open();
    virtual void seek2(int64_t offset);
    virtual int64_t tellg();
// Interface ISrsWriteSeeker
public:
    virtual srs_error_t write(void* buf, size_t count, ssize_t* pnwrite);
    virtual srs_error_t writev(const iovec* iov, int iovcnt, ssize_t* pnwrite);
    virtual srs_error_t lseek(off_t offset, int whence, off_t* seeked);

Review comment (suggestion):
This function does not need to be prefixed with 'srs_', usually only single-purpose functions need to be prefixed with 'srs_'.

`TRANS_BY_GPT3`

Code after:
#include <string>

// for srs-librtmp, @see https://github.com/ossrs/srs/issues/213
#ifndef _WIN32
#include <sys/uio.h>
#endif

class SrsFileReader;

/**
 * file writer, to write to file.
 */
class SrsFileWriter : public ISrsWriteSeeker
{
private:
    std::string path_;
    FILE *fp_;
    char *buf_;
public:
    SrsFileWriter();
    virtual ~SrsFileWriter();
public:
    /**
     * set io buf size
    */
   virtual srs_error_t set_iobuf_size(int size);

    /**
     * open file writer, in truncate mode.
     * @param p a string indicates the path of file to open.
     */
    virtual srs_error_t open(std::string p);
    /**
     * open file writer, in append mode.
     * @param p a string indicates the path of file to open.
     */
    virtual srs_error_t open_append(std::string p);
    /**
     * close current writer.
     * @remark user can reopen again.
     */
    virtual void close();
public:
    virtual bool is_open();
    virtual void seek2(int64_t offset);
    virtual int64_t tellg();
// Interface ISrsWriteSeeker
public:
    virtual srs_error_t write(void* buf, size_t count, ssize_t* pnwrite);
    virtual srs_error_t writev(const iovec* iov, int iovcnt, ssize_t* pnwrite);
    virtual srs_error_t lseek(off_t offset, int whence, off_t* seeked);
Repository: ossrs/srs
File: trunk/src/kernel/srs_kernel_file.cpp (C++)

Code before:
    buf_ = NULL;
}

SrsFileWriter::~SrsFileWriter()
{
    close();
    srs_freepa(buf_);
}


srs_error_t SrsFileWriter::srs_set_iobuf_size(int size)
{
    srs_error_t err = srs_success;

    if (fd_ == NULL){
        return srs_error_new(ERROR_SYSTEM_FILE_NOT_OPEN, "file %s is not opened", path_.c_str());
    }

    srs_freepa(buf_);

    int ret;

    if (size > 0){
        buf_ = new char[size];
        ret = setvbuf(fd_, buf_, _IOFBF, size);
    }else{
        ret = setvbuf(fd_, NULL, _IONBF, size);
    }

    if (ret != 0){
        return srs_error_new(ERROR_SYSTEM_FILE_SETVBUF, "file %s set vbuf error", path_.c_str());
    }

    return err;
}


srs_error_t SrsFileWriter::open(string p)
{
    srs_error_t err = srs_success;
    
    if (fd_ != NULL) {
        return srs_error_new(ERROR_SYSTEM_FILE_ALREADY_OPENED, "file %s already opened", p.c_str());
    }
    
    if ((fd_ = fopen(p.c_str(), "wb")) == NULL) {
        return srs_error_new(ERROR_SYSTEM_FILE_OPENE, "open file %s failed", p.c_str());
    }
    
    path_ = p;
    

Review comment (suggestion):
Is it better to not handle size <= 0? man setvbuf, _IONBF should mean no buffer, so it's the same as write?

`TRANS_BY_GPT3`

Code after:
srs_fseek_t _srs_fseek_fn = ::fseek;
srs_fclose_t _srs_fclose_fn = ::fclose;
srs_ftell_t _srs_ftell_fn = ::ftell;
srs_setvbuf_t _srs_setvbuf_fn = ::setvbuf;

SrsFileWriter::SrsFileWriter()
{
    fp_  = NULL;
    buf_ = NULL;
}

SrsFileWriter::~SrsFileWriter()
{
    close();
    srs_freepa(buf_);
}

srs_error_t SrsFileWriter::set_iobuf_size(int size)
{
    srs_error_t err = srs_success;

    if (fp_ == NULL) {
        return srs_error_new(ERROR_SYSTEM_FILE_NOT_OPEN, "file %s is not opened", path_.c_str());
    }

    srs_freepa(buf_);
    buf_ = size > 0 ? new char[size] : NULL;
    int r0 = _srs_setvbuf_fn(fp_, buf_, _IOFBF, size);
    if (r0) {
        return srs_error_new(ERROR_SYSTEM_FILE_SETVBUF, "setvbuf err, file=%s, r0=%d", path_.c_str(), r0);
    }

    return err;
}

srs_error_t SrsFileWriter::open(string p)
{
    srs_error_t err = srs_success;
    
    if (fp_ != NULL) {
        return srs_error_new(ERROR_SYSTEM_FILE_ALREADY_OPENED, "file %s already opened", p.c_str());
    }
    
    if ((fp_ = _srs_fopen_fn(p.c_str(), "wb")) == NULL) {
        return srs_error_new(ERROR_SYSTEM_FILE_OPENE, "open file %s failed", p.c_str());
    }
    
    path_ = p;
    
    return err;
}
Repository: ossrs/srs
File: trunk/src/kernel/srs_kernel_file.cpp (C++)

Code before:
{
    fp_  = NULL;
    buf_ = NULL;
}

SrsFileWriter::~SrsFileWriter()
{
    close();
    srs_freepa(buf_);
}


srs_error_t SrsFileWriter::set_iobuf_size(int size)
{
    srs_error_t err = srs_success;

    if (fp_ == NULL) {
        return srs_error_new(ERROR_SYSTEM_FILE_NOT_OPEN, "file %s is not opened", path_.c_str());
    }

    srs_freepa(buf_);

    int ret;

    if (size > 0) {
        buf_ = new char[size];
        ret = _srs_setvbuf_fn(fp_, buf_, _IOFBF, size);
    }
    else {
        ret = _srs_setvbuf_fn(fp_, NULL, _IONBF, size);
    }

    if (ret != 0) {
        return srs_error_new(ERROR_SYSTEM_FILE_SETVBUF, "file %s set vbuf error", path_.c_str());
    }

    return err;
}


srs_error_t SrsFileWriter::open(string p)
{
    srs_error_t err = srs_success;
    
    if (fp_ != NULL) {
        return srs_error_new(ERROR_SYSTEM_FILE_ALREADY_OPENED, "file %s already opened", p.c_str());
    }
    
    if ((fp_ = _srs_fopen_fn(p.c_str(), "wb")) == NULL) {
        return srs_error_new(ERROR_SYSTEM_FILE_OPENE, "open file %s failed", p.c_str());
    }

Review comment (suggestion):
I made some changes to this section:

```cpp
    srs_freepa(buf_);
    buf_ = size > 0 ? new char[size] : NULL;
    int r0 = _srs_setvbuf_fn(fp_, buf_, _IOFBF, size);
    if (!r0) {
        return srs_error_new(ERROR_SYSTEM_FILE_SETVBUF, "setvbuf err, file=%s, r0=%d", path_.c_str(), r0);
    }
```

Special attention should be paid to the fact that the previous value of "ret" was lost.

`TRANS_BY_GPT3`

Code after:
{
    fp_  = NULL;
    buf_ = NULL;
}

SrsFileWriter::~SrsFileWriter()
{
    close();
    srs_freepa(buf_);
}

srs_error_t SrsFileWriter::set_iobuf_size(int size)
{
    srs_error_t err = srs_success;

    if (fp_ == NULL) {
        return srs_error_new(ERROR_SYSTEM_FILE_NOT_OPEN, "file %s is not opened", path_.c_str());
    }

    srs_freepa(buf_);
    buf_ = size > 0 ? new char[size] : NULL;
    int r0 = _srs_setvbuf_fn(fp_, buf_, _IOFBF, size);
    if (r0) {
        return srs_error_new(ERROR_SYSTEM_FILE_SETVBUF, "setvbuf err, file=%s, r0=%d", path_.c_str(), r0);
    }

    return err;
}

srs_error_t SrsFileWriter::open(string p)
{
    srs_error_t err = srs_success;
    
    if (fp_ != NULL) {
        return srs_error_new(ERROR_SYSTEM_FILE_ALREADY_OPENED, "file %s already opened", p.c_str());
    }
    
    if ((fp_ = _srs_fopen_fn(p.c_str(), "wb")) == NULL) {
        return srs_error_new(ERROR_SYSTEM_FILE_OPENE, "open file %s failed", p.c_str());
    }
    
    path_ = p;
    
    return err;
}

srs_error_t SrsFileWriter::open_append(string p)
{
    srs_error_t err = srs_success;
    
    if (fp_ != NULL) {
Repository: ossrs/srs
File: trunk/src/app/srs_app_gb28181.hpp (C++)

Code before:
#include <srs_protocol_http_conn.hpp>
#include <srs_kernel_ps.hpp>
#include <srs_app_conn.hpp>

#include <sstream>

class SrsConfDirective;
class SrsTcpListener;
class SrsResourceManager;
class SrsTcpConnection;
class SrsCoroutine;
class SrsPackContext;
class SrsBuffer;
class SrsSipMessage;
class SrsLazyGbSession;
class SrsLazyGbSipTcpConn;
class SrsLazyGbMediaTcpConn;
class SrsLazyGbSipTcpReceiver;
class SrsLazyGbSipTcpSender;
class SrsAlonePithyPrint;
class SrsGbMuxer;
class SrsSimpleRtmpClient;
struct SrsRawAacStreamCodec;
class SrsRawH264Stream;
class SrsRawHEVCStream;
class SrsSharedPtrMessage;
class SrsPithyPrint;
class SrsRawAacStream;

// The state machine for GB session.
// init:
//      to connecting: sip is registered. Note that also send invite request if media not connected.
// connecting:
//      to established: sip is stable, media is connected.
// established:
//      init: media is not connected.
//      dispose session: sip is bye.
// Please see SrsLazyGbSession::drive_state for detail.
enum SrsGbSessionState
{
    SrsGbSessionStateInit = 0,
    SrsGbSessionStateConnecting,
    SrsGbSessionStateEstablished,
};
std::string srs_gb_session_state(SrsGbSessionState state);

// The state machine for GB SIP connection.
// init:
//      to registered: Got REGISTER SIP message.
//      to stable: Got MESSAGE SIP message, when SIP TCP connection re-connect.
// registered:

Review comment (suggestion):
Increase macro judgment
```
#ifdef SRS_H265
class SrsRawHEVCStream;
#endif
```

`TRANS_BY_GPT3`

Code after:
#include <srs_protocol_http_conn.hpp>
#include <srs_kernel_ps.hpp>
#include <srs_app_conn.hpp>

#include <sstream>

class SrsConfDirective;
class SrsTcpListener;
class SrsResourceManager;
class SrsTcpConnection;
class SrsCoroutine;
class SrsPackContext;
class SrsBuffer;
class SrsSipMessage;
class SrsLazyGbSession;
class SrsLazyGbSipTcpConn;
class SrsLazyGbMediaTcpConn;
class SrsLazyGbSipTcpReceiver;
class SrsLazyGbSipTcpSender;
class SrsAlonePithyPrint;
class SrsGbMuxer;
class SrsSimpleRtmpClient;
struct SrsRawAacStreamCodec;
class SrsRawH264Stream;
#ifdef SRS_H265
class SrsRawHEVCStream;
#endif
class SrsSharedPtrMessage;
class SrsPithyPrint;
class SrsRawAacStream;

// The state machine for GB session.
// init:
//      to connecting: sip is registered. Note that also send invite request if media not connected.
// connecting:
//      to established: sip is stable, media is connected.
// established:
//      init: media is not connected.
//      dispose session: sip is bye.
// Please see SrsLazyGbSession::drive_state for detail.
enum SrsGbSessionState
{
    SrsGbSessionStateInit = 0,
    SrsGbSessionStateConnecting,
    SrsGbSessionStateEstablished,
};
std::string srs_gb_session_state(SrsGbSessionState state);

// The state machine for GB SIP connection.
// init:
//      to registered: Got REGISTER SIP message.
Repository: ossrs/srs
File: trunk/3rdparty/srs-bench/gb28181/gb_test.go (Go)

Code before:
		return nil
	}()
	if err := filterTestError(ctx.Err(), err); err != nil {
		t.Errorf("err %+v", err)
	}
}

func TestGbPublishRegularlyH265(t *testing.T) {
	ctx := logger.WithContext(context.Background())
	ctx, cancel := context.WithTimeout(ctx, time.Duration(*srsTimeout)*time.Millisecond)
	defer cancel()

	err := func() error {
		t := NewGBTestPublisher()
		defer t.Close()

		var nnPackets int
		t.ingester.onSendPacket = func(pack *PSPackStream) error {
			if nnPackets += 1; nnPackets > 10 {
				cancel()
			}
			return nil
		}

		t.ingester.conf.psConfig.video = "avatar.h265"
		t.ingester.conf.psConfig.videoCodec = mpeg2.PS_STREAM_H265
		if err := t.Run(ctx); err != nil {
			return err
		}

		return nil
	}()
	if err := filterTestError(ctx.Err(), err); err != nil {
		t.Errorf("err %+v", err)
	}
}

func TestGbSessionHandshake(t *testing.T) {
	ctx := logger.WithContext(context.Background())
	ctx, cancel := context.WithTimeout(ctx, time.Duration(*srsTimeout)*time.Millisecond)
	defer cancel()

	err := func() error {
		t := NewGBTestSession()
		defer t.Close()

		// Use fast heartbeat for utest.
		t.session.heartbeatInterval = 100 * time.Millisecond

		if err := t.Run(ctx); err != nil {
			return err

Review comment (suggestion):
If it is GB pressure test, refer to [here](https://github.com/ossrs/srs-bench#gb28181-test) for instructions on how to use 265.

```
`-srs-publish-video` is the video file used during streaming. The default value is `avatar.h264`.
```

Do we need to add a parameter to the GB command line load test? Specify the encoding? Or can it be analyzed from the file?

`TRANS_BY_GPT3`

Code after:
	}()
	if err := filterTestError(ctx.Err(), err); err != nil {
		t.Errorf("err %+v", err)
	}
}

func TestGbPublishRegularlyH265(t *testing.T) {
	ctx := logger.WithContext(context.Background())
	ctx, cancel := context.WithTimeout(ctx, time.Duration(*srsTimeout)*time.Millisecond)
	defer cancel()

	err := func() error {
		t := NewGBTestPublisher()
		defer t.Close()

		var nnPackets int
		t.ingester.onSendPacket = func(pack *PSPackStream) error {
			if nnPackets += 1; nnPackets > 10 {
				cancel()
			}
			return nil
		}

		t.ingester.conf.psConfig.video = "avatar.h265"
		if err := t.Run(ctx); err != nil {
			return err
		}

		return nil
	}()
	if err := filterTestError(ctx.Err(), err); err != nil {
		t.Errorf("err %+v", err)
	}
}

func TestGbSessionHandshake(t *testing.T) {
	ctx := logger.WithContext(context.Background())
	ctx, cancel := context.WithTimeout(ctx, time.Duration(*srsTimeout)*time.Millisecond)
	defer cancel()

	err := func() error {
		t := NewGBTestSession()
		defer t.Close()

		// Use fast heartbeat for utest.
		t.session.heartbeatInterval = 100 * time.Millisecond

		if err := t.Run(ctx); err != nil {
			return err
		}
Repository: ossrs/srs
File: trunk/src/app/srs_app_rtc_dtls.cpp (C++)

Code before:

        int expire_day = 365;
        const long cert_duration = 60*60*24*expire_day;

        X509_gmtime_adj(X509_get_notBefore(dtls_cert), 0);
        X509_gmtime_adj(X509_get_notAfter(dtls_cert), cert_duration);

        X509_set_version(dtls_cert, 2);
        srs_assert(X509_set_pubkey(dtls_cert, dtls_pkey) == 1);
        srs_assert(X509_sign(dtls_cert, dtls_pkey, EVP_sha1()) != 0);

        X509_NAME_free(subject);
    }

    // Show DTLS fingerprint
    if (true) {
        char fp[100] = {0};
        char *p = fp;
        unsigned char md[EVP_MAX_MD_SIZE];
        unsigned int n = 0;

        // TODO: FIXME: Unused variable.
        /*int r = */X509_digest(dtls_cert, EVP_sha256(), md, &n);

        for (unsigned int i = 0; i < n; i++, ++p) {
            snprintf(p, 3, "%02X", md[i]);
            p += 2;

            if(i < (n-1)) {
                *p = ':';
            } else {
                *p = '\0';
            }
        }

        fingerprint.assign(fp, strlen(fp));
        srs_trace("fingerprint=%s", fingerprint.c_str());
    }

    return err;
}

X509* SrsDtlsCertificate::get_cert()
{
    return dtls_cert;
}

EVP_PKEY* SrsDtlsCertificate::get_public_key()
{
    return dtls_pkey;
}

Review comment (suggestion):
If the return value of snprintf is an error, then it should be checked and the function should be returned.

Code after:

        int expire_day = 365;
        const long cert_duration = 60*60*24*expire_day;

        X509_gmtime_adj(X509_get_notBefore(dtls_cert), 0);
        X509_gmtime_adj(X509_get_notAfter(dtls_cert), cert_duration);

        X509_set_version(dtls_cert, 2);
        srs_assert(X509_set_pubkey(dtls_cert, dtls_pkey) == 1);
        srs_assert(X509_sign(dtls_cert, dtls_pkey, EVP_sha1()) != 0);

        X509_NAME_free(subject);
    }

    // Show DTLS fingerprint
    if (true) {
        unsigned char md[EVP_MAX_MD_SIZE];
        unsigned int n = 0;

        // TODO: FIXME: Unused variable.
        /*int r = */X509_digest(dtls_cert, EVP_sha256(), md, &n);

        char* fp = new char[3 * n];
        SrsAutoFreeA(char, fp);
        char *p = fp;

        for (unsigned int i = 0; i < n; i++, ++p) {
            int nb = snprintf(p, 3, "%02X", md[i]);
            srs_assert(nb > 0 && nb < (3 * n - (p - fp)));
            p += nb;

            if(i < (n-1)) {
                *p = ':';
            } else {
                *p = '\0';
            }
        }

        fingerprint.assign(fp, strlen(fp));
        srs_trace("fingerprint=%s", fingerprint.c_str());
    }

    return err;
}

X509* SrsDtlsCertificate::get_cert()
{
    return dtls_cert;
}

EVP_PKEY* SrsDtlsCertificate::get_public_key()
Repository: ossrs/srs
File: trunk/src/main/srs_main_server.cpp (C++)

Code before:
    }
    
    // we check the config when the log initialized.
    if ((err = _srs_config->check_config()) != srs_success) {
        return srs_error_wrap(err, "check config");
    }
    
    // features
    show_macro_features();

#ifdef SRS_GPERF
    // For tcmalloc, use slower release rate.
    if (true) {
        double trr = _srs_config->tcmalloc_release_rate();
        double otrr = MallocExtension::instance()->GetMemoryReleaseRate();
        MallocExtension::instance()->SetMemoryReleaseRate(trr);
        srs_trace("tcmalloc: set release-rate %.2f=>%.2f", otrr, trr);
    }
#endif

#ifdef SRS_SANITIZER_LOG
    __asan_set_error_report_callback(asan_report_callback);
#endif
    
    if ((err = run_directly_or_daemon()) != srs_success) {
        srs_free_global_system_ips();
        return srs_error_wrap(err, "run");
    }

    srs_free_global_system_ips();

    return err;
}

int main(int argc, char** argv, char** envp)
{
    srs_error_t err = do_main(argc, argv, envp);

    if (err != srs_success) {
        srs_error("Failed, %s", srs_error_desc(err).c_str());
    }
    
    int ret = srs_error_code(err);
    srs_freep(err);
    return ret;
}

/**
 * show the features by macro, the actual macro values.
 */
void show_macro_features()

Review comment (refactor):
Please refine the code:

```cpp
    if ((err = run_directly_or_daemon()) != srs_success) {
        srs_free_global_system_ips();
        return srs_error_wrap(err, "run");
    }

    srs_free_global_system_ips();
```

to reduce some duplicated code by:

```cpp    
err = run_directly_or_daemon();
srs_free_global_system_ips();
if (err != srs_success) {
    return srs_error_wrap(err, "run");
}
```

Code after:
    }
    
    // we check the config when the log initialized.
    if ((err = _srs_config->check_config()) != srs_success) {
        return srs_error_wrap(err, "check config");
    }
    
    // features
    show_macro_features();

#ifdef SRS_GPERF
    // For tcmalloc, use slower release rate.
    if (true) {
        double trr = _srs_config->tcmalloc_release_rate();
        double otrr = MallocExtension::instance()->GetMemoryReleaseRate();
        MallocExtension::instance()->SetMemoryReleaseRate(trr);
        srs_trace("tcmalloc: set release-rate %.2f=>%.2f", otrr, trr);
    }
#endif

#ifdef SRS_SANITIZER_LOG
    __asan_set_error_report_callback(asan_report_callback);
#endif

    err = run_directly_or_daemon();
    srs_free_global_system_ips();
    if (err != srs_success) {
        return srs_error_wrap(err, "run");
    }

    return err;
}

int main(int argc, char** argv, char** envp)
{
    srs_error_t err = do_main(argc, argv, envp);

    if (err != srs_success) {
        srs_error("Failed, %s", srs_error_desc(err).c_str());
    }
    
    int ret = srs_error_code(err);
    srs_freep(err);
    return ret;
}

/**
 * show the features by macro, the actual macro values.
 */
void show_macro_features()
{