<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Phonon on Roberto Selbach</title><link>https://rselbach.com/tags/phonon/</link><description>Recent content in Phonon on Roberto Selbach</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Tue, 07 Oct 2008 20:32:00 +0000</lastBuildDate><atom:link href="https://rselbach.com/tags/phonon/index.xml" rel="self" type="application/rss+xml"/><item><title>Phonon and the Boring Audio Button</title><link>https://rselbach.com/phonon-and-the-boring-audio-button/</link><pubDate>Tue, 07 Oct 2008 20:32:00 +0000</pubDate><guid>https://rselbach.com/phonon-and-the-boring-audio-button/</guid><description>&lt;p&gt;My sound preview worked with the Xine Phonon backend and failed as soon as I switched the machine to GStreamer. Same file, same button, no sound. So much for my five-line multimedia triumph.&lt;/p&gt;
&lt;p&gt;The application called &lt;code&gt;play()&lt;/code&gt; and immediately checked &lt;code&gt;state()&lt;/code&gt;. Xine reached &lt;code&gt;PlayingState&lt;/code&gt; quickly on my machine. GStreamer was still in &lt;code&gt;LoadingState&lt;/code&gt;, which my code treated as failure and answered with &lt;code&gt;stop()&lt;/code&gt;. I had accidentally made backend speed part of the program&amp;rsquo;s contract.&lt;/p&gt;
&lt;p&gt;Phonon state changes are asynchronous. The fix was to let the &lt;code&gt;MediaObject&lt;/code&gt; report &lt;code&gt;stateChanged()&lt;/code&gt; and handle &lt;code&gt;ErrorState&lt;/code&gt; there instead of demanding synchronous playback:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;connect(media, SIGNAL(stateChanged(Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;State, Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;State)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, SLOT(mediaStateChanged(Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;State, Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;State)));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;media&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;setCurrentSource(fileName);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;media&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;play();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The slot updates the button when playback really starts and displays &lt;code&gt;errorString()&lt;/code&gt; if the object enters &lt;code&gt;ErrorState&lt;/code&gt;. &lt;code&gt;LoadingState&lt;/code&gt; is just progress, not proof that the backend rejected the file.&lt;/p&gt;
&lt;p&gt;Switching backends was useful precisely because it broke this. The common API kept Xine and GStreamer details out of the application, but it did not turn asynchronous operations into synchronous ones. One backend had merely been fast enough to hide my bad assumption.&lt;/p&gt;
&lt;p&gt;The preview button is boring again. I left both backends in the test pass; otherwise the next timing assumption will wait for a user to find it.&lt;/p&gt;</description></item><item><title>Phonon Is Not a Codec Collection</title><link>https://rselbach.com/phonon-is-not-a-codec-collection/</link><pubDate>Fri, 07 Jul 2006 17:39:00 +0000</pubDate><guid>https://rselbach.com/phonon-is-not-a-codec-collection/</guid><description>&lt;p&gt;A test player handled one Ogg file and failed on another machine before lunch. My first reaction was to ask which Phonon codec was missing. That question contains the bug in my mental model.&lt;/p&gt;
&lt;p&gt;Phonon is intended as a multimedia API above actual playback engines. The application builds a graph of media objects, audio outputs, and paths. A backend translates that graph to whatever engine is available. Codec support therefore depends on the backend and its installed components, not on Phonon carrying a suitcase of decoders.&lt;/p&gt;
&lt;p&gt;The small playback case looks roughly like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;MediaObject &lt;span style="color:#f92672"&gt;*&lt;/span&gt;media &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;MediaObject(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;AudioOutput &lt;span style="color:#f92672"&gt;*&lt;/span&gt;output &lt;span style="color:#f92672"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;AudioOutput(Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;MusicCategory, &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;createPath(media, output);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;media&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;setCurrentSource(Phonon&lt;span style="color:#f92672"&gt;::&lt;/span&gt;MediaSource(fileName));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;media&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;play();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The category matters. It describes the purpose of the sound so system policy can distinguish music from notifications or communication. It is not merely a friendly enum to satisfy the compiler.&lt;/p&gt;
&lt;p&gt;Errors remain asynchronous. Calling &lt;code&gt;play()&lt;/code&gt; starts a process; it does not certify that bytes will reach speakers. The application must listen for state changes and present the backend&amp;rsquo;s error without pretending every failure is a missing file.&lt;/p&gt;
&lt;p&gt;I prefer depending on a narrow playback abstraction instead of teaching each KDE application the details of several multimedia engines. That should make device selection and policy consistent. The caveat is the least-common-denominator problem: specialised editors and unusual pipelines may need capabilities the abstraction cannot sensibly expose.&lt;/p&gt;
&lt;p&gt;I am also avoiding backend detection in the application. Branching on a backend name would make today&amp;rsquo;s workaround tomorrow&amp;rsquo;s required behaviour. If a capability is necessary, the API should expose that capability or the application should report that it cannot perform the operation.&lt;/p&gt;
&lt;p&gt;For porting, I am keeping the boundary obvious. The document remembers a URL and playback position; a small controller owns Phonon objects; widgets issue commands and display state. This makes backend surprises testable without turning the main window into an audio engine wearing buttons.&lt;/p&gt;
&lt;p&gt;The architecture is still settling, and backend behaviour will not be perfectly identical. Today&amp;rsquo;s useful certainty is modest: &amp;ldquo;works through one engine here&amp;rdquo; is not the same claim as &amp;ldquo;Phonon supports this format everywhere.&amp;rdquo; Computers remain attentive readers of fine print.&lt;/p&gt;</description></item></channel></rss>