shithub: sox

Download patch

ref: 39ab8048446fcaf580885353244b4f48c981319d
parent: ef624ab558952482058e8fd4444afc1a0a1cdba6
author: Chris Bagwell <chris@cnpbagwell.com>
date: Sun Mar 4 06:12:33 EST 2012

Revert "Apple CoreAudio - use virtual formats (works on more hardware)"

This change is to risky to go in right before releasing 14.4.0 and
I suspect doesn't compile on OS X 10.5.  It can be added back when
longer testing can occur.

This reverts commit 621b1586820b67ec7b5989f6eef8616c79ba8d86.

--- a/src/coreaudio.c
+++ b/src/coreaudio.c
@@ -6,24 +6,20 @@
 #include "sox_i.h"
 
 #include <CoreAudio/CoreAudio.h>
-
-#include <assert.h>
-#include <limits.h>
 #include <pthread.h>
 
-#define Buffactor 8
+#define Buffactor 4
 
 typedef struct {
-    AudioDeviceID adid;
-    pthread_mutex_t mutex;
-    pthread_cond_t cond;
-    int device_started;
-    size_t bufsize;
-    size_t bufrd;
-    size_t bufwr;
-    size_t bufrdavail;
-    float *buf;
-    UInt32 strmidx;
+  AudioDeviceID adid;
+  pthread_mutex_t mutex;
+  pthread_cond_t cond;
+  int device_started;
+  size_t bufsize;
+  size_t bufrd;
+  size_t bufwr;
+  size_t bufrdavail;
+  float *buf;
 } priv_t;
 
 static OSStatus PlaybackIOProc(AudioDeviceID inDevice UNUSED,
@@ -37,33 +33,23 @@
     priv_t *ac = (priv_t*)((sox_format_t*)inClientData)->priv;
     AudioBuffer *buf;
     size_t copylen, avail;
-    UInt32 i;
 
     pthread_mutex_lock(&ac->mutex);
 
-    assert(ac->strmidx < outOutputData->mNumberBuffers);
+    for(buf = outOutputData->mBuffers;
+        buf != outOutputData->mBuffers + outOutputData->mNumberBuffers;
+        buf++){
 
-    for(i = 0; i < outOutputData->mNumberBuffers; i++) {
-	buf = outOutputData->mBuffers + i;
+        copylen = buf->mDataByteSize / sizeof(float);
+        if(copylen > ac->bufrdavail)
+            copylen = ac->bufrdavail;
 
-	if(i != ac->strmidx) {
-	    buf->mDataByteSize = 0;
-	    continue;
-	}
-
-	assert(buf->mData != NULL);
-
-	copylen = buf->mDataByteSize / sizeof(float);
-	if(copylen > ac->bufrdavail)
-	    copylen = ac->bufrdavail;
-
         avail = ac->bufsize - ac->bufrd;
         if(buf->mData == NULL){
             /*do nothing-hardware can't play audio*/
         }else if(copylen > avail){
             memcpy(buf->mData, ac->buf + ac->bufrd, avail * sizeof(float));
-            memcpy((float*)buf->mData + avail, ac->buf,
-		   (copylen - avail) * sizeof(float));
+            memcpy((float*)buf->mData + avail, ac->buf, (copylen - avail) * sizeof(float));
         }else{
             memcpy(buf->mData, ac->buf + ac->bufrd, copylen * sizeof(float));
         }
@@ -90,36 +76,40 @@
                           void *inClientData)
 {
     priv_t *ac = (priv_t *)((sox_format_t*)inClientData)->priv;
-    const AudioBuffer *buf;
+    AudioBuffer *buf;
     size_t nfree, copylen, avail;
 
     pthread_mutex_lock(&ac->mutex);
 
-    assert(ac->strmidx < inInputData->mNumberBuffers);
-    buf = inInputData->mBuffers + ac->strmidx;
-    assert(buf->mData != NULL);
+    for(buf = inInputData->mBuffers;
+        buf != inInputData->mBuffers + inInputData->mNumberBuffers;
+        buf++){
 
-    copylen = buf->mDataByteSize / sizeof(float);
-    nfree = ac->bufsize - ac->bufrdavail - 1;
-    if(nfree == 0)
-	lsx_warn("coreaudio: unhandled buffer overrun.  Data discarded.");
+        if(buf->mData == NULL)
+            continue;
 
-    if(copylen > nfree)
-	copylen = nfree;
+        copylen = buf->mDataByteSize / sizeof(float);
+        nfree = ac->bufsize - ac->bufrdavail - 1;
+        if(nfree == 0)
+            lsx_warn("coreaudio: unhandled buffer overrun.  Data discarded.");
 
-    avail = ac->bufsize - ac->bufwr;
-    if(copylen > avail){
-	memcpy(ac->buf + ac->bufwr, buf->mData, avail * sizeof(float));
-	memcpy(ac->buf, (float*)buf->mData + avail, (copylen - avail) * sizeof(float));
-    }else{
-	memcpy(ac->buf + ac->bufwr, buf->mData, copylen * sizeof(float));
-    }
+        if(copylen > nfree)
+            copylen = nfree;
 
-    ac->bufwr += copylen;
-    if(ac->bufwr >= ac->bufsize)
-	ac->bufwr -= ac->bufsize;
-    ac->bufrdavail += copylen;
+        avail = ac->bufsize - ac->bufwr;
+        if(copylen > avail){
+            memcpy(ac->buf + ac->bufwr, buf->mData, avail * sizeof(float));
+            memcpy(ac->buf, (float*)buf->mData + avail, (copylen - avail) * sizeof(float));
+        }else{
+            memcpy(ac->buf + ac->bufwr, buf->mData, copylen * sizeof(float));
+        }
 
+        ac->bufwr += copylen;
+        if(ac->bufwr >= ac->bufsize)
+            ac->bufwr -= ac->bufsize;
+        ac->bufrdavail += copylen;
+    }
+
     pthread_cond_signal(&ac->cond);
     pthread_mutex_unlock(&ac->mutex);
 
@@ -126,244 +116,171 @@
     return kAudioHardwareNoError;
 }
 
-static int
-distance(const struct AudioStreamRangedDescription *desc,
-        const sox_format_t *ft)
+static int setup(sox_format_t *ft, int is_input)
 {
-    int distance = 0;
+  priv_t *ac = (priv_t *)ft->priv;
+  OSStatus status;
+  UInt32 property_size;
+  struct AudioStreamBasicDescription stream_desc;
+  int32_t buf_size;
+  int rc;
 
-    if ((desc->mFormat.mFormatFlags & kLinearPCMFormatFlagIsFloat) == 0)
-        return INT_MAX;
-    
-    if (desc->mSampleRateRange.mMinimum > ft->signal.rate)
-        distance += (desc->mSampleRateRange.mMinimum - ft->signal.rate) / 1000;
+  if (strncmp(ft->filename, "default", (size_t)7) == 0)
+  {
+      property_size = sizeof(ac->adid);
+      if (is_input)
+          status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &property_size, &ac->adid);
+      else
+          status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &property_size, &ac->adid);
+  }
+  else
+  {
+      Boolean is_writable;
+      status = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &property_size, &is_writable);
 
-    if (desc->mSampleRateRange.mMaximum < ft->signal.rate)
-        distance += (ft->signal.rate - desc->mSampleRateRange.mMaximum) / 1000;
+      if (status == noErr)
+      {
+          int device_count = property_size/sizeof(AudioDeviceID);
+          AudioDeviceID *devices;
 
-    distance += abs(ft->signal.channels - desc->mFormat.mChannelsPerFrame);
+          devices = malloc(property_size);
+              status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &property_size, devices);
 
-    return distance;
-}
+          if (status == noErr)
+          {
+              int i;
+              for (i = 0; i < device_count; i++)
+              {
+                  char name[256];
+                  status = AudioDeviceGetProperty(devices[i],0,false,kAudioDevicePropertyDeviceName,&property_size,&name);
 
-static int setup(sox_format_t *ft, int is_input)
-{
-    priv_t *ac = (priv_t *)ft->priv;
-    OSStatus status;
-    UInt32 property_size;
-    struct AudioStreamBasicDescription stream_desc;
-    int32_t buf_size;
-    int rc, i , count, best;
-    AudioStreamID *strms, strm;
-    Boolean is_writable;
-    struct AudioStreamRangedDescription *strmdescs;
+                  lsx_report("Found Audio Device \"%s\"\n",name);
 
-    if (strncmp(ft->filename, "default", (size_t)7) == 0) {
-        property_size = sizeof(ac->adid);
-        status = AudioHardwareGetProperty(
-                is_input? kAudioHardwarePropertyDefaultInputDevice :
-                    kAudioHardwarePropertyDefaultOutputDevice,
-                &property_size, &ac->adid);
-        if (status != noErr || ac->adid == kAudioDeviceUnknown) {
-            lsx_fail_errno(ft, SOX_EPERM, "can not open default audio device");
-            return SOX_EOF;
-        }
-	
-    } else {
-        AudioDeviceID *devices;
-        
-        status = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
-                &property_size, &is_writable);
-        if (status != noErr) {
-            lsx_fail_errno(ft, SOX_EPERM, "can not get hardware prop info");
-            return SOX_EOF;
-        }
-        
-        count = property_size / sizeof(AudioDeviceID);
-        devices = malloc((size_t)property_size);
-        status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
-                &property_size, devices);
-        if (status != noErr) {
-            lsx_fail_errno(ft, SOX_EPERM, "can not enum devices");
-            free(devices);
-            return SOX_EOF;
-        }
+                  /* String returned from OS is truncated so only compare
+                   * as much as returned.
+                   */
+                  if (strncmp(name,ft->filename,strlen(name)) == 0)
+                  {
+                      ac->adid = devices[i];
+                      break;
+                  }
+              }
+          }
+          free(devices);
+      }
+  }
 
