ronantakizawa/codereview-bench huggingface dataset:
Repository: onlook-dev/onlook
File: apps/web/client/src/app/project/[id]/_components/right-panel/dev-tab/index.tsx (TypeScript)

Code before:
        if (!isSandboxReady()) {
            handleSandboxNotReady('get file path from OID');
            return null;
        }

        return ide.getFilePathFromOid(oid);
    }

    // Add saving functionality
    async function saveFile() {
        if (!ide.activeFile) {
            return;
        }

        if (!isSandboxReady()) {
            handleSandboxNotReady('save file');
            return;
        }

        if (pendingCloseAll) {
            const file = ide.openedFiles.find((f) => f.id === ide.activeFile?.id);
            if (file) {
                await ide.saveActiveFile();
                closeFile(file.id);
            }

            const remainingDirty = ide.openedFiles.filter((f) => f.isDirty);
            if (remainingDirty.length === 0) {
                ide.closeAllFiles();
                setPendingCloseAll(false);
                setShowUnsavedDialog(false);
            } else {
                setShowUnsavedDialog(true);
            }

            return;
        }

        await ide.saveActiveFile();

        if (showUnsavedDialog) {
            setShowUnsavedDialog(false);
            closeFile(ide.activeFile.id);
        }

        toast('File saved!');
    }

    const handleFileTreeSelect = async (nodes: any[]) => {
        if (nodes.length > 0 && !nodes[0].data.isDirectory) {
            await loadFile(nodes[0].data.path);

Review comment (suggestion):
Rather early return? 
```
const remainingDirty = ide.openedFiles.filter((f) => f.isDirty);

if (remainingDirty.length !== 0) {
    setShowUnsavedDialog(true);
    return;
}

ide.closeAllFiles();
setPendingCloseAll(false);
setShowUnsavedDialog(false);

Code after:
        if (!isSandboxReady()) {
            handleSandboxNotReady('get file path from OID');
            return null;
        }

        return ide.getFilePathFromOid(oid);
    }

    async function saveFile() {
        if (!ide.activeFile) {
            return;
        }

        if (!isSandboxReady()) {
            handleSandboxNotReady('save file');
            return;
        }

        if (pendingCloseAll) {
            const file = ide.openedFiles.find((f) => f.id === ide.activeFile?.id);
            if (file) {
                await ide.saveActiveFile();
                closeFile(file.id);
            }

            const remainingDirty = ide.openedFiles.filter((f) => f.isDirty);
            if (remainingDirty.length !== 0) {
                setShowUnsavedDialog(true);
                return;
            }

            ide.closeAllFiles();
            setPendingCloseAll(false);
            setShowUnsavedDialog(false);

            return;
        }

        await ide.saveActiveFile();

        if (showUnsavedDialog) {
            setShowUnsavedDialog(false);
            closeFile(ide.activeFile.id);
        }

        toast('File saved!');
    }

    const handleFileTreeSelect = async (nodes: any[]) => {
        if (nodes.length > 0 && !nodes[0].data.isDirectory) {
            await loadFile(nodes[0].data.path);
Repository: onlook-dev/onlook
File: apps/web/client/src/components/store/editor/frames/manager.ts (TypeScript)

Code before:

    get(id: string): FrameData | undefined {
        return this._frameIdToData.get(id);
    }

    registerView(frame: Frame, view: WebFrameView) {
        const isSelected = this.isSelected(frame.id);
        this._frameIdToData.set(frame.id, { frame, view, selected: isSelected });
        const framePathname = new URL(view.src).pathname;
        this._navigation.registerFrame(frame.id, framePathname);
    }

    deregister(frame: Frame) {
        this._frameIdToData.delete(frame.id);
    }

    deregisterAll() {
        this._frameIdToData.clear();
    }

    isSelected(id: string) {
        return this._frameIdToData.get(id)?.selected ?? false;
    }

    select(frames: Frame[], exclusive = true) {
        if (exclusive) {
            this.deselectAll();
        }
        for (const frame of frames) {
            this.updateFrameSelection(frame.id, true);
        }
        this.notify();
    }

    deselect(frame: Frame) {
        this.updateFrameSelection(frame.id, false);
        this.notify();
    }

    deselectAll() {
        for (const [id] of this._frameIdToData) {
            this.updateFrameSelection(id, false);
        }
        this.notify();
    }

    private notify() {
        this._frameIdToData = new Map(this._frameIdToData);
    }

    clear() {

Review comment (suggestion):
Since we're here can we instead of exclusive makes it something like multiselect = false and handle the case where it's already selected to unselect it?

https://github.com/onlook-dev/onlook/blob/main/apps/web/client/src/components/store/editor/element/index.ts#L54

Code after:

    get(id: string): FrameData | undefined {
        return this._frameIdToData.get(id);
    }

    registerView(frame: Frame, view: WebFrameView) {
        const isSelected = this.isSelected(frame.id);
        this._frameIdToData.set(frame.id, { frame, view, selected: isSelected });
        const framePathname = new URL(view.src).pathname;
        this._navigation.registerFrame(frame.id, framePathname);
    }

    deregister(frame: Frame) {
        this._frameIdToData.delete(frame.id);
    }

    deregisterAll() {
        this._frameIdToData.clear();
    }

    isSelected(id: string) {
        return this._frameIdToData.get(id)?.selected ?? false;
    }

    select(frames: Frame[], multiselect = false) {
        if (!multiselect) {
            this.deselectAll();
        }
        for (const frame of frames) {
            this.updateFrameSelection(frame.id, !this.isSelected(frame.id));
        }
        this.notify();
    }

    deselect(frame: Frame) {
        this.updateFrameSelection(frame.id, false);
        this.notify();
    }

    deselectAll() {
        for (const [id] of this._frameIdToData) {
            this.updateFrameSelection(id, false);
        }
        this.notify();
    }

    private notify() {
        this._frameIdToData = new Map(this._frameIdToData);
    }

    clear() {
Repository: ossrs/srs
File: trunk/src/app/srs_app_rtsp.cpp (C++)

Code before:
    local_port_min = _srs_config->get_stream_caster_rtp_port_min(c);
    local_port_max = _srs_config->get_stream_caster_rtp_port_max(c);
}

SrsRtspCaster::~SrsRtspCaster()
{
    std::vector<SrsRtspConn*>::iterator it;
    for (it = clients.begin(); it != clients.end(); ++it) {
        SrsRtspConn* conn = *it;
        srs_freep(conn);
    }
    clients.clear();
    used_ports.clear();
}

srs_error_t SrsRtspCaster::alloc_port(int* pport)
{
    srs_error_t err = srs_success;
    
    // use a pair of port.
    for (int i = local_port_min; i < local_port_max - 1; i += 2) {
        if (!used_ports[i]) {
            used_ports[i] = true;
            used_ports[i + 1] = true;
            *pport = i;
            break;
        }
    }
    srs_info("rtsp: alloc port=%d-%d", *pport, *pport + 1);
    
    return err;
}

void SrsRtspCaster::free_port(int lpmin, int lpmax)
{
    for (int i = lpmin; i < lpmax; i++) {
        used_ports[i] = false;
    }
    srs_trace("rtsp: free rtp port=%d-%d", lpmin, lpmax);
}

srs_error_t SrsRtspCaster::on_tcp_client(srs_netfd_t stfd)
{
    srs_error_t err = srs_success;
    
    SrsRtspConn* conn = new SrsRtspConn(this, stfd, output);
    
    if ((err = conn->serve()) != srs_success) {
        srs_freep(conn);
        return srs_error_wrap(err, "serve conn");
    }

Review comment (suggestion):
This function should return an error, otherwise there may be unknown behavior. It has already been fixed.

`TRANS_BY_GPT3`

Code after:
    // TODO: FIXME: support reload.
    output = _srs_config->get_stream_caster_output(c);
    local_port_min = _srs_config->get_stream_caster_rtp_port_min(c);
    local_port_max = _srs_config->get_stream_caster_rtp_port_max(c);
    manager = new SrsCoroutineManager();
}

SrsRtspCaster::~SrsRtspCaster()
{
    std::vector<SrsRtspConn*>::iterator it;
    for (it = clients.begin(); it != clients.end(); ++it) {
        SrsRtspConn* conn = *it;
        manager->remove(conn);
    }
    clients.clear();
    used_ports.clear();

    srs_freep(manager);
}

srs_error_t SrsRtspCaster::initialize()
{
    srs_error_t err = srs_success;
    if ((err = manager->start()) != srs_success) {
        return srs_error_wrap(err, "start manager");
    }
}

srs_error_t SrsRtspCaster::alloc_port(int* pport)
{
    srs_error_t err = srs_success;
    
    // use a pair of port.
    for (int i = local_port_min; i < local_port_max - 1; i += 2) {
        if (!used_ports[i]) {
            used_ports[i] = true;
            used_ports[i + 1] = true;
            *pport = i;
            break;
        }
    }
    srs_info("rtsp: alloc port=%d-%d", *pport, *pport + 1);
    
    return err;
}

void SrsRtspCaster::free_port(int lpmin, int lpmax)
{
    for (int i = lpmin; i < lpmax; i++) {
        used_ports[i] = false;
    }
Repository: ossrs/srs
File: trunk/src/srt/srt_conn.cpp (C++)

Code before:
bool get_streamid_info(const std::string& streamid, int& mode, std::string& url_subpash) {
    std::vector<std::string> info_vec;
    std::string real_streamid;

    size_t pos = streamid.find("#!::h");
    if (pos != 0) {
        return false;
    }
    real_streamid = streamid.substr(4);

    string_split(real_streamid, ",", info_vec);
    if (info_vec.size() < 2) {
        return false;
    }

    for (size_t index = 0; index < info_vec.size(); index++) {
        std::string key;
        std::string value;

        bool ret = get_key_value(info_vec[index], key, value);
        if (!ret) {
            continue;
        }
        
        if (key == "h") {
            url_subpash = value;//eg. h=live/stream
        } else if (key == "m") {
            std::string mode_str = string_lower(value);//m=publish or m=request
            if (mode_str == "publish") {
                mode = PUSH_SRT_MODE;
            } else if (mode_str == "request") {
                mode = PULL_SRT_MODE;
            } else {
                mode = ERR_SRT_MODE;
                return false;
            }
        } else {//not suport
            continue;
        }
    }

    return true;
}

srt_conn::srt_conn(SRTSOCKET conn_fd, const std::string& streamid):_conn_fd(conn_fd),
    _streamid(streamid) {
    get_streamid_info(streamid, _mode, _url_subpath);
    _update_timestamp = now_ms();
    
    std::vector<std::string> path_vec;
    

Review comment (suggestion):
https://github.com/ossrs/srs/commit/90afd06c85fb76e81f6a9d9931649fffde1713b0

Specify the default app name in the configuration file, which is set to "live" by default.

`TRANS_BY_GPT3`

Code after:

    if (pos == info.npos) {
        return false;
    }

    key = info.substr(0, pos);
    value = info.substr(pos+1);

    if (key.empty() || value.empty()) {
        return false;
    }
    return true;
}

//eg. streamid=#!::h:live/livestream,m:publish
bool get_streamid_info(const std::string& streamid, int& mode, std::string& url_subpath) {
    std::vector<std::string> info_vec;
    std::string real_streamid;

    mode = PUSH_SRT_MODE;

    size_t pos = streamid.find("#!::");
    if (pos != 0) {
        pos = streamid.find("/");
        if (pos == streamid.npos) {
            url_subpath = "live/" + streamid;
            return true;
        }
        url_subpath = streamid;
        return true;
    }
    real_streamid = streamid.substr(4);

    string_split(real_streamid, ",", info_vec);
    if (info_vec.size() < 2) {
        return false;
    }

    for (size_t index = 0; index < info_vec.size(); index++) {
        std::string key;
        std::string value;

        bool ret = get_key_value(info_vec[index], key, value);
        if (!ret) {
            continue;
        }
        
        if (key == "h") {
            url_subpath = value;//eg. h=live/stream
        } else if (key == "m") {
            std::string mode_str = string_lower(value);//m=publish or m=request
Repository: ossrs/srs
File: trunk/src/app/srs_app_config.cpp (C++)

Code before:
{
    static unsigned short DEFAULT = 10080;
    SrsConfDirective* conf = root->get("srt_server");
    if (!conf) {
        return DEFAULT;
    }
    
    conf = conf->get("listen");
    if (!conf || conf->arg0().empty()) {
        return DEFAULT;
    }
    return (unsigned short)atoi(conf->arg0().c_str());
}

bool SrsConfig::get_srt_mix_correct() {
    static bool DEFAULT = true;
    SrsConfDirective* conf = root->get("srt_server");
    if (!conf) {
        return DEFAULT;
    }
    
    conf = conf->get("mix_correct");
    if (!conf || conf->arg0().empty()) {
        return DEFAULT;
    }
    return SRS_CONF_PERFER_FALSE(conf->arg0());
}

int SrsConfig::get_srto_maxbw() {
    static int64_t DEFAULT = -1;
    SrsConfDirective* conf = root->get("srt_server");
    if (!conf) {
        return DEFAULT;
    }
    
    conf = conf->get("maxbw");
    if (!conf || conf->arg0().empty()) {
        return DEFAULT;
    }
    return atoi(conf->arg0().c_str());
}

int SrsConfig::get_srto_mss() {
    static int DEFAULT = 1500;
    SrsConfDirective* conf = root->get("srt_server");
    if (!conf) {
        return DEFAULT;
    }
    
    conf = conf->get("mms");
    if (!conf || conf->arg0().empty()) {

Review comment (suggestion):
Should perfer true, consistent with default.
```suggestion
    return SRS_CONF_PERFER_TRUE(conf->arg0());
```

`TRANS_BY_GPT3`

Code after:
{
    static unsigned short DEFAULT = 10080;
    SrsConfDirective* conf = root->get("srt_server");
    if (!conf) {
        return DEFAULT;
    }
    
    conf = conf->get("listen");
    if (!conf || conf->arg0().empty()) {
        return DEFAULT;
    }
    return (unsigned short)atoi(conf->arg0().c_str());
}

bool SrsConfig::get_srt_mix_correct() {
    static bool DEFAULT = true;
    SrsConfDirective* conf = root->get("srt_server");
    if (!conf) {
        return DEFAULT;
    }
    
    conf = conf->get("mix_correct");
    if (!conf || conf->arg0().empty()) {
        return DEFAULT;
    }
    return SRS_CONF_PERFER_TRUE(conf->arg0());
}

int SrsConfig::get_srto_maxbw() {
    static int64_t DEFAULT = -1;
    SrsConfDirective* conf = root->get("srt_server");
    if (!conf) {
        return DEFAULT;
    }
    
    conf = conf->get("maxbw");
    if (!conf || conf->arg0().empty()) {
        return DEFAULT;
    }
    return atoi(conf->arg0().c_str());
}

int SrsConfig::get_srto_mss() {
    static int DEFAULT = 1500;
    SrsConfDirective* conf = root->get("srt_server");
    if (!conf) {
        return DEFAULT;
    }
    
    conf = conf->get("mms");
    if (!conf || conf->arg0().empty()) {
Repository: ossrs/srs
File: trunk/src/app/srs_app_gb28181.cpp (C++)

Code before:
    return err;
}

SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer(std::string id)
{
    SrsGb28181RtmpMuxer* muxer = NULL;
    
    if (rtmpmuxers.find(id) == rtmpmuxers.end()) {
        return NULL;
    }
    
    muxer = rtmpmuxers[id];
    return muxer;
}

void SrsGb28181Manger::update_rtmpmuxer_to_newssrc_by_id(std::string id, uint32_t ssrc)
{
    SrsGb28181RtmpMuxer* muxer = NULL;

    if (rtmpmuxers.find(id) == rtmpmuxers.end()) {
        srs_warn("gb28181: at update_rtmpmuxer_to_newssrc_by_id() client_id not found. client_id=%s",id.c_str());
        return;
    }

    muxer = rtmpmuxers[id];
    //TODO: find out whether muxer->get_channel().set_ssrc(new_ssrc) is different with the under codes
    SrsGb28181StreamChannel mc = muxer->get_channel();
    uint32_t old_ssrc = mc.get_ssrc();
    if (old_ssrc == ssrc) {
        return;
    } else {
        srs_trace("gb28181: update ssrc of muxer %s from %x to %x", id.c_str(), old_ssrc, ssrc);
    }
    rtmpmuxer_unmap_by_ssrc(old_ssrc);
    mc.set_ssrc(ssrc);
    muxer->copy_channel(&mc);
    rtmpmuxer_map_by_ssrc(muxer, ssrc);
    srs_trace("gb28181: update_rtmpmuxer_to_newssrc_by_id success. client_id=%s, new_ssrc=%#x, old_ssrc=%#x",id.c_str(),ssrc,old_ssrc);
}

SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer_by_ssrc(uint32_t ssrc)
{
    SrsGb28181RtmpMuxer* muxer = NULL;
    if (rtmpmuxers_ssrc.find(ssrc) == rtmpmuxers_ssrc.end()) {
        return NULL;
    }
    
    muxer = rtmpmuxers_ssrc[ssrc];
    return muxer;
}


Review comment (bug):
Delete this comment.
You will understand if you debug it with gdb. Need to consolidate C++ knowledge.

`TRANS_BY_GPT3`

Code after:
    return err;
}

SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer(std::string id)
{
    SrsGb28181RtmpMuxer* muxer = NULL;
    
    if (rtmpmuxers.find(id) == rtmpmuxers.end()) {
        return NULL;
    }
    
    muxer = rtmpmuxers[id];
    return muxer;
}

void SrsGb28181Manger::update_rtmpmuxer_to_newssrc_by_id(std::string id, uint32_t ssrc)
{
    SrsGb28181RtmpMuxer* muxer = NULL;

    if (rtmpmuxers.find(id) == rtmpmuxers.end()) {
        srs_warn("gb28181: at update_rtmpmuxer_to_newssrc_by_id() client_id not found. client_id=%s",id.c_str());
        return;
    }

    muxer = rtmpmuxers[id];
    
    SrsGb28181StreamChannel mc = muxer->get_channel();
    uint32_t old_ssrc = mc.get_ssrc();
    if (old_ssrc == ssrc) {
        return;
    } else {
        srs_trace("gb28181: update ssrc of muxer %s from %x to %x", id.c_str(), old_ssrc, ssrc);
    }
    rtmpmuxer_unmap_by_ssrc(old_ssrc);
    mc.set_ssrc(ssrc);
    muxer->copy_channel(&mc);
    rtmpmuxer_map_by_ssrc(muxer, ssrc);
}

SrsGb28181RtmpMuxer* SrsGb28181Manger::fetch_rtmpmuxer_by_ssrc(uint32_t ssrc)
{
    SrsGb28181RtmpMuxer* muxer = NULL;
    if (rtmpmuxers_ssrc.find(ssrc) == rtmpmuxers_ssrc.end()) {
        return NULL;
    }
    
    muxer = rtmpmuxers_ssrc[ssrc];
    return muxer;
}

void SrsGb28181Manger::rtmpmuxer_map_by_ssrc(SrsGb28181RtmpMuxer*muxer, uint32_t ssrc)
Repository: ossrs/srs
File: trunk/src/kernel/srs_kernel_utility.cpp (C++)

Code before:
{
    return str.find(flag) != string::npos;
}

bool srs_string_contains(string str, string flag0, string flag1)
{
    return str.find(flag0) != string::npos || str.find(flag1) != string::npos;
}

bool srs_string_contains(string str, string flag0, string flag1, string flag2)
{
    return str.find(flag0) != string::npos || str.find(flag1) != string::npos || str.find(flag2) != string::npos;
}

int srs_string_count(string str, string flag)
{
    int nn = 0;
    for (int i = 0; i < (int)flag.length(); i++) {
        char ch = flag.at(i);
        nn += std::count(str.begin(), str.end(), ch);
    }
    return nn;
}


vector<string> srs_string_split(string s, string seperator) {
     vector<string> result;
     unsigned int posBegin = 0;
     size_t posSeperator = s.find(seperator);
 
     while (posSeperator != string::npos) {
         result.push_back(s.substr(posBegin, posSeperator - posBegin));
         posBegin = posSeperator + seperator.size(); // next byte of seperator
         posSeperator = s.find(seperator, posBegin);
     }
     if (posBegin != s.length()) // push the last element
         result.push_back(s.substr(posBegin));
 
     return result;
 }

string srs_string_min_match(string str, vector<string> flags)
{
    string match;
    
    if (flags.empty()) {
        return str;
    }
    
    size_t min_pos = string::npos;
    for (vector<string>::iterator it = flags.begin(); it != flags.end(); ++it) {

Review comment (suggestion):
The new srs_string_split seems to not handle the case where the separator is empty (the original code does handle it).
Note that string::find("") returns 0, not string::npos.

`TRANS_BY_GPT3`

Code after:
{
    return str.find(flag) != string::npos;
}

bool srs_string_contains(string str, string flag0, string flag1)
{
    return str.find(flag0) != string::npos || str.find(flag1) != string::npos;
}

bool srs_string_contains(string str, string flag0, string flag1, string flag2)
{
    return str.find(flag0) != string::npos || str.find(flag1) != string::npos || str.find(flag2) != string::npos;
}

int srs_string_count(string str, string flag)
{
    int nn = 0;
    for (int i = 0; i < (int)flag.length(); i++) {
        char ch = flag.at(i);
        nn += std::count(str.begin(), str.end(), ch);
    }
    return nn;
}


vector<string> srs_string_split(string s, string seperator) {
    vector<string> result;
    if(seperator.empty()){
        result.push_back(s);
        return result;
    }
    
    size_t posBegin = 0;
    size_t posSeperator = s.find(seperator);
    while (posSeperator != string::npos) {
        result.push_back(s.substr(posBegin, posSeperator - posBegin));
        posBegin = posSeperator + seperator.length(); // next byte of seperator
        posSeperator = s.find(seperator, posBegin);
    }
    // push the last element
    result.push_back(s.substr(posBegin));
    return result;
}

string srs_string_min_match(string str, vector<string> flags)
{
    string match;
    
    if (flags.empty()) {
        return str;
    }
Repository: ossrs/srs
File: trunk/src/app/srs_app_rtc_conn.cpp (C++)

Code before:
    // @remark Allow start multiple times, for DTLS may retransmit the final packet.
    if (is_started) {
        return err;
    }

    srs_freep(trd_);
    trd_ = new SrsFastCoroutine("rtc_sender", this, cid_);

    if ((err = trd_->start()) != srs_success) {
        return srs_error_wrap(err, "rtc_sender");
    }

    if ((err = pli_worker_->start()) != srs_success) {
        return srs_error_wrap(err, "start pli worker");
    }

    if (_srs_rtc_hijacker) {
        if ((err = _srs_rtc_hijacker->on_start_play(session_, this, req_)) != srs_success) {
            return srs_error_wrap(err, "on start play");
        }
    }
	
    // update the statistic when client discoveried.
    SrsStatistic* stat = SrsStatistic::instance();
    if ((err = stat->on_client(cid_.c_str(), req_, session_, SrsRtcConnPlay)) != srs_success) {
        srs_trace("webrtc: add client failed!");
    }

    is_started = true;

    return err;
}

void SrsRtcPlayStream::stop()
{
    if (trd_) {
        trd_->stop();
    }
}

srs_error_t SrsRtcPlayStream::cycle()
{
    srs_error_t err = srs_success;

    SrsRtcSource* source = source_;

    SrsRtcConsumer* consumer = NULL;
    SrsAutoFree(SrsRtcConsumer, consumer);
    if ((err = source->create_consumer(consumer)) != srs_success) {
        return srs_error_wrap(err, "create consumer, source=%s", req_->get_stream_url().c_str());
    }

Review comment (performance):
1. Can this err be ignored?
2. Even if it is ignored, srs_freep(err) should still be done to avoid memory leaks.

`TRANS_BY_GPT3`

Code after:
    // @remark Allow start multiple times, for DTLS may retransmit the final packet.
    if (is_started) {
        return err;
    }

    srs_freep(trd_);
    trd_ = new SrsFastCoroutine("rtc_sender", this, cid_);

    if ((err = trd_->start()) != srs_success) {
        return srs_error_wrap(err, "rtc_sender");
    }

    if ((err = pli_worker_->start()) != srs_success) {
        return srs_error_wrap(err, "start pli worker");
    }

    if (_srs_rtc_hijacker) {
        if ((err = _srs_rtc_hijacker->on_start_play(session_, this, req_)) != srs_success) {
            return srs_error_wrap(err, "on start play");
        }
    }
	
    // update the statistic when client discoveried.
    SrsStatistic* stat = SrsStatistic::instance();
    if ((err = stat->on_client(cid_.c_str(), req_, session_, SrsRtcConnPlay)) != srs_success) {
	return srs_error_wrap(err, "rtc: stat client");
    }

    is_started = true;

    return err;
}

void SrsRtcPlayStream::stop()
{
    if (trd_) {
        trd_->stop();
    }
}

srs_error_t SrsRtcPlayStream::cycle()
{
    srs_error_t err = srs_success;

    SrsRtcSource* source = source_;

    SrsRtcConsumer* consumer = NULL;
    SrsAutoFree(SrsRtcConsumer, consumer);
    if ((err = source->create_consumer(consumer)) != srs_success) {
        return srs_error_wrap(err, "create consumer, source=%s", req_->get_stream_url().c_str());
    }