shithub: sox

Download patch

ref: 4b17639fb7591153dbd3e234eea21b1a2a29fcfa
parent: 013f942d1d890937e7e1794046cfa1ee9ab6c7dd
author: Doug Cook <idigdoug@users.sourceforge.net>
date: Tue Mar 27 17:58:56 EDT 2012

sunaudio.c - don't use private fd member of sox_format_t

--- a/src/sunaudio.c
+++ b/src/sunaudio.c
@@ -16,6 +16,7 @@
  */
 
 #include "sox_i.h"
+#include "g711.h"
 
 #include <sys/ioctl.h>
 #include <sys/types.h>
@@ -31,8 +32,18 @@
 #include <stdlib.h>
 #include <fcntl.h>
 #include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 
-typedef sox_fileinfo_t priv_t;
+typedef struct
+{
+    char* pOutput;
+    unsigned cOutput;
+    int device;
+    unsigned sample_shift;
+} priv_t;
+
 /*
  * Do anything required before you start reading samples.
  * Read file header.
@@ -40,9 +51,11 @@
  *      size and encoding of samples,
  *      mono/stereo/quad.
  */
-static int sox_sunstartread(sox_format_t * ft)
+static int sunstartread(sox_format_t * ft)
 {
-    priv_t *file = (priv_t *)ft->priv;
+    char const* szDevname;
+    priv_t* pPriv = (priv_t*)ft->priv;
+ 
     size_t samplesize, encoding;
     audio_info_t audio_if;
 #ifdef __SVR4
@@ -52,18 +65,24 @@
 
     lsx_set_signal_defaults(ft);
 
-    /* Hard-code for now. */
-    file->count = 0;
-    file->pos = 0;
-    file->size = 1024;
-    file->buf = lsx_malloc (file->size);
+    if (ft->filename == 0 || ft->filename[0] == 0 || !strcasecmp("default", ft->filename)) {
+        szDevname = "/dev/audio";
+    } else {
+        szDevname = ft->filename;
+    }
 
+    pPriv->device = open(szDevname, O_RDONLY);
+    if (pPriv->device < 0) {
+        lsx_fail_errno(ft, errno, "open failed for device %s", szDevname);
+        return SOX_EOF;
+    }
+
     if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) ft->encoding.encoding = SOX_ENCODING_ULAW;
 
 #ifdef __SVR4
     /* Read in old values, change to what we need and then send back */