-        for (i = 0; i < count; i++) {
-            char name[256];
-            
-            property_size = sizeof(name);
-            status = AudioDeviceGetProperty(devices[i], 0, false,
-                    kAudioDevicePropertyDeviceName, &property_size,
-                    &name);
-            if (status != noErr)
-                continue;
-            
-            lsx_report("Found Audio Device \"%s\"\n",name);
-            
-            /* String returned from OS is truncated so only compare
-             * as much as returned.
-             */
-            if (strncmp(name,ft->filename,strlen(name)) == 0) {
-                ac->adid = devices[i];
-                break;
-            }
-        }
-        free(devices);
-    }
+  if (status || ac->adid == kAudioDeviceUnknown)
+  {
+    lsx_fail_errno(ft, SOX_EPERM, "can not open audio device");
+    return SOX_EOF;
+  }
 
-    /* Find the stream */
-    status = AudioDeviceGetPropertyInfo(ac->adid, 0, is_input,
-            kAudioDevicePropertyStreams, &property_size,
-            &is_writable);
-    if (status != noErr) {
-        lsx_fail_errno(ft, SOX_EPERM, "can not get audio device properties");
-        return SOX_EOF;
-    }
+  /* Query device to get initial values */
+  property_size = sizeof(struct AudioStreamBasicDescription);
+  status = AudioDeviceGetProperty(ac->adid, 0, is_input,
+                                  kAudioDevicePropertyStreamFormat,
+                                  &property_size, &stream_desc);
+  if (status)
+  {
+    lsx_fail_errno(ft, SOX_EPERM, "can not get audio device properties");
+    return SOX_EOF;
+  }
 
