Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

adin_mic_darwin_coreaudio.c

Go to the documentation of this file.
00001 
00035 /*
00036  * adin_mic_darwin_coreaudio.c
00037  *
00038  * adin microphone library for CoreAudio API
00039  *
00040  * by Masatomo Hashimoto <m.hashimoto@aist.go.jp>
00041  *
00042  * Tested on Mac OS X v10.3.9 and v10.4.1
00043  *
00044  */
00045 
00046 /* $Id: adin_mic_darwin_coreaudio.c,v 1.1.1.1 2005/11/17 11:11:49 sumomo Exp $ */
00047 
00048 #include <CoreAudio/CoreAudio.h>
00049 #include <AudioUnit/AudioUnit.h>
00050 #include <AudioUnit/AudioOutputUnit.h>
00051 #include <AudioToolbox/AudioConverter.h>
00052 #include <pthread.h>
00053 #include <stdio.h>
00054 
00055 #define DEVICE_NAME_LEN 128
00056 #define BUF_SAMPLES 4096
00057 
00058 static UInt32 ConvQuality = kAudioConverterQuality_Medium;
00059 
00060 typedef SInt16 Sample;
00061 static UInt32 BytesPerSample = sizeof(Sample);
00062 
00063 #define BITS_PER_BYTE 8
00064 
00065 static AudioDeviceID InputDeviceID;
00066 static AudioUnit InputUnit;
00067 static AudioConverterRef Converter;
00068 
00069 static pthread_mutex_t MutexInput;
00070 static pthread_cond_t CondInput;
00071 
00072 static bool CoreAudioRecordStarted = FALSE;
00073 static bool CoreAudioHasInputDevice = FALSE;
00074 static bool CoreAudioInit = FALSE;
00075 
00076 static UInt32 NumSamplesAvailable = 0;
00077 
00078 static UInt32 InputDeviceBufferSamples = 0;
00079 static UInt32 InputBytesPerPacket = 0;
00080 static UInt32 InputFramesPerPacket = 0;
00081 static UInt32 InputSamplesPerPacket = 0;
00082 static UInt32 OutputBitsPerChannel = 0;
00083 static UInt32 OutputBytesPerPacket = 0;
00084 static UInt32 OutputSamplesPerPacket = 0;
00085 
00086 static AudioBufferList* BufList;
00087 static AudioBufferList BufListBackup;
00088 static AudioBufferList* BufListConverted;
00089 
00090 
00091 static void printStreamInfo(AudioStreamBasicDescription* desc) {
00092   j_printf("----- details of stream -----\n");
00093   j_printf("sample rate: %f\n", desc->mSampleRate);
00094   j_printf("format flags: %s%s%s%s%s%s%s\n", 
00095            desc->mFormatFlags & kAudioFormatFlagIsFloat ? 
00096            "[float]" : "",
00097            desc->mFormatFlags & kAudioFormatFlagIsBigEndian ? 
00098            "[big endian]" : "",
00099            desc->mFormatFlags & kAudioFormatFlagIsSignedInteger ? 
00100            "[signed integer]" : "",
00101            desc->mFormatFlags & kAudioFormatFlagIsPacked ? 
00102            "[packed]" : "",
00103            desc->mFormatFlags & kAudioFormatFlagIsAlignedHigh ? 
00104            "[aligned high]" : "",
00105            desc->mFormatFlags & kAudioFormatFlagIsNonInterleaved ? 
00106            "[non interleaved]" : "",
00107            desc->mFormatFlags & kAudioFormatFlagsAreAllClear ? 
00108            "[all clear]" : ""
00109            );
00110   j_printf("bytes per packet: %d\n", desc->mBytesPerPacket);
00111   j_printf("frames per packet: %d\n", desc->mFramesPerPacket);
00112   j_printf("bytes per frame: %d\n", desc->mBytesPerFrame);
00113   j_printf("channels per frame: %d\n", desc->mChannelsPerFrame);
00114   j_printf("bits per channel: %d\n", desc->mBitsPerChannel);
00115   j_printf("-----------------------------------\n");
00116 }
00117 
00118 static void printAudioBuffer(AudioBuffer* buf) {
00119   int sz = buf->mDataByteSize / BytesPerSample;
00120   int i;
00121   Sample* p = (Sample*)(buf->mData);
00122   for (i = 0; i < sz; i++) {
00123     j_printf("%d ", p[i]);
00124   }
00125 }
00126 
00127 static AudioBufferList* 
00128 allocateAudioBufferList(UInt32 data_bytes, UInt32 nsamples, UInt32 nchan) {
00129 
00130   AudioBufferList* bufl;
00131 
00132 #ifdef DEBUG
00133   j_printf("allocateAudioBufferList: data_bytes:%d nsamples:%d nchan:%d\n",
00134            data_bytes, nsamples, nchan);
00135 #endif
00136 
00137   bufl = (AudioBufferList*)(malloc(sizeof(AudioBufferList)));
00138 
00139   if(bufl == NULL) {
00140     j_printerr("allocateAudioBufferList: failed\n");
00141     exit(1);
00142   }
00143 
00144   bufl->mNumberBuffers = nchan;
00145 
00146   int i;
00147   for (i = 0; i < nchan; i++) {
00148     bufl->mBuffers[i].mNumberChannels = nchan;
00149     bufl->mBuffers[i].mDataByteSize = data_bytes * nsamples;
00150     bufl->mBuffers[i].mData = malloc(data_bytes * nsamples);
00151     
00152     if(bufl->mBuffers[i].mData == NULL) {
00153       j_printerr("allocateAudioBufferList: malloc for mBuffers[%d] failed\n", i);
00154       exit(1);
00155     }
00156   }
00157   return bufl;
00158 }
00159 
00160 /* gives input data for Converter */
00161 static OSStatus 
00162 ConvInputProc(AudioConverterRef inConv,
00163               UInt32* ioNumDataPackets,
00164               AudioBufferList* ioData, // to be filled
00165               AudioStreamPacketDescription** outDataPacketDesc,
00166               void* inUserData)
00167 {
00168   int i;
00169   UInt32 nPacketsRequired = *ioNumDataPackets;
00170   UInt32 nBytesProvided = 0;
00171   UInt32 nBytesRequired;
00172   UInt32 n;
00173   
00174   pthread_mutex_lock(&MutexInput);
00175 
00176 #ifdef DEBUG
00177   j_printf("ConvInputProc: required %d packets\n", nPacketsRequired);
00178 #endif
00179 
00180   while(NumSamplesAvailable == 0){
00181     pthread_cond_wait(&CondInput, &MutexInput);
00182   }
00183 
00184   for(i = 0; i < BufList->mNumberBuffers; i++) {
00185     n = BufList->mBuffers[i].mDataByteSize;
00186     if (nBytesProvided != 0 && nBytesProvided != n) {
00187       j_printerr("WARNING: buffer size mismatch\n");
00188     }
00189     nBytesProvided = n;
00190   }
00191 
00192 #ifdef DEBUG
00193   j_printf("ConvInputProc: %d bytes in buffer\n", nBytesProvided);
00194 #endif
00195 
00196   for(i = 0; i < BufList->mNumberBuffers; i++) {
00197     ioData->mBuffers[i].mNumberChannels = 
00198       BufList->mBuffers[i].mNumberChannels;
00199 
00200     nBytesRequired = nPacketsRequired * InputBytesPerPacket;
00201 
00202     if(nBytesRequired < nBytesProvided) {
00203       ioData->mBuffers[i].mData = BufList->mBuffers[i].mData;
00204       ioData->mBuffers[i].mDataByteSize = nBytesRequired;
00205       BufList->mBuffers[i].mData += nBytesRequired;
00206       BufList->mBuffers[i].mDataByteSize = nBytesProvided - nBytesRequired;
00207     } else {
00208       ioData->mBuffers[i].mData = BufList->mBuffers[i].mData;
00209       ioData->mBuffers[i].mDataByteSize = nBytesProvided;
00210       
00211       BufList->mBuffers[i].mData = BufListBackup.mBuffers[i].mData;
00212 
00213     }
00214 
00215   }
00216 
00217   *ioNumDataPackets = ioData->mBuffers[0].mDataByteSize / InputBytesPerPacket;
00218 
00219 #ifdef DEBUG
00220   j_printf("ConvInputProc: provided %d packets\n", *ioNumDataPackets);
00221 #endif
00222 
00223   NumSamplesAvailable = 
00224     nBytesProvided / BytesPerSample - *ioNumDataPackets * InputSamplesPerPacket;
00225 
00226 #ifdef DEBUG
00227   j_printf("ConvInputProc: %d samples available\n", NumSamplesAvailable);
00228 #endif
00229 
00230   pthread_mutex_unlock(&MutexInput);
00231 
00232   return noErr;
00233 }
00234 
00235 
00236 /* called when input data are available (an AURenderCallback) */
00237 static OSStatus 
00238 InputProc(void* inRefCon,
00239           AudioUnitRenderActionFlags* ioActionFlags,
00240           const AudioTimeStamp* inTimeStamp,
00241           UInt32 inBusNumber,
00242           UInt32 inNumberFrames,
00243           AudioBufferList* ioData // null
00244           )
00245 {
00246   OSStatus status = noErr;
00247   int i;
00248 
00249   pthread_mutex_lock(&MutexInput);
00250 
00251   if (NumSamplesAvailable == 0) {
00252 
00253     status = AudioUnitRender(InputUnit,
00254                              ioActionFlags,
00255                              inTimeStamp,
00256                              inBusNumber,
00257                              inNumberFrames,
00258                              BufList);
00259     NumSamplesAvailable = 
00260       BufList->mBuffers[0].mDataByteSize / InputBytesPerPacket;
00261 
00262 #ifdef DEBUG
00263     printAudioBuffer(BufList->mBuffers);
00264 #endif
00265   }
00266 
00267   pthread_mutex_unlock(&MutexInput);
00268   
00269   pthread_cond_signal(&CondInput);
00270 
00271   /*
00272   j_printf("InputProc: %d bytes filled (BufList)\n", 
00273           BufList->mBuffers[0].mDataByteSize);
00274   */
00275 
00276   return status;
00277 }
00278 
00279 
00280 /* initialize default sound device */
00281 bool adin_mic_standby(int sfreq, void* dummy) {
00282   OSStatus status;
00283   UInt32 propertySize;
00284   char deviceName[DEVICE_NAME_LEN];
00285   struct AudioStreamBasicDescription inDesc;
00286   int err;
00287 
00288   j_printf("adin_mic_standby: sample rate = %d\n", sfreq);
00289 
00290   if (CoreAudioInit) 
00291     return TRUE;
00292 
00293   Component halout;
00294   ComponentDescription haloutDesc;
00295 
00296   haloutDesc.componentType = kAudioUnitType_Output;
00297   haloutDesc.componentSubType = kAudioUnitSubType_HALOutput;
00298   haloutDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
00299   haloutDesc.componentFlags = 0;
00300   haloutDesc.componentFlagsMask = 0;
00301   halout = FindNextComponent(NULL, &haloutDesc);
00302 
00303   if(halout == NULL) {
00304     j_printerr("no HALOutput component found\n");
00305     return FALSE;
00306   }
00307 
00308   OpenAComponent(halout, &InputUnit);
00309 
00310   UInt32 enableIO;
00311   
00312   enableIO = 1;
00313   status = AudioUnitSetProperty(InputUnit, 
00314                                 kAudioOutputUnitProperty_EnableIO,
00315                                 kAudioUnitScope_Input,
00316                                 1,
00317                                 &enableIO,
00318                                 sizeof(enableIO));
00319     if (status != noErr) {
00320       j_printerr("cannot set InputUnit's EnableIO(Input)\n");
00321       return FALSE;
00322     }
00323 
00324   enableIO = 0;
00325   status = AudioUnitSetProperty(InputUnit, 
00326                                 kAudioOutputUnitProperty_EnableIO,
00327                                 kAudioUnitScope_Output,
00328                                 0,
00329                                 &enableIO,
00330                                 sizeof(enableIO));
00331     if (status != noErr) {
00332       j_printerr("cannot set InputUnit's EnableIO(Output)\n");
00333       return FALSE;
00334     }
00335 
00336 
00337   /* get default input device */
00338   propertySize = sizeof(InputDeviceID);
00339   status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
00340                                     &propertySize,
00341                                     &InputDeviceID);
00342   if (status != noErr) {
00343     j_printerr("cannot get default input device\n");
00344     return FALSE;
00345   }
00346 
00347   if (InputDeviceID == kAudioDeviceUnknown) {
00348     j_printerr("no available input device found\n");
00349     return FALSE;
00350 
00351   } else {
00352 
00353     CoreAudioHasInputDevice = TRUE;
00354 
00355     /* get input device name */
00356     propertySize = sizeof(char) * DEVICE_NAME_LEN;
00357     status = AudioDeviceGetProperty(InputDeviceID,
00358                                     1,
00359                                     1,
00360                                     kAudioDevicePropertyDeviceName,
00361                                     &propertySize,
00362                                     deviceName);
00363     if (status != noErr) {
00364       j_printerr("cannot get device name\n");
00365       return FALSE;
00366     }
00367 
00368     status = AudioUnitSetProperty(InputUnit,
00369                                   kAudioOutputUnitProperty_CurrentDevice,
00370                                   kAudioUnitScope_Global,
00371                                   0,
00372                                   &InputDeviceID,
00373                                   sizeof(InputDeviceID));
00374 
00375     if (status != noErr) {
00376       j_printerr("cannot bind default input device to AudioUnit\n");
00377       return FALSE;
00378     }
00379 
00380     /* get input device's format */
00381     propertySize = sizeof(inDesc);
00382     status = AudioDeviceGetProperty(InputDeviceID,
00383                                     1,
00384                                     1,
00385                                     kAudioDevicePropertyStreamFormat,
00386                                     &propertySize,
00387                                     &inDesc);
00388     if (status != noErr) {
00389       j_printerr("cannot get input device's stream format\n");
00390       return FALSE;
00391     }
00392 
00393     /* get input device's buffer frame size */
00394     UInt32 bufferFrameSize;
00395     propertySize = sizeof(bufferFrameSize);
00396     status = AudioDeviceGetProperty(InputDeviceID,
00397                                     1,
00398                                     1,
00399                                     kAudioDevicePropertyBufferFrameSize,
00400                                     &propertySize,
00401                                     &bufferFrameSize);
00402     if (status != noErr) {
00403       j_printerr("cannot get input device's buffer frame size\n");
00404       return FALSE;
00405     }
00406 
00407     j_printf("using device \"%s\" for input\n", deviceName);
00408     j_printf("\tsample rate %f\n\t%ld channels\n\t%ld-bit sample\n",
00409             inDesc.mSampleRate,
00410             inDesc.mChannelsPerFrame,
00411             inDesc.mBitsPerChannel);
00412 
00413     j_printf("\t%d buffer frames\n", bufferFrameSize);
00414 
00415 
00416     printStreamInfo(&inDesc);
00417 
00418     UInt32 formatFlagEndian = 
00419       inDesc.mFormatFlags & kAudioFormatFlagIsBigEndian;
00420 
00421     inDesc.mFormatFlags = 
00422       kAudioFormatFlagIsSignedInteger | 
00423       kAudioFormatFlagIsPacked | 
00424       formatFlagEndian;
00425 
00426     inDesc.mBytesPerPacket = BytesPerSample;
00427     inDesc.mFramesPerPacket = 1;
00428     inDesc.mBytesPerFrame = BytesPerSample;
00429     inDesc.mChannelsPerFrame = 1;
00430     inDesc.mBitsPerChannel = BytesPerSample * BITS_PER_BYTE;
00431 
00432     printStreamInfo(&inDesc);
00433 
00434     propertySize = sizeof(inDesc);
00435     status = AudioUnitSetProperty(InputUnit, 
00436                                   kAudioUnitProperty_StreamFormat,
00437                                   kAudioUnitScope_Output,
00438                                   1,
00439                                   &inDesc,
00440                                   propertySize
00441                                   );
00442     if (status != noErr) {
00443       j_printerr("cannot set InputUnit's stream format\n");
00444       return FALSE;
00445     }
00446 
00447     InputBytesPerPacket = inDesc.mBytesPerPacket;
00448     InputFramesPerPacket = inDesc.mFramesPerPacket;
00449     InputSamplesPerPacket = InputBytesPerPacket / BytesPerSample;
00450 
00451     InputDeviceBufferSamples = 
00452       bufferFrameSize * InputSamplesPerPacket * InputFramesPerPacket;
00453 
00454     j_printf("input device's buffer size (# of samples): %d\n", 
00455              InputDeviceBufferSamples);
00456 
00457     AudioStreamBasicDescription outDesc;
00458     outDesc.mSampleRate = sfreq;
00459     outDesc.mFormatID = kAudioFormatLinearPCM;
00460     outDesc.mFormatFlags = 
00461       kAudioFormatFlagIsSignedInteger | 
00462       kAudioFormatFlagIsPacked | 
00463       formatFlagEndian;
00464     outDesc.mBytesPerPacket = BytesPerSample;
00465     outDesc.mFramesPerPacket = 1;
00466     outDesc.mBytesPerFrame = BytesPerSample;
00467     outDesc.mChannelsPerFrame = 1;
00468     outDesc.mBitsPerChannel = BytesPerSample * BITS_PER_BYTE;
00469 
00470     printStreamInfo(&outDesc);
00471 
00472     OutputBitsPerChannel = outDesc.mBitsPerChannel;
00473     OutputBytesPerPacket = outDesc.mBytesPerPacket;
00474 
00475     OutputSamplesPerPacket = (OutputBitsPerChannel / BITS_PER_BYTE) / OutputBytesPerPacket;
00476 
00477     status = AudioConverterNew(&inDesc, &outDesc, &Converter);
00478     if (status != noErr){
00479       j_printerr("cannot create audio converter\n");
00480       exit(1);
00481     }
00482 
00483     /*
00484     UInt32 nChan = inDesc.mChannelsPerFrame;
00485     int i;
00486 
00487     if (inDesc.mFormatFlags & kAudioFormatFlagIsNonInterleaved && nChan > 1) {
00488       UInt32 chmap[nChan];
00489       for (i = 0; i < nChan; i++)
00490         chmap[i] = 0;
00491 
00492       status = AudioConverterSetProperty(Converter, 
00493                                          kAudioConverterChannelMap,
00494                                          sizeof(chmap), chmap);
00495       if (status != noErr){
00496         j_printerr("cannot set audio converter's channel map\n");
00497         exit(1);
00498       }
00499     }
00500     */
00501 
00502     status = 
00503       AudioConverterSetProperty(Converter, 
00504                                 kAudioConverterSampleRateConverterQuality,
00505                                 sizeof(ConvQuality), &ConvQuality);
00506     if (status != noErr){
00507       j_printerr("cannot set audio converter quality\n");
00508       exit(1);
00509     }
00510 
00511 
00512     //j_printf("audio converter generated\n");
00513 
00514     /* allocate buffers */
00515     BufList = allocateAudioBufferList(inDesc.mBitsPerChannel / BITS_PER_BYTE, 
00516                                       InputDeviceBufferSamples, 1);
00517 
00518     BufListBackup.mNumberBuffers = BufList->mNumberBuffers;
00519 
00520     BufListBackup.mBuffers[0].mNumberChannels = 1;
00521     BufListBackup.mBuffers[0].mDataByteSize = 
00522       BufList->mBuffers[0].mDataByteSize;
00523     BufListBackup.mBuffers[0].mData = BufList->mBuffers[0].mData;
00524 
00525     BufListConverted = allocateAudioBufferList(BytesPerSample, BUF_SAMPLES, 1);
00526     //j_printf("buffers allocated\n");
00527 
00528     err = pthread_mutex_init(&MutexInput, NULL);
00529     if (err) {
00530       j_printerr("cannot init mutex\n");
00531       return FALSE;
00532     }
00533     err = pthread_cond_init(&CondInput, NULL);
00534     if (err) {
00535       j_printerr("cannot init condition variable\n");
00536       return FALSE;
00537     }
00538 
00539     /* register the callback */
00540     AURenderCallbackStruct input;
00541     input.inputProc = InputProc; // an AURenderCallback
00542     input.inputProcRefCon = 0;
00543     AudioUnitSetProperty(InputUnit,
00544                          kAudioOutputUnitProperty_SetInputCallback,
00545                          kAudioUnitScope_Global,
00546                          0,
00547                          &input,
00548                          sizeof(input));
00549 
00550     status = AudioUnitInitialize(InputUnit);
00551     if (status != noErr){
00552       j_printerr("InputUnit initialize failed\n");
00553       exit(1);
00554     }
00555 
00556   }
00557 
00558   CoreAudioInit = TRUE;
00559 
00560   j_printf("CoreAudio: initialized\n");
00561 
00562   return TRUE;
00563 }
00564 
00565 bool adin_mic_start(){ return TRUE; }
00566 bool adin_mic_stop(){ return TRUE; }
00567 
00568 int adin_mic_read(void *buffer, int nsamples) {
00569   OSStatus status;
00570 
00571 #ifdef DEBUG
00572   j_printf("adin_mic_read: %d samples required\n", nsamples);
00573 #endif
00574 
00575   if (!CoreAudioHasInputDevice) 
00576     return -1;
00577 
00578   if (!CoreAudioRecordStarted) {
00579     status = AudioOutputUnitStart(InputUnit);
00580     CoreAudioRecordStarted = TRUE;
00581   }
00582   
00583   UInt32 capacity = BUF_SAMPLES * OutputSamplesPerPacket;
00584   UInt32 npackets = nsamples * OutputSamplesPerPacket;
00585 
00586   UInt32 numDataPacketsNeeded;
00587 
00588   Sample* inputDataBuf = (Sample*)(BufListConverted->mBuffers[0].mData);
00589 
00590   numDataPacketsNeeded = npackets < capacity ? npackets : capacity;
00591 
00592 #ifdef DEBUG
00593   j_printf("adin_mic_read: numDataPacketsNeeded=%d\n", numDataPacketsNeeded);
00594 #endif
00595 
00596   status = AudioConverterFillComplexBuffer(Converter, 
00597                                            ConvInputProc, 
00598                                            NULL, // user data
00599                                            &numDataPacketsNeeded, 
00600                                            BufListConverted, 
00601                                            NULL // packet description
00602                                            );
00603   if (status != noErr) {
00604     j_printerr("AudioConverterFillComplexBuffer: failed\n");
00605     return -1;
00606   }
00607 
00608 #ifdef DEBUG
00609   j_printf("adin_mic_read: %d bytes filled (BufListConverted)\n", 
00610            BufListConverted->mBuffers[0].mDataByteSize);
00611 #endif
00612 
00613   int providedSamples = numDataPacketsNeeded / OutputSamplesPerPacket;
00614 
00615   pthread_mutex_lock(&MutexInput);
00616 
00617 #ifdef DEBUG
00618   j_printf("adin_mic_read: provided samples: %d\n", providedSamples);
00619 #endif
00620 
00621   Sample* dst_data = (Sample*)buffer;
00622 
00623   int i;
00624 
00625   int count = 0;
00626 
00627   for (i = 0; i < providedSamples; i++) {
00628     dst_data[i] = inputDataBuf[i];
00629     if (dst_data[i] == 0) count++;
00630   }
00631 
00632   //j_printf("%d zero samples\n", count);
00633 
00634 
00635   pthread_mutex_unlock(&MutexInput);
00636 
00637 #ifdef DEBUG
00638   j_printf("adin_mic_read: EXIT: %d samples provided\n", providedSamples);
00639 #endif
00640 
00641   return providedSamples;
00642 }
00643 
00644 void adin_mic_pause() {
00645   OSStatus status;
00646 
00647   if (CoreAudioHasInputDevice && CoreAudioRecordStarted) {
00648     status = AudioOutputUnitStop(InputUnit);
00649     CoreAudioRecordStarted = FALSE;
00650   }
00651   return;
00652 }

Generated on Tue Mar 28 16:01:39 2006 for Julius by  doxygen 1.4.2