libsent/src/adin/adin_mic_darwin_coreaudio.c

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

Generated on Tue Dec 18 15:59:54 2007 for Julius by  doxygen 1.5.4