-    count = property_size / sizeof(AudioStreamID);
-    assert(count >= 1);
-    strms = (AudioStreamID *)malloc(property_size);
+  if (!(stream_desc.mFormatFlags & kLinearPCMFormatFlagIsFloat))
+  {
+    lsx_fail_errno(ft, SOX_EPERM, "audio device does not accept floats");
+    return SOX_EOF;
+  }
 
-    status = AudioDeviceGetProperty(ac->adid, 0, is_input,
-            kAudioDevicePropertyStreams, &property_size,
-            strms);
-    if (status != noErr) {
-        lsx_fail_errno(ft, SOX_EPERM, "can not enum streams");
-        free(strms);
-        return SOX_EOF;
-    }
+  /* OS X effectively only supports these values. */
+  ft->signal.channels = 2;
+  ft->signal.rate = 44100;
+  ft->encoding.bits_per_sample = 32;
 
-    /* TODO: allow the user to select the stream */
-    lsx_report("Found %d Streams for selected audio device, defaulting to 0\n",
-	       count);
+  /* TODO: My limited experience with hardware can only get floats working
+   * withh a fixed sample rate and stereo.  I know that is a limitiation of
+   * audio device I have so this may not be standard operating orders.
+   * If some hardware supports setting sample rates and channel counts
+   * then should do that over resampling and mixing.
+   */
+#if  0
+  stream_desc.mSampleRate = ft->signal.rate;
+  stream_desc.mChannelsPerFrame = ft->signal.channels;
 
