Bug 103750 - enabling amaroK scripts or visualizations makes Audio output unavailable; the device is busy
Summary: enabling amaroK scripts or visualizations makes Audio output unavailable; the...
Status: RESOLVED FIXED
Alias: None
Product: amarok
Classification: Applications
Component: Tools/Script Manager (show other bugs)
Version: 1.3
Platform: Gentoo Packages Linux
: NOR normal
Target Milestone: ---
Assignee: Amarok Developers
URL:
Keywords:
: 94119 112630 (view as bug list)
Depends on:
Blocks:
 
Reported: 2005-04-12 21:27 UTC by illogic-al
Modified: 2006-06-11 12:32 UTC (History)
2 users (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description illogic-al 2005-04-12 21:27:19 UTC
Version:           1.3-CVS (using KDE 3.3.0, SuSE)
Compiler:          gcc version 3.3.4 (pre 3.3.5 20040809)
OS:                Linux (i686) release 2.6.8-24-default

turning on any script when using the xine engine causes a pop up saying "Audio output unavailable; the device is busy." and then amaroK can't play any music. Turning the script off fixes that problem.
Comment 1 illogic-al 2005-04-12 21:27:46 UTC
setting bug to unconfirmed.
Comment 2 Mark Kretschmann 2005-05-02 09:18:58 UTC
I can't reproduce this, and frankly, for the life of me can't think of a technical explanation. Waaaay strange bug :)

Can anyone besides the reporter reproduce this?
Comment 3 illogic-al 2005-05-08 00:16:39 UTC
markey did you use the xine engine when you tried to reproduce this?
Hope these instructions are clearer:
1) Enable xine engine but turn start playing any songs
2) Go to scripts and select alarm.py. 
3) Click run.
4) Configure the alarm to start a minute from the current time.
5) Hopefully amaroK freezes for about a minute and then gives the "Audio output unavailable; the device is busy." popup.
Comment 4 illogic-al 2005-08-20 03:33:52 UTC
Can no one reproduce this? It still happens in 1.3 on a separate OS (gentoo now) and separate sound card. 

Modified steps to reproduce:
1) Enable xine engine.
2) start playing any songs 
 3) Go to scripts and select alarm.py. 
 3) Click run. 
 4) Configure the alarm to start a minute from the current time. 
 5) After playing the third or fourth song in the playlist the "Audio output unavailable; the device is busy." pops up. 
Comment 5 Alexandre Oliveira 2005-08-20 03:54:45 UTC
Quoting what Alastair said in a mail forwarded to mail list:
"It seems that the script inherits all the open files from the parent
    amarok process. For me this included /dev/snd/pcmC0D0c, which blocked
    other sound applications including the Xine engine when it moved to
    the next track. Once I worked out that this was the cause of sound on
    my computer being blocked, I modified the script to close all files
    apart from stdin, stdout and stderr. I think this could bite other
    people apart from me."
So, the problem is that because of the way the scripts are run, they would inherit open files, and then unless the plugins would close the files, we'd have this problem. This would also explain similar problems with visualizations.
Now we need to find a way to avoid this. :-(
Comment 6 Alexandre Oliveira 2005-08-20 03:55:13 UTC
*** Bug 94119 has been marked as a duplicate of this bug. ***
Comment 7 Mark Kretschmann 2005-08-20 09:15:52 UTC
On Saturday 20 August 2005 03:54, Alexandre Oliveira wrote:
> So, the problem is that because of the way the scripts are run, they would
> inherit open files, and then unless the plugins would close the files, we'd
> have this problem. This would also explain similar problems with
> visualizations. Now we need to find a way to avoid this. :-(


This seems to be the normal behavior of the fork() system call. From the 
Solaris fork() man page:

     The fork() and fork1() functions create a new  process.  The
     new  process (child process) is an exact copy of the calling
     process (parent process). The  child  process  inherits  the
     following attributes from the parent process:

        o  real user ID, real group ID, effective user ID, effec-
           tive group ID
        o  environment
        o  open file descriptors

     [..]
Comment 8 Alexandre Oliveira 2005-09-17 21:50:49 UTC
*** Bug 112630 has been marked as a duplicate of this bug. ***
Comment 9 Alexandre Oliveira 2005-09-25 00:12:27 UTC
SVN commit 463706 by aoliveira:

Reimplementing KProcess/KprocIO::commSetupDoneC to close all file descriptors (apart from in, out and err).
This seems to be the only way to fix the "device is busy" problem with xine, explained on bug #103750. As the child would inherit the fds, files wouldn't be closed, and xine-lib wouldn't work due to that.
If anyone can think of a better fix, please point it out!
BUG: 103750


 M  +19 -1     scriptmanager.cpp  
 M  +16 -1     socketserver.cpp  


--- trunk/extragear/multimedia/amarok/src/scriptmanager.cpp #463705:463706
@@ -58,7 +58,25 @@
 #include <knewstuff/provider.h>       // "
 
 
+
 ////////////////////////////////////////////////////////////////////////////////
+// class AmaroKProcIO
+////////////////////////////////////////////////////////////////////////////////
+/** Due to xine-lib, we have to make KProcIO close all fds, otherwise we get "device is busy" messages
+  * See bug #103750 for more information.
+  */
+class AmaroKProcIO : public KProcIO {
+    public:
+    virtual int commSetupDoneC() {
+        for (int i = sysconf(_SC_OPEN_MAX) - 1; i > 2; i--)
+            if (i!=KProcIO::out[0] && i!=KProcIO::in[0] && i!=KProcIO::err[0])
+                close(i);
+        return KProcIO::commSetupDoneC();
+    };
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
 // class AmarokScriptNewStuff
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -436,7 +454,7 @@
     if ( m_scripts[name].process ) return false;
 
     const KURL url = m_scripts[name].url;
-    KProcIO* script = new KProcIO();
+    AmaroKProcIO* script = new AmaroKProcIO();
 //     script->setComm( (KProcess::Communication) ( KProcess::Stdin | KProcess::Stdout | KProcess::Stderr ) );
 
     *script << url.path();
--- trunk/extragear/multimedia/amarok/src/socketserver.cpp #463705:463706
@@ -36,6 +36,21 @@
 //TODO decide whether to use 16 bit integers or 32 bit floats as data sent to analyzers
 //TODO allow visualisations to determine their own data sizes
 
+////////////////////////////////////////////////////////////////////////////////
+// class AmaroKProcess
+////////////////////////////////////////////////////////////////////////////////
+/** Due to xine-lib, we have to make KProcess close all fds, otherwise we get "device is busy" messages
+  * See bug #103750 for more information.
+  */
+class AmaroKProcess : public KProcess {
+    public:
+    virtual int commSetupDoneC() {
+        for (int i = sysconf(_SC_OPEN_MAX) - 1; i > 2; i--)
+            if (i!=KProcess::out[0] && i!=KProcess::in[0] && i!=KProcess::err[0])
+                close(i);
+        return KProcess::commSetupDoneC();
+    };
+};
 
 
 /// @class amaroK::SocketServer
@@ -296,7 +311,7 @@
 {
     switch( state() ) {
     case On:
-        m_proc = new KProcess();
+        m_proc = new AmaroKProcess();
        *m_proc << KStandardDirs::findExe( m_command )
                << Selector::instance()->m_server->path()
                << text( 0 );