Index: /trunk/src/VBox/Devices/Audio/solaudio.c
===================================================================
--- /trunk/src/VBox/Devices/Audio/solaudio.c	(revision 7453)
+++ /trunk/src/VBox/Devices/Audio/solaudio.c	(revision 7454)
@@ -24,5 +24,4 @@
 #include <fcntl.h>
 #include <sys/audio.h>
-#include <sys/fcntl.h>
 #include <sys/stat.h>
 #include <sys/time.h>
@@ -30,4 +29,5 @@
 #define LOG_GROUP LOG_GROUP_DEV_AUDIO
 #include <VBox/log.h>
+#include <iprt/env.h>
 
 #include "Builtins.h"
@@ -39,10 +39,9 @@
 #include "audio_int.h"
 
-
 /*******************************************************************************
 *   Structures and Typedefs                                                    *
 *******************************************************************************/
 typedef struct solaudioVoiceOut {
-    HWVoiceOut hw;
+    HWVoiceOut Hw;
     int        AudioDev;
     int        AudioCtl;
@@ -57,10 +56,8 @@
 struct
 {
-    int buffer_size;
-    int nbuffers;
+    int cbBuffer;
 } conf =
 {
-    INIT_FIELD (buffer_size =) 8192,
-    INIT_FIELD (nbuffers =) 4,
+    INIT_FIELD (cbBuffer =) 8912,
 };
 
@@ -70,9 +67,9 @@
     va_list ap;
 
-    va_start (ap, fmt);
-    AUD_vlog (AUDIO_CAP, fmt, ap);
-    va_end (ap);
-
-    AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
+    va_start(ap, fmt);
+    AUD_vlog(AUDIO_CAP, fmt, ap);
+    va_end(ap);
+
+    AUD_log(AUDIO_CAP, "Reason: %s\n", strerror(err));
 }
 
@@ -111,5 +108,11 @@
 
         case AUDIO_PRECISION_16:
-            return AUD_FMT_U16;
+        {
+            if (encoding == AUDIO_ENCODING_LINEAR)
+                return AUD_FMT_S16;
+            else
+                return AUD_FMT_U16;
+            break;
+        }
 
         default:
