diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-02-26 10:24:09 +0200 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-02-26 10:24:09 +0200 |
commit | 91a6225d8508db01574d7da2c013cb30d6a87ec8 (patch) | |
tree | e3bd2c2f24a22c694c1c23aefd5fc531ae108723 /src/media.c | |
parent | 4708a6580e9af65cd15769e87487fdf4456f1e00 (diff) |
DocumentWidget: Inline downloads
Diffstat (limited to 'src/media.c')
-rw-r--r-- | src/media.c | 93 |
1 files changed, 89 insertions, 4 deletions
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. */ | |||
27 | #include "audio/player.h" | 27 | #include "audio/player.h" |
28 | #include "app.h" | 28 | #include "app.h" |
29 | 29 | ||
30 | #include <the_Foundation/file.h> | ||
30 | #include <the_Foundation/ptrarray.h> | 31 | #include <the_Foundation/ptrarray.h> |
31 | #include <stb_image.h> | 32 | #include <stb_image.h> |
32 | #include <SDL_hints.h> | 33 | #include <SDL_hints.h> |
33 | #include <SDL_render.h> | 34 | #include <SDL_render.h> |
35 | #include <SDL_timer.h> | ||
34 | 36 | ||
35 | iDeclareType(GmMediaProps) | 37 | iDeclareType(GmMediaProps) |
36 | 38 | ||
@@ -132,15 +134,63 @@ iDeclareType(GmDownload) | |||
132 | 134 | ||
133 | struct Impl_GmDownload { | 135 | struct Impl_GmDownload { |
134 | iGmMediaProps props; | 136 | iGmMediaProps props; |
135 | /* TODO: Speed statistics. */ | 137 | uint64_t numBytes; |
138 | iTime startTime; | ||
139 | uint32_t rateStartTime; | ||
140 | size_t rateNumBytes; | ||
141 | float currentRate; | ||
142 | iString * path; | ||
143 | iFile * file; | ||
136 | }; | 144 | }; |
137 | 145 | ||
146 | static iBool openFile_GmDownload_(iGmDownload *d) { | ||
147 | iAssert(!isEmpty_String(&d->props.url)); | ||
148 | d->path = copy_String(downloadPathForUrl_App(&d->props.url, &d->props.mime)); | ||
149 | d->file = new_File(d->path); | ||
150 | if (!open_File(d->file, writeOnly_FileMode)) { | ||
151 | return iFalse; | ||
152 | } | ||
153 | return iTrue; | ||
154 | } | ||
155 | |||
156 | static void closeFile_GmDownload_(iGmDownload *d) { | ||
157 | d->currentRate = (float) (d->numBytes / elapsedSeconds_Time(&d->startTime)); | ||
158 | iReleasePtr(&d->file); | ||
159 | } | ||
160 | |||
138 | void init_GmDownload(iGmDownload *d) { | 161 | void init_GmDownload(iGmDownload *d) { |
139 | init_GmMediaProps_(&d->props); | 162 | init_GmMediaProps_(&d->props); |
163 | initCurrent_Time(&d->startTime); | ||
164 | d->numBytes = 0; | ||
165 | d->rateStartTime = SDL_GetTicks(); | ||
166 | d->rateNumBytes = 0; | ||
167 | d->currentRate = 0.0f; | ||
168 | d->path = NULL; | ||
169 | d->file = NULL; | ||
140 | } | 170 | } |
141 | 171 | ||
142 | void deinit_GmDownload(iGmDownload *d) { | 172 | void deinit_GmDownload(iGmDownload *d) { |
173 | closeFile_GmDownload_(d); | ||
143 | deinit_GmMediaProps_(&d->props); | 174 | deinit_GmMediaProps_(&d->props); |
175 | delete_String(d->path); | ||
176 | } | ||
177 | |||
178 | static void writeToFile_GmDownload_(iGmDownload *d, const iBlock *data) { | ||
179 | const static unsigned rateInterval_ = 1000; | ||
180 | iAssert(d->file); | ||
181 | writeData_File(d->file, | ||
182 | constBegin_Block(data) + d->numBytes, | ||
183 | size_Block(data) - d->numBytes); | ||
184 | const size_t newBytes = size_Block(data) - d->numBytes; | ||
185 | d->numBytes = size_Block(data); | ||
186 | d->rateNumBytes += newBytes; | ||
187 | const uint32_t now = SDL_GetTicks(); | ||
188 | if (now - d->rateStartTime > rateInterval_) { | ||
189 | const double elapsed = (double) (now - d->rateStartTime) / 1000.0; | ||
190 | d->rateStartTime = now; | ||
191 | d->currentRate = (float) (d->rateNumBytes / elapsed); | ||
192 | d->rateNumBytes = 0; | ||
193 | } | ||
144 | } | 194 | } |
145 | 195 | ||
146 | iDefineTypeConstruction(GmDownload) | 196 | iDefineTypeConstruction(GmDownload) |
@@ -183,7 +233,7 @@ void clear_Media(iMedia *d) { | |||
183 | clear_PtrArray(&d->downloads); | 233 | clear_PtrArray(&d->downloads); |
184 | } | 234 | } |
185 | 235 | ||
186 | iBool setUrl_Media(iMedia *d, iGmLinkId linkId, const iString *url) { | 236 | iBool setDownloadUrl_Media(iMedia *d, iGmLinkId linkId, const iString *url) { |
187 | iGmDownload *dl = NULL; | 237 | iGmDownload *dl = NULL; |
188 | iMediaId existing = findLinkDownload_Media(d, linkId); | 238 | iMediaId existing = findLinkDownload_Media(d, linkId); |
189 | iBool isNew = iFalse; | 239 | iBool isNew = iFalse; |
@@ -251,8 +301,16 @@ iBool setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlo | |||
251 | } | 301 | } |
252 | else { | 302 | else { |
253 | dl = at_PtrArray(&d->downloads, existing - 1); | 303 | dl = at_PtrArray(&d->downloads, existing - 1); |
254 | iAssert(equal_String(&dl->props.mime, mime)); /* MIME cannot change */ | 304 | if (isEmpty_String(&dl->props.mime)) { |
255 | /* TODO: Write data chunk to file. */ | 305 | set_String(&dl->props.mime, mime); |
306 | } | ||
307 | if (!dl->file) { | ||
308 | openFile_GmDownload_(dl); | ||
309 | } | ||
310 | writeToFile_GmDownload_(dl, data); | ||
311 | if (!isPartial) { | ||
312 | closeFile_GmDownload_(dl); | ||
313 | } | ||
256 | } | 314 | } |
257 | } | 315 | } |
258 | else if (!isDeleting) { | 316 | else if (!isDeleting) { |
@@ -378,6 +436,33 @@ iPlayer *audioPlayer_Media(const iMedia *d, iMediaId audioId) { | |||
378 | return NULL; | 436 | return NULL; |
379 | } | 437 | } |
380 | 438 | ||
439 | iBool downloadInfo_Media(const iMedia *d, iMediaId downloadId, iGmMediaInfo *info_out) { | ||
440 | if (downloadId > 0 && downloadId <= size_PtrArray(&d->downloads)) { | ||
441 | const iGmDownload *dl = constAt_PtrArray(&d->downloads, downloadId - 1); | ||
442 | info_out->type = cstr_String(&dl->props.mime); | ||
443 | info_out->isPermanent = dl->props.isPermanent; | ||
444 | info_out->numBytes = dl->numBytes; | ||
445 | return iTrue; | ||
446 | } | ||
447 | iZap(*info_out); | ||
448 | return iFalse; | ||
449 | } | ||
450 | |||
451 | void downloadStats_Media(const iMedia *d, iMediaId downloadId, const iString **path_out, | ||
452 | float *bytesPerSecond_out, iBool *isFinished_out) { | ||
453 | *path_out = NULL; | ||
454 | *bytesPerSecond_out = 0.0f; | ||
455 | *isFinished_out = iFalse; | ||
456 | if (downloadId > 0 && downloadId <= size_PtrArray(&d->downloads)) { | ||
457 | const iGmDownload *dl = constAt_PtrArray(&d->downloads, downloadId - 1); | ||
458 | if (dl->path) { | ||
459 | *path_out = dl->path; | ||
460 | } | ||
461 | *bytesPerSecond_out = dl->currentRate; | ||
462 | *isFinished_out = (dl->path && !dl->file); | ||
463 | } | ||
464 | } | ||
465 | |||
381 | /*----------------------------------------------------------------------------------------------*/ | 466 | /*----------------------------------------------------------------------------------------------*/ |
382 | 467 | ||
383 | static void updated_MediaRequest_(iAnyObject *obj) { | 468 | static void updated_MediaRequest_(iAnyObject *obj) { |