shithub: sox

Download patch

ref: fb63a6fa508985d070cb3267fc686b8a88718716
parent: fc168d5a7c3365953eb291dfdd0a5df9e34e708d
author: Doug Cook <idigdoug@users.sourceforge.net>
date: Fri Feb 3 00:06:15 EST 2012

Circular buffer for coreaudio.c
Patch from Michael Chen (plus a bit of whitespace cleanup from me).

--- a/src/coreaudio.c
+++ b/src/coreaudio.c
@@ -8,14 +8,18 @@
 #include <CoreAudio/CoreAudio.h>
 #include <pthread.h>
 
+#define Buffactor 4
+
 typedef struct {
   AudioDeviceID adid;
   pthread_mutex_t mutex;
   pthread_cond_t cond;
   int device_started;
-  size_t buf_size;
-  size_t buf_offset;
-  float *buffer;
+  size_t bufsize;
+  size_t bufrd;
+  size_t bufwr;
+  size_t bufrdavail;
+  float *buf;
 } priv_t;
 
 static OSStatus PlaybackIOProc(AudioDeviceID inDevice UNUSED,
@@ -26,40 +30,41 @@
                                const AudioTimeStamp *inOutputTime UNUSED,
                                void *inClientData)
 {
-  sox_format_t *ft = (sox_format_t *)inClientData;
-  priv_t *ac = (priv_t *)ft->priv;
-  char *buf = outOutputData->mBuffers[0].mData;
-  unsigned int len, output_len;
+    priv_t *ac = (priv_t*)((sox_format_t*)inClientData)->priv;
+    AudioBuffer *buf;
+    size_t copylen, avail;
 
-  if (outOutputData->mNumberBuffers != 1)
-  {
-	  lsx_warn("coreaudio: unhandled extra buffer.  Data discarded.");
-	  return kAudioHardwareNoError;
-  }
+    pthread_mutex_lock(&ac->mutex);
 
-  buf = (char *)outOutputData->mBuffers[0].mData;
-  output_len = outOutputData->mBuffers[0].mDataByteSize;
+    for(buf = outOutputData->mBuffers;
+        buf != outOutputData->mBuffers + outOutputData->mNumberBuffers;
+        buf++){
 
-  pthread_mutex_lock(&ac->mutex);
+        copylen = buf->mDataByteSize / sizeof(float);
+        if(copylen > ac->bufrdavail)
+            copylen = ac->bufrdavail;
 
-  len = (ac->buf_offset < output_len) ? ac->buf_offset : output_len;
+        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));
+        }else{
+            memcpy(buf->mData, ac->buf + ac->bufrd, copylen * sizeof(float));
+        }
 
-  /* Make sure to write 2 (stereo) floats at a time */
-  if (len % 8)
-      len -= len % 8;
+        buf->mDataByteSize = copylen * sizeof(float);
+        ac->bufrd += copylen;
+        if(ac->bufrd >= ac->bufsize)
+            ac->bufrd -= ac->bufsize;
+        ac->bufrdavail -= copylen;
+    }
 
-  memcpy(buf, ac->buffer, len);
+    pthread_cond_signal(&ac->cond);
+    pthread_mutex_unlock(&ac->mutex);
 
-  /* Fill partial output buffers with silence */
-  if (len < output_len)
-      memset(buf+len, 0, output_len-len);
-
-  ac->buf_offset -= len;
-
-  pthread_mutex_unlock(&ac->mutex);
-  pthread_cond_signal(&ac->cond);
-
-  return kAudioHardwareNoError;
+    return kAudioHardwareNoError;
 }
 
 static OSStatus RecIOProc(AudioDeviceID inDevice UNUSED,
@@ -70,51 +75,45 @@
                           const AudioTimeStamp *inOutputTime UNUSED,
                           void *inClientData)
 {
-  sox_format_t *ft = (sox_format_t *)inClientData;
-  priv_t *ac = (priv_t *)ft->priv;
-  size_t len, output_len;
-  char *destbuf;
-  char *buf;
-  int i;
+    priv_t *ac = (priv_t *)((sox_format_t*)inClientData)->priv;
+    AudioBuffer *buf;
+    size_t nfree, copylen, avail;
 
-  pthread_mutex_lock(&ac->mutex);
+    pthread_mutex_lock(&ac->mutex);
 
-  if (inInputData->mNumberBuffers != 1)
-  {
-    lsx_warn("coreaudio: unhandled extra buffer.  Data discarded.");
-    return kAudioHardwareNoError;
-  }
+    for(buf = inInputData->mBuffers;
+        buf != inInputData->mBuffers + inInputData->mNumberBuffers;
+        buf++){
 
-  destbuf = ((char *)ac->buffer + ac->buf_offset);
-  buf = inInputData->mBuffers[0].mData;
-  output_len = inInputData->mBuffers[0].mDataByteSize;
+        if(buf->mData == NULL)
+            continue;
 
-  /* mDataByteSize may be non-zero even when mData is NULL, but that is
-   * not an error.
-   */
-  if (buf == NULL)
-    return kAudioHardwareNoError;
+        copylen = buf->mDataByteSize / sizeof(float);
+        nfree = ac->bufsize - ac->bufrdavail - 1;
+        if(nfree == 0)
+            lsx_warn("coreaudio: unhandled buffer overrun.  Data discarded.");
 
-  len = ac->buf_size - ac->buf_offset;
+        if(copylen > nfree)
+            copylen = nfree;
 
-  /* Make sure to read 2 (stereo) floats at a time */
-  if (len % 8)
-      len -= len % 8;
+        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 (len > output_len)
-    len = output_len;
+        ac->bufwr += copylen;
+        if(ac->bufwr >= ac->bufsize)
+            ac->bufwr -= ac->bufsize;
+        ac->bufrdavail += copylen;
+    }
 
-  /* FIXME: Handle buffer overrun. */
-  if (len < output_len)
-      lsx_warn("coreaudio: unhandled buffer overrun.  Data discarded.");
+    pthread_cond_signal(&ac->cond);
+    pthread_mutex_unlock(&ac->mutex);
 
-  memcpy(destbuf, buf, len);
-  ac->buf_offset += len;
-
-  pthread_mutex_unlock(&ac->mutex);
-  pthread_cond_signal(&ac->cond);
-
-  return kAudioHardwareNoError;
+    return kAudioHardwareNoError;
 }
 
 static int setup(sox_format_t *ft, int is_input)
