Rob Sykesfix warnings619cfdb14 years agoHistory
418 lines · 12.1 KB · C
RawDownload
/* AudioCore sound handler * * Copyright 2008 Chris Bagwell And Sundry Contributors */ #include "sox_i.h" #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 bufsize;  size_t bufrd;  size_t bufwr;  size_t bufrdavail;  float *buf;} priv_t; static OSStatus PlaybackIOProc(AudioDeviceID inDevice UNUSED,                               const AudioTimeStamp *inNow UNUSED,                               const AudioBufferList *inInputData UNUSED,                               const AudioTimeStamp *inInputTime UNUSED,                               AudioBufferList *outOutputData,                               const AudioTimeStamp *inOutputTime UNUSED,                               void *inClientData){    priv_t *ac = (priv_t*)((sox_format_t*)inClientData)->priv;    AudioBuffer *buf;    size_t copylen, avail;     pthread_mutex_lock(&ac->mutex);     for(buf = outOutputData->mBuffers;        buf != outOutputData->mBuffers + outOutputData->mNumberBuffers;        buf++){         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));        }else{            memcpy(buf->mData, ac->buf + ac->bufrd, copylen * sizeof(float));        }         buf->mDataByteSize = copylen * sizeof(float);        ac->bufrd += copylen;        if(ac->bufrd >= ac->bufsize)            ac->bufrd -= ac->bufsize;        ac->bufrdavail -= copylen;    }     pthread_cond_signal(&ac->cond);    pthread_mutex_unlock(&ac->mutex);     return kAudioHardwareNoError;} static OSStatus RecIOProc(AudioDeviceID inDevice UNUSED,                          const AudioTimeStamp *inNow UNUSED,                          const AudioBufferList *inInputData,                          const AudioTimeStamp *inInputTime UNUSED,                          AudioBufferList *outOutputData UNUSED,                          const AudioTimeStamp *inOutputTime UNUSED,                          void *inClientData){    priv_t *ac = (priv_t *)((sox_format_t*)inClientData)->priv;    AudioBuffer const *buf;    size_t nfree, copylen, avail;     pthread_mutex_lock(&ac->mutex);     for(buf = inInputData->mBuffers;        buf != inInputData->mBuffers + inInputData->mNumberBuffers;        buf++){         if(buf->mData == NULL)            continue;         copylen = buf->mDataByteSize / sizeof(float);        nfree = ac->bufsize - ac->bufrdavail - 1;        if(nfree == 0)            lsx_warn("coreaudio: unhandled buffer overrun.  Data discarded.");         if(copylen > nfree)            copylen = nfree;         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);     return kAudioHardwareNoError;} 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;   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 (status == noErr)      {          int device_count = property_size/sizeof(AudioDeviceID);          AudioDeviceID *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);                   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;  }   /* 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;  }   if (!(stream_desc.mFormatFlags & kLinearPCMFormatFlagIsFloat))  {    lsx_fail_errno(ft, SOX_EPERM, "audio device does not accept floats");    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: 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;   /* 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;  }   /* Query device to see if it worked */  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;  }#endif   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 (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) * sizeof(float);  property_size = sizeof(buf_size);  status = AudioDeviceSetProperty(ac->adid, NULL, 0, is_input,                                  kAudioDevicePropertyBufferSize,                                  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. */  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){    return setup(ft, 1);} 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;    SOX_SAMPLE_LOCALS;     if (!ac->device_started) {        AudioDeviceStart(ac->adid, RecIOProc);        ac->device_started = 1;    }     pthread_mutex_lock(&ac->mutex);     /* Wait until input buffer has been filled by device driver */    while (ac->bufrdavail == 0)        pthread_cond_wait(&ac->cond, &ac->mutex);     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);     return len;} static int stopread(sox_format_t * ft){  priv_t *ac = (priv_t *)ft->priv;   AudioDeviceStop(ac->adid, RecIOProc);  AudioDeviceRemoveIOProc(ac->adid, RecIOProc);  pthread_cond_destroy(&ac->cond);  pthread_mutex_destroy(&ac->mutex);  free(ac->buf);   return SOX_SUCCESS;} static int startwrite(sox_format_t * ft){    return setup(ft, 0);} 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 i;     SOX_SAMPLE_LOCALS;     pthread_mutex_lock(&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;    }     /* 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);         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++;    }     pthread_mutex_unlock(&ac->mutex);    return nsamp;}  static int stopwrite(sox_format_t * ft){    priv_t *ac = (priv_t *)ft->priv;     if(ac->device_started){        pthread_mutex_lock(&ac->mutex);         while (ac->bufrdavail > 0)            pthread_cond_wait(&ac->cond, &ac->mutex);         pthread_mutex_unlock(&ac->mutex);         AudioDeviceStop(ac->adid, PlaybackIOProc);    }     AudioDeviceRemoveIOProc(ac->adid, PlaybackIOProc);    pthread_cond_destroy(&ac->cond);    pthread_mutex_destroy(&ac->mutex);    free(ac->buf);     return SOX_SUCCESS;} LSX_FORMAT_HANDLER(coreaudio){  static char const *const names[] = { "coreaudio", NULL };  static unsigned const write_encodings[] = {    SOX_ENCODING_FLOAT, 32, 0,    0};  static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,    "Mac AudioCore device driver",    names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO,    startread, read_samples, stopread,    startwrite, write_samples, stopwrite,    NULL, write_encodings, NULL, sizeof(priv_t)  };  return &handler;}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t