qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] ossaudio enhancements...


From: Leonardo E. Reiter
Subject: [Qemu-devel] [PATCH] ossaudio enhancements...
Date: Sun, 12 Feb 2006 19:15:25 -0500
User-agent: Debian Thunderbird 1.0.2 (X11/20051002)

Hi,

attached is a patch that gives ossaudio the following new functionality:

1. the ability to retry opening the DSP devices at later times if they are busy (i.e. another application is playing sound); if the device is busy, the code falls back to the noaudio mechanisms for playback and recording until the device is released by whichever other process is holding it.

2. a default 1500 millisecond. "release" timer from last playback or record activity. After this timeout, the corresponding audio DSP is "released" so that other applications may open it without getting an EBUSY error.

Basically, this makes the OSS sound in QEMU much friendlier when running on a desktop with other apps - for example, QEMU will not tie up the audio device indefinitely after the first time the guest tries to use it.

For malc (et al): there is probably a better way to do #2 than with a fixed timer, or at least, possible to use a shorter timeout. It was just not obvious to me how to figure out when was a good time to release the device without such a hack. It may be the best way, but perhaps OSS_RELEASE_MSEC should be reduced significantly or made variable depending on how big the buffers are.

Also, this has not been tested with the mmap option, but the code is in place to handle it the same way as without mmap, which works fine.

Best regards,

Leo Reiter



--
Leonardo E. Reiter
Vice President of Product Development, CTO

Win4Lin, Inc.
Virtual Computing from Desktop to Data Center
Main: +1 512 339 7979
Fax: +1 512 532 6501
http://www.win4lin.com
Index: audio/ossaudio.c
===================================================================
RCS file: /cvsroot/qemu/qemu/audio/ossaudio.c,v
retrieving revision 1.9
diff -a -u -r1.9 ossaudio.c
--- audio/ossaudio.c    20 Nov 2005 16:24:34 -0000      1.9
+++ audio/ossaudio.c    30 Jan 2006 15:31:31 -0000
@@ -30,23 +30,58 @@
 #define AUDIO_CAP "oss"
 #include "audio_int.h"
 
+/* milliseconds of idle input or output prior to device being released... */
+#define OSS_RELEASE_MSEC    1500
+
+/* statics we use before they are defined */
+static int oss_init_in(HWVoiceIn *hw, audsettings_t *as);
+static void oss_fini_in(HWVoiceIn *hw);
+static int oss_init_out(HWVoiceOut *hw, audsettings_t *as);
+static void oss_fini_out(HWVoiceOut *hw);
+static int oss_ctl_out(HWVoiceOut *hw, int cmd, ...);
+
+/* import and MACROs for calling noaudio PCM ops; this avoids having to
+ * globally export entrypoints into noaudio driver */
+extern struct audio_driver no_audio_driver;
+#define no_init_in(hw, as)  no_audio_driver.pcm_ops->init_in(hw, as)
+#define no_fini_in(hw)      no_audio_driver.pcm_ops->fini_in(hw)
+#define no_init_out(hw, as) no_audio_driver.pcm_ops->init_out(hw, as)
+#define no_fini_out(hw)     no_audio_driver.pcm_ops->fini_out(hw)
+#define no_run_in(hw)       no_audio_driver.pcm_ops->run_in(hw)
+#define no_run_out(hw)      no_audio_driver.pcm_ops->run_out(hw)
+
 typedef struct OSSVoiceOut {
     HWVoiceOut hw;
+    int64_t old_ticks;
+/* NOTE: the first portion of this structure is identical to NoVoiceOut in
+ * noaudio.c, since no_run_out() is used if the audio device cannot open;
+ * if NoVoiceOut changes, this above portion must change here as well */
     void *pcm_buf;
     int fd;
     int nfrags;
     int fragsize;
     int mmapped;
     int old_optr;
+    audsettings_t saved_as;
+    QEMUTimer *rel_timer;
+    int released;
+    int pending_cmd;
 } OSSVoiceOut;
 
 typedef struct OSSVoiceIn {
     HWVoiceIn hw;
+    int64_t old_ticks;
+/* NOTE: the first portion of this structure is identical to NoVoiceIn in
+ * noaudio.c, since no_run_in() is used if the audio device cannot open;
+ * if NoVoiceIn changes, this above portion must change here as well */
     void *pcm_buf;
     int fd;
     int nfrags;
     int fragsize;
     int old_optr;
+    audsettings_t saved_as;
+    QEMUTimer *rel_timer;
+    int released;
 } OSSVoiceIn;
 
 static struct {
@@ -194,7 +229,7 @@
 #endif
 
 static int oss_open (int in, struct oss_params *req,
-                     struct oss_params *obt, int *pfd)
+                     struct oss_params *obt, int *pfd, int *released)
 {
     int fd;
     int mmmmssss;
@@ -205,9 +240,11 @@
 
     fd = open (dspname, (in ? O_RDONLY : O_WRONLY) | O_NONBLOCK);
     if (-1 == fd) {
+        *released = (int) (errno == EBUSY);
         oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
         return -1;
     }
+    *released = 0;
 
     freq = req->freq;
     nchannels = req->nchannels;
@@ -290,6 +327,18 @@
         return 0;
     }
 
+    /* if the audio device was released (or was busy when the last open was
+     * attempted, then we try to open it again; if it failed for other reasons,
+     * then we'll just use noaudio's run_out */
+    if (oss->released)
+        oss_init_out(hw, &oss->saved_as);
+    if (oss->fd < 0)
+        return no_run_out(hw);  /* permanent failure, or busy for now */
+    else {
+        qemu_mod_timer(oss->rel_timer, qemu_get_clock(rt_clock) +
+                OSS_RELEASE_MSEC);
+    }
+
     bufsize = hw->samples << hw->info.shift;
 
     if (oss->mmapped) {
@@ -386,6 +435,7 @@
     }
 
     hw->rpos = rpos;
