diff options
Diffstat (limited to 'tinyDAV/src/audio/coreaudio/tdav_audiounit.c')
-rwxr-xr-x | tinyDAV/src/audio/coreaudio/tdav_audiounit.c | 497 |
1 files changed, 249 insertions, 248 deletions
diff --git a/tinyDAV/src/audio/coreaudio/tdav_audiounit.c b/tinyDAV/src/audio/coreaudio/tdav_audiounit.c index dc11f10..d00f8ee 100755 --- a/tinyDAV/src/audio/coreaudio/tdav_audiounit.c +++ b/tinyDAV/src/audio/coreaudio/tdav_audiounit.c @@ -2,19 +2,19 @@ * Copyright (C) 2010-2011 Mamadou Diop. * * Contact: Mamadou Diop <diopmamadou(at)doubango.org> - * + * * This file is part of Open Source Doubango Framework. * * DOUBANGO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * DOUBANGO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with DOUBANGO. * @@ -36,15 +36,15 @@ static UInt32 kZero = 0; #endif /* TARGET_OS_IPHONE */ #if TARGET_OS_IPHONE - #if TARGET_IPHONE_SIMULATOR // VoiceProcessingIO will give unexpected result on the simulator when using iOS 5 - #define kDoubangoAudioUnitSubType kAudioUnitSubType_RemoteIO - #else // Echo cancellation, AGC, ... - #define kDoubangoAudioUnitSubType kAudioUnitSubType_VoiceProcessingIO - #endif +#if TARGET_IPHONE_SIMULATOR // VoiceProcessingIO will give unexpected result on the simulator when using iOS 5 +#define kDoubangoAudioUnitSubType kAudioUnitSubType_RemoteIO +#else // Echo cancellation, AGC, ... +#define kDoubangoAudioUnitSubType kAudioUnitSubType_VoiceProcessingIO +#endif #elif TARGET_OS_MAC - #define kDoubangoAudioUnitSubType kAudioUnitSubType_HALOutput +#define kDoubangoAudioUnitSubType kAudioUnitSubType_HALOutput #else - #error "Unknown target" +#error "Unknown target" #endif #undef kInputBus @@ -52,21 +52,20 @@ static UInt32 kZero = 0; #undef kOutputBus #define kOutputBus 0 -typedef struct tdav_audiounit_instance_s -{ - TSK_DECLARE_OBJECT; - uint64_t session_id; - uint32_t frame_duration; - AudioComponentInstance audioUnit; - struct{ - unsigned consumer:1; - unsigned producer:1; - } prepared; - unsigned started:1; +typedef struct tdav_audiounit_instance_s { + TSK_DECLARE_OBJECT; + uint64_t session_id; + uint32_t frame_duration; + AudioComponentInstance audioUnit; + struct { + unsigned consumer:1; + unsigned producer:1; + } prepared; + unsigned started:1; unsigned interrupted:1; - - TSK_DECLARE_SAFEOBJ; - + + TSK_DECLARE_SAFEOBJ; + } tdav_audiounit_instance_t; TINYDAV_GEXTERN const tsk_object_def_t *tdav_audiounit_instance_def_t; @@ -78,133 +77,133 @@ static tdav_audiounit_instances_L_t* __audioUnitInstances = tsk_null; static int _tdav_audiounit_handle_signal_xxx_prepared(tdav_audiounit_handle_t* self, tsk_bool_t consumer) { - tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self; - if(!inst || !inst->audioUnit){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - tsk_safeobj_lock(inst); - - if(consumer){ - inst->prepared.consumer = tsk_true; - } - else { - inst->prepared.producer = tsk_true; - } - - OSStatus status; - - // For iOS we are using full-duplex AudioUnit and we wait for both consumer and producer to be prepared + tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self; + if(!inst || !inst->audioUnit) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + tsk_safeobj_lock(inst); + + if(consumer) { + inst->prepared.consumer = tsk_true; + } + else { + inst->prepared.producer = tsk_true; + } + + OSStatus status; + + // For iOS we are using full-duplex AudioUnit and we wait for both consumer and producer to be prepared #if TARGET_OS_IPHONE - if(inst->prepared.consumer && inst->prepared.producer) + if(inst->prepared.consumer && inst->prepared.producer) #endif - { - status = AudioUnitInitialize(inst->audioUnit); - if(status != noErr){ - TSK_DEBUG_ERROR("AudioUnitInitialize failed with status =%ld", (signed long)status); - tsk_safeobj_unlock(inst); - return -2; - } - } - - tsk_safeobj_unlock(inst); - return 0; + { + status = AudioUnitInitialize(inst->audioUnit); + if(status != noErr) { + TSK_DEBUG_ERROR("AudioUnitInitialize failed with status =%ld", (signed long)status); + tsk_safeobj_unlock(inst); + return -2; + } + } + + tsk_safeobj_unlock(inst); + return 0; } tdav_audiounit_handle_t* tdav_audiounit_handle_create(uint64_t session_id) { - tdav_audiounit_instance_t* inst = tsk_null; - - // create audio unit component - if(!__audioSystem){ - AudioComponentDescription audioDescription; - audioDescription.componentType = kAudioUnitType_Output; - audioDescription.componentSubType = kDoubangoAudioUnitSubType; - audioDescription.componentManufacturer = kAudioUnitManufacturer_Apple; - audioDescription.componentFlags = 0; - audioDescription.componentFlagsMask = 0; - if((__audioSystem = AudioComponentFindNext(NULL, &audioDescription))){ - // leave blank - } - else { - TSK_DEBUG_ERROR("Failed to find new audio component"); - goto done; - } - - } - // create list used to hold instances - if(!__audioUnitInstances && !(__audioUnitInstances = tsk_list_create())){ - TSK_DEBUG_ERROR("Failed to create new list"); - goto done; - } - - //= lock the list - tsk_list_lock(__audioUnitInstances); - - // For iOS we are using full-duplex AudioUnit and to keep it unique for both - // the consumer and producer we use the session id. + tdav_audiounit_instance_t* inst = tsk_null; + + // create audio unit component + if(!__audioSystem) { + AudioComponentDescription audioDescription; + audioDescription.componentType = kAudioUnitType_Output; + audioDescription.componentSubType = kDoubangoAudioUnitSubType; + audioDescription.componentManufacturer = kAudioUnitManufacturer_Apple; + audioDescription.componentFlags = 0; + audioDescription.componentFlagsMask = 0; + if((__audioSystem = AudioComponentFindNext(NULL, &audioDescription))) { + // leave blank + } + else { + TSK_DEBUG_ERROR("Failed to find new audio component"); + goto done; + } + + } + // create list used to hold instances + if(!__audioUnitInstances && !(__audioUnitInstances = tsk_list_create())) { + TSK_DEBUG_ERROR("Failed to create new list"); + goto done; + } + + //= lock the list + tsk_list_lock(__audioUnitInstances); + + // For iOS we are using full-duplex AudioUnit and to keep it unique for both + // the consumer and producer we use the session id. #if TARGET_OS_IPHONE - // find the instance from the list - const tsk_list_item_t* item; - tsk_list_foreach(item,__audioUnitInstances){ - if(((tdav_audiounit_instance_t*)item->data)->session_id == session_id){ - inst = tsk_object_ref(item->data); - goto done; - } - } + // find the instance from the list + const tsk_list_item_t* item; + tsk_list_foreach(item,__audioUnitInstances) { + if(((tdav_audiounit_instance_t*)item->data)->session_id == session_id) { + inst = tsk_object_ref(item->data); + goto done; + } + } #endif - - // create instance object and put it into the list - if((inst = tsk_object_new(tdav_audiounit_instance_def_t))){ - OSStatus status = noErr; - tdav_audiounit_instance_t* _inst; - - // create new instance - if((status= AudioComponentInstanceNew(__audioSystem, &inst->audioUnit)) != noErr){ - TSK_DEBUG_ERROR("AudioComponentInstanceNew() failed with status=%ld", (signed long)status); - TSK_OBJECT_SAFE_FREE(inst); - goto done; - } - _inst = inst, _inst->session_id = session_id; - tsk_list_push_back_data(__audioUnitInstances, (void**)&_inst); - } - + + // create instance object and put it into the list + if((inst = tsk_object_new(tdav_audiounit_instance_def_t))) { + OSStatus status = noErr; + tdav_audiounit_instance_t* _inst; + + // create new instance + if((status= AudioComponentInstanceNew(__audioSystem, &inst->audioUnit)) != noErr) { + TSK_DEBUG_ERROR("AudioComponentInstanceNew() failed with status=%ld", (signed long)status); + TSK_OBJECT_SAFE_FREE(inst); + goto done; + } + _inst = inst, _inst->session_id = session_id; + tsk_list_push_back_data(__audioUnitInstances, (void**)&_inst); + } + done: - //= unlock the list - tsk_list_unlock(__audioUnitInstances); - return (tdav_audiounit_handle_t*)inst; + //= unlock the list + tsk_list_unlock(__audioUnitInstances); + return (tdav_audiounit_handle_t*)inst; } AudioComponentInstance tdav_audiounit_handle_get_instance(tdav_audiounit_handle_t* self) { - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - return ((tdav_audiounit_instance_t*)self)->audioUnit; + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return tsk_null; + } + return ((tdav_audiounit_instance_t*)self)->audioUnit; } int tdav_audiounit_handle_signal_consumer_prepared(tdav_audiounit_handle_t* self) { - return _tdav_audiounit_handle_signal_xxx_prepared(self, tsk_true); + return _tdav_audiounit_handle_signal_xxx_prepared(self, tsk_true); } int tdav_audiounit_handle_signal_producer_prepared(tdav_audiounit_handle_t* self) { - return _tdav_audiounit_handle_signal_xxx_prepared(self, tsk_false); + return _tdav_audiounit_handle_signal_xxx_prepared(self, tsk_false); } int tdav_audiounit_handle_start(tdav_audiounit_handle_t* self) { - tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self; - OSStatus status = noErr; - if(!inst || !inst->audioUnit){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - tsk_safeobj_lock(inst); + tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self; + OSStatus status = noErr; + if(!inst || !inst->audioUnit) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + tsk_safeobj_lock(inst); status = (OSStatus)tdav_apple_enable_audio(); if (status == noErr) { if ((!inst->started || inst->interrupted) && (status = AudioOutputUnitStart(inst->audioUnit))) { @@ -215,106 +214,108 @@ int tdav_audiounit_handle_start(tdav_audiounit_handle_t* self) TSK_DEBUG_ERROR("tdav_apple_enable_audio() failed with status=%ld", (signed long)status); } inst->started = (status == noErr) ? tsk_true : tsk_false; - if (inst->started) inst->interrupted = 0; - tsk_safeobj_unlock(inst); - return status ? -2 : 0; + if (inst->started) { + inst->interrupted = 0; + } + tsk_safeobj_unlock(inst); + return status ? -2 : 0; } uint32_t tdav_audiounit_handle_get_frame_duration(tdav_audiounit_handle_t* self) { - if(self){ - return ((tdav_audiounit_instance_t*)self)->frame_duration; - } - return 0; + if(self) { + return ((tdav_audiounit_instance_t*)self)->frame_duration; + } + return 0; } int tdav_audiounit_handle_configure(tdav_audiounit_handle_t* self, tsk_bool_t consumer, uint32_t ptime, AudioStreamBasicDescription* audioFormat) { - OSStatus status = noErr; - tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self; - - if(!inst || !audioFormat){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + OSStatus status = noErr; + tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self; + + if(!inst || !audioFormat) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } #if TARGET_OS_IPHONE - // set preferred buffer size - Float32 preferredBufferSize = ((Float32)ptime / 1000.f); // in seconds - UInt32 size = sizeof(preferredBufferSize); - status = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize); - if(status != noErr){ - TSK_DEBUG_ERROR("AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration) failed with status=%d", (int)status); - TSK_OBJECT_SAFE_FREE(inst); - goto done; - } - status = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &size, &preferredBufferSize); - if(status == noErr){ - inst->frame_duration = (preferredBufferSize * 1000); - TSK_DEBUG_INFO("Frame duration=%d", inst->frame_duration); - } - else { - TSK_DEBUG_ERROR("AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, %f) failed", preferredBufferSize); - } - - - UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord; - status = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory); - if(status != noErr){ - TSK_DEBUG_ERROR("AudioSessionSetProperty(kAudioSessionProperty_AudioCategory) failed with status code=%d", (int)status); - goto done; - } - + // set preferred buffer size + Float32 preferredBufferSize = ((Float32)ptime / 1000.f); // in seconds + UInt32 size = sizeof(preferredBufferSize); + status = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize); + if(status != noErr) { + TSK_DEBUG_ERROR("AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration) failed with status=%d", (int)status); + TSK_OBJECT_SAFE_FREE(inst); + goto done; + } + status = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &size, &preferredBufferSize); + if(status == noErr) { + inst->frame_duration = (preferredBufferSize * 1000); + TSK_DEBUG_INFO("Frame duration=%d", inst->frame_duration); + } + else { + TSK_DEBUG_ERROR("AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, %f) failed", preferredBufferSize); + } + + + UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord; + status = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory); + if(status != noErr) { + TSK_DEBUG_ERROR("AudioSessionSetProperty(kAudioSessionProperty_AudioCategory) failed with status code=%d", (int)status); + goto done; + } + #elif TARGET_OS_MAC #if 1 - // set preferred buffer size - UInt32 preferredBufferSize = ((ptime * audioFormat->mSampleRate)/1000); // in bytes - UInt32 size = sizeof(preferredBufferSize); - status = AudioUnitSetProperty(inst->audioUnit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, &preferredBufferSize, size); - if(status != noErr){ - TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_SetInputCallback) failed with status=%ld", (signed long)status); - } - status = AudioUnitGetProperty(inst->audioUnit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, &preferredBufferSize, &size); - if(status == noErr){ - inst->frame_duration = ((preferredBufferSize * 1000)/audioFormat->mSampleRate); - TSK_DEBUG_INFO("Frame duration=%d", inst->frame_duration); - } - else { - TSK_DEBUG_ERROR("AudioUnitGetProperty(kAudioDevicePropertyBufferFrameSize, %lu) failed", (unsigned long)preferredBufferSize); - } + // set preferred buffer size + UInt32 preferredBufferSize = ((ptime * audioFormat->mSampleRate)/1000); // in bytes + UInt32 size = sizeof(preferredBufferSize); + status = AudioUnitSetProperty(inst->audioUnit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, &preferredBufferSize, size); + if(status != noErr) { + TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_SetInputCallback) failed with status=%ld", (signed long)status); + } + status = AudioUnitGetProperty(inst->audioUnit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, &preferredBufferSize, &size); + if(status == noErr) { + inst->frame_duration = ((preferredBufferSize * 1000)/audioFormat->mSampleRate); + TSK_DEBUG_INFO("Frame duration=%d", inst->frame_duration); + } + else { + TSK_DEBUG_ERROR("AudioUnitGetProperty(kAudioDevicePropertyBufferFrameSize, %lu) failed", (unsigned long)preferredBufferSize); + } #endif - + #endif - + done: - return (status == noErr) ? 0 : -2; + return (status == noErr) ? 0 : -2; } int tdav_audiounit_handle_mute(tdav_audiounit_handle_t* self, tsk_bool_t mute) { - tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self; - if(!inst || !inst->audioUnit){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self; + if(!inst || !inst->audioUnit) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } #if TARGET_OS_IPHONE - OSStatus status = noErr; - status = AudioUnitSetProperty(inst->audioUnit, kAUVoiceIOProperty_MuteOutput, - kAudioUnitScope_Output, kOutputBus, mute ? &kOne : &kZero, mute ? sizeof(kOne) : sizeof(kZero)); - - return (status == noErr) ? 0 : -2; + OSStatus status = noErr; + status = AudioUnitSetProperty(inst->audioUnit, kAUVoiceIOProperty_MuteOutput, + kAudioUnitScope_Output, kOutputBus, mute ? &kOne : &kZero, mute ? sizeof(kOne) : sizeof(kZero)); + + return (status == noErr) ? 0 : -2; #else - return 0; + return 0; #endif } int tdav_audiounit_handle_interrupt(tdav_audiounit_handle_t* self, tsk_bool_t interrupt) { tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self; - if (!inst){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if (!inst) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } OSStatus status = noErr; if (inst->interrupted != interrupt && inst->started) { if (interrupt) { @@ -346,37 +347,38 @@ bail: int tdav_audiounit_handle_stop(tdav_audiounit_handle_t* self) { - tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self; - OSStatus status = noErr; - if(!inst || (inst->started && !inst->audioUnit)){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - tsk_safeobj_lock(inst); - if(inst->started && (status = AudioOutputUnitStop(inst->audioUnit))){ - TSK_DEBUG_ERROR("AudioOutputUnitStop failed with status=%ld", (signed long)status); - } + tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self; + OSStatus status = noErr; + if(!inst || (inst->started && !inst->audioUnit)) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + tsk_safeobj_lock(inst); + if(inst->started && (status = AudioOutputUnitStop(inst->audioUnit))) { + TSK_DEBUG_ERROR("AudioOutputUnitStop failed with status=%ld", (signed long)status); + } inst->started = (status == noErr ? tsk_false : tsk_true); - tsk_safeobj_unlock(inst); - return (status != noErr) ? -2 : 0; + tsk_safeobj_unlock(inst); + return (status != noErr) ? -2 : 0; } -int tdav_audiounit_handle_destroy(tdav_audiounit_handle_t** self){ - if(!self || !*self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - tsk_list_lock(__audioUnitInstances); - if(tsk_object_get_refcount(*self)==1){ - tsk_list_remove_item_by_data(__audioUnitInstances, *self); - } - else { - tsk_object_unref(*self); - } - tsk_list_unlock(__audioUnitInstances); - *self = tsk_null; - return 0; +int tdav_audiounit_handle_destroy(tdav_audiounit_handle_t** self) +{ + if(!self || !*self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + tsk_list_lock(__audioUnitInstances); + if(tsk_object_get_refcount(*self)==1) { + tsk_list_remove_item_by_data(__audioUnitInstances, *self); + } + else { + tsk_object_unref(*self); + } + tsk_list_unlock(__audioUnitInstances); + *self = tsk_null; + return 0; } // @@ -384,39 +386,38 @@ int tdav_audiounit_handle_destroy(tdav_audiounit_handle_t** self){ // static tsk_object_t* tdav_audiounit_instance_ctor(tsk_object_t * self, va_list * app) { - tdav_audiounit_instance_t* inst = self; - if(inst){ - tsk_safeobj_init(inst); - } - return self; + tdav_audiounit_instance_t* inst = self; + if(inst) { + tsk_safeobj_init(inst); + } + return self; } static tsk_object_t* tdav_audiounit_instance_dtor(tsk_object_t * self) -{ - tdav_audiounit_instance_t* inst = self; - if(inst){ +{ + tdav_audiounit_instance_t* inst = self; + if(inst) { tsk_safeobj_lock(inst); - if(inst->audioUnit){ + if(inst->audioUnit) { AudioUnitUninitialize(inst->audioUnit); AudioComponentInstanceDispose(inst->audioUnit); inst->audioUnit = tsk_null; - } + } tsk_safeobj_unlock(inst); - - tsk_safeobj_deinit(inst); + + tsk_safeobj_deinit(inst); TSK_DEBUG_INFO("*** AudioUnit Instance destroyed ***"); - } - return self; + } + return self; } static int tdav_audiounit_instance_cmp(const tsk_object_t *_ai1, const tsk_object_t *_ai2) { - return (int)(_ai1 - _ai2); + return (int)(_ai1 - _ai2); } -static const tsk_object_def_t tdav_audiounit_instance_def_s = -{ - sizeof(tdav_audiounit_instance_t), - tdav_audiounit_instance_ctor, - tdav_audiounit_instance_dtor, - tdav_audiounit_instance_cmp, +static const tsk_object_def_t tdav_audiounit_instance_def_s = { + sizeof(tdav_audiounit_instance_t), + tdav_audiounit_instance_ctor, + tdav_audiounit_instance_dtor, + tdav_audiounit_instance_cmp, }; const tsk_object_def_t *tdav_audiounit_instance_def_t = &tdav_audiounit_instance_def_s; |