@@ -120,64 +123,90 @@
 
 
+static char *solaudio_getdevice ()
+{
+    /* This is for multiple audio devices where env. var determines current one,
+     * otherwise else we fallback to default.
+     */
+    char *pszAudioDev = RTEnvGet("AUDIODEV");
+    if (pszAudioDev)
+        return RTStrDup(pszAudioDev);
+
+    return RTStrDup("/dev/audio");
+}
+
+
 static int solaudio_open (int in, audio_info_t *info, int *pfd, int *pctl_fd)
 {
-    int fd;
-    int ctl_fd;
-    struct stat st;
-    const char *deviceName = "/dev/audio";
-    const char *ctlDeviceName = "/dev/audioctl";
-    audio_info_t audInfo;
-
-    /* @todo Use AUDIO_GETDEV instead of hardcoding /dev/audio */
-    if (stat(deviceName, &st) < 0)
-    {
-        LogRel(("solaudio: failed to stat %s\n", deviceName));
-        return -1;
-    }
-
-    if (!S_ISCHR(st.st_mode))
-    {
-        LogRel(("solaudio: invalid mode for %s\n", deviceName));
-        return -1;
-    }
-
-    fd = open(deviceName, O_WRONLY | O_NONBLOCK);
-    if (fd < 0)
-    {
-        LogRel(("solaudio: failed to open %s\n", deviceName));
-        return -1;
-    }
-
-    ctl_fd = open(ctlDeviceName, O_WRONLY | O_NONBLOCK);
-    if (ctl_fd < 0)
-    {
-        LogRel(("solaudio: failed to open %s\n", ctlDeviceName));
-        close(fd);
-        return -1;
-    }
-
-    AUDIO_INITINFO(&audInfo);
-    if (ioctl(fd, AUDIO_GETINFO, &audInfo) < 0)
+    int AudioDev;
+    int AudioCtl;
+    struct stat FileStat;
+    const char *pszAudioDev = NULL;
+    const char *pszAudioCtl = "/dev/audioctl";
+    audio_info_t AudioInfo;
+
+    pszAudioDev = solaudio_getdevice();
+    if (!pszAudioDev)
+    {
+        LogRel(("solaudio: solaudio_getdevice() failed to return a valid device.\n"));
+        goto err;
+    }
+
+    if (stat(pszAudioDev, &FileStat) < 0)
+    {
+        LogRel(("solaudio: failed to stat %s\n", pszAudioDev));
+        goto err;
+    }
+
+    if (!S_ISCHR(FileStat.st_mode))
+    {
+        LogRel(("solaudio: invalid mode for %s\n", pszAudioDev));
+        goto err;
+    }
+
+    AudioDev = open(pszAudioDev, O_WRONLY | O_NONBLOCK);
+    if (AudioDev < 0)
+    {
+        LogRel(("solaudio: failed to open %s\n", pszAudioDev));
+        goto err;
+    }
+
+    AudioCtl = open(pszAudioCtl, O_WRONLY | O_NONBLOCK);
+    if (AudioCtl < 0)
+    {
+        LogRel(("solaudio: failed to open %s\n", pszAudioCtl));
+        close(AudioDev);
+        goto err;
+    }
+
+    AUDIO_INITINFO(&AudioInfo);
+    if (ioctl(AudioDev, AUDIO_GETINFO, &AudioInfo) < 0)
     {
         LogRel(("solaudio: AUDIO_GETINFO failed\n"));
-        close(fd);
-        return -1;
-    }
-    audInfo.play.sample_rate = info->play.sample_rate;
-    audInfo.play.channels = info->play.channels;
-    audInfo.play.precision = info->play.precision;
-    audInfo.play.encoding = info->play.encoding;
-    audInfo.play.buffer_size = info->play.buffer_size;
-    audInfo.play.gain = AUDIO_MID_GAIN;
-    if (ioctl(fd, AUDIO_SETINFO, &audInfo) < 0)
+        close(AudioDev);
+        close(AudioCtl);
+        goto err;
+    }
+    AudioInfo.play.sample_rate = info->play.sample_rate;
+    AudioInfo.play.channels = info->play.channels;
+    AudioInfo.play.precision = info->play.precision;
+    AudioInfo.play.encoding = info->play.encoding;
+    AudioInfo.play.buffer_size = info->play.buffer_size;
+    AudioInfo.play.gain = AUDIO_MAX_GAIN;
+    AudioInfo.play.balance = AUDIO_MID_BALANCE;
+    if (ioctl(AudioDev, AUDIO_SETINFO, &AudioInfo) < 0)
     {
         LogRel(("solaudio: AUDIO_SETINFO failed\n"));
-        close(fd);
-        return -1;
-    }
-    LogFlow(("solaudio: system buffer_size=%d\n", audInfo.play.buffer_size));
-    *pfd = fd;
-    *pctl_fd = ctl_fd;
+        close(AudioDev);
+        close(AudioCtl);
+        goto err;
+    }
+    LogFlow(("solaudio: buffer_size=%d\n", AudioInfo.play.buffer_size));
+    *pfd = AudioDev;
+    *pctl_fd = AudioCtl;
     return 0;
+
+err:
+    RTStrFree(pszAudioDev);
+    return -1;
 }
 
