Mardy (Articoli su Ubuntu)http://mardy.it/it/categories/ubuntu.atom2024-02-02T20:11:10ZAlberto MardeganNikolaLeaving Canonical, againhttp://mardy.it/it/blog/2022/12/leaving-canonical-again.html2022-12-03T10:03:58+03:002022-12-03T10:03:58+03:00Alberto Mardegan<p>For the <a href="http://mardy.it/it/blog/2017/04/looking-for-new-adventures.html">second time</a>, I'm being shown
the door at Canonical. Well, technically, this time it was me who handed over my
resignation, but that was only after I was told in very clear terms that I
would eventually be fired. No timeframe was given, but since I don't
particularly enjoy the feeling of checking my e-mail every morning to find out
whether this is the day when I'm being fired, I decided to take the initiative
and leave myself.</p>
<p>The reason? Those who know me well might suspect that it's related to some
complications with that fact that I'm living in Russia, or maybe with some
remarks I might have made about the war in Ukraine or about other current
events, since <a href="http://mardy.it/it/blog/2019/09/principles-and-privileges.html">I tent to be quite outspoken and
provocative</a>. Nothing of all that: it's about my
<strong>refusal to get vaccinated</strong> against COVID-19; unfortunately, it has now
become apparent that I'm not the only one leaving, and other employees who have
refused either to get vaccinated or to disclose their vaccination status are
also being shown the door (including people who have been in the company for
more than 10 years). This has sparked some internal discussions in the company, and
several different point of views have been voiced: from those who welcome this
policy and would like to see it extended to flu vaccinations (which makes a lot
of sense, since once you've accepted to renounce your freedom in order to
protect the weak, you should accept it for all transmissible diseases), to
those who voiced concerns about the legality of this move, or would have found
this reasonable one year ago but not in the current situation as restrictions
are getting lifted and the current variants are less scary than the previous
ones; those who pointed out that being vaccinated has little impact on
transmissibility of the virus; that we are mostly a remote company and we could
instead have exceptions to allow unvaccinated people (or people with a weak
immune system) to remotely attend the few in-person meetings we have;
that as long as there are no vaccination mandates for plane flights and other
guests attending the same hotel premises where we meet, mandating employees to
get vaccinated might not help a lot; and whether this is a decision that a
company should make, or shouldn't it rather lobby the politics to have it
mandated at state level. I think there's merit to all these arguments, but I'm
personally not particularly interested in discussing any of them, since my
point is another.</p>
<p>Before talking about that, though, let me clearly set one thing straight: I
hate lies, and <strong>Canonical's management is lying</strong> about this matter. The
vaccination mandate measure is being justified on the grounds that it allows
employees to travel (something that I've been able to do as unvaccinated
throughout the last two years, even when restrictions were at their peak) and,
most importantly, to protect our weaker colleagues. This is what I find most
disgusting: using genuine feelings like love and compassion to justify
repressive measures. No, dear Canonical, this has nothing to do with protecting
the weak; not only because a vaccinated person can still spread the virus (and
our employees know this from first-hand experience), but also because, if this
was the real reason, then you'd accept people who have recently recovered from
COVID-19, since <a href="https://academic.oup.com/cid/article/75/1/e545/6563799">immunisation after recovery is not worse than that of
vaccination</a>; but you
don't, as I was explicitly told by HR that any previous infection is irrelevant.
It's also significant that you didn't establish clear rules about how often
one needs to get vaccinated, since all recent scientific literature on vaccine
efficacy shows that this is not a minor detail. Why not just be honest with
ourselves, and admit it's <a href="https://www.enr.com/articles/52481-us-announces-revised-vaccine-mandate-rules-for-federal-contractors">just for
business</a>?
Being open about the fact that having a fully vaccinated workforce can grant us
access to more business deals would not change a lot in the practical life of
the (ex-)employees, but at least we won't feel that the company is treating us
as fools while embellishing its image with fake care and compassion. Or, if
there are other reasons, state them, because these ones don't stand up to logic
scrutiny.</p>
<p>Another thing that doesn't match (though maybe this is a timing issue, so I
cannot for sure call it out as a lie) is the fact that HR claims to have an
exemption process through which one could opt-out of the vaccination for
religious beliefs. Well, I was explicitly told in very clear terms by HR that
no exceptions would be made on either moral or religious grounds. But maybe
this has changed since the time I was told this (mid October) and now?</p>
<p>Here, finally, let me state why I believe that such a mandate is wrong. The
first thing I want to put on the table is that even though I see very little
reason for this mandate (given all what we know about the virus mutability and
infectiousness, the shortcomings of the vaccines, etc. — by the way, if you are
into science I suggest reading <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC9062939/">this
article</a> which raises
some questions you won't hear in mainstream media and has a comprehensive
bibliography for further study), I recognize that in principle there are very
solid reasons for vaccination mandates, for example in the case where a virus
is extremely lethal, its symptoms otherwise uncurable and the vaccine is 100%
safe and highly effective. But even in that case, while getting vaccinated
myself, I would still oppose a mandate. Why? Because of freedom, which trumps
everything. The choice is never between a healthy life and freedom: if there's
no freedom, there's no life worth living. Even if some decision has very solid
reasons behind it, this doesn't automatically make it a good decision.</p>
<p>Let me make a few examples: if a company (I'm talking about companies here, but
the reasoning could be extended to states as well) decided that smokers will be
fired, or that those who drink alcoholics will be fired, or that you cannot eat
meat, or that you must take a pill whenever your head aches, or that
transgender people must undergo gender reassignment surgery, or that
everyone should wear a black band on their arm whenever a relative of a
colleague dies, or that employees' households must use the product made by the
employer, or that they have to excercise sports for at least two hours per
week, etc.; I would be categorically opposed to every single of these
impositions, despite recognising that there are reasons behind each of them,
and that I even dream of a world in which some of their goals are attained
(could we just all be fit and healthy?!). Because I think that personal freedom
is more important. You can always find good reasons to justify this or that
action; surely, if we think back at the fascist and totalitarian regimes of the
first half of last century, we must acknowledge that they were supported by the
(overwhelming?) majority of the population. An effective propaganda machine
could convince the population on this and that matter, but ultimately it's the
population who <em>reasoned</em> and accepted that storytelling. Nowadays the
situation is different, but the mechanisms are the same, except that propaganda
has become way more effective (<a href="http://mardy.it/it/blog/2022/11/the-idiotism-of-software-developers.html">or have we become
dumber?</a>) and aligned over the
same direction, thanks to the globalisation process.</p>
<p>I'm well aware that societies are made of rules and therefore inevitably
restrict personal freedom: Western societies, for example, forbid nudity in
public places, and that's something I accept because it's part of my culture;
it's a rule deeply entrenched in our history, and I don't feel it as a burden.
I'm convinced, however, that the evolution of human society should be that, as
we become more conscious, we should be moving towards more free societies, with
fewer rules and more tolerant for diversity.</p><p>For the <a href="http://mardy.it/it/blog/2017/04/looking-for-new-adventures.html">second time</a>, I'm being shown
the door at Canonical. Well, technically, this time it was me who handed over my
resignation, but that was only after I was told in very clear terms that I
would eventually be fired. No timeframe was given, but since I don't
particularly enjoy the feeling of checking my e-mail every morning to find out
whether this is the day when I'm being fired, I decided to take the initiative
and leave myself.</p>
<p>The reason? Those who know me well might suspect that it's related to some
complications with that fact that I'm living in Russia, or maybe with some
remarks I might have made about the war in Ukraine or about other current
events, since <a href="http://mardy.it/it/blog/2019/09/principles-and-privileges.html">I tent to be quite outspoken and
provocative</a>. Nothing of all that: it's about my
<strong>refusal to get vaccinated</strong> against COVID-19; unfortunately, it has now
become apparent that I'm not the only one leaving, and other employees who have
refused either to get vaccinated or to disclose their vaccination status are
also being shown the door (including people who have been in the company for
more than 10 years). This has sparked some internal discussions in the company, and
several different point of views have been voiced: from those who welcome this
policy and would like to see it extended to flu vaccinations (which makes a lot
of sense, since once you've accepted to renounce your freedom in order to
protect the weak, you should accept it for all transmissible diseases), to
those who voiced concerns about the legality of this move, or would have found
this reasonable one year ago but not in the current situation as restrictions
are getting lifted and the current variants are less scary than the previous
ones; those who pointed out that being vaccinated has little impact on
transmissibility of the virus; that we are mostly a remote company and we could
instead have exceptions to allow unvaccinated people (or people with a weak
immune system) to remotely attend the few in-person meetings we have;
that as long as there are no vaccination mandates for plane flights and other
guests attending the same hotel premises where we meet, mandating employees to
get vaccinated might not help a lot; and whether this is a decision that a
company should make, or shouldn't it rather lobby the politics to have it
mandated at state level. I think there's merit to all these arguments, but I'm
personally not particularly interested in discussing any of them, since my
point is another.</p>
<p>Before talking about that, though, let me clearly set one thing straight: I
hate lies, and <strong>Canonical's management is lying</strong> about this matter. The
vaccination mandate measure is being justified on the grounds that it allows
employees to travel (something that I've been able to do as unvaccinated
throughout the last two years, even when restrictions were at their peak) and,
most importantly, to protect our weaker colleagues. This is what I find most
disgusting: using genuine feelings like love and compassion to justify
repressive measures. No, dear Canonical, this has nothing to do with protecting
the weak; not only because a vaccinated person can still spread the virus (and
our employees know this from first-hand experience), but also because, if this
was the real reason, then you'd accept people who have recently recovered from
COVID-19, since <a href="https://academic.oup.com/cid/article/75/1/e545/6563799">immunisation after recovery is not worse than that of
vaccination</a>; but you
don't, as I was explicitly told by HR that any previous infection is irrelevant.
It's also significant that you didn't establish clear rules about how often
one needs to get vaccinated, since all recent scientific literature on vaccine
efficacy shows that this is not a minor detail. Why not just be honest with
ourselves, and admit it's <a href="https://www.enr.com/articles/52481-us-announces-revised-vaccine-mandate-rules-for-federal-contractors">just for
business</a>?
Being open about the fact that having a fully vaccinated workforce can grant us
access to more business deals would not change a lot in the practical life of
the (ex-)employees, but at least we won't feel that the company is treating us
as fools while embellishing its image with fake care and compassion. Or, if
there are other reasons, state them, because these ones don't stand up to logic
scrutiny.</p>
<p>Another thing that doesn't match (though maybe this is a timing issue, so I
cannot for sure call it out as a lie) is the fact that HR claims to have an
exemption process through which one could opt-out of the vaccination for
religious beliefs. Well, I was explicitly told in very clear terms by HR that
no exceptions would be made on either moral or religious grounds. But maybe
this has changed since the time I was told this (mid October) and now?</p>
<p>Here, finally, let me state why I believe that such a mandate is wrong. The
first thing I want to put on the table is that even though I see very little
reason for this mandate (given all what we know about the virus mutability and
infectiousness, the shortcomings of the vaccines, etc. — by the way, if you are
into science I suggest reading <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC9062939/">this
article</a> which raises
some questions you won't hear in mainstream media and has a comprehensive
bibliography for further study), I recognize that in principle there are very
solid reasons for vaccination mandates, for example in the case where a virus
is extremely lethal, its symptoms otherwise uncurable and the vaccine is 100%
safe and highly effective. But even in that case, while getting vaccinated
myself, I would still oppose a mandate. Why? Because of freedom, which trumps
everything. The choice is never between a healthy life and freedom: if there's
no freedom, there's no life worth living. Even if some decision has very solid
reasons behind it, this doesn't automatically make it a good decision.</p>
<p>Let me make a few examples: if a company (I'm talking about companies here, but
the reasoning could be extended to states as well) decided that smokers will be
fired, or that those who drink alcoholics will be fired, or that you cannot eat
meat, or that you must take a pill whenever your head aches, or that
transgender people must undergo gender reassignment surgery, or that
everyone should wear a black band on their arm whenever a relative of a
colleague dies, or that employees' households must use the product made by the
employer, or that they have to excercise sports for at least two hours per
week, etc.; I would be categorically opposed to every single of these
impositions, despite recognising that there are reasons behind each of them,
and that I even dream of a world in which some of their goals are attained
(could we just all be fit and healthy?!). Because I think that personal freedom
is more important. You can always find good reasons to justify this or that
action; surely, if we think back at the fascist and totalitarian regimes of the
first half of last century, we must acknowledge that they were supported by the
(overwhelming?) majority of the population. An effective propaganda machine
could convince the population on this and that matter, but ultimately it's the
population who <em>reasoned</em> and accepted that storytelling. Nowadays the
situation is different, but the mechanisms are the same, except that propaganda
has become way more effective (<a href="http://mardy.it/it/blog/2022/11/the-idiotism-of-software-developers.html">or have we become
dumber?</a>) and aligned over the
same direction, thanks to the globalisation process.</p>
<p>I'm well aware that societies are made of rules and therefore inevitably
restrict personal freedom: Western societies, for example, forbid nudity in
public places, and that's something I accept because it's part of my culture;
it's a rule deeply entrenched in our history, and I don't feel it as a burden.
I'm convinced, however, that the evolution of human society should be that, as
we become more conscious, we should be moving towards more free societies, with
fewer rules and more tolerant for diversity.</p>MiTubo 1.4 adds feed foldershttp://mardy.it/it/blog/2022/10/mitubo-14-adds-feed-folders.html2022-10-10T17:40:09+03:002022-10-10T17:40:09+03:00Alberto Mardegan<p>Exactly one month has passed since the previous release, just the right time
needed to complete the feafure I've been working on since several weeks and to
fix a few bugfixes introduced with the previous release. So it's time a new
release of <a href="https://gitlab.com/mardy/mitubo">MiTubo</a>:</p>
<p></p><center>
<video id="video" controls preload="metadata" width="100%">
<source src="http://mardy.it/archivos/videos/mitubo-1.4.webm" type="video/webm">
</source></video>
<p></p></center>
<p>I realized that I'm not that good at making release videos, but the point of
the video above is to show that you can organize your feeds into folders. When
clicking on a folder, a page opens with the folder's contents; but you can also
directly click on a feed, as long as its preview is visible in the folder's
delegate, and then the feeds open directly. This means that if you organize the
feeds inside your folders so that the favourite ones are at the top, they'll
also be visible in the folder preview and you'll be able to jump to them in
just one click.</p>
<p>Maybe I'm not that good with textual explanations either, so why don't you
check it out for yourself? ☺ Get it at
<a href="http://www.mardy.it/mitubo">mardy.it/mitubo</a> (builds for Linux, Ubuntu Touch,
Windows and macOS are available)!</p><p>Exactly one month has passed since the previous release, just the right time
needed to complete the feafure I've been working on since several weeks and to
fix a few bugfixes introduced with the previous release. So it's time a new
release of <a href="https://gitlab.com/mardy/mitubo">MiTubo</a>:</p>
<p></p><center>
<video id="video" controls preload="metadata" width="100%">
<source src="http://mardy.it/archivos/videos/mitubo-1.4.webm" type="video/webm">
</source></video>
<p></p></center>
<p>I realized that I'm not that good at making release videos, but the point of
the video above is to show that you can organize your feeds into folders. When
clicking on a folder, a page opens with the folder's contents; but you can also
directly click on a feed, as long as its preview is visible in the folder's
delegate, and then the feeds open directly. This means that if you organize the
feeds inside your folders so that the favourite ones are at the top, they'll
also be visible in the folder preview and you'll be able to jump to them in
just one click.</p>
<p>Maybe I'm not that good with textual explanations either, so why don't you
check it out for yourself? ☺ Get it at
<a href="http://www.mardy.it/mitubo">mardy.it/mitubo</a> (builds for Linux, Ubuntu Touch,
Windows and macOS are available)!</p>MiTubo 1.3: sorting of QML ListView via Drag&Drophttp://mardy.it/it/blog/2022/09/mitubo-13-sorting-of-qml-listview-via-dragdrop.html2022-09-10T13:38:51+03:002022-09-10T13:38:51+03:00Alberto Mardegan<p>One feature that I've been asked to add to
<a href="https://gitlab.com/mardy/mitubo">MiTubo</a>, and that indeed becomes more and
more important as the number of subscriptions increases, is the ability to
group subscriptions into folders. I've spent a good amount of time implementing
the needed support in the C++ backend, which is now able to handle nested
folders too, but given that building the UI parts was not a quick task and
seeing how much time has passed since the last release, I thought of releasing
a partial implementation of the whole feature, consisting only of the ability
to manually sort the subscriptions via drag&drop (that, is no folder support).
It turns out this is already not a trivial work!</p>
<p>I found a <a href="https://agateau.com/2016/reordering-a-listview-via-dragndrop-3/">nice tutorial on ListView DnD
sorting</a> by
the great Aurélien Gâteau which I found very inspiring, and while I didn't
actually reuse the same code (mostly because I was already halfway through with
my implementation, which I started before finding his tutorial), it was helpful
to have it as a reference. I added a few animations to make it look more
pleasant, and I'm rather satisfied with the result:</p>
<p></p><center>
<video id="video" controls preload="metadata" width="100%">
<source src="http://mardy.it/archivos/videos/mitubo-1.3.webm" type="video/webm">
</source></video>
<p></p></center>
<p>I'm not showing you the code yet (though, indeed, you can find it in the
<code>DraggableListView</code> and <code>DraggableDelegate</code> items <a href="https://gitlab.com/mardy/mitubo/-/tree/master/src/desktop/qml">in the source
repository</a>)
because it's not yet in a shape where it's generally reusable in other
projects, but if I happen to need the same feature elsewhere I'll eventually
try to turn it into a couple fully reusable components.</p>
<p>Anyway, here's what's new in this latest MiTubo release:</p>
<ul>
<li>Subscriptions can be sorted by means of Drag&drop</li>
<li>For systems with python 3.5 or older (such as Ubuntu Touch), use the daily
builds of <a href="https://youtube-dl.org/">youtube-dl</a> instead of the official
releases</li>
<li>Implement <strong>PeerTube search</strong> (this should reserve a post of its own!)</li>
</ul>
<p>You can get it <a href="http://www.mardy.it/mitubo">at the usual place</a>. This time
there are only Linux and Windows builds as I'm a bit lazy to make a macOS
version, but should you need it, don't hesitate to ask!</p><p>One feature that I've been asked to add to
<a href="https://gitlab.com/mardy/mitubo">MiTubo</a>, and that indeed becomes more and
more important as the number of subscriptions increases, is the ability to
group subscriptions into folders. I've spent a good amount of time implementing
the needed support in the C++ backend, which is now able to handle nested
folders too, but given that building the UI parts was not a quick task and
seeing how much time has passed since the last release, I thought of releasing
a partial implementation of the whole feature, consisting only of the ability
to manually sort the subscriptions via drag&drop (that, is no folder support).
It turns out this is already not a trivial work!</p>
<p>I found a <a href="https://agateau.com/2016/reordering-a-listview-via-dragndrop-3/">nice tutorial on ListView DnD
sorting</a> by
the great Aurélien Gâteau which I found very inspiring, and while I didn't
actually reuse the same code (mostly because I was already halfway through with
my implementation, which I started before finding his tutorial), it was helpful
to have it as a reference. I added a few animations to make it look more
pleasant, and I'm rather satisfied with the result:</p>
<p></p><center>
<video id="video" controls preload="metadata" width="100%">
<source src="http://mardy.it/archivos/videos/mitubo-1.3.webm" type="video/webm">
</source></video>
<p></p></center>
<p>I'm not showing you the code yet (though, indeed, you can find it in the
<code>DraggableListView</code> and <code>DraggableDelegate</code> items <a href="https://gitlab.com/mardy/mitubo/-/tree/master/src/desktop/qml">in the source
repository</a>)
because it's not yet in a shape where it's generally reusable in other
projects, but if I happen to need the same feature elsewhere I'll eventually
try to turn it into a couple fully reusable components.</p>
<p>Anyway, here's what's new in this latest MiTubo release:</p>
<ul>
<li>Subscriptions can be sorted by means of Drag&drop</li>
<li>For systems with python 3.5 or older (such as Ubuntu Touch), use the daily
builds of <a href="https://youtube-dl.org/">youtube-dl</a> instead of the official
releases</li>
<li>Implement <strong>PeerTube search</strong> (this should reserve a post of its own!)</li>
</ul>
<p>You can get it <a href="http://www.mardy.it/mitubo">at the usual place</a>. This time
there are only Linux and Windows builds as I'm a bit lazy to make a macOS
version, but should you need it, don't hesitate to ask!</p>MiTubo comes to macOShttp://mardy.it/it/blog/2022/06/mitubo-comes-to-macos.html2022-06-22T22:44:47+03:002022-06-22T22:44:47+03:00Alberto Mardegan<p>I just released <a href="http://mardy.it/mitubo/#downloads">MiTubo 1.2</a>. New in this version:</p>
<ul>
<li>As suggested by <code>alphas12</code> in the comments, I added the author name in the
YouTube search results.</li>
<li>In the same results list, there's now a clickable link to the channel, which
makes it easier to subscribe to it.</li>
<li>Improve layout of some pages on narrow displays (though there's still much to
be done!).</li>
<li>Skip invoking youtube-dl if the video information is already encoded in the
page <code>HEAD</code> meta properties.</li>
<li>Remember the preferred playback resolution; this can be helpful on low
bandwith connections.</li>
<li>First macOS release!</li>
</ul>
<p>While bringing in the macOS version, I updated the <a href="https://gitlab.com/qt-goodies/qscreensaver">QScreenSaver
library</a> to support inhibiting the
screensaver on macOS too.</p>
<p>I also tested the AppImage on openSUSE, and it seems to work fine there too.
So, fewer and fewer people have valid excuses not to try out MiTubo!</p><p>I just released <a href="http://mardy.it/mitubo/#downloads">MiTubo 1.2</a>. New in this version:</p>
<ul>
<li>As suggested by <code>alphas12</code> in the comments, I added the author name in the
YouTube search results.</li>
<li>In the same results list, there's now a clickable link to the channel, which
makes it easier to subscribe to it.</li>
<li>Improve layout of some pages on narrow displays (though there's still much to
be done!).</li>
<li>Skip invoking youtube-dl if the video information is already encoded in the
page <code>HEAD</code> meta properties.</li>
<li>Remember the preferred playback resolution; this can be helpful on low
bandwith connections.</li>
<li>First macOS release!</li>
</ul>
<p>While bringing in the macOS version, I updated the <a href="https://gitlab.com/qt-goodies/qscreensaver">QScreenSaver
library</a> to support inhibiting the
screensaver on macOS too.</p>
<p>I also tested the AppImage on openSUSE, and it seems to work fine there too.
So, fewer and fewer people have valid excuses not to try out MiTubo!</p>MiTubo 1.1: screensaver inhibitorhttp://mardy.it/it/blog/2022/06/mitubo-11-screensaver-inhibitor.html2022-06-04T13:46:54+03:002022-06-04T13:46:54+03:00Alberto Mardegan<p>Looks like I'm posting a bit too often about <a href="http://mardy.it/mitubo">MiTubo</a>, but don't
worry, I'll soon find something else to write about.</p>
<p>Version 1.1 is now released, bringing you:</p>
<ul>
<li>A screensaver inhibitor, at last!</li>
<li>AppImage now works in Arch and Manjaro</li>
</ul>
<p>More in detail, this means that your computer won't go to sleep or start the
screen saver while you are watching a video. To achieve this, I wrote a
portable (well, for the time being it only supports Linux and Windows, but
macOS support will eventually arrive too) library for inhibiting the
screensaver: <a href="https://gitlab.com/qt-goodies/qscreensaver">QScreenSaver</a>. It
lives in its own repository, and it's written in a way that should be easy to
integrate with your own project. You are welcome to try it out (and add support
for cmake/qmake/meson/…).</p>
<p>The AppImage support has been improved after a user filed a bug about MiTubo
not working in Arch; I myself could not verify the issue as I've grown too lazy
to install a distribution like Arch, but I did it on Manjaro (which is also
based on Arch), and indeed the MiTubo AppImage contained some unnecessary
libraries (while missing some others) that rendered it non-functional in those
distributions. Now it's all fixed, so there's a good chance that the AppImage
will work on your distribution, too.</p><p>Looks like I'm posting a bit too often about <a href="http://mardy.it/mitubo">MiTubo</a>, but don't
worry, I'll soon find something else to write about.</p>
<p>Version 1.1 is now released, bringing you:</p>
<ul>
<li>A screensaver inhibitor, at last!</li>
<li>AppImage now works in Arch and Manjaro</li>
</ul>
<p>More in detail, this means that your computer won't go to sleep or start the
screen saver while you are watching a video. To achieve this, I wrote a
portable (well, for the time being it only supports Linux and Windows, but
macOS support will eventually arrive too) library for inhibiting the
screensaver: <a href="https://gitlab.com/qt-goodies/qscreensaver">QScreenSaver</a>. It
lives in its own repository, and it's written in a way that should be easy to
integrate with your own project. You are welcome to try it out (and add support
for cmake/qmake/meson/…).</p>
<p>The AppImage support has been improved after a user filed a bug about MiTubo
not working in Arch; I myself could not verify the issue as I've grown too lazy
to install a distribution like Arch, but I did it on Manjaro (which is also
based on Arch), and indeed the MiTubo AppImage contained some unnecessary
libraries (while missing some others) that rendered it non-functional in those
distributions. Now it's all fixed, so there's a good chance that the AppImage
will work on your distribution, too.</p>MiTubo 1.0: playlist support, new “website”http://mardy.it/it/blog/2022/05/mitubo-10-playlist-support-new-website.html2022-05-21T15:53:56+03:002022-05-21T15:53:56+03:00Alberto Mardegan<p>Some news from the MiTubo world:</p>
<ul>
<li>Version 1.0 has been released!</li>
<li>It's also available for Windows (boo!)</li>
<li>Some basic support for remote playlists</li>
<li>New “Check for updates” dialog</li>
<li>Added support for translations</li>
<li>Added Italian translation, of course</li>
<li>Minor cosmetic changes (like using a different unicode symbol for the “Back” button)</li>
<li>New web page for MiTubo</li>
</ul>
<p>Expanding a bit on the points above, the first thing worth saying is that the
choice of releasing this version as “1.0” does not mean that it's more stable
than the previous ones; it just means that I'm rather satisfied with the
feature set, and that I believe that the program is ready for more widespread
use.</p>
<p>This is also the reason why I decided to prepare a web page for it:
<a href="http://mardy.it/mitubo">mardy.it/mitubo</a>. I didn't go for a completely separate website,
unlike what I previously did for <a href="https://mappero.mardy.it">Mappero Geotagger</a>,
<a href="https://phototeleport.com">PhotoTeleport</a> and
<a href="https://imaginario.mardy.it">Imaginario</a> (which reminds me that I haven't been
working on the latter for a long time! I should try to correct this soon!),
both because this way it's simpler to publish news about it (I'll continue
doing that here, instead of cross-posting in two sites), and because having it
in the same domain might be mutually beneficial for the SEO ranking of the blog
and of MiTubo.</p>
<p>As for the Windows version, I want to thank <a href="http://mardy.it/it/blog/2020/04/new-website-for-mappero-geotagger.html">once
again</a>
the <a href="http://mxe.cc">MXE project</a> for their fantastic cross-compiling suite. I
find it very cumbersome working in Windows, and being able to build my programs
from Linux makes my life a lot easier (if you want to have more information
about how this works with QBS, have a look at the previous MXE post). I wish
there was something similar for macOS; and that's why the macOs version is
going to take more time to arrive — on the other hand, I haven't received any
requests for it, so I'm not in a hurry to work on that.</p>
<p>Last but not least, translation support means that if you want to help with
translations, now you can. I've myself tried
<a href="https://doc.qt.io/qt-5/linguist-translators.html">QtLinguist</a> for the first
time to write the Italian translation, and I found it to be an extremely
effective tool, once you learn the key bindings by heart.</p><p>Some news from the MiTubo world:</p>
<ul>
<li>Version 1.0 has been released!</li>
<li>It's also available for Windows (boo!)</li>
<li>Some basic support for remote playlists</li>
<li>New “Check for updates” dialog</li>
<li>Added support for translations</li>
<li>Added Italian translation, of course</li>
<li>Minor cosmetic changes (like using a different unicode symbol for the “Back” button)</li>
<li>New web page for MiTubo</li>
</ul>
<p>Expanding a bit on the points above, the first thing worth saying is that the
choice of releasing this version as “1.0” does not mean that it's more stable
than the previous ones; it just means that I'm rather satisfied with the
feature set, and that I believe that the program is ready for more widespread
use.</p>
<p>This is also the reason why I decided to prepare a web page for it:
<a href="http://mardy.it/mitubo">mardy.it/mitubo</a>. I didn't go for a completely separate website,
unlike what I previously did for <a href="https://mappero.mardy.it">Mappero Geotagger</a>,
<a href="https://phototeleport.com">PhotoTeleport</a> and
<a href="https://imaginario.mardy.it">Imaginario</a> (which reminds me that I haven't been
working on the latter for a long time! I should try to correct this soon!),
both because this way it's simpler to publish news about it (I'll continue
doing that here, instead of cross-posting in two sites), and because having it
in the same domain might be mutually beneficial for the SEO ranking of the blog
and of MiTubo.</p>
<p>As for the Windows version, I want to thank <a href="http://mardy.it/it/blog/2020/04/new-website-for-mappero-geotagger.html">once
again</a>
the <a href="http://mxe.cc">MXE project</a> for their fantastic cross-compiling suite. I
find it very cumbersome working in Windows, and being able to build my programs
from Linux makes my life a lot easier (if you want to have more information
about how this works with QBS, have a look at the previous MXE post). I wish
there was something similar for macOS; and that's why the macOs version is
going to take more time to arrive — on the other hand, I haven't received any
requests for it, so I'm not in a hurry to work on that.</p>
<p>Last but not least, translation support means that if you want to help with
translations, now you can. I've myself tried
<a href="https://doc.qt.io/qt-5/linguist-translators.html">QtLinguist</a> for the first
time to write the Italian translation, and I found it to be an extremely
effective tool, once you learn the key bindings by heart.</p>Mitubo 0.9: multiple concurrent video downloadshttp://mardy.it/it/blog/2022/05/mitubo-09-multiple-concurrent-video-downloads.html2022-05-05T22:16:40+03:002022-05-05T22:16:40+03:00Alberto Mardegan<p>It will never stop surprising me how easy it is to implement big new features
in a QML application! The assumption here is that the C++ part of the
application should be well-written: objects should not be overloaded with
unrelated functionalities just because it seems faster to code them that way,
but one should rather design classes so that each exposes <em>one</em> functionality,
and then QML and javascript act as the glue which binds all the parts together.</p>
<p>In a way, <strong>QML stands to C++ classes like the POSIX shell stands to
command-line tools</strong>: a simple language which allows concatenating small units
of functionality together to build a powerful program.</p>
<p>Anyway, that was not what I wanted to talk you about today. ☺ Today's post is
about <a href="https://gitlab.com/mardy/mitubo">MiTubo</a>, whose version 0.9 has been
released today:</p>
<p></p><center>
<video id="video" controls preload="metadata" width="100%">
<source src="http://mardy.it/archivos/videos/mitubo-0.9.webm" type="video/webm">
</source></video>
<p></p></center>
<p>The big feature in this release is download of audio/video files: I thought,
since I'm using <a href="https://github.com/yt-dlp/yt-dlp">yt-dlp</a> (or
<a href="https://youtube-dl.org/">youtube-dl</a> on Ubuntu Touch) anyway for
extracting video streams, why not add an option to let users download the media
content? This turned out to be easier than expected, so if you were looking for
a graphical frontend to the YouTube downloader, well, now MiTubo is an option
you could try.</p><p>It will never stop surprising me how easy it is to implement big new features
in a QML application! The assumption here is that the C++ part of the
application should be well-written: objects should not be overloaded with
unrelated functionalities just because it seems faster to code them that way,
but one should rather design classes so that each exposes <em>one</em> functionality,
and then QML and javascript act as the glue which binds all the parts together.</p>
<p>In a way, <strong>QML stands to C++ classes like the POSIX shell stands to
command-line tools</strong>: a simple language which allows concatenating small units
of functionality together to build a powerful program.</p>
<p>Anyway, that was not what I wanted to talk you about today. ☺ Today's post is
about <a href="https://gitlab.com/mardy/mitubo">MiTubo</a>, whose version 0.9 has been
released today:</p>
<p></p><center>
<video id="video" controls preload="metadata" width="100%">
<source src="http://mardy.it/archivos/videos/mitubo-0.9.webm" type="video/webm">
</source></video>
<p></p></center>
<p>The big feature in this release is download of audio/video files: I thought,
since I'm using <a href="https://github.com/yt-dlp/yt-dlp">yt-dlp</a> (or
<a href="https://youtube-dl.org/">youtube-dl</a> on Ubuntu Touch) anyway for
extracting video streams, why not add an option to let users download the media
content? This turned out to be easier than expected, so if you were looking for
a graphical frontend to the YouTube downloader, well, now MiTubo is an option
you could try.</p>MiTubo 0.8: search, channels, watch later queuehttp://mardy.it/it/blog/2022/04/mitubo-update-search-channels-watch-later-queue.html2022-04-10T19:06:30+03:002022-04-10T19:06:30+03:00Alberto Mardegan<p>It has been a while since I last posted about
<a href="https://gitlab.com/mardy/mitubo">MiTubo</a>, despite releasing a few new versions
in the last months. But now I think that there is enough new stuff that's worth
a mention here.</p>
<p></p><center>
<figure>
<a href="http://mardy.it/archivos/imagines/blog/Mitubo-search.png"><img src="http://mardy.it/archivos/imagines/blog/Mitubo-search.png" width="80%"></a>
<figcaption>Search on YouTube</figcaption>
</figure>
<p></p></center>
<p>Initially MiTubo only came with a search feature that was using Yandex video as
a backend; while that worked generally well, most of the returned results were
not playable due to youtube-dl being unable to extract the video information
from the returned web pages. So, now we have the option to search on YouTube,
via the <a href="https://invidious.io/">Invidious API</a>; furthermore, it's also possible
to search for channels, whose RSS feed can then be added as a subscription.</p>
<p>One other thing that has always bothered me is not being able to enqueue a new
video while watching another one, without having to pause the current one, go
back to the main page, add the new video to a playlist, go back to the current
video, and finally, once that is over, open the playlist and start the new
video.</p>
<p></p><center>
<figure>
<a href="http://mardy.it/archivos/imagines/blog/Mitubo-dnd.png"><img src="http://mardy.it/archivos/imagines/blog/Mitubo-dnd.png" width="80%"></a>
<figcaption>Drag and drop a new URL while watching a video</figcaption>
</figure>
<p></p></center>
<p>So now we have that. One can drag and drop an URL (or even a longer text
containing several URLs) while watching another video, and a popup will appear
with a few choices (see the screenshot above). I've also added a “Next” button
next to the “Play” one, which is enabled if the “Watch later” playlist is not
empty, and does the obvious thing when pressed. Once started, the new video is
automatically removed from the “Watch later” playlist and moved into the
“Continue watching” list, where it will remain until it's being watched till
the end, which will cause it to part that list and be added to the watch
history.</p>
<p>To be fair, I haven't being testing this extensively, and this last one is a
feature I've developed just in a few hours during this weekend, so I wouldn't
be surprised if there are serious bugs in it. But hey, that's part of the
adrenaline which comes with hobby projects, I guess.</p><p>It has been a while since I last posted about
<a href="https://gitlab.com/mardy/mitubo">MiTubo</a>, despite releasing a few new versions
in the last months. But now I think that there is enough new stuff that's worth
a mention here.</p>
<p></p><center>
<figure>
<a href="http://mardy.it/archivos/imagines/blog/Mitubo-search.png"><img src="http://mardy.it/archivos/imagines/blog/Mitubo-search.png" width="80%"></a>
<figcaption>Search on YouTube</figcaption>
</figure>
<p></p></center>
<p>Initially MiTubo only came with a search feature that was using Yandex video as
a backend; while that worked generally well, most of the returned results were
not playable due to youtube-dl being unable to extract the video information
from the returned web pages. So, now we have the option to search on YouTube,
via the <a href="https://invidious.io/">Invidious API</a>; furthermore, it's also possible
to search for channels, whose RSS feed can then be added as a subscription.</p>
<p>One other thing that has always bothered me is not being able to enqueue a new
video while watching another one, without having to pause the current one, go
back to the main page, add the new video to a playlist, go back to the current
video, and finally, once that is over, open the playlist and start the new
video.</p>
<p></p><center>
<figure>
<a href="http://mardy.it/archivos/imagines/blog/Mitubo-dnd.png"><img src="http://mardy.it/archivos/imagines/blog/Mitubo-dnd.png" width="80%"></a>
<figcaption>Drag and drop a new URL while watching a video</figcaption>
</figure>
<p></p></center>
<p>So now we have that. One can drag and drop an URL (or even a longer text
containing several URLs) while watching another video, and a popup will appear
with a few choices (see the screenshot above). I've also added a “Next” button
next to the “Play” one, which is enabled if the “Watch later” playlist is not
empty, and does the obvious thing when pressed. Once started, the new video is
automatically removed from the “Watch later” playlist and moved into the
“Continue watching” list, where it will remain until it's being watched till
the end, which will cause it to part that list and be added to the watch
history.</p>
<p>To be fair, I haven't being testing this extensively, and this last one is a
feature I've developed just in a few hours during this weekend, so I wouldn't
be surprised if there are serious bugs in it. But hey, that's part of the
adrenaline which comes with hobby projects, I guess.</p>Debugging the “Factory mode” of BQ devices in Ubuntu Touchhttp://mardy.it/it/blog/2021/12/debugging-the-factory-mode-of-bq-devices-in-ubuntu-touch.html2021-12-25T10:13:54+03:002021-12-25T10:13:54+03:00Alberto Mardegan<p>As you know, I'm trying to <a href="http://mardy.it/it/blog/2021/12/enabling-the-fm-radio-in-ubuntu-touch.html">get the FM radio to work in Ubuntu
Touch</a>, and I basically have
it working on the Redmi Note 7 Pro. But then I remembered that the BQ Aquaris
E4.5 (which is the first commercial device officially supporting Ubuntu Touch)
also comes with an FM radio, so I decided to put some effort in getting that to
work, too. You might think it's a waste of time, but as a matter of fact this
device is built on a Mediatek SoC, and FM radio support is exposed to userspace
in a very similar way across all Mediatek devices — so this work should be
covering other devices as well.</p>
<p>It was relatively easy to get the FM radio to work on this phone: I can now
tune to a frequency and see that the RDS data is received, but I cannot get any
sound out of the speakers or headphones, which makes the whole radio experience
a bit, uhm… suboptimal, let's say.</p>
<p>The problem is not new: back in the days when Ubuntu Touch was still supported
by Canonical, <a href="http://www.lieberbiber.de/">sturmflut</a> was trying to get the FM
radio to work, and he met the same issues (see
<a href="https://lists.launchpad.net/ubuntu-phone/msg17256.html">this</a> and
<a href="https://lists.launchpad.net/ubuntu-phone/msg17340.html">this</a> messages in the
mailing list). He also spent some time investigating how the <a href="http://sturmflut.github.io/ubuntu/bq/2015/05/04/hacking-the-bq-part-2-factory-mode/">Factory
mode</a>
works (the FM radio is indeed one of the features that can be tested via the
Factory mode, and it <em>does</em> work) and he mentioned that he could get <code>gdb</code> to
attach to the factory mode program and could see the various <code>ioctl</code>s being
executed. Yesterday I tried to follow the same steps, but I failed quite soon:
I simply could not connect with <code>adb shell</code> while the device was in factory
mode, so no chances of debugging for me. ☹</p>
<p>Out of dispair, I tried just to manually run the program <code>/system/bin/factory</code>
inside a Lomiri session and, to my surprise, it overlayed its yellow “Factory
Mode” title on the screen — just to immediately quit afterwards. I tried
running it with <code>strace</code>, and noticed these lines:</p>
<div class="code"><pre class="code literal-block">open("/sys/class/BOOT/BOOT/boot/boot_mode", O_RDWR|O_LARGEFILE) = 15
read(15, "0\n", 4) = 2
close(15) = 0
writev(5, [{"\3", 1}, {"FTM\0", 4}, {"[FTM UTILS] Unsupported factory "..., 39}], 3) = 44
writev(5, [{"\6", 1}, {"NVRAM\0", 6}, {"[MAIN] Unsupported Factory mode\n"..., 33}], 3) = 40
</pre></div>
<p>Of course, the <code>/sys/class/BOOT/BOOT/boot/boot_mode</code> file is read-only, so I
couldn't just write <code>1</code> into it, but could a bind-mount work? Indeed it did!
And after a few attempts, I verified that writing a value of <code>4</code> in the
<code>boot_mode</code> file made the factory program happy. It was still unusable because
it was acting as if the volume down button was being constantly pressed, so the
cursor was always moving downwards, but killing the Lomiri session did the
trick.
In short, these are the steps you need to follow in order to run the Factory
Mode from an ordinary boot session:</p>
<div class="code"><pre class="code literal-block">sudo<span class="w"> </span>-i<span class="w"> </span><span class="c1"># become root</span>
<span class="nb">echo</span><span class="w"> </span><span class="m">4</span><span class="w"> </span>><span class="w"> </span>/tmp/trick
mount<span class="w"> </span>-o<span class="w"> </span><span class="nb">bind</span><span class="w"> </span>/tmp/trick<span class="w"> </span>/sys/class/BOOT/BOOT/boot/boot_mode
service<span class="w"> </span>lightdm<span class="w"> </span>stop<span class="w"> </span><span class="c1"># wait a few seconds until this returns</span>
<span class="nb">unset</span><span class="w"> </span>LD_PRELOAD
/system/bin/factory
</pre></div>
<p>What is more surprising, is that the FM radio test is working even in this
environment, and you can actually hear the sounds (for some reason, the FM
radio item takes about 40 seconds to initialize when run under these
conditions, but it eventually works). At this point, not only I could run <code>gdb</code>
(which I didn't), but I could even run the <code>factory</code> program under strace and
collect the logs.</p>
<p>At the moment of writing this post, I haven't yet examined the logs, so I'm not
at all sure that they'll be enough to make audio work (I suspect that the
factory mode binary might be playing some tricks that are somehow not
replicable in a proper Linux system with Pulseaudio and lots of other services
running), but I do have enough information to make at least a few attempts.</p>
<p>Stay tuned, and have a Merry Christmas!</p><p>As you know, I'm trying to <a href="http://mardy.it/it/blog/2021/12/enabling-the-fm-radio-in-ubuntu-touch.html">get the FM radio to work in Ubuntu
Touch</a>, and I basically have
it working on the Redmi Note 7 Pro. But then I remembered that the BQ Aquaris
E4.5 (which is the first commercial device officially supporting Ubuntu Touch)
also comes with an FM radio, so I decided to put some effort in getting that to
work, too. You might think it's a waste of time, but as a matter of fact this
device is built on a Mediatek SoC, and FM radio support is exposed to userspace
in a very similar way across all Mediatek devices — so this work should be
covering other devices as well.</p>
<p>It was relatively easy to get the FM radio to work on this phone: I can now
tune to a frequency and see that the RDS data is received, but I cannot get any
sound out of the speakers or headphones, which makes the whole radio experience
a bit, uhm… suboptimal, let's say.</p>
<p>The problem is not new: back in the days when Ubuntu Touch was still supported
by Canonical, <a href="http://www.lieberbiber.de/">sturmflut</a> was trying to get the FM
radio to work, and he met the same issues (see
<a href="https://lists.launchpad.net/ubuntu-phone/msg17256.html">this</a> and
<a href="https://lists.launchpad.net/ubuntu-phone/msg17340.html">this</a> messages in the
mailing list). He also spent some time investigating how the <a href="http://sturmflut.github.io/ubuntu/bq/2015/05/04/hacking-the-bq-part-2-factory-mode/">Factory
mode</a>
works (the FM radio is indeed one of the features that can be tested via the
Factory mode, and it <em>does</em> work) and he mentioned that he could get <code>gdb</code> to
attach to the factory mode program and could see the various <code>ioctl</code>s being
executed. Yesterday I tried to follow the same steps, but I failed quite soon:
I simply could not connect with <code>adb shell</code> while the device was in factory
mode, so no chances of debugging for me. ☹</p>
<p>Out of dispair, I tried just to manually run the program <code>/system/bin/factory</code>
inside a Lomiri session and, to my surprise, it overlayed its yellow “Factory
Mode” title on the screen — just to immediately quit afterwards. I tried
running it with <code>strace</code>, and noticed these lines:</p>
<div class="code"><pre class="code literal-block">open("/sys/class/BOOT/BOOT/boot/boot_mode", O_RDWR|O_LARGEFILE) = 15
read(15, "0\n", 4) = 2
close(15) = 0
writev(5, [{"\3", 1}, {"FTM\0", 4}, {"[FTM UTILS] Unsupported factory "..., 39}], 3) = 44
writev(5, [{"\6", 1}, {"NVRAM\0", 6}, {"[MAIN] Unsupported Factory mode\n"..., 33}], 3) = 40
</pre></div>
<p>Of course, the <code>/sys/class/BOOT/BOOT/boot/boot_mode</code> file is read-only, so I
couldn't just write <code>1</code> into it, but could a bind-mount work? Indeed it did!
And after a few attempts, I verified that writing a value of <code>4</code> in the
<code>boot_mode</code> file made the factory program happy. It was still unusable because
it was acting as if the volume down button was being constantly pressed, so the
cursor was always moving downwards, but killing the Lomiri session did the
trick.
In short, these are the steps you need to follow in order to run the Factory
Mode from an ordinary boot session:</p>
<div class="code"><pre class="code literal-block">sudo<span class="w"> </span>-i<span class="w"> </span><span class="c1"># become root</span>
<span class="nb">echo</span><span class="w"> </span><span class="m">4</span><span class="w"> </span>><span class="w"> </span>/tmp/trick
mount<span class="w"> </span>-o<span class="w"> </span><span class="nb">bind</span><span class="w"> </span>/tmp/trick<span class="w"> </span>/sys/class/BOOT/BOOT/boot/boot_mode
service<span class="w"> </span>lightdm<span class="w"> </span>stop<span class="w"> </span><span class="c1"># wait a few seconds until this returns</span>
<span class="nb">unset</span><span class="w"> </span>LD_PRELOAD
/system/bin/factory
</pre></div>
<p>What is more surprising, is that the FM radio test is working even in this
environment, and you can actually hear the sounds (for some reason, the FM
radio item takes about 40 seconds to initialize when run under these
conditions, but it eventually works). At this point, not only I could run <code>gdb</code>
(which I didn't), but I could even run the <code>factory</code> program under strace and
collect the logs.</p>
<p>At the moment of writing this post, I haven't yet examined the logs, so I'm not
at all sure that they'll be enough to make audio work (I suspect that the
factory mode binary might be playing some tricks that are somehow not
replicable in a proper Linux system with Pulseaudio and lots of other services
running), but I do have enough information to make at least a few attempts.</p>
<p>Stay tuned, and have a Merry Christmas!</p>Enabling the FM radio in Ubuntu Touchhttp://mardy.it/it/blog/2021/12/enabling-the-fm-radio-in-ubuntu-touch.html2021-12-07T19:41:26+03:002021-12-07T19:41:26+03:00Alberto Mardegan<p>I recently realized that my Xiaomi Redmi Note 7 Pro, on which <a href="http://mardy.it/it/blog/2021/01/ubuntu-touch-porting-notes-for-the-redmi-note-7-pro.html">I installed
Ubuntu Touch not so long
ago</a>, has a
working FM radio. One of the many psychological bugs of mine is the irrational
urge I feel of having my hardware, no matter whether I use it or not,
<a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8c47311d34eccedb06bc60fc9435a53bd4aff392">supported by
Linux</a>.
So, the fact that I never listen to the radio is unfortunately not a reason to
dissuade me from wasting time on getting the FM radio working in Ubuntu Touch.</p>
<p>This post is a quick summary of my investigation, which should serve as a note
keeper for when I'll actually get to implement the feature.</p>
<h4>The Android story</h4>
<p>It was a bit surprising to find out that Android does not offer an API to use
the FM radio, meaning that we cannot simply expose an API via libhybris. Every
manufacturer is therefore choosing their own API, and Android applications are
most often developed for a specific chipset family, or need to carry the code
to support all the various devices.</p>
<p>For example, I found the <a href="https://github.com/vladislav805/RFM-Radio">RFM Radio Android
application</a> which supports a few
Qualcomm Snapdragon processors, for which the FM radio functionality is exposed
by a kernel driver via the V4L API. This means that the FM radio is probably
working out of the box with <a href="https://code.qt.io/cgit/qt/qtmultimedia.git/tree/src/plugins/v4l?h=5.12">QtMultimedia's
QRadioTuner</a>.
Unfortunately the Note 7 Pro uses a newer Snapdragon, and even after some days
of investigations <a href="https://www.spinics.net/lists/linux-arm-msm/msg98952.html">I couldn't find out how the radio driver communicates to the
userspace</a>; but more
on this below. Other chipsets offer other APIs, and I was glad to find that
someone already wrote a <a href="https://github.com/Venji10/fmradio-volla">Ubuntu Touch FM radio application for the Volla
phone</a>, which has a Mediatek board.</p>
<p>Anyway, the lack of a unified FM radio API is probably the reason why most of
the so-called “FM radio” applications on Android are not really using the FM
radio but rather streaming audio from the internet.</p>
<h4>The FM radio in the Note 7 Pro</h4>
<p>Before I start talking about a phone that no one cares about, let me say that
what I'm going to write applies to several other Snapdragon chipsets and could
be relevant to other phones. For one, the Redmi Note 9 Pro uses the very same
bluetooth chipset as the Note 7 Pro (and in case you are wondering why I
mentioned bluetooth, it's because the FM radio functionality is delivered by
the same BT chip), so all what I'm going to write here is also relevant for
that phone.</p>
<p>In order to figure out how the radio worked on this device, I took the drastic
decision to reflash the stock Android (well, MIUI), started the preinstalled FM
radio application, and meanwhile looked at the logcat messages (I'm not sure if
this is needed, but before doing so I went to the “Developer options” in the
system settings and set the debugging level to the maximum). Among a lot of
noise, this showed me lines like these:</p>
<div class="code"><pre class="code literal-block">I android_hardware_fm: Opened fm_helium.so shared object library successfully
I android_hardware_fm: Obtaining handle: 'FM_HELIUM_LIB_INTERFACE' to the shared object library...
D FmReceiverJNI: init native called
D android_hardware_fm: BT soc is cherokee
I android_hardware_fm: Init native called
I android_hardware_fm: Initializing the FM HAL module & registering the JNI callback functions...
D radio_helium: ++hal_init
D fm_hci : ++fm_hci_init
I fm_hci : hci_initialize
</pre></div>
<p>Well, even without knowing nothing about all what these lines meant, I had
something I could search the internet for. So I found <a href="https://source.codeaurora.org/quic/la/platform/vendor/qcom-opensource/fm-commonsys">the Qualcomm FM code in
CodeAurora</a>,
and search for the code relative to my Snapdragon 675 (aka <code>sm6150</code>). I quickly
gave up on trying to make some sense out of the git tag naming in that
repository, and just tried to search for a tag which could be referring to my
device. I found one, and started browsing <a href="https://source.codeaurora.org/quic/la/platform/vendor/qcom-opensource/fm-commonsys/tree/?h=LA.UM.7.9.r1-11400-sm6150.0">its source
tree</a>.</p>
<p>It turns out that Qualcomm provides a Java package which applications can use,
and which internally <code>dlopen()</code>s the <code>fm_helium.so</code> library, which in turn
depends on the <code>libfm_hci.so</code> library. I had a quick look at the source code of
these libraries, which are also present in the repository, but decided that I
would have had more chances of success if I just tried to follow the JNI code,
and in particular the
<a href="https://source.codeaurora.org/quic/la/platform/vendor/qcom-opensource/fm-commonsys/tree/jni/android_hardware_fm.cpp?h=LA.UM.7.9.r1-11400-sm6150.0"><code>android_hardware_fm.cpp</code></a>
file. I'm not sure why this code is not using the C structure types defined in
the headers provided by the helium library, and instead redefines all the
constants and accesses the character buffers by offsets — it might be just for
historical reasons — but in any case I decided to follow along.</p>
<h4>The <code>fm-bridge</code> program</h4>
<p>Since we have a rather net separation between the Ubuntu Touch and the Android
worlds (the Android services are running inside an LXC container, with all
their Android libs and dependencies), one should not attempt to write an Ubuntu
process that loads the Android libraries, because the libc used in Android is
different, so things are likely not to work. But we can have Ubuntu and Android
processes communicate over a socket or other kind of IPC; so, what I decided to
go for, is writing a small C program that will live in the Android side, it
will talk to the FM radio (via <code>helium_fm</code>), and accept commands / give replies
via its <code>stdin</code> / <code>stdout</code>.</p>
<p>I unimaginatively called it “<code>fm-bridge</code>”, and you can look at its horrible
code <a href="https://gitlab.com/ubuntu-touch-xiaomi-violet/fm-bridge">here</a>. Really, I
just said it was terrible, so why did you look at it? I definitely need to
rewrite it from scratch, possibly using the helium headers, but as a proof of
concept this also works. Then I carefully examined the logcat output while
using the MIUI FM radio application in Android, and figured out what was the
command sequence I had to input into <code>fm-bridge</code>'s standard input in order to
have it tune onto a given frequency. I'm publishing the commands here too,
should I ever lose my notes:</p>
<div class="code"><pre class="code literal-block">enableSlimbus 1
setControl 0x8000004 1
enableSoftMute 1
setControl 0x8000029 0
setControl 0x800000c 1
setControl 0x800000d 1
setControl 0x800000e 1
setControl 0x800002b 0
setControl 0x8000007 4
setControl 0x8000006 0x40
setControl 0x8000006 0x40
setControl 0x8000011 0
setControl 0x800000f 1
getControl 0x8000010
setControl 0x8000010 0xef
setControl 0x800000f 1
setControl 0x800001b 1
setControl 0x8000012 0
setFreq 89300
setMonoStereo 1
</pre></div>
<p>I'm sure that not all of them are needed, but I'll figure out the optimal
sequence later. In order to use this program on Ubuntu Touch, I had to alter
the vendor partition to add this program, but also the <code>fm_helium.so</code> and
<code>libfm_hci.so</code> libraries (more on that below).</p>
<p>When feeding the above commands to the <code>fm-bridge</code> in Ubuntu, I saw that I was
getting a logcat output similar to the one from Android, which was mildly
comforting. No sound was comint out of the speaker or out of the earplugs, but
I was hardly expecting it all to work at the first try. And I got convinced
that the FM tuner was indeed working, because typing the command “<code>startSearch
1</code>” made a new frequency appear in the logs, proving that the tuner had found
another station and tuned onto it.</p>
<h4>Getting the sound out</h4>
<p>This was actually the easiest of the steps, thanks to the Ubuntu Touch FM radio
application we have for the Volla: its source code mentions a few pulseaudio
commands that worked perfectly in the Note 7 Pro too, despite the fact that the
underlying chipset is totally different. This should not be as surprising as it
might sound like, given that Android has a common audio API.</p>
<p>Just for my future reference, the commands are these:</p>
<div class="code"><pre class="code literal-block">pacmd set-source-port 1 input-fm_tuner
pactl load-module module-loopback source=1 sink=0
</pre></div>
<p>Ta-daaa! The radio was now playing from the phone loudspeakers! It was indeed
quite loud, and the volume buttons did not seem to have any effect on it, but
the volume can be controlled with pulseaudio:</p>
<div class="code"><pre class="code literal-block">pactl set-source-volume 1 50%
</pre></div>
<p>Of course, if we ever manage to make this into an Ubuntu Touch feature, we'll
have to find a way to make the volume respond to the volume buttons.</p>
<h4>Addind the needed files to the vendor partition</h4>
<p>The simplest approach (and the one I took initially) is that of downloading the
<code>vendor.img</code> into your PC, loop-mounting it, adding the <code>fm_helium.so</code>,
<code>libfm_hci.so</code> and <code>fm-bridge</code> files to it and then umount the partition and
reflash it (remembering to converting it from/to a sparse image before
downloading/uploading it). This approach works flawlessly, but I'm wondering if
one might incur into issues if the version of the NDK used to compile fm-bridge
is different from the one that was used to compile the other vendor binaries,
so I decided to give it a try to build the whole vendor partition myself.</p>
<p>This turned out to be a non trivial process, because I was using the Halium
tree to build the vendor image, and not the LineageOS which was used to build
the vendor image for my device: I could make an image, but it took some time
before I figured out which were the needed packages that somehow got lost
because of the Halium changes and that <a href="https://gitlab.com/ubuntu-touch-xiaomi-violet/android_vendor_xiaomi_violet/-/commit/495c83065c1f135d84c8e08563cece4fd4e4d3a5">had to be added to the
Makefile</a>.</p>
<p>To help my weak memory, I expanded the <a href="https://gitlab.com/ubports/community-ports/android9/xiaomi-redmi-note-7-pro/xiaomi-violet/-/blob/master/README.md">README file in the <code>violet</code>
port</a>
with the steps needed in order to build the vendor image.</p>
<h4>A system service for the FM radio</h4>
<p>While it could be possible for Ubuntu Touch applications to directly access the
FM radio device in the same way that Android applications do, this is
suboptimal for a few reasons. Even if we provided a shared library to deal with
the various radio chipset implementations, the application would either need to
be unconfined, or we'd had to provide an ever-changing AppArmor profile that
peeks new holes every time that a new device implementation is added (and what
if this implemenation uses a generic kernel device, which could be used for
other goals too?) and in any case we'd have to make this policy restricted,
since the RDS data provided by the radio stations would reveal the user
location (well, the city at least) to the application. Not to talk about
concurrent access to the radio device if two applications attempt to use it.</p>
<p>Therefore, my proposition (and what I'll implement, if I'll live long enough or
if someone doesn't beat me to it) is to have a system service deal with the
various hardware differences and expose a D-Bus API that will be hooked up as a
QRadioTunerControl plugin, so that Qt applications will be able to just use the
QtMultimedia APIs to access the radio.</p>
<p>The service would also need to talk to the trust-store, to let the user decide
whether the application should really be granted access to the FM receiver (and
when using the turst-store, this decision is remembered, and revocable from the
System Settings's Security panel). Of course we'll also need to add a
<code>fm-radio</code> AppArmor policy to let applications use this service.</p><p>I recently realized that my Xiaomi Redmi Note 7 Pro, on which <a href="http://mardy.it/it/blog/2021/01/ubuntu-touch-porting-notes-for-the-redmi-note-7-pro.html">I installed
Ubuntu Touch not so long
ago</a>, has a
working FM radio. One of the many psychological bugs of mine is the irrational
urge I feel of having my hardware, no matter whether I use it or not,
<a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8c47311d34eccedb06bc60fc9435a53bd4aff392">supported by
Linux</a>.
So, the fact that I never listen to the radio is unfortunately not a reason to
dissuade me from wasting time on getting the FM radio working in Ubuntu Touch.</p>
<p>This post is a quick summary of my investigation, which should serve as a note
keeper for when I'll actually get to implement the feature.</p>
<h4>The Android story</h4>
<p>It was a bit surprising to find out that Android does not offer an API to use
the FM radio, meaning that we cannot simply expose an API via libhybris. Every
manufacturer is therefore choosing their own API, and Android applications are
most often developed for a specific chipset family, or need to carry the code
to support all the various devices.</p>
<p>For example, I found the <a href="https://github.com/vladislav805/RFM-Radio">RFM Radio Android
application</a> which supports a few
Qualcomm Snapdragon processors, for which the FM radio functionality is exposed
by a kernel driver via the V4L API. This means that the FM radio is probably
working out of the box with <a href="https://code.qt.io/cgit/qt/qtmultimedia.git/tree/src/plugins/v4l?h=5.12">QtMultimedia's
QRadioTuner</a>.
Unfortunately the Note 7 Pro uses a newer Snapdragon, and even after some days
of investigations <a href="https://www.spinics.net/lists/linux-arm-msm/msg98952.html">I couldn't find out how the radio driver communicates to the
userspace</a>; but more
on this below. Other chipsets offer other APIs, and I was glad to find that
someone already wrote a <a href="https://github.com/Venji10/fmradio-volla">Ubuntu Touch FM radio application for the Volla
phone</a>, which has a Mediatek board.</p>
<p>Anyway, the lack of a unified FM radio API is probably the reason why most of
the so-called “FM radio” applications on Android are not really using the FM
radio but rather streaming audio from the internet.</p>
<h4>The FM radio in the Note 7 Pro</h4>
<p>Before I start talking about a phone that no one cares about, let me say that
what I'm going to write applies to several other Snapdragon chipsets and could
be relevant to other phones. For one, the Redmi Note 9 Pro uses the very same
bluetooth chipset as the Note 7 Pro (and in case you are wondering why I
mentioned bluetooth, it's because the FM radio functionality is delivered by
the same BT chip), so all what I'm going to write here is also relevant for
that phone.</p>
<p>In order to figure out how the radio worked on this device, I took the drastic
decision to reflash the stock Android (well, MIUI), started the preinstalled FM
radio application, and meanwhile looked at the logcat messages (I'm not sure if
this is needed, but before doing so I went to the “Developer options” in the
system settings and set the debugging level to the maximum). Among a lot of
noise, this showed me lines like these:</p>
<div class="code"><pre class="code literal-block">I android_hardware_fm: Opened fm_helium.so shared object library successfully
I android_hardware_fm: Obtaining handle: 'FM_HELIUM_LIB_INTERFACE' to the shared object library...
D FmReceiverJNI: init native called
D android_hardware_fm: BT soc is cherokee
I android_hardware_fm: Init native called
I android_hardware_fm: Initializing the FM HAL module & registering the JNI callback functions...
D radio_helium: ++hal_init
D fm_hci : ++fm_hci_init
I fm_hci : hci_initialize
</pre></div>
<p>Well, even without knowing nothing about all what these lines meant, I had
something I could search the internet for. So I found <a href="https://source.codeaurora.org/quic/la/platform/vendor/qcom-opensource/fm-commonsys">the Qualcomm FM code in
CodeAurora</a>,
and search for the code relative to my Snapdragon 675 (aka <code>sm6150</code>). I quickly
gave up on trying to make some sense out of the git tag naming in that
repository, and just tried to search for a tag which could be referring to my
device. I found one, and started browsing <a href="https://source.codeaurora.org/quic/la/platform/vendor/qcom-opensource/fm-commonsys/tree/?h=LA.UM.7.9.r1-11400-sm6150.0">its source
tree</a>.</p>
<p>It turns out that Qualcomm provides a Java package which applications can use,
and which internally <code>dlopen()</code>s the <code>fm_helium.so</code> library, which in turn
depends on the <code>libfm_hci.so</code> library. I had a quick look at the source code of
these libraries, which are also present in the repository, but decided that I
would have had more chances of success if I just tried to follow the JNI code,
and in particular the
<a href="https://source.codeaurora.org/quic/la/platform/vendor/qcom-opensource/fm-commonsys/tree/jni/android_hardware_fm.cpp?h=LA.UM.7.9.r1-11400-sm6150.0"><code>android_hardware_fm.cpp</code></a>
file. I'm not sure why this code is not using the C structure types defined in
the headers provided by the helium library, and instead redefines all the
constants and accesses the character buffers by offsets — it might be just for
historical reasons — but in any case I decided to follow along.</p>
<h4>The <code>fm-bridge</code> program</h4>
<p>Since we have a rather net separation between the Ubuntu Touch and the Android
worlds (the Android services are running inside an LXC container, with all
their Android libs and dependencies), one should not attempt to write an Ubuntu
process that loads the Android libraries, because the libc used in Android is
different, so things are likely not to work. But we can have Ubuntu and Android
processes communicate over a socket or other kind of IPC; so, what I decided to
go for, is writing a small C program that will live in the Android side, it
will talk to the FM radio (via <code>helium_fm</code>), and accept commands / give replies
via its <code>stdin</code> / <code>stdout</code>.</p>
<p>I unimaginatively called it “<code>fm-bridge</code>”, and you can look at its horrible
code <a href="https://gitlab.com/ubuntu-touch-xiaomi-violet/fm-bridge">here</a>. Really, I
just said it was terrible, so why did you look at it? I definitely need to
rewrite it from scratch, possibly using the helium headers, but as a proof of
concept this also works. Then I carefully examined the logcat output while
using the MIUI FM radio application in Android, and figured out what was the
command sequence I had to input into <code>fm-bridge</code>'s standard input in order to
have it tune onto a given frequency. I'm publishing the commands here too,
should I ever lose my notes:</p>
<div class="code"><pre class="code literal-block">enableSlimbus 1
setControl 0x8000004 1
enableSoftMute 1
setControl 0x8000029 0
setControl 0x800000c 1
setControl 0x800000d 1
setControl 0x800000e 1
setControl 0x800002b 0
setControl 0x8000007 4
setControl 0x8000006 0x40
setControl 0x8000006 0x40
setControl 0x8000011 0
setControl 0x800000f 1
getControl 0x8000010
setControl 0x8000010 0xef
setControl 0x800000f 1
setControl 0x800001b 1
setControl 0x8000012 0
setFreq 89300
setMonoStereo 1
</pre></div>
<p>I'm sure that not all of them are needed, but I'll figure out the optimal
sequence later. In order to use this program on Ubuntu Touch, I had to alter
the vendor partition to add this program, but also the <code>fm_helium.so</code> and
<code>libfm_hci.so</code> libraries (more on that below).</p>
<p>When feeding the above commands to the <code>fm-bridge</code> in Ubuntu, I saw that I was
getting a logcat output similar to the one from Android, which was mildly
comforting. No sound was comint out of the speaker or out of the earplugs, but
I was hardly expecting it all to work at the first try. And I got convinced
that the FM tuner was indeed working, because typing the command “<code>startSearch
1</code>” made a new frequency appear in the logs, proving that the tuner had found
another station and tuned onto it.</p>
<h4>Getting the sound out</h4>
<p>This was actually the easiest of the steps, thanks to the Ubuntu Touch FM radio
application we have for the Volla: its source code mentions a few pulseaudio
commands that worked perfectly in the Note 7 Pro too, despite the fact that the
underlying chipset is totally different. This should not be as surprising as it
might sound like, given that Android has a common audio API.</p>
<p>Just for my future reference, the commands are these:</p>
<div class="code"><pre class="code literal-block">pacmd set-source-port 1 input-fm_tuner
pactl load-module module-loopback source=1 sink=0
</pre></div>
<p>Ta-daaa! The radio was now playing from the phone loudspeakers! It was indeed
quite loud, and the volume buttons did not seem to have any effect on it, but
the volume can be controlled with pulseaudio:</p>
<div class="code"><pre class="code literal-block">pactl set-source-volume 1 50%
</pre></div>
<p>Of course, if we ever manage to make this into an Ubuntu Touch feature, we'll
have to find a way to make the volume respond to the volume buttons.</p>
<h4>Addind the needed files to the vendor partition</h4>
<p>The simplest approach (and the one I took initially) is that of downloading the
<code>vendor.img</code> into your PC, loop-mounting it, adding the <code>fm_helium.so</code>,
<code>libfm_hci.so</code> and <code>fm-bridge</code> files to it and then umount the partition and
reflash it (remembering to converting it from/to a sparse image before
downloading/uploading it). This approach works flawlessly, but I'm wondering if
one might incur into issues if the version of the NDK used to compile fm-bridge
is different from the one that was used to compile the other vendor binaries,
so I decided to give it a try to build the whole vendor partition myself.</p>
<p>This turned out to be a non trivial process, because I was using the Halium
tree to build the vendor image, and not the LineageOS which was used to build
the vendor image for my device: I could make an image, but it took some time
before I figured out which were the needed packages that somehow got lost
because of the Halium changes and that <a href="https://gitlab.com/ubuntu-touch-xiaomi-violet/android_vendor_xiaomi_violet/-/commit/495c83065c1f135d84c8e08563cece4fd4e4d3a5">had to be added to the
Makefile</a>.</p>
<p>To help my weak memory, I expanded the <a href="https://gitlab.com/ubports/community-ports/android9/xiaomi-redmi-note-7-pro/xiaomi-violet/-/blob/master/README.md">README file in the <code>violet</code>
port</a>
with the steps needed in order to build the vendor image.</p>
<h4>A system service for the FM radio</h4>
<p>While it could be possible for Ubuntu Touch applications to directly access the
FM radio device in the same way that Android applications do, this is
suboptimal for a few reasons. Even if we provided a shared library to deal with
the various radio chipset implementations, the application would either need to
be unconfined, or we'd had to provide an ever-changing AppArmor profile that
peeks new holes every time that a new device implementation is added (and what
if this implemenation uses a generic kernel device, which could be used for
other goals too?) and in any case we'd have to make this policy restricted,
since the RDS data provided by the radio stations would reveal the user
location (well, the city at least) to the application. Not to talk about
concurrent access to the radio device if two applications attempt to use it.</p>
<p>Therefore, my proposition (and what I'll implement, if I'll live long enough or
if someone doesn't beat me to it) is to have a system service deal with the
various hardware differences and expose a D-Bus API that will be hooked up as a
QRadioTunerControl plugin, so that Qt applications will be able to just use the
QtMultimedia APIs to access the radio.</p>
<p>The service would also need to talk to the trust-store, to let the user decide
whether the application should really be granted access to the FM receiver (and
when using the turst-store, this decision is remembered, and revocable from the
System Settings's Security panel). Of course we'll also need to add a
<code>fm-radio</code> AppArmor policy to let applications use this service.</p>