@@ -130,9 +129,9 @@
   {
       property_size = sizeof(ac->adid);
       if (is_input)
-	  status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &property_size, &ac->adid);
+          status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &property_size, &ac->adid);
       else
-	  status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &property_size, &ac->adid);
+          status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &property_size, &ac->adid);
   }
   else
   {
@@ -141,33 +140,33 @@
 
       if (status == noErr)
       {
-	  int device_count = property_size/sizeof(AudioDeviceID);
-	  AudioDeviceID *devices;
+          int device_count = property_size/sizeof(AudioDeviceID);
+          AudioDeviceID *devices;
 
-	  devices = malloc(property_size);
-    	  status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &property_size, devices);
+          devices = malloc(property_size);
+              status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &property_size, devices);
 
-	  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);
+          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);
 
-		  lsx_report("Found Audio Device \"%s\"\n",name);
+                  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);
+                  /* 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);
       }
   }
 
@@ -247,11 +246,13 @@
     ft->signal.rate = stream_desc.mSampleRate;
   }
 
-  ac->buf_size = sox_globals.bufsiz * sizeof(float);
-  ac->buf_offset = 0;
-  ac->buffer = lsx_malloc(ac->buf_size);
+  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 = ac->buf_size;
+  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,
@@ -289,33 +290,34 @@
 
 static size_t read_samples(sox_format_t *ft, sox_sample_t *buf, size_t nsamp)
 {
-  priv_t *ac = (priv_t *)ft->priv;
-  size_t len = nsamp;
-  size_t samp_left;
-  OSStatus status;
-  float *p;
-  SOX_SAMPLE_LOCALS;
+    priv_t *ac = (priv_t *)ft->priv;
+    size_t len;
+    SOX_SAMPLE_LOCALS;
 
-  if (!ac->device_started)
-  {
-    status = AudioDeviceStart(ac->adid, RecIOProc);
-    ac->device_started = 1;
-  }
+    if (!ac->device_started) {
+        AudioDeviceStart(ac->adid, RecIOProc);
+        ac->device_started = 1;
+    }
 
-  pthread_mutex_lock(&ac->mutex);
+    pthread_mutex_lock(&ac->mutex);
 
-  /* Wait until input buffer has been filled by device driver */
-  while (ac->buf_offset < ac->buf_size)
-    pthread_cond_wait(&ac->cond, &ac->mutex);
+    /* Wait until input buffer has been filled by device driver */
+    while (ac->bufrdavail == 0)
+        pthread_cond_wait(&ac->cond, &ac->mutex);
 
-  len = ac->buf_offset / sizeof(float);
-  for (p = ac->buffer, samp_left = len; samp_left > 0; samp_left--, buf++, p++)
-    *buf = SOX_FLOAT_32BIT_TO_SAMPLE(*p, ft->clips);
-  ac->buf_offset = 0;
+    len = 0;
+    while(len < nsamp && ac->bufrdavail > 0){
+        buf[len] = SOX_FLOAT_32BIT_TO_SAMPLE(ac->buf[ac->bufrd], ft->clips);
+        len++;
+        ac->bufrd++;
+        if(ac->bufrd == ac->bufsize)
+            ac->bufrd = 0;
+        ac->bufrdavail--;
+    }
 
-  pthread_mutex_unlock(&ac->mutex);
+    pthread_mutex_unlock(&ac->mutex);
 
