From d96524968d47fa2399168a35a459074436025228 Mon Sep 17 00:00:00 2001 From: Thulinma Date: Thu, 9 Mar 2023 16:00:38 +0100 Subject: [PATCH] Send boot-up progress percentages to status websocket for HLS input --- lib/stream.cpp | 10 +++++++++- lib/stream.h | 1 + src/input/input.cpp | 14 ++++++-------- src/input/input_hls.cpp | 18 ++++++++++++++++-- src/output/output_http_internal.cpp | 16 +++++++++++----- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/lib/stream.cpp b/lib/stream.cpp index 77eaa724..a811cd84 100644 --- a/lib/stream.cpp +++ b/lib/stream.cpp @@ -850,11 +850,19 @@ pid_t Util::startPush(const std::string &streamname, std::string &target, int de uint8_t Util::getStreamStatus(const std::string &streamname){ char pageName[NAME_BUFFER_SIZE]; snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamname.c_str()); - IPC::sharedPage streamStatus(pageName, 1, false, false); + IPC::sharedPage streamStatus(pageName, 2, false, false); if (!streamStatus){return STRMSTAT_OFF;} return streamStatus.mapped[0]; } +uint8_t Util::getStreamStatusPercentage(const std::string &streamname){ + char pageName[NAME_BUFFER_SIZE]; + snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamname.c_str()); + IPC::sharedPage streamStatus(pageName, 2, false, false); + if (!streamStatus || streamStatus.len < 2){return 0;} + return streamStatus.mapped[1]; +} + /// Checks if a given user agent is allowed according to the given exception. bool Util::checkException(const JSON::Value &ex, const std::string &useragent){ // No user agent? Always allow everything. diff --git a/lib/stream.h b/lib/stream.h index 4e07c3e7..509c023c 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -27,6 +27,7 @@ namespace Util{ JSON::Value getGlobalConfig(const std::string &optionName); JSON::Value getInputBySource(const std::string &filename, bool isProvider = false); uint8_t getStreamStatus(const std::string &streamname); + uint8_t getStreamStatusPercentage(const std::string &streamname); bool checkException(const JSON::Value &ex, const std::string &useragent); std::string codecString(const std::string &codec, const std::string &initData = ""); diff --git a/src/input/input.cpp b/src/input/input.cpp index b5186158..9c14fc27 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -56,7 +56,6 @@ namespace Mist{ } uint32_t pageNumber = tPages.getInt("firstkey", pageIdx); if (i == key){ - INFO_MSG("Track %zu key %zu is on page %" PRIu32, track, key, pageNumber); keyLoadPriority[trackKey(track, pageNumber)] += 10000; }else{ keyLoadPriority[trackKey(track, pageNumber)] += 1000 - (key - i); @@ -69,7 +68,6 @@ namespace Mist{ } void Input::userOnDisconnect(size_t id){} void Input::userLeadOut(){ - INFO_MSG("Wanna load %zu keys", keyLoadPriority.size()); if (!keyLoadPriority.size()){return;} //Make reverse mapping std::multimap reverse; @@ -412,7 +410,7 @@ namespace Mist{ //Set stream status to STRMSTAT_INIT, then close the page in non-master mode to keep it around char pageName[NAME_BUFFER_SIZE]; snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamName.c_str()); - streamStatus.init(pageName, 1, true, false); + streamStatus.init(pageName, 2, true, false); if (streamStatus){streamStatus.mapped[0] = STRMSTAT_INIT;} streamStatus.master = false; streamStatus.close(); @@ -459,7 +457,7 @@ namespace Mist{ // Re-init streamStatus, previously closed char pageName[NAME_BUFFER_SIZE]; snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamName.c_str()); - streamStatus.init(pageName, 1, true, false); + streamStatus.init(pageName, 2, true, false); streamStatus.master = false; if (streamStatus){streamStatus.mapped[0] = STRMSTAT_INIT;} } @@ -469,7 +467,7 @@ namespace Mist{ playerLock.unlink(); char pageName[NAME_BUFFER_SIZE]; snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamName.c_str()); - streamStatus.init(pageName, 1, true, false); + streamStatus.init(pageName, 2, true, false); streamStatus.close(); } playerLock.unlink(); @@ -490,7 +488,7 @@ namespace Mist{ // Re-init streamStatus, previously closed char pageName[NAME_BUFFER_SIZE]; snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamName.c_str()); - streamStatus.init(pageName, 1, true, false); + streamStatus.init(pageName, 2, true, false); streamStatus.master = false; if (streamStatus){streamStatus.mapped[0] = STRMSTAT_INIT;} } @@ -528,7 +526,7 @@ namespace Mist{ if (playerLock){ char pageName[NAME_BUFFER_SIZE]; snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamName.c_str()); - streamStatus.init(pageName, 1, true, false); + streamStatus.init(pageName, 2, true, false); if (streamStatus){streamStatus.mapped[0] = STRMSTAT_INVALID;} } #if DEBUG >= DLVL_DEVEL @@ -559,7 +557,7 @@ namespace Mist{ pidPage.close(); //Clear stream state snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamName.c_str()); - streamStatus.init(pageName, 1, true, false); + streamStatus.init(pageName, 2, true, false); streamStatus.close(); //Delete lock playerLock.unlink(); diff --git a/src/input/input_hls.cpp b/src/input/input_hls.cpp index 6873a2a9..645b712f 100644 --- a/src/input/input_hls.cpp +++ b/src/input/input_hls.cpp @@ -825,13 +825,21 @@ namespace Mist{ meta.reInit(isSingular() ? streamName : ""); tthread::lock_guard guard(entryMutex); + + size_t totalSegments = 0, currentSegment = 0; for (std::map >::iterator pListIt = listEntries.begin(); pListIt != listEntries.end(); pListIt++){ + totalSegments += pListIt->second.size(); + } + + for (std::map >::iterator pListIt = listEntries.begin(); + pListIt != listEntries.end() && config->is_active; pListIt++){ tsStream.clear(); uint32_t entId = 0; for (std::deque::iterator entryIt = pListIt->second.begin(); - entryIt != pListIt->second.end(); entryIt++){ + entryIt != pListIt->second.end() && config->is_active; entryIt++){ + ++currentSegment; tsStream.partialClear(); if (!segDowner.loadSegment(*entryIt)){ @@ -840,7 +848,7 @@ namespace Mist{ } entId++; allowRemap = true; - while (!segDowner.atEnd()){ + while (!segDowner.atEnd() && config->is_active){ // Wait for packets on each track to make sure the offset is set based on the earliest packet hasPacket = tsStream.hasPacketOnEachTrack() || (segDowner.atEnd() && tsStream.hasPacket()); if (hasPacket){ @@ -902,8 +910,14 @@ namespace Mist{ std::deque &curList = listEntries[pListIt->first]; curList.at(entId-1).timeOffset = 0; } + + //Set progress counter + if (streamStatus && streamStatus.len > 1){ + streamStatus.mapped[1] = (255 * currentSegment) / totalSegments; + } } } + if (!config->is_active){return false;} // set bootMsOffset in order to display the program time correctly in the player if (meta.getLive()){meta.setUTCOffset(streamOffset + (Util::unixMS() - Util::bootMS()));} diff --git a/src/output/output_http_internal.cpp b/src/output/output_http_internal.cpp index ff1225cc..3c2f0b47 100644 --- a/src/output/output_http_internal.cpp +++ b/src/output/output_http_internal.cpp @@ -437,6 +437,7 @@ namespace Mist{ json_resp["redirected"].append(streamName); } uint8_t streamStatus = Util::getStreamStatus(streamName); + uint8_t streamStatusPerc = Util::getStreamStatusPercentage(streamName); if (streamStatus != STRMSTAT_READY){ // If we haven't rewritten the stream name yet to a fallback, attempt to do so if (origStreamName == streamName){ @@ -488,6 +489,7 @@ namespace Mist{ case STRMSTAT_INVALID: json_resp["error"] = "Stream status is invalid?!"; break; default: json_resp["error"] = "Stream status is unknown?!"; break; } + if (streamStatusPerc){json_resp["perc"] = ((double)streamStatusPerc)/2.55;} return json_resp; } initialize(); @@ -806,7 +808,6 @@ namespace Mist{ if (!useragent.size()){useragent = req.GetHeader("User-Agent");} std::string response; std::string rURL = req.url; - if (headersOnly){initialize();} if (rURL.substr(0, 6) != "/json_"){ H.SetHeader("Content-Type", "application/javascript"); }else{ @@ -1125,26 +1126,30 @@ namespace Mist{ if (!ws){return false;} setBlocking(false); // start the stream, if needed - Util::startInput(streamName, "", true, false); + Util::sanitizeName(streamName); + if (!Util::streamAlive(streamName)){Util::startInput(streamName, "", true, false);} char pageName[NAME_BUFFER_SIZE]; std::string currStreamName; currStreamName = streamName; snprintf(pageName, NAME_BUFFER_SIZE, SHM_STREAM_STATE, streamName.c_str()); - IPC::sharedPage streamStatus(pageName, 1, false, false); + IPC::sharedPage streamStatus(pageName, 2, false, false); uint8_t prevState, newState, pingCounter = 0; + uint8_t prevStatePerc = 0, newStatePerc = 0; std::set prevTracks; prevState = newState = STRMSTAT_INVALID; while (keepGoing()){ - if (!streamStatus || !streamStatus.exists()){streamStatus.init(pageName, 1, false, false);} + if (!streamStatus || !streamStatus.exists()){streamStatus.init(pageName, 2, false, false);} if (!streamStatus){ newState = STRMSTAT_OFF; + newStatePerc = 0; }else{ newState = streamStatus.mapped[0]; + if (streamStatus.len > 1){newStatePerc = streamStatus.mapped[1];} } if (meta){meta.reloadReplacedPagesIfNeeded();} - if (newState != prevState || (newState == STRMSTAT_READY && M.getValidTracks() != prevTracks)){ + if (newState != prevState || (newState == STRMSTAT_READY && M.getValidTracks() != prevTracks) || (newState != STRMSTAT_READY && newStatePerc != prevStatePerc)){ if (newState == STRMSTAT_READY){ thisError = ""; reconnect(); @@ -1170,6 +1175,7 @@ namespace Mist{ } ws.sendFrame(resp.toString()); prevState = newState; + prevStatePerc = newStatePerc; }else{ if (newState == STRMSTAT_READY){stats();} if (myConn.spool() && ws.readFrame()){