shithub: sox

Download patch

ref: 9f5e9c55a1f180c2a4213f4d9c7d30466fb40740
parent: 4ee6e3c11553c2883eba0da18cb1608ca9880d96
author: cbagwell <cbagwell>
date: Fri Aug 6 20:01:10 EDT 2010

Fix segfaults when recording on OS X.

--- a/ChangeLog
+++ b/ChangeLog
@@ -12,6 +12,11 @@
 o Fix regression where MP3 handler required libmad headers to be installed.
   (Samuli Suominen) 
 
+Audio device drivers:
+
+o Fix immediate segfault on OSX while attempting to record.  May also
+  prevent segfaults on playing that some people reported.  (Adam Fritzler)
+
 sox-14.3.1	2010-04-11
 ----------
 
--- a/src/coreaudio.c
+++ b/src/coreaudio.c
@@ -18,8 +18,8 @@
   float *buffer;
 } priv_t;
 
-static OSStatus PlaybackIOProc(AudioDeviceID inDevice UNUSED, 
-                               const AudioTimeStamp *inNow UNUSED, 
+static OSStatus PlaybackIOProc(AudioDeviceID inDevice UNUSED,
+                               const AudioTimeStamp *inNow UNUSED,
                                const AudioBufferList *inInputData UNUSED,
                                const AudioTimeStamp *inInputTime UNUSED,
                                AudioBufferList *outOutputData,
@@ -32,7 +32,7 @@
 
   pthread_mutex_lock(&ac->mutex);
 
-  memcpy(buf, ac->buffer, (ac->buf_offset) * sizeof(float));
+  memcpy(buf, ac->buffer, ac->buf_offset);
   ac->buf_offset = 0;
 
   pthread_mutex_unlock(&ac->mutex);
@@ -41,8 +41,8 @@
   return kAudioHardwareNoError;
 }
 
-static OSStatus RecIOProc(AudioDeviceID inDevice UNUSED, 
-                          const AudioTimeStamp *inNow UNUSED, 
+static OSStatus RecIOProc(AudioDeviceID inDevice UNUSED,
+                          const AudioTimeStamp *inNow UNUSED,
                           const AudioBufferList *inInputData,
                           const AudioTimeStamp *inInputTime UNUSED,
                           AudioBufferList *outOutputData UNUSED,
@@ -52,11 +52,24 @@
   sox_format_t *ft = (sox_format_t *)inClientData;
   priv_t *ac = (priv_t *)ft->priv;
   float *buf = inInputData->mBuffers[0].mData;
+  size_t buflen = inInputData->mBuffers[0].mDataByteSize;
+  float *destbuf = (float *)((unsigned char *)ac->buffer + ac->buf_offset);
+  int i;
 
+  /* mDataByteSize may be non-zero even when mData is NULL, but that is not an error */
+  if (buf == NULL)
+    return kAudioHardwareNoError;
+
+  if (buflen > (ac->buf_size + ac->buf_offset))
+    buflen = ac->buf_size - ac->buf_offset;
+
   pthread_mutex_lock(&ac->mutex);
 
-  memcpy(ac->buffer, buf, ac->buf_size * sizeof(float));
-  ac->buf_offset = ac->buf_size-1;
+  for (i = 0; i < (int)(buflen / sizeof(float)); i += 2) {
+    destbuf[i] = buf[i];
+    destbuf[i + 1] = buf[i + 1];
+    ac->buf_offset += sizeof(float) * 2;
+  }
 
   pthread_mutex_unlock(&ac->mutex);
   pthread_cond_signal(&ac->cond);
@@ -104,20 +117,10 @@
     return SOX_EOF;
   }
 
-  /* If user doesn't specify, default to some reasonable values.
-   * Since this is mainly for recording case, default to typical
-   * 16-bit values to prevent saving larger files then average user
-   * wants.  Power users can override to 32-bit if they wish.
-   */
-  if (ft->signal.channels == 0)
-    ft->signal.channels = 2;
-  if (ft->signal.rate == 0)
-    ft->signal.rate = 44100;
-  if (ft->encoding.bits_per_sample == 0)
-  {
-    ft->encoding.bits_per_sample = 16;
-    ft->encoding.encoding = SOX_ENCODING_SIGN2;
-  }
+  /* OS X effectively only supports these values. */
+  ft->signal.channels = 2;
+  ft->signal.rate = 44100;
+  ft->encoding.bits_per_sample = 32;
 
   /* TODO: My limited experience with hardware can only get floats working which a fixed sample
    * rate and stereo.  I know that is a limitiation of audio device I have so this may not be
@@ -166,18 +169,18 @@
     ft->signal.rate = stream_desc.mSampleRate;
   }
 
-  ac->buf_size = sox_globals.bufsiz;
+  ac->buf_size = sox_globals.bufsiz * sizeof(float);
   ac->buf_offset = 0;
-  ac->buffer = lsx_malloc(ac->buf_size * sizeof(sox_sample_t));
+  ac->buffer = lsx_malloc(ac->buf_size);
 
-  buf_size = sox_globals.bufsiz * sizeof(float);
+  buf_size = ac->buf_size;
   property_size = sizeof(buf_size);
-  status = AudioDeviceSetProperty(ac->adid, NULL, 0, is_input, 
+  status = AudioDeviceSetProperty(ac->adid, NULL, 0, is_input,
                                   kAudioDevicePropertyBufferSize,
                                   property_size, &buf_size);
 
   rc = pthread_mutex_init(&ac->mutex, NULL);
-  if (rc) 
+  if (rc)
   {
     lsx_fail_errno(ft, SOX_EPERM, "failed initializing mutex");
     return SOX_EOF;
@@ -184,7 +187,7 @@
   }
 
   rc = pthread_cond_init(&ac->cond, NULL);
-  if (rc) 
+  if (rc)
   {
     lsx_fail_errno(ft, SOX_EPERM, "failed initializing condition");
     return SOX_EOF;
@@ -224,20 +227,14 @@
   pthread_mutex_lock(&ac->mutex);
 
   /* Wait until input buffer has been filled by device driver */
-  while (ac->buf_offset == 0 || ac->buf_offset > ac->buf_size)
+  while (ac->buf_offset < ac->buf_size)
     pthread_cond_wait(&ac->cond, &ac->mutex);
 
-  if (len > ac->buf_size - ac->buf_offset)
-    len = ac->buf_size - ac->buf_offset;
-  samp_left = len;
+  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;
 
-  p = &ac->buffer[ac->buf_offset];
-
-  while (samp_left--)
-    *buf++ = SOX_FLOAT_32BIT_TO_SAMPLE(*p++, ft->clips);
-
-  ac->buf_offset -= len;
-
   pthread_mutex_unlock(&ac->mutex);
 
   return len;
@@ -274,23 +271,28 @@
 
   pthread_mutex_lock(&ac->mutex);
 
+  /* globals.bufsize is in samples
+   * buf_offset is in bytes
+   * buf_size is in bytes
+   */
   do {
-
-    /* Wait until there is some room to copy some samples */
-    while (ac->buf_offset >= ac->buf_size - 1)
+    /* Wait until callback has cleared the buffer. We move in
+     * lock-step with the callback; we never deal with a partially
+     * written buffer. */
+    while (ac->buf_offset != 0)
       pthread_cond_wait(&ac->cond, &ac->mutex);
 
     len = nsamp - written;
-    if (len > ac->buf_size - ac->buf_offset)
-      len = ac->buf_size - ac->buf_offset;
+    if (len > (ac->buf_size - ac->buf_offset) / sizeof(float))
+      len = (ac->buf_size - ac->buf_offset) / sizeof(float);
     samp_left = len;
 
-    p = &ac->buffer[ac->buf_offset];
+    p = ((unsigned char *)ac->buffer) + ac->buf_offset;
 
     while (samp_left--)
       *p++ = SOX_SAMPLE_TO_FLOAT_32BIT(*buf++, ft->clips);
 
-    ac->buf_offset += len;
+    ac->buf_offset += len * sizeof(float);
     written += len;
   } while (written < nsamp);