-    ac->strmidx = 0;
-    strm = strms[0];
-    free(strms);
-    
-    status = AudioStreamGetPropertyInfo(strm, 0,
-            kAudioStreamPropertyAvailableVirtualFormats, &property_size,
-            &is_writable);
-    if (status != noErr) {
-        lsx_fail_errno(ft, SOX_EPERM, "failed to get format size");
-        return SOX_EOF;
-    }
+  /* Write them back */
+  property_size = sizeof(struct AudioStreamBasicDescription);
+  status = AudioDeviceSetProperty(ac->adid, NULL, 0, is_input,
+                                  kAudioDevicePropertyStreamFormat,
+                                  property_size, &stream_desc);
+  if (status)
+  {
+    lsx_fail_errno(ft, SOX_EPERM, "can not set audio device properties");
+    return SOX_EOF;
+  }
 
-    count = property_size / sizeof(struct AudioStreamRangedDescription);
-    assert(count > 0);
+  /* Query device to see if it worked */
+  property_size = sizeof(struct AudioStreamBasicDescription);
+  status = AudioDeviceGetProperty(ac->adid, 0, is_input,
+                                  kAudioDevicePropertyStreamFormat,
+                                  &property_size, &stream_desc);
 
-    strmdescs = (struct AudioStreamRangedDescription *) malloc(property_size);
-    
-    status = AudioStreamGetProperty(strm, 0,
-            kAudioStreamPropertyAvailableVirtualFormats, &property_size,
-            strmdescs);
-    if (status != noErr) {
-        lsx_fail_errno(ft, SOX_EPERM, "failed to get formats");
-        free(strmdescs);
-        return SOX_EOF;
-    }
+  if (status)
+  {
+    lsx_fail_errno(ft, SOX_EPERM, "can not get audio device properties");
+    return SOX_EOF;
+  }
+#endif
 
-    best = 0;
-    for (i = 0; i < count; i++) {
-        lsx_report("Supported format: %lu bits, %lu nchan, %lf rate, %lf min"
-                ", %lf max\n",
-                strmdescs[i].mFormat.mBitsPerChannel,
-                strmdescs[i].mFormat.mChannelsPerFrame,
-                strmdescs[i].mFormat.mSampleRate,
-                strmdescs[i].mSampleRateRange.mMinimum,
-                strmdescs[i].mSampleRateRange.mMaximum);
+  if (stream_desc.mChannelsPerFrame != ft->signal.channels)
+  {
+    lsx_debug("audio device did not accept %d channels. Use %d channels instead.", (int)ft->signal.channels,
+              (int)stream_desc.mChannelsPerFrame);
+    ft->signal.channels = stream_desc.mChannelsPerFrame;
+  }
 
-        if (distance(&strmdescs[i], ft) < distance(&strmdescs[best], ft))
-            best = i;
-    }
+  if (stream_desc.mSampleRate != ft->signal.rate)
+  {
+    lsx_debug("audio device did not accept %d sample rate. Use %d instead.", (int)ft->signal.rate,
+              (int)stream_desc.mSampleRate);
+    ft->signal.rate = stream_desc.mSampleRate;
+  }
 
-    stream_desc = strmdescs[best].mFormat;
-    if (ft->signal.rate < strmdescs[best].mSampleRateRange.mMinimum) {
-        ft->signal.rate = strmdescs[best].mSampleRateRange.mMinimum;
-        stream_desc.mSampleRate = strmdescs[best].mSampleRateRange.mMinimum;
+  ac->bufsize = sox_globals.bufsiz / sizeof(sox_sample_t) * Buffactor;
+  ac->bufrd = 0;
+  ac->bufwr = 0;
+  ac->bufrdavail = 0;
+  ac->buf = lsx_malloc(ac->bufsize * sizeof(float));
 
-    } else if (ft->signal.rate > strmdescs[best].mSampleRateRange.mMaximum) {
-        ft->signal.rate = strmdescs[best].mSampleRateRange.mMaximum;
-        stream_desc.mSampleRate = strmdescs[best].mSampleRateRange.mMaximum;
+  buf_size = sox_globals.bufsiz / sizeof(sox_sample_t) * sizeof(float);
+  property_size = sizeof(buf_size);
+  status = AudioDeviceSetProperty(ac->adid, NULL, 0, is_input,
+                                  kAudioDevicePropertyBufferSize,
+                                  property_size, &buf_size);
 
-    } else {
-        stream_desc.mSampleRate = ft->signal.rate;
-    }
+  rc = pthread_mutex_init(&ac->mutex, NULL);
+  if (rc)
+  {
+    lsx_fail_errno(ft, SOX_EPERM, "failed initializing mutex");
+    return SOX_EOF;
+  }
 
