static void ca_stop_r(CAData *d){ OSErr err; if(d->read_started == TRUE) { if(AudioOutputUnitStop(d->caInAudioUnit) == noErr) d->read_started=FALSE; } if (d->caInConverter!=NULL) { AudioConverterDispose(d->caInConverter); d->caInConverter=NULL; } if (d->caInAudioUnit!=NULL) { AudioUnitUninitialize(d->caInAudioUnit); d->caInAudioUnit=NULL; } if (d->fAudioBuffer) DestroyAudioBufferList(d->fAudioBuffer); d->fAudioBuffer=NULL; if (d->fMSBuffer) DestroyAudioBufferList(d->fMSBuffer); d->fMSBuffer=NULL; }
// Convenience function to allocate our audio buffers AudioBufferList * AllocateAudioBufferList (UInt32 numChannels, UInt32 size) { AudioBufferList *list; list = (AudioBufferList *) calloc (1, sizeof (AudioBufferList)); if (list == NULL) return NULL; list->mNumberBuffers = 1; list->mBuffers[0].mNumberChannels = numChannels; list->mBuffers[0].mDataByteSize = size; list->mBuffers[0].mData = malloc (size); if (list->mBuffers[0].mData == NULL) { DestroyAudioBufferList (list); return NULL; } return list; }
// Convenience function to allocate our audio buffers AudioBufferList *AllocateAudioBufferList(UInt32 numChannels, UInt32 size) { AudioBufferList* list; UInt32 i; list = (AudioBufferList*)calloc(1, sizeof(AudioBufferList) + numChannels * sizeof(AudioBuffer)); if(list == NULL) return NULL; list->mNumberBuffers = numChannels; for(i = 0; i < numChannels; ++i) { list->mBuffers[i].mNumberChannels = 1; list->mBuffers[i].mDataByteSize = size; list->mBuffers[i].mData = malloc(size); if(list->mBuffers[i].mData == NULL) { DestroyAudioBufferList(list); return NULL; } } return list; }
static void audio_cap_ca_done(void *state) { struct state_ca_capture *s = (struct state_ca_capture *) state; if(!s) return; pthread_mutex_destroy(&s->lock); pthread_cond_destroy(&s->cv); DestroyAudioBufferList(s->theBufferList); free(s->frame.data); ring_buffer_destroy(s->buffer); free(s->tmp); #ifdef HAVE_SPEEX if(s->resampler) { speex_resampler_destroy(s->resampler); } free(s->resampled); #endif // HAVE_SPEEX free(s); }
OSStatus readRenderProc(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumFrames, AudioBufferList *ioData) { CAData *d=(CAData*)inRefCon; OSStatus err = noErr; err = AudioUnitRender(d->caInAudioUnit, inActionFlags, inTimeStamp, inBusNumber, inNumFrames, d->fAudioBuffer); if(err != noErr) { ms_error("AudioUnitRender %d size = %d", err, d->fAudioBuffer->mBuffers[0].mDataByteSize); return err; } UInt32 AvailableOutputBytes = inNumFrames * sizeof (float) * d->caInASBD.mChannelsPerFrame; UInt32 propertySize = sizeof (AvailableOutputBytes); err = AudioConverterGetProperty (d->caInConverter, kAudioConverterPropertyCalculateOutputBufferSize, &propertySize, &AvailableOutputBytes); if(err != noErr) { ms_error("AudioConverterGetProperty kAudioConverterPropertyCalculateOutputBufferSize %d", err); return err; } if (AvailableOutputBytes>d->fMSBuffer->mBuffers[0].mDataByteSize) { DestroyAudioBufferList(d->fMSBuffer); d->fMSBuffer = AllocateAudioBufferList(d->stereo ? 2 : 1, AvailableOutputBytes); } UInt32 ActualOutputFrames = AvailableOutputBytes / ((d->bits / 8) * 1) / d->caInASBD.mChannelsPerFrame; err = AudioConverterFillComplexBuffer (d->caInConverter, (AudioConverterComplexInputDataProc)(readACInputProc), inRefCon, &ActualOutputFrames, d->fMSBuffer, NULL); if(err != noErr) { ms_error("readRenderProc:AudioConverterFillComplexBuffer %d", err); return err; } mblk_t *rm=NULL; rm=allocb(ActualOutputFrames*2,0); memcpy(rm->b_wptr, d->fMSBuffer->mBuffers[0].mData, ActualOutputFrames*2); rm->b_wptr+=ActualOutputFrames*2; if (gain_volume_in != 1.0f) { int16_t *ptr=(int16_t *)rm->b_rptr; for (;ptr<(int16_t *)rm->b_wptr;ptr++) { *ptr=(int16_t)(((float)(*ptr))*gain_volume_in); } } ms_mutex_lock(&d->mutex); putq(&d->rq,rm); ms_mutex_unlock(&d->mutex); rm=NULL; return err; }
static void * audio_cap_ca_init(char *cfg) { if(cfg && strcmp(cfg, "help") == 0) { printf("Available Core Audio capture devices:\n"); audio_cap_ca_help(NULL); return &audio_init_state_ok; } struct state_ca_capture *s; OSErr ret = noErr; #if OS_VERSION_MAJOR <= 9 Component comp; ComponentDescription desc; #else AudioComponent comp; AudioComponentDescription desc; #endif UInt32 size; AudioDeviceID device; s = (struct state_ca_capture *) calloc(1, sizeof(struct state_ca_capture)); size=sizeof(device); if(cfg != NULL) { device = atoi(cfg); } else { ret = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &size, &device); if(ret) { fprintf(stderr, "Error finding default input device.\n"); goto error; } } pthread_mutex_init(&s->lock, NULL); pthread_cond_init(&s->cv, NULL); s->boss_waiting = FALSE; s->data_ready = FALSE; s->frame.bps = audio_capture_bps ? audio_capture_bps : 2; s->frame.ch_count = audio_capture_channels; double rate; size = sizeof(double); ret = AudioDeviceGetProperty(device, 0, 0, kAudioDevicePropertyNominalSampleRate, &size, &rate); s->nominal_sample_rate = rate; s->frame.sample_rate = audio_capture_sample_rate ? audio_capture_sample_rate : rate; #if !defined HAVE_SPEEX || defined DISABLE_SPPEX_RESAMPLER s->frame.sample_rate = rate; #if !defined HAVE_SPEEX fprintf(stderr, "[CoreAudio] Libspeex support not compiled in, resampling won't work (check manual or wiki how to enable it)!\n"); #endif #else s->resampler = NULL; if(s->frame.sample_rate != s->nominal_sample_rate) { int err; s->resampler = speex_resampler_init(s->frame.ch_count, s->nominal_sample_rate, s->frame.sample_rate, 10, &err); if(err) { s->frame.sample_rate = s->nominal_sample_rate; } } #endif s->frame.max_size = s->frame.bps * s->frame.ch_count * s->frame.sample_rate; int nonres_channel_size = s->frame.bps * s->nominal_sample_rate; s->theBufferList = AllocateAudioBufferList(s->frame.ch_count, nonres_channel_size); s->tmp = (char *) malloc(nonres_channel_size * s->frame.ch_count); s->buffer = ring_buffer_init(s->frame.max_size); s->frame.data = (char *) malloc(s->frame.max_size); #ifdef HAVE_SPEEX s->resampled = (char *) malloc(s->frame.max_size); #endif //There are several different types of Audio Units. //Some audio units serve as Outputs, Mixers, or DSP //units. See AUComponent.h for listing desc.componentType = kAudioUnitType_Output; //Every Component has a subType, which will give a clearer picture //of what this components function will be. //desc.componentSubType = kAudioUnitSubType_DefaultOutput; desc.componentSubType = kAudioUnitSubType_HALOutput; //all Audio Units in AUComponent.h must use //"kAudioUnitManufacturer_Apple" as the Manufacturer desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; #if OS_VERSION_MAJOR > 9 comp = AudioComponentFindNext(NULL, &desc); if(!comp) { fprintf(stderr, "Error finding AUHAL component.\n"); goto error; } ret = AudioComponentInstanceNew(comp, &s->auHALComponentInstance); if (ret != noErr) { fprintf(stderr, "Error opening AUHAL component.\n"); goto error; } #else comp = FindNextComponent(NULL, &desc); if(!comp) { fprintf(stderr, "Error finding AUHAL component.\n"); goto error; } ret = OpenAComponent(comp, &s->auHALComponentInstance); if (ret != noErr) { fprintf(stderr, "Error opening AUHAL component.\n"); goto error; } #endif UInt32 enableIO; //When using AudioUnitSetProperty the 4th parameter in the method //refer to an AudioUnitElement. When using an AudioOutputUnit //the input element will be '1' and the output element will be '0'. enableIO = 1; ret = AudioUnitSetProperty(s->auHALComponentInstance, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, // input element &enableIO, sizeof(enableIO)); if (ret != noErr) { fprintf(stderr, "Error enabling input on AUHAL.\n"); goto error; } enableIO = 0; ret = AudioUnitSetProperty(s->auHALComponentInstance, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, //output element &enableIO, sizeof(enableIO)); if (ret != noErr) { fprintf(stderr, "Error disabling output on AUHAL.\n"); goto error; } size=sizeof(device); ret = AudioUnitSetProperty(s->auHALComponentInstance, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &device, sizeof(device)); if(ret) { fprintf(stderr, "[CoreAudio] Error setting device to AUHAL instance.\n"); goto error; } { AudioStreamBasicDescription desc; size = sizeof(desc); ret = AudioUnitGetProperty(s->auHALComponentInstance, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &desc, &size); if(ret) { fprintf(stderr, "[CoreAudio] Error getting default device properties.\n"); goto error; } desc.mChannelsPerFrame = s->frame.ch_count; desc.mSampleRate = (double) s->nominal_sample_rate; desc.mFormatID = kAudioFormatLinearPCM; desc.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved; if (desc.mFormatID == kAudioFormatLinearPCM && s->frame.ch_count == 1) desc.mFormatFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; /*#if __BIG_ENDIAN__ desc.mFormatFlags |= kAudioFormatFlagIsBigEndian; #endif */ desc.mBitsPerChannel = s->frame.bps * 8; desc.mBytesPerFrame = desc.mBitsPerChannel / 8; desc.mFramesPerPacket = 1; desc.mBytesPerPacket = desc.mBytesPerFrame; s->audio_packet_size = desc.mBytesPerPacket; ret = AudioUnitSetProperty(s->auHALComponentInstance, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &desc, sizeof(desc)); if(ret) { fprintf(stderr, "[CoreAudio] Error setting device properties.\n"); goto error; } AURenderCallbackStruct input; input.inputProc = InputProc; input.inputProcRefCon = s; ret = AudioUnitSetProperty(s->auHALComponentInstance, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(input)); if(ret) { fprintf(stderr, "[CoreAudio] Error setting input callback.\n"); goto error; } } ret = AudioUnitInitialize(s->auHALComponentInstance); if(ret) { fprintf(stderr, "[CoreAudio] Error initializing device.\n"); goto error; } ret = AudioOutputUnitStart(s->auHALComponentInstance); if(ret) { fprintf(stderr, "[CoreAudio] Error starting device.\n"); goto error; } return s; error: pthread_mutex_destroy(&s->lock); pthread_cond_destroy(&s->cv); DestroyAudioBufferList(s->theBufferList); free(s->frame.data); ring_buffer_destroy(s->buffer); free(s->tmp); free(s); return NULL; }