diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-10-04 17:20:41 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-10-04 17:20:41 +0300 |
commit | efb40105d657da935d3854e6ea7a513c6210224b (patch) | |
tree | 0327d88d68c0a402f0f90307756bb8536c54dc8b /src/ui | |
parent | 25346114f96a29e8af6125e0cac3d5f8a2ffd551 (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.c | 76 |
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) : ""); |