-    ft->signal.channels = stream_desc.mChannelsPerFrame;
-    free(strmdescs);
+  rc = pthread_cond_init(&ac->cond, NULL);
+  if (rc)
+  {
+    lsx_fail_errno(ft, SOX_EPERM, "failed initializing condition");
+    return SOX_EOF;
+  }
 
-    if (!(stream_desc.mFormatFlags & kLinearPCMFormatFlagIsFloat)) {
-        lsx_fail_errno(ft, SOX_EPERM, "audio device does not accept floats");
-        return SOX_EOF;
-    }
+  ac->device_started = 0;
 
-    /* Write them back */
-    property_size = sizeof(stream_desc);
-    status = AudioStreamSetProperty(strm, NULL, 0,
-            kAudioStreamPropertyVirtualFormat, property_size, &stream_desc);
-    if (status != noErr) {
-        lsx_fail_errno(ft, SOX_EPERM, "can not set audio device properties");
-        return SOX_EOF;
-    }
-    
-    /* Query device to see if it worked */
-    property_size = sizeof(struct AudioStreamBasicDescription);
-    status = AudioStreamGetProperty(strm, 0,kAudioStreamPropertyPhysicalFormat,
-            &property_size, &stream_desc);
-    
-    if (status) {
-        lsx_fail_errno(ft, SOX_EPERM, "can not get audio device properties");
-        return SOX_EOF;
-    }
-    
-    assert(stream_desc.mChannelsPerFrame == ft->signal.channels);
-    if (stream_desc.mChannelsPerFrame != ft->signal.channels) {
-        lsx_debug("audio device did not accept %d channels. Use %d channels instead.", (int)ft->signal.channels,
-            (int)stream_desc.mChannelsPerFrame);
-        ft->signal.channels = stream_desc.mChannelsPerFrame;
-    }
-    
-    assert(stream_desc.mSampleRate == ft->signal.rate);
-    if (stream_desc.mSampleRate != ft->signal.rate) {
-        lsx_debug("audio device did not accept %d sample rate. Use %d instead.", (int)ft->signal.rate,
-            (int)stream_desc.mSampleRate);
-        ft->signal.rate = stream_desc.mSampleRate;
-    }
-    
-    ac->bufsize = sox_globals.bufsiz / sizeof(sox_sample_t) * Buffactor;
-    ac->bufrd = 0;
-    ac->bufwr = 0;
-    ac->bufrdavail = 0;
-    ac->buf = lsx_malloc(ac->bufsize * sizeof(float));
-    
-    buf_size = sox_globals.bufsiz / sizeof(sox_sample_t) /
-        stream_desc.mChannelsPerFrame;
-    property_size = sizeof(buf_size);
-    status = AudioDeviceSetProperty(ac->adid, NULL, 0, is_input,
-        kAudioDevicePropertyBufferFrameSize,
-        property_size, &buf_size);
-    
-    rc = pthread_mutex_init(&ac->mutex, NULL);
-    if (rc) {
-        lsx_fail_errno(ft, SOX_EPERM, "failed initializing mutex");
-        return SOX_EOF;
-    }
-    
-    rc = pthread_cond_init(&ac->cond, NULL);
-    if (rc) {
-        lsx_fail_errno(ft, SOX_EPERM, "failed initializing condition");
-        return SOX_EOF;
-    }
-    
-    ac->device_started = 0;
-    
-    /* Registers callback with the device without activating it. */
-    status = AudioDeviceAddIOProc(ac->adid,
-            is_input? RecIOProc : PlaybackIOProc, ft);
-    
-    return SOX_SUCCESS;
+  /* Registers callback with the device without activating it. */
+  if (is_input)
+    status = AudioDeviceAddIOProc(ac->adid, RecIOProc, (void *)ft);
+  else
+    status = AudioDeviceAddIOProc(ac->adid, PlaybackIOProc, (void *)ft);
+
+  return SOX_SUCCESS;
 }
 
 static int startread(sox_format_t *ft)