@@ -185,21 +214,21 @@
 static int solaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
 {
-    solaudioVoiceOut *sol = (solaudioVoiceOut *) hw;
-    audio_info_t audioInfo;
-    audsettings_t obt_as;
-    int fd = -1;
-    int ctl_fd = -1;
-
-    AUDIO_INITINFO(&audioInfo);
-    audioInfo.play.sample_rate = as->freq;
-    audioInfo.play.channels = as->nchannels;
-    audioInfo.play.precision = aud_to_solfmt(as->fmt);
-    audioInfo.play.buffer_size = conf.buffer_size;
+    solaudioVoiceOut *pSol = (solaudioVoiceOut *)hw;
+    audio_info_t AudioInfo;
+    audsettings_t ObtAudioInfo;
+    int AudioDev = -1;
+    int AudioCtl = -1;
+
+    AUDIO_INITINFO(&AudioInfo);
+    AudioInfo.play.sample_rate = as->freq;
+    AudioInfo.play.channels = as->nchannels;
+    AudioInfo.play.precision = aud_to_solfmt(as->fmt);
+    AudioInfo.play.buffer_size = conf.cbBuffer;
     if (as->fmt == AUD_FMT_U8)
-        audioInfo.play.encoding = AUDIO_ENCODING_LINEAR8;
+        AudioInfo.play.encoding = AUDIO_ENCODING_LINEAR8;
     else
-        audioInfo.play.encoding = AUDIO_ENCODING_LINEAR;
-
-    if (solaudio_open(0, &audioInfo, &fd, &ctl_fd))
+        AudioInfo.play.encoding = AUDIO_ENCODING_LINEAR;
+
+    if (solaudio_open(0, &AudioInfo, &AudioDev, &AudioCtl))
     {
         LogRel(("solaudio: solaudio_open failed\n"));
@@ -207,30 +236,30 @@
     }
 
-    sol->AudioDev = fd;
-    sol->AudioCtl = ctl_fd;
-    obt_as.freq = audioInfo.play.sample_rate;
-    obt_as.nchannels = audioInfo.play.channels;
-    obt_as.fmt = sol_to_audfmt(audioInfo.play.precision, audioInfo.play.encoding);
-    obt_as.endianness = as->endianness;
-
-    audio_pcm_init_info (&hw->info, &obt_as);
-    sol->cBuffersPlayed = audioInfo.play.eof;
-
-    hw->samples = audioInfo.play.buffer_size >> hw->info.shift;
-    sol->pPCMBuf = RTMemAllocZ(audioInfo.play.buffer_size);
-    if (!sol->pPCMBuf)
+    pSol->AudioDev = AudioDev;
+    pSol->AudioCtl = AudioCtl;
+    ObtAudioInfo.freq = AudioInfo.play.sample_rate;
+    ObtAudioInfo.nchannels = AudioInfo.play.channels;
+    ObtAudioInfo.fmt = sol_to_audfmt(AudioInfo.play.precision, AudioInfo.play.encoding);
+    ObtAudioInfo.endianness = as->endianness;
+
+    audio_pcm_init_info(&hw->info, &ObtAudioInfo);
+    pSol->cBuffersPlayed = AudioInfo.play.eof;
+
+    hw->samples = AudioInfo.play.buffer_size >> hw->info.shift;
+    pSol->pPCMBuf = RTMemAllocZ(AudioInfo.play.buffer_size);
+    if (!pSol->pPCMBuf)
     {
         LogRel(("solaudio: failed to alloc %d %d bytes to pPCMBuf\n", hw->samples << hw->info.shift, hw->samples));
         return -1;
     }
-    LogFlow(("solaudio: hw->samples=%d play.buffer_size=%d\n", hw->samples, audioInfo.play.buffer_size));
+    LogFlow(("solaudio: hw->samples=%d play.buffer_size=%d\n", hw->samples, AudioInfo.play.buffer_size));
     return 0;
 }
 
 
