summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-10-04 17:20:41 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-10-04 17:20:41 +0300
commitefb40105d657da935d3854e6ea7a513c6210224b (patch)
tree0327d88d68c0a402f0f90307756bb8536c54dc8b /src/ui
parent25346114f96a29e8af6125e0cac3d5f8a2ffd551 (diff)
Working on audio playback
Audio players are displayed the same way as images. When playing, a decoder runs in a background thread producing samples suitable for output.
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/documentwidget.c76
1 files changed, 48 insertions, 28 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index f63d93f4..be9da513 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -723,24 +723,26 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse
723 docFormat = gemini_GmDocumentFormat; 723 docFormat = gemini_GmDocumentFormat;
724 setRange_String(&d->sourceMime, param); 724 setRange_String(&d->sourceMime, param);
725 } 725 }
726 else if (startsWith_Rangecc(param, "image/")) { 726 else if (startsWith_Rangecc(param, "image/") ||
727 startsWith_Rangecc(param, "audio/")) {
727 docFormat = gemini_GmDocumentFormat; 728 docFormat = gemini_GmDocumentFormat;
728 setRange_String(&d->sourceMime, param); 729 setRange_String(&d->sourceMime, param);
729 if (!d->request || isFinished_GmRequest(d->request)) { 730 if (!d->request || isFinished_GmRequest(d->request)) {
730 /* Make a simple document with an image. */ 731 /* Make a simple document with an image or audio player. */
731 const char *imageTitle = "Image"; 732 const char *linkTitle =
733 startsWith_String(mimeStr, "image/") ? "Image" : "Audio";
732 iUrl parts; 734 iUrl parts;
733 init_Url(&parts, d->mod.url); 735 init_Url(&parts, d->mod.url);
734 if (!isEmpty_Range(&parts.path)) { 736 if (!isEmpty_Range(&parts.path)) {
735 imageTitle = 737 linkTitle =
736 baseName_Path(collect_String(newRange_String(parts.path))).start; 738 baseName_Path(collect_String(newRange_String(parts.path))).start;
737 } 739 }
738 format_String(&str, "=> %s %s\n", cstr_String(d->mod.url), imageTitle); 740 format_String(&str, "=> %s %s\n", cstr_String(d->mod.url), linkTitle);
739 setImage_Media(media_GmDocument(d->doc), 741 setData_Media(media_GmDocument(d->doc),
740 1, 742 1,
741 mimeStr, 743 mimeStr,
742 &response->body, 744 &response->body,
743 iFalse /* it's fixed */); 745 iFalse /* it's fixed */);
744 redoLayout_GmDocument(d->doc); 746 redoLayout_GmDocument(d->doc);
745 } 747 }
746 else { 748 else {
@@ -1132,6 +1134,8 @@ static iBool handleMediaCommand_DocumentWidget_(iDocumentWidget *d, const char *
1132 return iFalse; /* not our request */ 1134 return iFalse; /* not our request */
1133 } 1135 }
1134 if (equal_Command(cmd, "media.updated")) { 1136 if (equal_Command(cmd, "media.updated")) {
1137 /* Pass new data to media players. */
1138
1135 /* Update the link's progress. */ 1139 /* Update the link's progress. */
1136 invalidateLink_DocumentWidget_(d, req->linkId); 1140 invalidateLink_DocumentWidget_(d, req->linkId);
1137 refresh_Widget(d); 1141 refresh_Widget(d);
@@ -1141,12 +1145,13 @@ static iBool handleMediaCommand_DocumentWidget_(iDocumentWidget *d, const char *
1141 const enum iGmStatusCode code = status_GmRequest(req->req); 1145 const enum iGmStatusCode code = status_GmRequest(req->req);
1142 /* Give the media to the document for presentation. */ 1146 /* Give the media to the document for presentation. */
1143 if (code == success_GmStatusCode) { 1147 if (code == success_GmStatusCode) {
1144 if (startsWith_String(meta_GmRequest(req->req), "image/")) { 1148 if (startsWith_String(meta_GmRequest(req->req), "image/") ||
1145 setImage_Media(media_GmDocument(d->doc), 1149 startsWith_String(meta_GmRequest(req->req), "audio/")) {
1146 req->linkId, 1150 setData_Media(media_GmDocument(d->doc),
1147 meta_GmRequest(req->req), 1151 req->linkId,
1148 body_GmRequest(req->req), 1152 meta_GmRequest(req->req),
1149 iTrue); 1153 body_GmRequest(req->req),
1154 iTrue);
1150 redoLayout_GmDocument(d->doc); 1155 redoLayout_GmDocument(d->doc);
1151 updateVisible_DocumentWidget_(d); 1156 updateVisible_DocumentWidget_(d);
1152 invalidate_DocumentWidget_(d); 1157 invalidate_DocumentWidget_(d);
@@ -1793,14 +1798,14 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
1793 if (isMediaLink_GmDocument(d->doc, linkId)) { 1798 if (isMediaLink_GmDocument(d->doc, linkId)) {
1794 const int linkFlags = linkFlags_GmDocument(d->doc, linkId); 1799 const int linkFlags = linkFlags_GmDocument(d->doc, linkId);
1795 if (linkFlags & content_GmLinkFlag && linkFlags & permanent_GmLinkFlag) { 1800 if (linkFlags & content_GmLinkFlag && linkFlags & permanent_GmLinkFlag) {
1796 /* We have the image and it cannot be dismissed, so nothing 1801 /* We have the content and it cannot be dismissed, so nothing
1797 further to do. */ 1802 further to do. */
1798 return iTrue; 1803 return iTrue;
1799 } 1804 }
1800 if (!requestMedia_DocumentWidget_(d, linkId)) { 1805 if (!requestMedia_DocumentWidget_(d, linkId)) {
1801 if (linkFlags & content_GmLinkFlag) { 1806 if (linkFlags & content_GmLinkFlag) {
1802 /* Dismiss shown content on click. */ 1807 /* Dismiss shown content on click. */
1803 setImage_Media(media_GmDocument(d->doc), linkId, NULL, NULL, iTrue); 1808 setData_Media(media_GmDocument(d->doc), linkId, NULL, NULL, iTrue);
1804 redoLayout_GmDocument(d->doc); 1809 redoLayout_GmDocument(d->doc);
1805 d->hoverLink = NULL; 1810 d->hoverLink = NULL;
1806 scroll_DocumentWidget_(d, 0); 1811 scroll_DocumentWidget_(d, 0);
@@ -1813,11 +1818,11 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
1813 /* Show the existing content again if we have it. */ 1818 /* Show the existing content again if we have it. */
1814 iMediaRequest *req = findMediaRequest_DocumentWidget_(d, linkId); 1819 iMediaRequest *req = findMediaRequest_DocumentWidget_(d, linkId);
1815 if (req) { 1820 if (req) {
1816 setImage_Media(media_GmDocument(d->doc), 1821 setData_Media(media_GmDocument(d->doc),
1817 linkId, 1822 linkId,
1818 meta_GmRequest(req->req), 1823 meta_GmRequest(req->req),
1819 body_GmRequest(req->req), 1824 body_GmRequest(req->req),
1820 iTrue); 1825 iTrue);
1821 redoLayout_GmDocument(d->doc); 1826 redoLayout_GmDocument(d->doc);
1822 updateVisible_DocumentWidget_(d); 1827 updateVisible_DocumentWidget_(d);
1823 invalidate_DocumentWidget_(d); 1828 invalidate_DocumentWidget_(d);
@@ -1913,6 +1918,11 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
1913 } 1918 }
1914 return; 1919 return;
1915 } 1920 }
1921 else if (run->audioId) {
1922 /* Draw the audio player interface. */
1923 fillRect_Paint(&d->paint, moved_Rect(run->visBounds, origin), red_ColorId);
1924 return;
1925 }
1916 enum iColorId fg = run->color; 1926 enum iColorId fg = run->color;
1917 const iGmDocument *doc = d->widget->doc; 1927 const iGmDocument *doc = d->widget->doc;
1918 const iBool isHover = 1928 const iBool isHover =
@@ -1989,13 +1999,23 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
1989 /* Show metadata about inline content. */ 1999 /* Show metadata about inline content. */
1990 if (flags & content_GmLinkFlag && run->flags & endOfLine_GmRunFlag) { 2000 if (flags & content_GmLinkFlag && run->flags & endOfLine_GmRunFlag) {
1991 fg = linkColor_GmDocument(doc, run->linkId, textHover_GmLinkPart); 2001 fg = linkColor_GmDocument(doc, run->linkId, textHover_GmLinkPart);
1992 iAssert(!isEmpty_Rect(run->bounds));
1993 iGmImageInfo info;
1994 imageInfo_Media(constMedia_GmDocument(doc), linkImage_GmDocument(doc, run->linkId), &info);
1995 iString text; 2002 iString text;
1996 init_String(&text); 2003 init_String(&text);
1997 format_String(&text, "%s \u2014 %d x %d \u2014 %.1fMB", 2004 iMediaId imageId = linkImage_GmDocument(doc, run->linkId);
1998 info.mime, info.size.x, info.size.y, info.numBytes / 1.0e6f); 2005 iMediaId audioId = !imageId ? linkAudio_GmDocument(doc, run->linkId) : 0;
2006 iAssert(imageId || audioId);
2007 if (imageId) {
2008 iAssert(!isEmpty_Rect(run->bounds));
2009 iGmImageInfo info;
2010 imageInfo_Media(constMedia_GmDocument(doc), imageId, &info);
2011 format_String(&text, "%s \u2014 %d x %d \u2014 %.1fMB",
2012 info.mime, info.size.x, info.size.y, info.numBytes / 1.0e6f);
2013 }
2014 else if (audioId) {
2015 iGmAudioInfo info;
2016 audioInfo_Media(constMedia_GmDocument(doc), audioId, &info);
2017 format_String(&text, "%s", info.mime);
2018 }
1999 if (findMediaRequest_DocumentWidget_(d->widget, run->linkId)) { 2019 if (findMediaRequest_DocumentWidget_(d->widget, run->linkId)) {
2000 appendFormat_String( 2020 appendFormat_String(
2001 &text, " %s\u2a2f", isHover ? escape_Color(tmLinkText_ColorId) : ""); 2021 &text, " %s\u2a2f", isHover ? escape_Color(tmLinkText_ColorId) : "");