00001
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
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
00161 static OSStatus
00162 ConvInputProc(AudioConverterRef inConv,
00163 UInt32* ioNumDataPackets,
00164 AudioBufferList* ioData,
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
00237 static OSStatus
00238 InputProc(void* inRefCon,
00239 AudioUnitRenderActionFlags* ioActionFlags,
00240 const AudioTimeStamp* inTimeStamp,
00241 UInt32 inBusNumber,
00242 UInt32 inNumberFrames,
00243 AudioBufferList* ioData
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
00273
00274
00275
00276 return status;
00277 }
00278
00279
00280
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
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
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
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
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
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
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
00513
00514
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
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
00540 AURenderCallbackStruct input;
00541 input.inputProc = InputProc;
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,
00599 &numDataPacketsNeeded,
00600 BufListConverted,
00601 NULL
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
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 }