-    if (ioctl(fileno((FILE*)ft->fp), AUDIO_GETDEV, &audio_dev) < 0) {
-        lsx_fail_errno(ft,errno,"Unable to get device information.");
+    if (ioctl(pPriv->device, AUDIO_GETDEV, &audio_dev) < 0) {
+        lsx_fail_errno(ft,errno,"Unable to get information for device %s", szDevname);
         return(SOX_EOF);
     }
     lsx_report("Hardware detected:  %s",audio_dev.name);
@@ -95,6 +114,7 @@
 
     if (ft->encoding.bits_per_sample == 8) {
         samplesize = 8;
+        pPriv->sample_shift = 0;
         if (ft->encoding.encoding != SOX_ENCODING_ULAW &&
             ft->encoding.encoding != SOX_ENCODING_ALAW &&
             ft->encoding.encoding != SOX_ENCODING_SIGN2) {
@@ -111,6 +131,7 @@
     }
     else if (ft->encoding.bits_per_sample == 16) {
         samplesize = 16;
+        pPriv->sample_shift = 1;
         if (ft->encoding.encoding != SOX_ENCODING_SIGN2) {
             lsx_fail_errno(ft,SOX_EFMT,"Sun audio driver only supports signed linear for words.");
             return(SOX_EOF);
@@ -121,7 +142,8 @@
         return(SOX_EOF);
     }
 
-    if (ft->signal.channels == 0) ft->signal.channels = 1;
+    if (ft->signal.channels == 0)
+        ft->signal.channels = 1;
     else if (ft->signal.channels > 1) {
         lsx_report("Warning: some Sun audio devices can not play stereo");
         lsx_report("at all or sometimes only with signed words.  If the");
@@ -132,8 +154,8 @@
     }
 
     /* Read in old values, change to what we need and then send back */
-    if (ioctl(fileno((FILE*)ft->fp), AUDIO_GETINFO, &audio_if) < 0) {
-        lsx_fail_errno(ft,errno,"Unable to initialize /dev/audio");
+    if (ioctl(pPriv->device, AUDIO_GETINFO, &audio_if) < 0) {
+        lsx_fail_errno(ft,errno,"Unable to initialize %s", szDevname);
         return(SOX_EOF);
     }
     audio_if.record.precision = samplesize;
@@ -147,40 +169,40 @@
         encoding = AUDIO_ENCODING_LINEAR;
     audio_if.record.encoding = encoding;
 
-    ioctl(fileno((FILE*)ft->fp), AUDIO_SETINFO, &audio_if);
+    ioctl(pPriv->device, AUDIO_SETINFO, &audio_if);
     if (audio_if.record.precision != samplesize) {
-        lsx_fail_errno(ft,errno,"Unable to initialize sample size for /dev/audio");
+        lsx_fail_errno(ft,errno,"Unable to initialize sample size for %s", szDevname);
         return(SOX_EOF);
     }
     if (audio_if.record.channels != ft->signal.channels) {
-        lsx_fail_errno(ft,errno,"Unable to initialize number of channels for /dev/audio");
+        lsx_fail_errno(ft,errno,"Unable to initialize number of channels for %s", szDevname);
         return(SOX_EOF);
     }
     if (audio_if.record.sample_rate != ft->signal.rate) {
-        lsx_fail_errno(ft,errno,"Unable to initialize rate for /dev/audio");
+        lsx_fail_errno(ft,errno,"Unable to initialize rate for %s", szDevname);
         return(SOX_EOF);
     }
     if (audio_if.record.encoding != encoding) {
-        lsx_fail_errno(ft,errno,"Unable to initialize encoding for /dev/audio");
+        lsx_fail_errno(ft,errno,"Unable to initialize encoding for %s", szDevname);
         return(SOX_EOF);
     }
     /* Flush any data in the buffers - its probably in the wrong format */
 #if defined(__NetBSD__) || defined(__OpenBSD__)
-    ioctl(fileno((FILE*)ft->fp), AUDIO_FLUSH);
+    ioctl(pPriv->device, AUDIO_FLUSH);
 #elif defined __GLIBC__
-    ioctl(fileno((FILE*)ft->fp), (unsigned long int)I_FLUSH, FLUSHR);
+    ioctl(pPriv->device, (unsigned long int)I_FLUSH, FLUSHR);
 #else
-    ioctl(fileno((FILE*)ft->fp), I_FLUSH, FLUSHR);
+    ioctl(pPriv->device, I_FLUSH, FLUSHR);
 #endif
-    /* Change to non-buffered I/O*/
-    setvbuf(ft->fp, NULL, _IONBF, sizeof(char) * file->size);
 
+    pPriv->cOutput = 0;
+    pPriv->pOutput = NULL;
+
     return (SOX_SUCCESS);
 }
 
-static int sox_sunstartwrite(sox_format_t * ft)
+static int sunstartwrite(sox_format_t * ft)
 {
-    priv_t *file = (priv_t *)ft->priv;
     size_t samplesize, encoding;
     audio_info_t audio_if;
 #ifdef __SVR4
@@ -187,16 +209,24 @@
     audio_device_t audio_dev;
 #endif
     char simple_hw=0;
+    char const* szDevname;
+    priv_t* pPriv = (priv_t*)ft->priv;
+ 
+    if (ft->filename == 0 || ft->filename[0] == 0 || !strcasecmp("default", ft->filename)) {
+        szDevname = "/dev/audio";
+    } else {
+        szDevname = ft->filename;
+    }
 
-    /* Hard-code for now. */
-    file->count = 0;
-    file->pos = 0;
-    file->size = 1024;
-    file->buf = lsx_malloc (file->size);
+    pPriv->device = open(szDevname, O_WRONLY);
+    if (pPriv->device < 0) {
+        lsx_fail_errno(ft, errno, "open failed for device: %s", szDevname);
+        return SOX_EOF;
+    }
 
 #ifdef __SVR4
     /* Read in old values, change to what we need and then send back */
-    if (ioctl(fileno((FILE*)ft->fp), AUDIO_GETDEV, &audio_dev) < 0) {
+    if (ioctl(pPriv->device, AUDIO_GETDEV, &audio_dev) < 0) {
         lsx_fail_errno(ft,errno,"Unable to get device information.");
         return(SOX_EOF);
     }
@@ -229,6 +259,7 @@
     if (ft->encoding.bits_per_sample == 8)
     {
         samplesize = 8;
+        pPriv->sample_shift = 0;
         if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
             ft->encoding.encoding = SOX_ENCODING_ULAW;
         else if (ft->encoding.encoding != SOX_ENCODING_ULAW &&
@@ -249,6 +280,7 @@
     }
     else if (ft->encoding.bits_per_sample == 16) {
         samplesize = 16;
+        pPriv->sample_shift = 1;
         if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
             ft->encoding.encoding = SOX_ENCODING_SIGN2;
         else if (ft->encoding.encoding != SOX_ENCODING_SIGN2) {
@@ -262,12 +294,13 @@
         ft->encoding.bits_per_sample = 16;
         ft->encoding.encoding = SOX_ENCODING_SIGN2;
         samplesize = 16;
+        pPriv->sample_shift = 1;
     }
 
     if (ft->signal.channels > 1) ft->signal.channels = 2;
 
     /* Read in old values, change to what we need and then send back */
-    if (ioctl(fileno((FILE*)ft->fp), AUDIO_GETINFO, &audio_if) < 0) {
+    if (ioctl(pPriv->device, AUDIO_GETINFO, &audio_if) < 0) {
         lsx_fail_errno(ft,errno,"Unable to initialize /dev/audio");
         return(SOX_EOF);
     }
@@ -282,7 +315,7 @@
         encoding = AUDIO_ENCODING_LINEAR;
     audio_if.play.encoding = encoding;
 
-    ioctl(fileno((FILE*)ft->fp), AUDIO_SETINFO, &audio_if);
+    ioctl(pPriv->device, AUDIO_SETINFO, &audio_if);
     if (audio_if.play.precision != samplesize) {
         lsx_fail_errno(ft,errno,"Unable to initialize sample size for /dev/audio");
         return(SOX_EOF);
@@ -299,12 +332,175 @@
         lsx_fail_errno(ft,errno,"Unable to initialize encoding for /dev/audio");
         return(SOX_EOF);
     }
-    /* Change to non-buffered I/O */
-    setvbuf(ft->fp, NULL, _IONBF, sizeof(char) * file->size);
 
+    pPriv->cOutput = sox_globals.bufsiz >> pPriv->sample_shift;
+    pPriv->pOutput = lsx_malloc((size_t)pPriv->cOutput << pPriv->sample_shift);
+
     return (SOX_SUCCESS);
 }
 
+static int sunstop(sox_format_t* ft)
+{
+    priv_t* pPriv = (priv_t*)ft->priv;
+    if (pPriv->device >= 0) {
+        close(pPriv->device);
+    }
+    if (pPriv->pOutput) {
+        free(pPriv->pOutput);
+    }
+    return SOX_SUCCESS;
+}
+
+typedef sox_uint16_t sox_uint14_t;
+typedef sox_uint16_t sox_uint13_t;
+typedef sox_int16_t sox_int14_t;
+typedef sox_int16_t sox_int13_t;
+#define SOX_ULAW_BYTE_TO_SAMPLE(d,clips)   SOX_SIGNED_16BIT_TO_SAMPLE(sox_ulaw2linear16(d),clips)
+#define SOX_ALAW_BYTE_TO_SAMPLE(d,clips)   SOX_SIGNED_16BIT_TO_SAMPLE(sox_alaw2linear16(d),clips)
+#define SOX_SAMPLE_TO_ULAW_BYTE(d,c) sox_14linear2ulaw(SOX_SAMPLE_TO_UNSIGNED(14,d,c) - 0x2000)
+#define SOX_SAMPLE_TO_ALAW_BYTE(d,c) sox_13linear2alaw(SOX_SAMPLE_TO_UNSIGNED(13,d,c) - 0x1000)
+
+static size_t sunread(sox_format_t* ft, sox_sample_t* pOutput, size_t cOutput)
+{
+    priv_t* pPriv = (priv_t*)ft->priv;
+    char* pbOutput = (char*)pOutput;
+    size_t cbOutputLeft = cOutput << pPriv->sample_shift;
+    size_t i, cRead;
+    int cbRead;
+    SOX_SAMPLE_LOCALS;
+    LSX_USE_VAR(sox_macro_temp_double);
+
+    while (cbOutputLeft) {
+        cbRead = read(pPriv->device, pbOutput, cbOutputLeft);
+        if (cbRead <= 0) {
+            if (cbRead < 0) {
+                lsx_fail_errno(ft, errno, "Error reading from device");
+                return 0;
+            }
+            break;
+        }
+        cbOutputLeft -= cbRead;
+        pbOutput += cbRead;
+    }
+
+    /* Convert in-place (backwards) */
+    cRead = cOutput - (cbOutputLeft >> pPriv->sample_shift);
+    switch (pPriv->sample_shift)
+    {
+    case 0:
+        switch (ft->encoding.encoding)
+        {
+        case SOX_ENCODING_SIGN2:
+            for (i = cRead; i != 0; i--) {
+                pOutput[i - 1] = SOX_UNSIGNED_8BIT_TO_SAMPLE(
+                ((sox_uint8_t*)pOutput)[i - 1],
+                dummy);
+            }
+            break;
+        case SOX_ENCODING_ULAW:
+            for (i = cRead; i != 0; i--) {
+                pOutput[i - 1] = SOX_ULAW_BYTE_TO_SAMPLE(
+                ((sox_uint8_t*)pOutput)[i - 1],
+                dummy);
+            }
+            break;
+        case SOX_ENCODING_ALAW:
+            for (i = cRead; i != 0; i--) {
+                pOutput[i - 1] = SOX_ALAW_BYTE_TO_SAMPLE(
+                ((sox_uint8_t*)pOutput)[i - 1],
+                dummy);
+            }
+            break;
+        default:
+            return 0;
+        }
+        break;
+    case 1:
+        for (i = cRead; i != 0; i--) {
+            pOutput[i - 1] = SOX_SIGNED_16BIT_TO_SAMPLE(
+            ((sox_int16_t*)pOutput)[i - 1],
+            dummy);
+        }
+        break;
+    }
+
+    return cRead;
+}
+
+static size_t sunwrite(
+    sox_format_t* ft,
+    const sox_sample_t* pInput,
+    size_t cInput)
+{
+    priv_t* pPriv = (priv_t*)ft->priv;
+    size_t cInputRemaining = cInput;
+    unsigned cClips = 0;
+    SOX_SAMPLE_LOCALS;
+
+    while (cInputRemaining) {
+        size_t cStride;
+        size_t i;
+        size_t cbStride;
+        int cbWritten;
+
+        cStride = cInput;
+        if (cStride > pPriv->cOutput) {
+            cStride = pPriv->cOutput;
+        }
+
+        switch (pPriv->sample_shift)
+        {
+        case 0:
+            switch (ft->encoding.encoding)
+            {
+            case SOX_ENCODING_SIGN2:
+                for (i = 0; i != cStride; i++) {
+                    ((sox_uint8_t*)pPriv->pOutput)[i] =
+                        SOX_SAMPLE_TO_UNSIGNED_8BIT(pInput[i], cClips);
+                }
+                break;
+            case SOX_ENCODING_ULAW:
+                for (i = 0; i != cStride; i++) {
+                    ((sox_uint8_t*)pPriv->pOutput)[i] =
+                        SOX_SAMPLE_TO_ULAW_BYTE(pInput[i], cClips);
+                }
+                break;
+            case SOX_ENCODING_ALAW:
+                for (i = 0; i != cStride; i++) {
+                    ((sox_uint8_t*)pPriv->pOutput)[i] =
+                        SOX_SAMPLE_TO_ALAW_BYTE(pInput[i], cClips);
+                }
+                break;
+            default:
+                return 0;
+            }
+            break;
+        case 1:
+            for (i = 0; i != cStride; i++) {
+                ((sox_int16_t*)pPriv->pOutput)[i] =
+                    SOX_SAMPLE_TO_SIGNED_16BIT(pInput[i], cClips);
+            }
+            break;
+        }
+
+        cbStride = cStride << pPriv->sample_shift;
+        i = 0;
+        do {
+            cbWritten = write(pPriv->device, &pPriv->pOutput[i], cbStride - i);
+            i += cbWritten;
+            if (cbWritten <= 0) {
+                lsx_fail_errno(ft, errno, "Error writing to device");
+                return 0;
+            }
+        } while (i != cbStride);
+
+        cInputRemaining -= cStride;
+        pInput += cStride;
+    }
+
+    return cInput;
+}
+
 LSX_FORMAT_HANDLER(sunau)
 {
   static char const * const names[] = {"sunau", NULL};
@@ -314,9 +510,10 @@
     SOX_ENCODING_SIGN2, 8, 16, 0,
     0};
   static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
-    "Sun audio device driver", names, SOX_FILE_DEVICE,
-    sox_sunstartread, lsx_rawread, lsx_rawstopread,
-    sox_sunstartwrite, lsx_rawwrite, lsx_rawstopwrite,
+    "Sun audio device driver",
+    names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO,
+    sunstartread, sunread, sunstop,
+    sunstartwrite, sunwrite, sunstop,
     NULL, write_encodings, NULL, sizeof(priv_t)
   };
   return &handler;