-static void solaudio_stop (solaudioVoiceOut *solvw)
+static void solaudio_stop (solaudioVoiceOut *sol)
 {
     LogFlow(("solaudio: stop\n"));
-    if (solvw->AudioDev < 0 || solvw->AudioCtl < 0)
+    if (sol->AudioDev < 0 || sol->AudioCtl < 0)
     {
         Log(("solaudio: invalid file descriptors\n"));
@@ -238,5 +267,5 @@
     }
 
-    if (ioctl(solvw->AudioCtl, I_SETSIG, 0) < 0)
+    if (ioctl(sol->AudioCtl, I_SETSIG, 0) < 0)
     {
         LogRel(("solaudio: failed to stop signalling\n"));
@@ -244,5 +273,5 @@
     }
 
-    if (ioctl(solvw->AudioDev, I_FLUSH, FLUSHW) < 0)
+    if (ioctl(sol->AudioDev, I_FLUSH, FLUSHW) < 0)
     {
         Log(("solaudio: failed to drop unplayed buffers\n"));
@@ -250,13 +279,13 @@
     }
 
-    close(solvw->AudioDev);
-    solvw->AudioDev = -1;
-    close(solvw->AudioCtl);
-    solvw->AudioCtl = -1;
-    solvw->cBuffersPlayed = 0;
-    if (solvw->pPCMBuf)
-    {
-        RTMemFree(solvw->pPCMBuf);
-        solvw->pPCMBuf = NULL;
+    close(sol->AudioDev);
+    sol->AudioDev = -1;
+    close(sol->AudioCtl);
+    sol->AudioCtl = -1;
+    sol->cBuffersPlayed = 0;
+    if (sol->pPCMBuf)
+    {
+        RTMemFree(sol->pPCMBuf);
+        sol->pPCMBuf = NULL;
     }
 }
@@ -271,11 +300,11 @@
 
 
-static int solaudio_availbuf (solaudioVoiceOut *solvw)
-{
-    audio_info_t audioInfo;
-    int buffers = 0;
-
-    AUDIO_INITINFO(&audioInfo);
-    if (ioctl(solvw->AudioDev, AUDIO_GETINFO, &audioInfo) < 0)
+static int solaudio_availbuf (solaudioVoiceOut *sol)
+{
+    audio_info_t AudioInfo;
+    int cbBuffer = 0;
+
+    AUDIO_INITINFO(&AudioInfo);
+    if (ioctl(sol->AudioDev, AUDIO_GETINFO, &AudioInfo) < 0)
     {
         Log(("solaudio: AUDIO_GETINFO ioctl failed\n"));
@@ -283,20 +312,21 @@
     }
 
-    buffers = audioInfo.play.buffer_size * (2 + audioInfo.play.eof - solvw->cBuffersPlayed);
-
-    LogFlow(("avail: eof=%d samples=%d bufsize=%d bufplayed=%d avail=%d\n", audioInfo.play.eof, audioInfo.play.samples,
-        audioInfo.play.buffer_size, solvw->cBuffersPlayed, buffers));
-    return buffers;
-}
-
+    cbBuffer = AudioInfo.play.buffer_size * (2 + AudioInfo.play.eof - sol->cBuffersPlayed);
+
+    LogFlow(("avail: eof=%d samples=%d bufsize=%d bufplayed=%d avail=%d\n", AudioInfo.play.eof, AudioInfo.play.samples,
+        AudioInfo.play.buffer_size, sol->cBuffersPlayed, cbBuffer));
+    return cbBuffer;
+}
+
+#if 0
 static void solaudio_yield (solaudioVoiceOut *pSol)
 {
     audio_info_t AudioInfo;
     timespec_t WaitTimeSpec;
-    if (ioctl (pSol->AudioDev, AUDIO_GETINFO, &AudioInfo) < 0)
+    if (ioctl(pSol->AudioDev, AUDIO_GETINFO, &AudioInfo) < 0)
         return;
 
     WaitTimeSpec.tv_sec = 0;
-    WaitTimeSpec.tv_nsec = 10000000;
+    WaitTimeSpec.tv_nsec = 1000000;
 
     while (AudioInfo.play.eof < pSol->cBuffersPlayed - 2)
@@ -307,5 +337,5 @@
     }
 }
-
+#endif
 
 static int solaudio_run_out (HWVoiceOut *hw)
