Repository: ossrs/srs
File: trunk/src/app/srs_app_hls.cpp (C++)

Code before:
    
    // create m3u8 dir once.
    m3u8_dir = srs_path_dirname(m3u8);
    if ((err = srs_create_dir_recursively(m3u8_dir)) != srs_success) {
        return srs_error_wrap(err, "create dir");
    }

    if (hls_keys && (hls_path != hls_key_file_path)) {
        string key_file = srs_path_build_stream(hls_key_file, req->vhost, req->app, req->stream);
        string key_url = hls_key_file_path + "/" + key_file;
        string key_dir = srs_path_dirname(key_url);
        if ((err = srs_create_dir_recursively(key_dir)) != srs_success) {
            return srs_error_wrap(err, "create dir");
        }
    }

    if(hls_keys) {
        writer = new SrsEncFileWriter();
    } else {
        writer = new SrsFileWriter();
    }

    return err;
}

srs_error_t SrsHlsMuxer::restore_stream()
{
    srs_error_t err = srs_success;

    // exist the m3u8 file.
    if (!srs_path_exists(m3u8)) {
        return err;
    }

    srs_trace("hls: restore stream m3u8=%s, m3u8_url=%s, hls_path=%s",
            m3u8.c_str(), m3u8_url.c_str(), hls_path.c_str());

    // read m3u8
    SrsFileReader fr;
    if ((err = fr.open(m3u8)) != srs_success) {
        return srs_error_wrap(err, "open file");
    }

    int nb_fbuf = fr.filesize();
    char* fbuf = new char[nb_fbuf];
    SrsAutoFreeA(char, fbuf);
    if ((err = fr.read(fbuf, nb_fbuf, NULL)) != srs_success) {
        return srs_error_wrap(err, "read data");
    }

    // parse

Review comment (refactor):
The logic of this exception recovery, because it is a very commonly used path, must be verified and ensured for correctness through utest, otherwise it is very easy to make mistakes.

From the perspective of utest, it would be best to split this function into two functions, making it easier to mock `fr`, that is, to read the m3u8 content from memory instead of from the actual file. It's somewhat like this:

```cpp
srs_error_t SrsHlsMuxer::restore_stream() {
    SrsFileReader fr;
    if ((err = fr.open(m3u8)) != srs_success) {
        return srs_error_wrap(err, "open file");
    }

    return do_restore_stream(&fr);
```

In this way, a mock can be used in utest to avoid reading the actual file.

```cpp
VOID TEST() {
    MOCKFileReader fr;
    SrsHlsMuxer muxer;
    muxer.do_restore_stream(&fr);
````

The above is just an example, you can refer to the Config section, which also requires mocking file reading.


`TRANS_BY_GPT4`

Code after:
}

SrsHlsFmp4Muxer::SrsHlsFmp4Muxer()
{
    req_ = NULL;
    hls_fragment_ = hls_window_ = 0;
    hls_aof_ratio_ = 1.0;
    deviation_ts_ = 0;
    hls_cleanup_ = true;
    hls_wait_keyframe_ = true;
    previous_floor_ts_ = 0;
    accept_floor_ts_ = 0;
    hls_ts_floor_ = false;
    max_td_ = 0;
    writer_ = NULL;
    sequence_no_ = 0;
    current_ = NULL;
    hls_keys_ = false;
    hls_fragments_per_key_ = 0;
    async_ = new SrsAsyncCallWorker();
    segments_ = new SrsFragmentWindow();
    latest_acodec_ = SrsAudioCodecIdForbidden;
    latest_vcodec_ = SrsVideoCodecIdForbidden;
    video_track_id_ = 0;
    audio_track_id_ = 0;
    init_mp4_ready_ = false;
    video_dts_ = 0;

    memset(key_, 0, 16);
    memset(iv_, 0, 16);
}

SrsHlsFmp4Muxer::~SrsHlsFmp4Muxer()
{
    srs_freep(segments_);
    srs_freep(current_);
    srs_freep(req_);
    srs_freep(async_);
    srs_freep(writer_);
}

void SrsHlsFmp4Muxer::dispose()
{
    srs_error_t err = srs_success;

    segments_->dispose();

    if (current_) {
        if ((err = current_->unlink_tmpfile()) != srs_success) {
            srs_warn("Unlink tmp ts failed %s", srs_error_desc(err).c_str());
            srs_freep(err);