diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-10-06 13:27:31 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-10-06 13:27:31 +0300 |
commit | 403d8fc06fda157b134f96328f98b9305509b5a3 (patch) | |
tree | a7ac4dc92dfcaa9fafddb65377a1d8a8cf61cccd /src | |
parent | 3ed9a627712bf6223e521e1f63a113404fea824a (diff) |
Updating media content
Making it possible for media to be partially updated, for streaming. Also fixed a problem with multiple concurrent audio players started on a single media item.
Diffstat (limited to 'src')
-rw-r--r-- | src/audio/player.c | 10 | ||||
-rw-r--r-- | src/media.c | 41 | ||||
-rw-r--r-- | src/media.h | 7 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 8 |
4 files changed, 49 insertions, 17 deletions
diff --git a/src/audio/player.c b/src/audio/player.c index f1d6a2c8..177613bb 100644 --- a/src/audio/player.c +++ b/src/audio/player.c | |||
@@ -477,10 +477,16 @@ void updateSourceData_Player(iPlayer *d, const iBlock *data, enum iPlayerUpdate | |||
477 | set_Block(&input->data, data); | 477 | set_Block(&input->data, data); |
478 | input->isComplete = iFalse; | 478 | input->isComplete = iFalse; |
479 | break; | 479 | break; |
480 | case append_PlayerUpdate: | 480 | case append_PlayerUpdate: { |
481 | append_Block(&input->data, data); | 481 | const size_t oldSize = size_Block(&input->data); |
482 | const size_t newSize = size_Block(data); | ||
483 | iAssert(newSize >= oldSize); | ||
484 | /* The old parts cannot have changed. */ | ||
485 | iAssert(memcmp(constData_Block(&input->data), constData_Block(data), oldSize) == 0); | ||
486 | appendData_Block(&input->data, constBegin_Block(data) + oldSize, newSize - oldSize); | ||
482 | input->isComplete = iFalse; | 487 | input->isComplete = iFalse; |
483 | break; | 488 | break; |
489 | } | ||
484 | case complete_PlayerUpdate: | 490 | case complete_PlayerUpdate: |
485 | input->isComplete = iTrue; | 491 | input->isComplete = iTrue; |
486 | break; | 492 | break; |
diff --git a/src/media.c b/src/media.c index ad0682b1..b72ec32c 100644 --- a/src/media.c +++ b/src/media.c | |||
@@ -140,21 +140,41 @@ void clear_Media(iMedia *d) { | |||
140 | } | 140 | } |
141 | 141 | ||
142 | void setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlock *data, | 142 | void setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlock *data, |
143 | iBool allowHide) { | 143 | int flags) { |
144 | if (!mime || !data) { | 144 | const iBool isPartial = (flags & partialData_MediaFlag) != 0; |
145 | iMediaId existing = findLinkImage_Media(d, linkId); | 145 | const iBool allowHide = (flags & allowHide_MediaFlag) != 0; |
146 | if (existing) { | 146 | const iBool isDeleting = (!mime || !data); |
147 | iMediaId existing = findLinkImage_Media(d, linkId); | ||
148 | if (existing) { | ||
149 | if (isDeleting) { | ||
147 | iGmImage *img; | 150 | iGmImage *img; |
148 | take_PtrArray(&d->images, existing - 1, (void **) &img); | 151 | take_PtrArray(&d->images, existing - 1, (void **) &img); |
149 | delete_GmImage(img); | 152 | delete_GmImage(img); |
150 | } | 153 | } |
151 | else if ((existing = findLinkAudio_Media(d, linkId)) != 0) { | 154 | else { |
152 | iGmAudio *audio; | 155 | iAssert(isDeleting); /* images cannot be modified once set */ |
156 | } | ||
157 | } | ||
158 | else if ((existing = findLinkAudio_Media(d, linkId)) != 0) { | ||
159 | iGmAudio *audio; | ||
160 | if (isDeleting) { | ||
153 | take_PtrArray(&d->audio, existing - 1, (void **) &audio); | 161 | take_PtrArray(&d->audio, existing - 1, (void **) &audio); |
154 | delete_GmAudio(audio); | 162 | delete_GmAudio(audio); |
155 | } | 163 | } |
164 | else { | ||
165 | audio = at_PtrArray(&d->audio, existing - 1); | ||
166 | iAssert(equal_String(&audio->props.mime, mime)); /* MIME cannot change */ | ||
167 | updateSourceData_Player(audio->player, data, append_PlayerUpdate); | ||
168 | if (!isStarted_Player(audio->player)) { | ||
169 | /* Maybe the previous updates didn't have enough data. */ | ||
170 | start_Player(audio->player); | ||
171 | } | ||
172 | if (!isPartial) { | ||
173 | updateSourceData_Player(audio->player, NULL, complete_PlayerUpdate); | ||
174 | } | ||
175 | } | ||
156 | } | 176 | } |
157 | else { | 177 | else if (!isDeleting) { |
158 | if (startsWith_String(mime, "image/")) { | 178 | if (startsWith_String(mime, "image/")) { |
159 | /* Copy the image to a texture. */ | 179 | /* Copy the image to a texture. */ |
160 | /* TODO: Resize down to min(maximum texture size, window size). */ | 180 | /* TODO: Resize down to min(maximum texture size, window size). */ |
@@ -171,13 +191,14 @@ void setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBloc | |||
171 | } | 191 | } |
172 | else if (startsWith_String(mime, "audio/")) { | 192 | else if (startsWith_String(mime, "audio/")) { |
173 | iGmAudio *audio = new_GmAudio(); | 193 | iGmAudio *audio = new_GmAudio(); |
174 | audio->props.linkId = linkId; | 194 | audio->props.linkId = linkId; /* TODO: use a hash? */ |
175 | audio->props.isPermanent = !allowHide; | 195 | audio->props.isPermanent = !allowHide; |
176 | set_String(&audio->props.mime, mime); | 196 | set_String(&audio->props.mime, mime); |
177 | /* TODO: What about update/complete, for streaming? */ | ||
178 | updateSourceData_Player(audio->player, data, replace_PlayerUpdate); | 197 | updateSourceData_Player(audio->player, data, replace_PlayerUpdate); |
198 | if (!isPartial) { | ||
199 | updateSourceData_Player(audio->player, NULL, complete_PlayerUpdate); | ||
200 | } | ||
179 | pushBack_PtrArray(&d->audio, audio); | 201 | pushBack_PtrArray(&d->audio, audio); |
180 | |||
181 | /* TEST: Start playing right away. */ | 202 | /* TEST: Start playing right away. */ |
182 | start_Player(audio->player); | 203 | start_Player(audio->player); |
183 | } | 204 | } |
diff --git a/src/media.h b/src/media.h index 6f460422..c19ad8ae 100644 --- a/src/media.h +++ b/src/media.h | |||
@@ -48,8 +48,13 @@ struct Impl_GmAudioInfo { | |||
48 | iDeclareType(Media) | 48 | iDeclareType(Media) |
49 | iDeclareTypeConstruction(Media) | 49 | iDeclareTypeConstruction(Media) |
50 | 50 | ||
51 | enum iMediaFlags { | ||
52 | allowHide_MediaFlag = iBit(1), | ||
53 | partialData_MediaFlag = iBit(2), | ||
54 | }; | ||
55 | |||
51 | void clear_Media (iMedia *); | 56 | void clear_Media (iMedia *); |
52 | void setData_Media (iMedia *, uint16_t linkId, const iString *mime, const iBlock *data, iBool allowHide); | 57 | void setData_Media (iMedia *, uint16_t linkId, const iString *mime, const iBlock *data, int flags); |
53 | 58 | ||
54 | iMediaId findLinkImage_Media (const iMedia *, uint16_t linkId); | 59 | iMediaId findLinkImage_Media (const iMedia *, uint16_t linkId); |
55 | iBool imageInfo_Media (const iMedia *, iMediaId imageId, iGmImageInfo *info_out); | 60 | iBool imageInfo_Media (const iMedia *, iMediaId imageId, iGmImageInfo *info_out); |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index be9da513..165bf9cf 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -742,7 +742,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse | |||
742 | 1, | 742 | 1, |
743 | mimeStr, | 743 | mimeStr, |
744 | &response->body, | 744 | &response->body, |
745 | iFalse /* it's fixed */); | 745 | 0); |
746 | redoLayout_GmDocument(d->doc); | 746 | redoLayout_GmDocument(d->doc); |
747 | } | 747 | } |
748 | else { | 748 | else { |
@@ -1151,7 +1151,7 @@ static iBool handleMediaCommand_DocumentWidget_(iDocumentWidget *d, const char * | |||
1151 | req->linkId, | 1151 | req->linkId, |
1152 | meta_GmRequest(req->req), | 1152 | meta_GmRequest(req->req), |
1153 | body_GmRequest(req->req), | 1153 | body_GmRequest(req->req), |
1154 | iTrue); | 1154 | allowHide_MediaFlag); |
1155 | redoLayout_GmDocument(d->doc); | 1155 | redoLayout_GmDocument(d->doc); |
1156 | updateVisible_DocumentWidget_(d); | 1156 | updateVisible_DocumentWidget_(d); |
1157 | invalidate_DocumentWidget_(d); | 1157 | invalidate_DocumentWidget_(d); |
@@ -1805,7 +1805,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
1805 | if (!requestMedia_DocumentWidget_(d, linkId)) { | 1805 | if (!requestMedia_DocumentWidget_(d, linkId)) { |
1806 | if (linkFlags & content_GmLinkFlag) { | 1806 | if (linkFlags & content_GmLinkFlag) { |
1807 | /* Dismiss shown content on click. */ | 1807 | /* Dismiss shown content on click. */ |
1808 | setData_Media(media_GmDocument(d->doc), linkId, NULL, NULL, iTrue); | 1808 | setData_Media(media_GmDocument(d->doc), linkId, NULL, NULL, allowHide_MediaFlag); |
1809 | redoLayout_GmDocument(d->doc); | 1809 | redoLayout_GmDocument(d->doc); |
1810 | d->hoverLink = NULL; | 1810 | d->hoverLink = NULL; |
1811 | scroll_DocumentWidget_(d, 0); | 1811 | scroll_DocumentWidget_(d, 0); |
@@ -1822,7 +1822,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
1822 | linkId, | 1822 | linkId, |
1823 | meta_GmRequest(req->req), | 1823 | meta_GmRequest(req->req), |
1824 | body_GmRequest(req->req), | 1824 | body_GmRequest(req->req), |
1825 | iTrue); | 1825 | allowHide_MediaFlag); |
1826 | redoLayout_GmDocument(d->doc); | 1826 | redoLayout_GmDocument(d->doc); |
1827 | updateVisible_DocumentWidget_(d); | 1827 | updateVisible_DocumentWidget_(d); |
1828 | invalidate_DocumentWidget_(d); | 1828 | invalidate_DocumentWidget_(d); |