@@ -317,18 +347,14 @@
     st_sample_t *psSrc;
 
-    csLive = audio_pcm_hw_get_live_out (hw);
+    csLive = audio_pcm_hw_get_live_out(hw);
     if (!csLive)
         return 0;
 
-    for (;;)
-    {
-        cbAvail = solaudio_availbuf (pSol);
-        if (cbAvail > 0)
-            break;
-        solaudio_yield(pSol);
-    }
+    cbAvail = solaudio_availbuf(pSol);
+    if (cbAvail <= 0)
+        return 0;
 
     csAvail   = cbAvail >> hw->info.shift; /* bytes => samples */
-    csDecr    = audio_MIN (csLive, csAvail);
+    csDecr    = audio_MIN(csLive, csAvail);
     csSamples = csDecr;
 
@@ -336,12 +362,12 @@
     {
         /* split request at the end of our samples buffer */
-        csToWrite = audio_MIN (csSamples, hw->samples - hw->rpos);
+        csToWrite = audio_MIN(csSamples, hw->samples - hw->rpos);
         cbToWrite = csToWrite << hw->info.shift;
         psSrc     = hw->mix_buf + hw->rpos;
-        pu8Dst    = advance (pSol->pPCMBuf, hw->rpos << hw->info.shift);
-
-        hw->clip (pu8Dst, psSrc, csToWrite);
-
-        cbWritten = write (pSol->AudioDev, pu8Dst, cbToWrite);
+        pu8Dst    = advance(pSol->pPCMBuf, hw->rpos << hw->info.shift);
+
+        hw->clip(pu8Dst, psSrc, csToWrite);
+
+        cbWritten = write(pSol->AudioDev, pu8Dst, cbToWrite);
         if (cbWritten < 0)
             break;
@@ -359,5 +385,5 @@
 static int solaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
 {
-    solaudioVoiceOut *sol = (solaudioVoiceOut *) hw;
+    solaudioVoiceOut *pSol = (solaudioVoiceOut *) hw;
     switch (cmd)
     {
@@ -365,13 +391,13 @@
         {
             /* reset the eof marker and samples markers */
-            audio_info_t audioInfo;
-            AUDIO_INITINFO(&audioInfo);
-            ioctl(sol->AudioDev, AUDIO_GETINFO, &audioInfo);
-            audioInfo.play.eof = 0;
-            audioInfo.play.samples = 0;
-            ioctl(sol->AudioDev, AUDIO_SETINFO, &audioInfo);
-
-            sol->cBuffersPlayed = 0;
-            audio_pcm_info_clear_buf (&hw->info, sol->pPCMBuf, hw->samples);
+            audio_info_t AudioInfo;
+            AUDIO_INITINFO(&AudioInfo);
+            ioctl(pSol->AudioDev, AUDIO_GETINFO, &AudioInfo);
+            AudioInfo.play.eof = 0;
+            AudioInfo.play.samples = 0;
+            ioctl(pSol->AudioDev, AUDIO_SETINFO, &AudioInfo);
+            pSol->cBuffersPlayed = 0;
+
+            audio_pcm_info_clear_buf(&hw->info, pSol->pPCMBuf, hw->samples);
             LogFlow(("solaudio: voice_enable\n"));
             break;
@@ -381,5 +407,5 @@
         {
             LogFlow(("solaudio: voice_disable\n"));
-            solaudio_stop(sol);
+            solaudio_stop(pSol);
             break;
         }
@@ -422,8 +448,6 @@
 
 static struct audio_option solaudio_options[] = {
-    {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size,
-     "Size of the buffer in frames", NULL, 0},
-    {"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers,
-     "Number of buffers", NULL, 0},
+    {"BUFFER_SIZE", AUD_OPT_INT, &conf.cbBuffer,
+     "Size of the buffer in bytes", NULL, 0},
     {NULL, 0, NULL, NULL, NULL, 0}
 };
