From 91a6225d8508db01574d7da2c013cb30d6a87ec8 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Fri, 26 Feb 2021 10:24:09 +0200 Subject: DocumentWidget: Inline downloads --- src/media.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 4 deletions(-) (limited to 'src/media.c') diff --git a/src/media.c b/src/media.c index 65454756..000214b2 100644 --- a/src/media.c +++ b/src/media.c @@ -27,10 +27,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "audio/player.h" #include "app.h" +#include #include #include #include #include +#include iDeclareType(GmMediaProps) @@ -132,15 +134,63 @@ iDeclareType(GmDownload) struct Impl_GmDownload { iGmMediaProps props; - /* TODO: Speed statistics. */ + uint64_t numBytes; + iTime startTime; + uint32_t rateStartTime; + size_t rateNumBytes; + float currentRate; + iString * path; + iFile * file; }; +static iBool openFile_GmDownload_(iGmDownload *d) { + iAssert(!isEmpty_String(&d->props.url)); + d->path = copy_String(downloadPathForUrl_App(&d->props.url, &d->props.mime)); + d->file = new_File(d->path); + if (!open_File(d->file, writeOnly_FileMode)) { + return iFalse; + } + return iTrue; +} + +static void closeFile_GmDownload_(iGmDownload *d) { + d->currentRate = (float) (d->numBytes / elapsedSeconds_Time(&d->startTime)); + iReleasePtr(&d->file); +} + void init_GmDownload(iGmDownload *d) { init_GmMediaProps_(&d->props); + initCurrent_Time(&d->startTime); + d->numBytes = 0; + d->rateStartTime = SDL_GetTicks(); + d->rateNumBytes = 0; + d->currentRate = 0.0f; + d->path = NULL; + d->file = NULL; } void deinit_GmDownload(iGmDownload *d) { + closeFile_GmDownload_(d); deinit_GmMediaProps_(&d->props); + delete_String(d->path); +} + +static void writeToFile_GmDownload_(iGmDownload *d, const iBlock *data) { + const static unsigned rateInterval_ = 1000; + iAssert(d->file); + writeData_File(d->file, + constBegin_Block(data) + d->numBytes, + size_Block(data) - d->numBytes); + const size_t newBytes = size_Block(data) - d->numBytes; + d->numBytes = size_Block(data); + d->rateNumBytes += newBytes; + const uint32_t now = SDL_GetTicks(); + if (now - d->rateStartTime > rateInterval_) { + const double elapsed = (double) (now - d->rateStartTime) / 1000.0; + d->rateStartTime = now; + d->currentRate = (float) (d->rateNumBytes / elapsed); + d->rateNumBytes = 0; + } } iDefineTypeConstruction(GmDownload) @@ -183,7 +233,7 @@ void clear_Media(iMedia *d) { clear_PtrArray(&d->downloads); } -iBool setUrl_Media(iMedia *d, iGmLinkId linkId, const iString *url) { +iBool setDownloadUrl_Media(iMedia *d, iGmLinkId linkId, const iString *url) { iGmDownload *dl = NULL; iMediaId existing = findLinkDownload_Media(d, linkId); iBool isNew = iFalse; @@ -251,8 +301,16 @@ iBool setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlo } else { dl = at_PtrArray(&d->downloads, existing - 1); - iAssert(equal_String(&dl->props.mime, mime)); /* MIME cannot change */ - /* TODO: Write data chunk to file. */ + if (isEmpty_String(&dl->props.mime)) { + set_String(&dl->props.mime, mime); + } + if (!dl->file) { + openFile_GmDownload_(dl); + } + writeToFile_GmDownload_(dl, data); + if (!isPartial) { + closeFile_GmDownload_(dl); + } } } else if (!isDeleting) { @@ -378,6 +436,33 @@ iPlayer *audioPlayer_Media(const iMedia *d, iMediaId audioId) { return NULL; } +iBool downloadInfo_Media(const iMedia *d, iMediaId downloadId, iGmMediaInfo *info_out) { + if (downloadId > 0 && downloadId <= size_PtrArray(&d->downloads)) { + const iGmDownload *dl = constAt_PtrArray(&d->downloads, downloadId - 1); + info_out->type = cstr_String(&dl->props.mime); + info_out->isPermanent = dl->props.isPermanent; + info_out->numBytes = dl->numBytes; + return iTrue; + } + iZap(*info_out); + return iFalse; +} + +void downloadStats_Media(const iMedia *d, iMediaId downloadId, const iString **path_out, + float *bytesPerSecond_out, iBool *isFinished_out) { + *path_out = NULL; + *bytesPerSecond_out = 0.0f; + *isFinished_out = iFalse; + if (downloadId > 0 && downloadId <= size_PtrArray(&d->downloads)) { + const iGmDownload *dl = constAt_PtrArray(&d->downloads, downloadId - 1); + if (dl->path) { + *path_out = dl->path; + } + *bytesPerSecond_out = dl->currentRate; + *isFinished_out = (dl->path && !dl->file); + } +} + /*----------------------------------------------------------------------------------------------*/ static void updated_MediaRequest_(iAnyObject *obj) { -- cgit v1.2.3