00001
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
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
00165 static OSStatus
00166 ConvInputProc(AudioConverterRef inConv,
00167 UInt32* ioNumDataPackets,
00168 AudioBufferList* ioData,
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
00241 static OSStatus
00242 InputProc(void* inRefCon,
00243 AudioUnitRenderActionFlags* ioActionFlags,
00244 const AudioTimeStamp* inTimeStamp,
00245 UInt32 inBusNumber,
00246 UInt32 inNumberFrames,
00247 AudioBufferList* ioData
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
00277
00278
00279
00280 return status;
00281 }
00282
00283
00284
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
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
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
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
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
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
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
00517
00518
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
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
00546 AURenderCallbackStruct input;
00547 input.inputProc = InputProc;
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,
00605 &numDataPacketsNeeded,
00606 BufListConverted,
00607 NULL
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
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 }