-  return len;
+    return len;
 }
 
 static int stopread(sox_format_t * ft)
@@ -326,6 +328,7 @@
   AudioDeviceRemoveIOProc(ac->adid, RecIOProc);
   pthread_cond_destroy(&ac->cond);
   pthread_mutex_destroy(&ac->mutex);
+  free(ac->buf);
 
   return SOX_SUCCESS;
 }
@@ -337,78 +340,65 @@
 
 static size_t write_samples(sox_format_t *ft, const sox_sample_t *buf, size_t nsamp)
 {
-  priv_t *ac = (priv_t *)ft->priv;
-  size_t len, written = 0;
-  size_t samp_left;
-  OSStatus status;
-  float *p;
-  SOX_SAMPLE_LOCALS;
+    priv_t *ac = (priv_t *)ft->priv;
+    size_t i;
 
-  pthread_mutex_lock(&ac->mutex);
+    SOX_SAMPLE_LOCALS;
 
-  /* Wait to start until mutex is locked to help prevent callback
-   * getting zero samples.
-   */
-  if (!ac->device_started)
-  {
-      status = AudioDeviceStart(ac->adid, PlaybackIOProc);
-      if (status)
-      {
-	  pthread_mutex_unlock(&ac->mutex);
-	  return SOX_EOF;
-      }
-      ac->device_started = 1;
-  }
+    pthread_mutex_lock(&ac->mutex);
 
-  /* globals.bufsize is in samples
-   * buf_offset is in bytes
-   * buf_size is in bytes
-   */
-  do {
-    while (ac->buf_offset >= ac->buf_size)
-	pthread_cond_wait(&ac->cond, &ac->mutex);
+    /* Wait to start until mutex is locked to help prevent callback
+    * getting zero samples.
+    */
+    if(!ac->device_started){
+        if(AudioDeviceStart(ac->adid, PlaybackIOProc)){
+            pthread_mutex_unlock(&ac->mutex);
+            return SOX_EOF;
+        }
+        ac->device_started = 1;
+    }
 
-    len = nsamp - written;
-    if (len > (ac->buf_size - ac->buf_offset) / sizeof(float))
-      len = (ac->buf_size - ac->buf_offset) / sizeof(float);
-    samp_left = len;
+    /* globals.bufsize is in samples
+    * buf_offset is in bytes
+    * buf_size is in bytes
+    */
+    for(i = 0; i < nsamp; i++){
+        while(ac->bufrdavail == ac->bufsize - 1)
+            pthread_cond_wait(&ac->cond, &ac->mutex);
 
-    p = ((unsigned char *)ac->buffer) + ac->buf_offset;
+        ac->buf[ac->bufwr] = SOX_SAMPLE_TO_FLOAT_32BIT(buf[i], ft->clips);
+        ac->bufwr++;
+        if(ac->bufwr == ac->bufsize)
+            ac->bufwr = 0;
+        ac->bufrdavail++;
+    }
 
-    while (samp_left--)
-      *p++ = SOX_SAMPLE_TO_FLOAT_32BIT(*buf++, ft->clips);
-
-    ac->buf_offset += len * sizeof(float);
-    written += len;
-  } while (written < nsamp);
-
-  pthread_mutex_unlock(&ac->mutex);
-
-  return written;
+    pthread_mutex_unlock(&ac->mutex);
+    return nsamp;
 }
 
 
 static int stopwrite(sox_format_t * ft)
 {
-  priv_t *ac = (priv_t *)ft->priv;
+    priv_t *ac = (priv_t *)ft->priv;
 
-  if (!ac->device_started)
-  {
-    pthread_mutex_lock(&ac->mutex);
+    if(ac->device_started){
+        pthread_mutex_lock(&ac->mutex);
 
-    while (ac->buf_offset)
-	pthread_cond_wait(&ac->cond, &ac->mutex);
+        while (ac->bufrdavail > 0)
+            pthread_cond_wait(&ac->cond, &ac->mutex);
 
-    pthread_mutex_unlock(&ac->mutex);
+        pthread_mutex_unlock(&ac->mutex);
 
-    AudioDeviceStop(ac->adid, PlaybackIOProc);
-  }
+        AudioDeviceStop(ac->adid, PlaybackIOProc);
+    }
 
-  AudioDeviceRemoveIOProc(ac->adid, PlaybackIOProc);
-  pthread_cond_destroy(&ac->cond);
-  pthread_mutex_destroy(&ac->mutex);
+    AudioDeviceRemoveIOProc(ac->adid, PlaybackIOProc);
+    pthread_cond_destroy(&ac->cond);
+    pthread_mutex_destroy(&ac->mutex);
+    free(ac->buf);
 
-  return SOX_SUCCESS;
+    return SOX_SUCCESS;
 }
 
 LSX_FORMAT_HANDLER(coreaudio)