+    oss->old_ticks = qemu_get_clock(vm_clock);
     return decr;
 }
 
@@ -395,7 +445,12 @@
     OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 
     ldebug ("oss_fini\n");
-    oss_anal_close (&oss->fd);
+    if (oss->fd < 0)
+        no_fini_out(hw);
+    else {
+        oss_anal_close (&oss->fd);
+        oss->released = 1;
+    }
 
     if (oss->pcm_buf) {
         if (oss->mmapped) {
@@ -410,6 +465,9 @@
         }
         oss->pcm_buf = NULL;
     }
+
+    if (oss->rel_timer != NULL)
+        qemu_del_timer(oss->rel_timer);
 }
 
 static int oss_init_out (HWVoiceOut *hw, audsettings_t *as)
@@ -423,6 +481,7 @@
     audsettings_t obt_as;
 
     oss->fd = -1;
+    oss->saved_as = *as;
 
     req.fmt = aud_to_ossfmt (as->fmt);
     req.freq = as->freq;
@@ -430,14 +489,14 @@
     req.fragsize = conf.fragsize;
     req.nfrags = conf.nfrags;
 
-    if (oss_open (0, &req, &obt, &fd)) {
-        return -1;
+    if (oss_open (0, &req, &obt, &fd, &oss->released)) {
+        return no_init_out(hw, as);
     }
 
     err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
     if (err) {
         oss_anal_close (&fd);
-        return -1;
+        return no_init_out(hw, as);
     }
 
     obt_as.freq = obt.freq;
@@ -514,11 +573,19 @@
                 1 << hw->info.shift
                 );
             oss_anal_close (&fd);
-            return -1;
+            return no_init_out(hw, as);
         }
     }
 
     oss->fd = fd;
+    if (oss->rel_timer == NULL) {
+        oss->rel_timer = qemu_new_timer(rt_clock,
+                (QEMUTimerCB *) oss_fini_out, oss);
+    }
+    if (oss->pending_cmd)
+        oss_ctl_out((HWVoiceOut *) hw, oss->pending_cmd);
+    qemu_mod_timer(oss->rel_timer, qemu_get_clock(rt_clock) +
+            OSS_RELEASE_MSEC);
     return 0;
 }
 
@@ -531,6 +598,12 @@
         return 0;
     }
 
+    if (oss->fd < 0) {
+        oss->pending_cmd = cmd;
+        return 0;
+    } else
+        oss->pending_cmd = 0;
+
     switch (cmd) {
     case VOICE_ENABLE:
         ldebug ("enabling voice\n");
@@ -568,20 +641,21 @@
     audsettings_t obt_as;
 
     oss->fd = -1;
+    oss->saved_as = *as;
 
     req.fmt = aud_to_ossfmt (as->fmt);
     req.freq = as->freq;
     req.nchannels = as->nchannels;
     req.fragsize = conf.fragsize;
     req.nfrags = conf.nfrags;
-    if (oss_open (1, &req, &obt, &fd)) {
-        return -1;
+    if (oss_open (1, &req, &obt, &fd, &oss->released)) {
+        return no_init_in(hw, as);
     }
 
     err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
     if (err) {
         oss_anal_close (&fd);
-        return -1;
+        return no_init_in(hw, as);
     }
 
     obt_as.freq = obt.freq;
@@ -607,10 +681,16 @@
         dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
                hw->samples, 1 << hw->info.shift);
         oss_anal_close (&fd);
-        return -1;
+        return no_init_in(hw, as);
     }
 
     oss->fd = fd;
+    if (oss->rel_timer == NULL) {
+        oss->rel_timer = qemu_new_timer(rt_clock,
+                (QEMUTimerCB *) oss_fini_in, oss);
+    }
+    qemu_mod_timer(oss->rel_timer, qemu_get_clock(rt_clock) +
+            OSS_RELEASE_MSEC);
     return 0;
 }
 
@@ -618,12 +698,20 @@
 {
     OSSVoiceIn *oss = (OSSVoiceIn *) hw;
 
-    oss_anal_close (&oss->fd);
+    if (oss->fd < 0)
+        no_fini_in(hw);
+    else {
+        oss_anal_close (&oss->fd);
+        oss->released = 1;
+    }
 
     if (oss->pcm_buf) {
         qemu_free (oss->pcm_buf);
         oss->pcm_buf = NULL;
     }
+
+    if (oss->rel_timer != NULL)
+        qemu_del_timer(oss->rel_timer);
 }
 
 static int oss_run_in (HWVoiceIn *hw)
@@ -654,6 +742,20 @@
         bufs[0].len = dead << hwshift;
     }
 
+    if (bufs[0].len || bufs[1].len) {
+
+        /* if the audio device was released (or was busy when the last open was
+         * attempted, then we try to open it again; if it failed for other 
+         * reasons, then we'll just use noaudio's run_in */
+        if (oss->released)
+            oss_init_in(hw, &oss->saved_as);
+        if (oss->fd < 0)
+            return no_run_in(hw);   /* permanent failure, or busy for now */
+        else {
+            qemu_mod_timer(oss->rel_timer, qemu_get_clock(rt_clock) +
+                    OSS_RELEASE_MSEC);
+        }
+    }
 
     for (i = 0; i < 2; ++i) {
         ssize_t nread;

reply via email to

[Prev in Thread] Current Thread [Next in Thread]