diff options
Diffstat (limited to 'tinyDAV/src/audio/coreaudio')
-rwxr-xr-x | tinyDAV/src/audio/coreaudio/tdav_audiounit.c | 497 | ||||
-rwxr-xr-x | tinyDAV/src/audio/coreaudio/tdav_consumer_audioqueue.c | 263 | ||||
-rwxr-xr-x | tinyDAV/src/audio/coreaudio/tdav_consumer_audiounit.c | 669 | ||||
-rwxr-xr-x | tinyDAV/src/audio/coreaudio/tdav_producer_audioqueue.c | 255 | ||||
-rwxr-xr-x | tinyDAV/src/audio/coreaudio/tdav_producer_audiounit.c | 627 |
5 files changed, 1154 insertions, 1157 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; diff --git a/tinyDAV/src/audio/coreaudio/tdav_consumer_audioqueue.c b/tinyDAV/src/audio/coreaudio/tdav_consumer_audioqueue.c index 2f5fd90..882a988 100755 --- a/tinyDAV/src/audio/coreaudio/tdav_consumer_audioqueue.c +++ b/tinyDAV/src/audio/coreaudio/tdav_consumer_audioqueue.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. * @@ -23,7 +23,7 @@ /**@file tdav_consumer_audioqueue.c * @brief Audio Consumer for MacOSX and iOS platforms. * - * @authors + * @authors * - Laurent Etiemble <laurent.etiemble(at)gmail.com> * - Mamadou Diop <diopmamadou(at)doubango(dot)org> * @@ -40,22 +40,23 @@ #include "tsk_memory.h" #include "tsk_debug.h" -static void __handle_output_buffer(void *userdata, AudioQueueRef queue, AudioQueueBufferRef buffer) { +static void __handle_output_buffer(void *userdata, AudioQueueRef queue, AudioQueueBufferRef buffer) +{ tdav_consumer_audioqueue_t* consumer = (tdav_consumer_audioqueue_t*)userdata; - + if (!consumer->started) { return; } - - if(!tdav_consumer_audio_get(TDAV_CONSUMER_AUDIO(consumer), buffer->mAudioData, consumer->buffer_size)){ - // Put silence - memset(buffer->mAudioData, 0, consumer->buffer_size); - } - + + if(!tdav_consumer_audio_get(TDAV_CONSUMER_AUDIO(consumer), buffer->mAudioData, consumer->buffer_size)) { + // Put silence + memset(buffer->mAudioData, 0, consumer->buffer_size); + } + // Re-enqueue the buffer AudioQueueEnqueueBuffer(consumer->queue, buffer, 0, NULL); - // alert the jitter buffer - tdav_consumer_audio_tick(TDAV_CONSUMER_AUDIO(consumer)); + // alert the jitter buffer + tdav_consumer_audio_tick(TDAV_CONSUMER_AUDIO(consumer)); } /* ============ Media Consumer Interface ================= */ @@ -64,25 +65,25 @@ static void __handle_output_buffer(void *userdata, AudioQueueRef queue, AudioQue int tdav_consumer_audioqueue_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec) { OSStatus ret; - tsk_size_t i; - tdav_consumer_audioqueue_t* consumer = (tdav_consumer_audioqueue_t*)self; - - if(!consumer || !codec && codec->plugin){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - TMEDIA_CONSUMER(consumer)->audio.ptime = TMEDIA_CODEC_PTIME_AUDIO_DECODING(codec); - TMEDIA_CONSUMER(consumer)->audio.in.channels = TMEDIA_CODEC_CHANNELS_AUDIO_DECODING(codec); - TMEDIA_CONSUMER(consumer)->audio.in.rate = TMEDIA_CODEC_RATE_DECODING(codec); - /* codec should have ptime */ - - // Set audio category + tsk_size_t i; + tdav_consumer_audioqueue_t* consumer = (tdav_consumer_audioqueue_t*)self; + + if(!consumer || !codec && codec->plugin) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + TMEDIA_CONSUMER(consumer)->audio.ptime = TMEDIA_CODEC_PTIME_AUDIO_DECODING(codec); + TMEDIA_CONSUMER(consumer)->audio.in.channels = TMEDIA_CODEC_CHANNELS_AUDIO_DECODING(codec); + TMEDIA_CONSUMER(consumer)->audio.in.rate = TMEDIA_CODEC_RATE_DECODING(codec); + /* codec should have ptime */ + + // Set audio category #if TARGET_OS_IPHONE - UInt32 category = kAudioSessionCategory_PlayAndRecord; - AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category); + UInt32 category = kAudioSessionCategory_PlayAndRecord; + AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category); #endif - + // Create the audio stream description AudioStreamBasicDescription *description = &(consumer->description); description->mSampleRate = TMEDIA_CONSUMER(consumer)->audio.out.rate ? TMEDIA_CONSUMER(consumer)->audio.out.rate : TMEDIA_CONSUMER(consumer)->audio.in.rate; @@ -94,107 +95,107 @@ int tdav_consumer_audioqueue_prepare(tmedia_consumer_t* self, const tmedia_codec description->mBytesPerPacket = description->mBitsPerChannel / 8 * description->mChannelsPerFrame; description->mBytesPerFrame = description->mBytesPerPacket; description->mReserved = 0; - + int packetperbuffer = 1000 / TMEDIA_CONSUMER(consumer)->audio.ptime; consumer->buffer_size = description->mSampleRate * description->mBytesPerFrame / packetperbuffer; - + // Create the playback audio queue ret = AudioQueueNewOutput(&(consumer->description), __handle_output_buffer, consumer, - NULL, + NULL, NULL, 0, &(consumer->queue)); - + for(i = 0; i < CoreAudioPlayBuffers; i++) { // Create the buffer for the queue ret = AudioQueueAllocateBuffer(consumer->queue, consumer->buffer_size, &(consumer->buffers[i])); if (ret) { break; } - + // Clear the data memset(consumer->buffers[i]->mAudioData, 0, consumer->buffer_size); consumer->buffers[i]->mAudioDataByteSize = consumer->buffer_size; - + // Enqueue the buffer ret = AudioQueueEnqueueBuffer(consumer->queue, consumer->buffers[i], 0, NULL); if (ret) { break; } } - - return ret; + + return ret; } int tdav_consumer_audioqueue_start(tmedia_consumer_t* self) { OSStatus ret; - tdav_consumer_audioqueue_t* consumer = (tdav_consumer_audioqueue_t*)self; - - if(!consumer){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(consumer->started){ - TSK_DEBUG_WARN("Consumer already started"); - return 0; - } - - consumer->started = tsk_true; + tdav_consumer_audioqueue_t* consumer = (tdav_consumer_audioqueue_t*)self; + + if(!consumer) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(consumer->started) { + TSK_DEBUG_WARN("Consumer already started"); + return 0; + } + + consumer->started = tsk_true; ret = AudioQueueStart(consumer->queue, NULL); - - return ret; + + return ret; } int tdav_consumer_audioqueue_consume(tmedia_consumer_t* self, const void* buffer, tsk_size_t size, const tsk_object_t* proto_hdr) { - tdav_consumer_audioqueue_t* consumer = (tdav_consumer_audioqueue_t*)self; - - if(!consumer || !buffer || !size){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - // buffer is already decoded - return tdav_consumer_audio_put(TDAV_CONSUMER_AUDIO(consumer), buffer, size, proto_hdr); + tdav_consumer_audioqueue_t* consumer = (tdav_consumer_audioqueue_t*)self; + + if(!consumer || !buffer || !size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + // buffer is already decoded + return tdav_consumer_audio_put(TDAV_CONSUMER_AUDIO(consumer), buffer, size, proto_hdr); } int tdav_consumer_audioqueue_pause(tmedia_consumer_t* self) { OSStatus ret; - tdav_consumer_audioqueue_t* consumer = (tdav_consumer_audioqueue_t*)self; - - if(!consumer){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - + tdav_consumer_audioqueue_t* consumer = (tdav_consumer_audioqueue_t*)self; + + if(!consumer) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + ret = AudioQueuePause(consumer->queue); - - return ret; + + return ret; } int tdav_consumer_audioqueue_stop(tmedia_consumer_t* self) { OSStatus ret; - tdav_consumer_audioqueue_t* consumer = (tdav_consumer_audioqueue_t*)self; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(!consumer->started){ - TSK_DEBUG_WARN("Consumer not started"); - return 0; - } - - consumer->started = tsk_false; + tdav_consumer_audioqueue_t* consumer = (tdav_consumer_audioqueue_t*)self; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(!consumer->started) { + TSK_DEBUG_WARN("Consumer not started"); + return 0; + } + + consumer->started = tsk_false; ret = AudioQueueStop(consumer->queue, false); - - return ret; + + return ret; } // @@ -203,64 +204,62 @@ int tdav_consumer_audioqueue_stop(tmedia_consumer_t* self) /* constructor */ static tsk_object_t* tdav_consumer_audioqueue_ctor(tsk_object_t * self, va_list * app) { - tdav_consumer_audioqueue_t *consumer = self; - if(consumer){ - /* init base */ - tdav_consumer_audio_init(TDAV_CONSUMER_AUDIO(consumer)); - } - return self; + tdav_consumer_audioqueue_t *consumer = self; + if(consumer) { + /* init base */ + tdav_consumer_audio_init(TDAV_CONSUMER_AUDIO(consumer)); + } + return self; } /* destructor */ static tsk_object_t* tdav_consumer_audioqueue_dtor(tsk_object_t * self) -{ - tdav_consumer_audioqueue_t *consumer = self; - if(consumer){ - // Stop the consumer if not done - if(consumer->started){ - tdav_consumer_audioqueue_stop(self); - } - - // Free all buffers and dispose the queue +{ + tdav_consumer_audioqueue_t *consumer = self; + if(consumer) { + // Stop the consumer if not done + if(consumer->started) { + tdav_consumer_audioqueue_stop(self); + } + + // Free all buffers and dispose the queue if (consumer->queue) { - tsk_size_t i; - - for(i=0; i<CoreAudioPlayBuffers; i++){ - AudioQueueFreeBuffer(consumer->queue, consumer->buffers[i]); - } - + tsk_size_t i; + + for(i=0; i<CoreAudioPlayBuffers; i++) { + AudioQueueFreeBuffer(consumer->queue, consumer->buffers[i]); + } + AudioQueueDispose(consumer->queue, true); } - - /* deinit base */ - tdav_consumer_audio_deinit(TDAV_CONSUMER_AUDIO(consumer)); - } - - return self; + + /* deinit base */ + tdav_consumer_audio_deinit(TDAV_CONSUMER_AUDIO(consumer)); + } + + return self; } /* object definition */ -static const tsk_object_def_t tdav_consumer_audioqueue_def_s = -{ - sizeof(tdav_consumer_audioqueue_t), - tdav_consumer_audioqueue_ctor, - tdav_consumer_audioqueue_dtor, - tdav_consumer_audio_cmp, +static const tsk_object_def_t tdav_consumer_audioqueue_def_s = { + sizeof(tdav_consumer_audioqueue_t), + tdav_consumer_audioqueue_ctor, + tdav_consumer_audioqueue_dtor, + tdav_consumer_audio_cmp, }; /* plugin definition*/ -static const tmedia_consumer_plugin_def_t tdav_consumer_audioqueue_plugin_def_s = -{ - &tdav_consumer_audioqueue_def_s, - - tmedia_audio, - "Apple CoreAudio consumer(AudioQueue)", - - tdav_consumer_audioqueue_set, - tdav_consumer_audioqueue_prepare, - tdav_consumer_audioqueue_start, - tdav_consumer_audioqueue_consume, - tdav_consumer_audioqueue_pause, - tdav_consumer_audioqueue_stop +static const tmedia_consumer_plugin_def_t tdav_consumer_audioqueue_plugin_def_s = { + &tdav_consumer_audioqueue_def_s, + + tmedia_audio, + "Apple CoreAudio consumer(AudioQueue)", + + tdav_consumer_audioqueue_set, + tdav_consumer_audioqueue_prepare, + tdav_consumer_audioqueue_start, + tdav_consumer_audioqueue_consume, + tdav_consumer_audioqueue_pause, + tdav_consumer_audioqueue_stop }; const tmedia_consumer_plugin_def_t *tdav_consumer_audioqueue_plugin_def_t = &tdav_consumer_audioqueue_plugin_def_s; diff --git a/tinyDAV/src/audio/coreaudio/tdav_consumer_audiounit.c b/tinyDAV/src/audio/coreaudio/tdav_consumer_audiounit.c index 947d782..12ed8db 100755 --- a/tinyDAV/src/audio/coreaudio/tdav_consumer_audiounit.c +++ b/tinyDAV/src/audio/coreaudio/tdav_consumer_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. * @@ -38,339 +38,340 @@ static tsk_size_t tdav_consumer_audiounit_get(tdav_consumer_audiounit_t* self, void* data, tsk_size_t size); -static OSStatus __handle_output_buffer(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList *ioData) { - OSStatus status = noErr; - // tsk_size_t out_size; - tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t* )inRefCon; - - if(!consumer->started || consumer->paused){ - goto done; - } - - if(!ioData){ - TSK_DEBUG_ERROR("Invalid argument"); - status = kNoDataError; - goto done; - } - // read from jitter buffer and fill ioData buffers - tsk_mutex_lock(consumer->ring.mutex); - for(int i=0; i<ioData->mNumberBuffers; i++){ - /* int ret = */ tdav_consumer_audiounit_get(consumer, ioData->mBuffers[i].mData, ioData->mBuffers[i].mDataByteSize); - } - tsk_mutex_unlock(consumer->ring.mutex); - -done: +static OSStatus __handle_output_buffer(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList *ioData) +{ + OSStatus status = noErr; + // tsk_size_t out_size; + tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t* )inRefCon; + + if(!consumer->started || consumer->paused) { + goto done; + } + + if(!ioData) { + TSK_DEBUG_ERROR("Invalid argument"); + status = kNoDataError; + goto done; + } + // read from jitter buffer and fill ioData buffers + tsk_mutex_lock(consumer->ring.mutex); + for(int i=0; i<ioData->mNumberBuffers; i++) { + /* int ret = */ tdav_consumer_audiounit_get(consumer, ioData->mBuffers[i].mData, ioData->mBuffers[i].mDataByteSize); + } + tsk_mutex_unlock(consumer->ring.mutex); + +done: return status; } static tsk_size_t tdav_consumer_audiounit_get(tdav_consumer_audiounit_t* self, void* data, tsk_size_t size) { - tsk_ssize_t retSize = 0; - + tsk_ssize_t retSize = 0; + #if DISABLE_JITTER_BUFFER - retSize = speex_buffer_read(self->ring.buffer, data, size); - if(retSize < size){ - memset(((uint8_t*)data)+retSize, 0, (size - retSize)); - } + retSize = speex_buffer_read(self->ring.buffer, data, size); + if(retSize < size) { + memset(((uint8_t*)data)+retSize, 0, (size - retSize)); + } #else - self->ring.leftBytes += size; - while (self->ring.leftBytes >= self->ring.chunck.size) { - self->ring.leftBytes -= self->ring.chunck.size; - retSize = (tsk_ssize_t)tdav_consumer_audio_get(TDAV_CONSUMER_AUDIO(self), self->ring.chunck.buffer, self->ring.chunck.size); - tdav_consumer_audio_tick(TDAV_CONSUMER_AUDIO(self)); - speex_buffer_write(self->ring.buffer, self->ring.chunck.buffer, retSize); - } - // IMPORTANT: looks like there is a bug in speex: continously trying to read more than avail - // many times can corrupt the buffer. At least on OS X 1.5 - if(speex_buffer_get_available(self->ring.buffer) >= size){ - retSize = (tsk_ssize_t)speex_buffer_read(self->ring.buffer, data, (int)size); - } - else{ - memset(data, 0, size); - } + self->ring.leftBytes += size; + while (self->ring.leftBytes >= self->ring.chunck.size) { + self->ring.leftBytes -= self->ring.chunck.size; + retSize = (tsk_ssize_t)tdav_consumer_audio_get(TDAV_CONSUMER_AUDIO(self), self->ring.chunck.buffer, self->ring.chunck.size); + tdav_consumer_audio_tick(TDAV_CONSUMER_AUDIO(self)); + speex_buffer_write(self->ring.buffer, self->ring.chunck.buffer, retSize); + } + // IMPORTANT: looks like there is a bug in speex: continously trying to read more than avail + // many times can corrupt the buffer. At least on OS X 1.5 + if(speex_buffer_get_available(self->ring.buffer) >= size) { + retSize = (tsk_ssize_t)speex_buffer_read(self->ring.buffer, data, (int)size); + } + else { + memset(data, 0, size); + } #endif - return retSize; + return retSize; } /* ============ Media Consumer Interface ================= */ int tdav_consumer_audiounit_set(tmedia_consumer_t* self, const tmedia_param_t* param) { tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self; - if (param->plugin_type == tmedia_ppt_consumer) { - if (param->value_type == tmedia_pvt_int32) { - if (tsk_striequals(param->key, "interrupt")) { - int32_t interrupt = *((uint8_t*)param->value) ? 1 : 0; + if (param->plugin_type == tmedia_ppt_consumer) { + if (param->value_type == tmedia_pvt_int32) { + if (tsk_striequals(param->key, "interrupt")) { + int32_t interrupt = *((uint8_t*)param->value) ? 1 : 0; return tdav_audiounit_handle_interrupt(consumer->audioUnitHandle, interrupt); } - } - } - return tdav_consumer_audio_set(TDAV_CONSUMER_AUDIO(self), param); + } + } + return tdav_consumer_audio_set(TDAV_CONSUMER_AUDIO(self), param); } static int tdav_consumer_audiounit_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec) { - static UInt32 flagOne = 1; - AudioStreamBasicDescription audioFormat; + static UInt32 flagOne = 1; + AudioStreamBasicDescription audioFormat; #define kOutputBus 0 - - tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self; - OSStatus status = noErr; - - if(!consumer || !codec || !codec->plugin){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(!consumer->audioUnitHandle){ - if(!(consumer->audioUnitHandle = tdav_audiounit_handle_create(TMEDIA_CONSUMER(consumer)->session_id))){ - TSK_DEBUG_ERROR("Failed to get audio unit instance for session with id=%lld", TMEDIA_CONSUMER(consumer)->session_id); - return -3; - } - } - - // enable - status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), - kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Output, - kOutputBus, - &flagOne, - sizeof(flagOne)); - if(status){ - TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%d", (int32_t)status); - return -4; - } - else { - + + tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self; + OSStatus status = noErr; + + if(!consumer || !codec || !codec->plugin) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(!consumer->audioUnitHandle) { + if(!(consumer->audioUnitHandle = tdav_audiounit_handle_create(TMEDIA_CONSUMER(consumer)->session_id))) { + TSK_DEBUG_ERROR("Failed to get audio unit instance for session with id=%lld", TMEDIA_CONSUMER(consumer)->session_id); + return -3; + } + } + + // enable + status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Output, + kOutputBus, + &flagOne, + sizeof(flagOne)); + if(status) { + TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%d", (int32_t)status); + return -4; + } + else { + #if !TARGET_OS_IPHONE // strange: TARGET_OS_MAC is equal to '1' on Smulator - UInt32 param; - - // disable input - param = 0; - status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, ¶m, sizeof(UInt32)); - if(status != noErr){ - TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%ld", (signed long)status); - return -4; - } - - // set default audio device - param = sizeof(AudioDeviceID); - AudioDeviceID outputDeviceID; - status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, ¶m, &outputDeviceID); - if(status != noErr){ - TSK_DEBUG_ERROR("AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice) failed with status=%ld", (signed long)status); - return -4; - } - - // set the current device to the default input unit - status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), - kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, - 0, - &outputDeviceID, - sizeof(AudioDeviceID)); - if(status != noErr){ - TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_CurrentDevice) failed with status=%ld", (signed long)status); - return -4; - } - + UInt32 param; + + // disable input + param = 0; + status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, ¶m, sizeof(UInt32)); + if(status != noErr) { + TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%ld", (signed long)status); + return -4; + } + + // set default audio device + param = sizeof(AudioDeviceID); + AudioDeviceID outputDeviceID; + status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, ¶m, &outputDeviceID); + if(status != noErr) { + TSK_DEBUG_ERROR("AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice) failed with status=%ld", (signed long)status); + return -4; + } + + // set the current device to the default input unit + status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + 0, + &outputDeviceID, + sizeof(AudioDeviceID)); + if(status != noErr) { + TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_CurrentDevice) failed with status=%ld", (signed long)status); + return -4; + } + #endif - TMEDIA_CONSUMER(consumer)->audio.ptime = TMEDIA_CODEC_PTIME_AUDIO_DECODING(codec); - TMEDIA_CONSUMER(consumer)->audio.in.channels = TMEDIA_CODEC_CHANNELS_AUDIO_DECODING(codec); - TMEDIA_CONSUMER(consumer)->audio.in.rate = TMEDIA_CODEC_RATE_DECODING(codec); - + TMEDIA_CONSUMER(consumer)->audio.ptime = TMEDIA_CODEC_PTIME_AUDIO_DECODING(codec); + TMEDIA_CONSUMER(consumer)->audio.in.channels = TMEDIA_CODEC_CHANNELS_AUDIO_DECODING(codec); + TMEDIA_CONSUMER(consumer)->audio.in.rate = TMEDIA_CODEC_RATE_DECODING(codec); + TSK_DEBUG_INFO("AudioUnit consumer: in.channels=%d, out.channles=%d, in.rate=%d, out.rate=%d, ptime=%d", TMEDIA_CONSUMER(consumer)->audio.in.channels, TMEDIA_CONSUMER(consumer)->audio.out.channels, TMEDIA_CONSUMER(consumer)->audio.in.rate, TMEDIA_CONSUMER(consumer)->audio.out.rate, TMEDIA_CONSUMER(consumer)->audio.ptime); - - audioFormat.mSampleRate = TMEDIA_CONSUMER(consumer)->audio.out.rate ? TMEDIA_CONSUMER(consumer)->audio.out.rate : TMEDIA_CONSUMER(consumer)->audio.in.rate; - audioFormat.mFormatID = kAudioFormatLinearPCM; - audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; - audioFormat.mChannelsPerFrame = TMEDIA_CONSUMER(consumer)->audio.in.channels; - audioFormat.mFramesPerPacket = 1; - audioFormat.mBitsPerChannel = TMEDIA_CONSUMER(consumer)->audio.bits_per_sample; - audioFormat.mBytesPerPacket = audioFormat.mBitsPerChannel / 8 * audioFormat.mChannelsPerFrame; - audioFormat.mBytesPerFrame = audioFormat.mBytesPerPacket; - audioFormat.mReserved = 0; - status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, - kOutputBus, - &audioFormat, - sizeof(audioFormat)); - - if(status){ - TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioUnitProperty_StreamFormat) failed with status=%ld", (signed long)status); - return -5; - } - else { - // configure - if(tdav_audiounit_handle_configure(consumer->audioUnitHandle, tsk_true, TMEDIA_CONSUMER(consumer)->audio.ptime, &audioFormat)){ - TSK_DEBUG_ERROR("tdav_audiounit_handle_set_rate(%d) failed", TMEDIA_CONSUMER(consumer)->audio.out.rate); - return -4; - } - - // set callback function - AURenderCallbackStruct callback; - callback.inputProc = __handle_output_buffer; - callback.inputProcRefCon = consumer; - status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), - kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, - kOutputBus, - &callback, - sizeof(callback)); - if(status){ - TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_SetInputCallback) failed with status=%ld", (signed long)status); - return -6; - } - } - } - - // allocate the chunck buffer and create the ring - consumer->ring.chunck.size = (TMEDIA_CONSUMER(consumer)->audio.ptime * audioFormat.mSampleRate * audioFormat.mBytesPerFrame) / 1000; - consumer->ring.size = kRingPacketCount * consumer->ring.chunck.size; - if(!(consumer->ring.chunck.buffer = tsk_realloc(consumer->ring.chunck.buffer, consumer->ring.chunck.size))){ - TSK_DEBUG_ERROR("Failed to allocate new buffer"); - return -7; - } - if(!consumer->ring.buffer){ - consumer->ring.buffer = speex_buffer_init((int)consumer->ring.size); - } - else { - int ret; - if((ret = (int)speex_buffer_resize(consumer->ring.buffer, (int)consumer->ring.size)) < 0){ - TSK_DEBUG_ERROR("speex_buffer_resize(%d) failed with error code=%d", (int)consumer->ring.size, ret); - return ret; - } - } - if(!consumer->ring.buffer){ - TSK_DEBUG_ERROR("Failed to create a new ring buffer with size = %d", (int)consumer->ring.size); - return -8; - } - if(!consumer->ring.mutex && !(consumer->ring.mutex = tsk_mutex_create_2(tsk_false))){ - TSK_DEBUG_ERROR("Failed to create mutex"); - return -9; - } - - // set maximum frames per slice as buffer size - //UInt32 numFrames = (UInt32)consumer->ring.chunck.size; - //status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), - // kAudioUnitProperty_MaximumFramesPerSlice, - // kAudioUnitScope_Global, - // 0, - // &numFrames, - // sizeof(numFrames)); - //if(status){ - // TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioUnitProperty_MaximumFramesPerSlice, %u) failed with status=%d", (unsigned)numFrames, (int32_t)status); - // return -6; - //} - - TSK_DEBUG_INFO("AudioUnit consumer prepared"); + + audioFormat.mSampleRate = TMEDIA_CONSUMER(consumer)->audio.out.rate ? TMEDIA_CONSUMER(consumer)->audio.out.rate : TMEDIA_CONSUMER(consumer)->audio.in.rate; + audioFormat.mFormatID = kAudioFormatLinearPCM; + audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; + audioFormat.mChannelsPerFrame = TMEDIA_CONSUMER(consumer)->audio.in.channels; + audioFormat.mFramesPerPacket = 1; + audioFormat.mBitsPerChannel = TMEDIA_CONSUMER(consumer)->audio.bits_per_sample; + audioFormat.mBytesPerPacket = audioFormat.mBitsPerChannel / 8 * audioFormat.mChannelsPerFrame; + audioFormat.mBytesPerFrame = audioFormat.mBytesPerPacket; + audioFormat.mReserved = 0; + status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + kOutputBus, + &audioFormat, + sizeof(audioFormat)); + + if(status) { + TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioUnitProperty_StreamFormat) failed with status=%ld", (signed long)status); + return -5; + } + else { + // configure + if(tdav_audiounit_handle_configure(consumer->audioUnitHandle, tsk_true, TMEDIA_CONSUMER(consumer)->audio.ptime, &audioFormat)) { + TSK_DEBUG_ERROR("tdav_audiounit_handle_set_rate(%d) failed", TMEDIA_CONSUMER(consumer)->audio.out.rate); + return -4; + } + + // set callback function + AURenderCallbackStruct callback; + callback.inputProc = __handle_output_buffer; + callback.inputProcRefCon = consumer; + status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, + kOutputBus, + &callback, + sizeof(callback)); + if(status) { + TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_SetInputCallback) failed with status=%ld", (signed long)status); + return -6; + } + } + } + + // allocate the chunck buffer and create the ring + consumer->ring.chunck.size = (TMEDIA_CONSUMER(consumer)->audio.ptime * audioFormat.mSampleRate * audioFormat.mBytesPerFrame) / 1000; + consumer->ring.size = kRingPacketCount * consumer->ring.chunck.size; + if(!(consumer->ring.chunck.buffer = tsk_realloc(consumer->ring.chunck.buffer, consumer->ring.chunck.size))) { + TSK_DEBUG_ERROR("Failed to allocate new buffer"); + return -7; + } + if(!consumer->ring.buffer) { + consumer->ring.buffer = speex_buffer_init((int)consumer->ring.size); + } + else { + int ret; + if((ret = (int)speex_buffer_resize(consumer->ring.buffer, (int)consumer->ring.size)) < 0) { + TSK_DEBUG_ERROR("speex_buffer_resize(%d) failed with error code=%d", (int)consumer->ring.size, ret); + return ret; + } + } + if(!consumer->ring.buffer) { + TSK_DEBUG_ERROR("Failed to create a new ring buffer with size = %d", (int)consumer->ring.size); + return -8; + } + if(!consumer->ring.mutex && !(consumer->ring.mutex = tsk_mutex_create_2(tsk_false))) { + TSK_DEBUG_ERROR("Failed to create mutex"); + return -9; + } + + // set maximum frames per slice as buffer size + //UInt32 numFrames = (UInt32)consumer->ring.chunck.size; + //status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), + // kAudioUnitProperty_MaximumFramesPerSlice, + // kAudioUnitScope_Global, + // 0, + // &numFrames, + // sizeof(numFrames)); + //if(status){ + // TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioUnitProperty_MaximumFramesPerSlice, %u) failed with status=%d", (unsigned)numFrames, (int32_t)status); + // return -6; + //} + + TSK_DEBUG_INFO("AudioUnit consumer prepared"); return tdav_audiounit_handle_signal_consumer_prepared(consumer->audioUnitHandle); } static int tdav_consumer_audiounit_start(tmedia_consumer_t* self) { - tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self; - - if(!consumer){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(consumer->paused){ - consumer->paused = tsk_false; - } - if(consumer->started){ - TSK_DEBUG_WARN("Already started"); - return 0; - } - else { - int ret = tdav_audiounit_handle_start(consumer->audioUnitHandle); - if(ret){ - TSK_DEBUG_ERROR("tdav_audiounit_handle_start failed with error code=%d", ret); - return ret; - } - } - consumer->started = tsk_true; - TSK_DEBUG_INFO("AudioUnit consumer started"); - return 0; + tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self; + + if(!consumer) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(consumer->paused) { + consumer->paused = tsk_false; + } + if(consumer->started) { + TSK_DEBUG_WARN("Already started"); + return 0; + } + else { + int ret = tdav_audiounit_handle_start(consumer->audioUnitHandle); + if(ret) { + TSK_DEBUG_ERROR("tdav_audiounit_handle_start failed with error code=%d", ret); + return ret; + } + } + consumer->started = tsk_true; + TSK_DEBUG_INFO("AudioUnit consumer started"); + return 0; } static int tdav_consumer_audiounit_consume(tmedia_consumer_t* self, const void* buffer, tsk_size_t size, const tsk_object_t* proto_hdr) -{ - tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self; - if(!consumer || !buffer || !size){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } +{ + tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self; + if(!consumer || !buffer || !size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } #if DISABLE_JITTER_BUFFER - { - if(consumer->ring.buffer){ - tsk_mutex_lock(consumer->ring.mutex); - speex_buffer_write(consumer->ring.buffer, (void*)buffer, size); - tsk_mutex_unlock(consumer->ring.mutex); - return 0; - } - return -2; - } + { + if(consumer->ring.buffer) { + tsk_mutex_lock(consumer->ring.mutex); + speex_buffer_write(consumer->ring.buffer, (void*)buffer, size); + tsk_mutex_unlock(consumer->ring.mutex); + return 0; + } + return -2; + } #else - { - return tdav_consumer_audio_put(TDAV_CONSUMER_AUDIO(consumer), buffer, size, proto_hdr); - } + { + return tdav_consumer_audio_put(TDAV_CONSUMER_AUDIO(consumer), buffer, size, proto_hdr); + } #endif } static int tdav_consumer_audiounit_pause(tmedia_consumer_t* self) { - tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self; - if(!consumer){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - consumer->paused = tsk_true; - TSK_DEBUG_INFO("AudioUnit consumer paused"); - return 0; + tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self; + if(!consumer) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + consumer->paused = tsk_true; + TSK_DEBUG_INFO("AudioUnit consumer paused"); + return 0; } static int tdav_consumer_audiounit_stop(tmedia_consumer_t* self) { - tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self; - - if(!consumer){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(!consumer->started){ - TSK_DEBUG_INFO("Not started"); - return 0; - } - else { - int ret = tdav_audiounit_handle_stop(consumer->audioUnitHandle); - if(ret){ - TSK_DEBUG_ERROR("tdav_audiounit_handle_stop failed with error code=%d", ret); - return ret; - } - } + tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self; + + if(!consumer) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(!consumer->started) { + TSK_DEBUG_INFO("Not started"); + return 0; + } + else { + int ret = tdav_audiounit_handle_stop(consumer->audioUnitHandle); + if(ret) { + TSK_DEBUG_ERROR("tdav_audiounit_handle_stop failed with error code=%d", ret); + return ret; + } + } #if TARGET_OS_IPHONE - //https://devforums.apple.com/thread/118595 - if(consumer->audioUnitHandle){ - tdav_audiounit_handle_destroy(&consumer->audioUnitHandle); - } + //https://devforums.apple.com/thread/118595 + if(consumer->audioUnitHandle) { + tdav_audiounit_handle_destroy(&consumer->audioUnitHandle); + } #endif - - consumer->started = tsk_false; - TSK_DEBUG_INFO("AudioUnit consumer stoppped"); - return 0; - + + consumer->started = tsk_false; + TSK_DEBUG_INFO("AudioUnit consumer stoppped"); + return 0; + } // @@ -379,67 +380,65 @@ static int tdav_consumer_audiounit_stop(tmedia_consumer_t* self) /* constructor */ static tsk_object_t* tdav_consumer_audiounit_ctor(tsk_object_t * self, va_list * app) { - tdav_consumer_audiounit_t *consumer = self; - if(consumer){ - /* init base */ - tdav_consumer_audio_init(TDAV_CONSUMER_AUDIO(consumer)); - /* init self */ - } - return self; + tdav_consumer_audiounit_t *consumer = self; + if(consumer) { + /* init base */ + tdav_consumer_audio_init(TDAV_CONSUMER_AUDIO(consumer)); + /* init self */ + } + return self; } /* destructor */ static tsk_object_t* tdav_consumer_audiounit_dtor(tsk_object_t * self) -{ - tdav_consumer_audiounit_t *consumer = self; - if(consumer){ - /* deinit self */ - // Stop the consumer if not done - if(consumer->started){ - tdav_consumer_audiounit_stop(self); - } - // destroy handle - if(consumer->audioUnitHandle){ - tdav_audiounit_handle_destroy(&consumer->audioUnitHandle); - } - TSK_FREE(consumer->ring.chunck.buffer); - if(consumer->ring.buffer){ - speex_buffer_destroy(consumer->ring.buffer); - } - if(consumer->ring.mutex){ - tsk_mutex_destroy(&consumer->ring.mutex); - } - - /* deinit base */ - tdav_consumer_audio_deinit(TDAV_CONSUMER_AUDIO(consumer)); +{ + tdav_consumer_audiounit_t *consumer = self; + if(consumer) { + /* deinit self */ + // Stop the consumer if not done + if(consumer->started) { + tdav_consumer_audiounit_stop(self); + } + // destroy handle + if(consumer->audioUnitHandle) { + tdav_audiounit_handle_destroy(&consumer->audioUnitHandle); + } + TSK_FREE(consumer->ring.chunck.buffer); + if(consumer->ring.buffer) { + speex_buffer_destroy(consumer->ring.buffer); + } + if(consumer->ring.mutex) { + tsk_mutex_destroy(&consumer->ring.mutex); + } + + /* deinit base */ + tdav_consumer_audio_deinit(TDAV_CONSUMER_AUDIO(consumer)); TSK_DEBUG_INFO("*** AudioUnit Consumer destroyed ***"); - } - - return self; + } + + return self; } /* object definition */ -static const tsk_object_def_t tdav_consumer_audiounit_def_s = -{ - sizeof(tdav_consumer_audiounit_t), - tdav_consumer_audiounit_ctor, - tdav_consumer_audiounit_dtor, - tdav_consumer_audio_cmp, +static const tsk_object_def_t tdav_consumer_audiounit_def_s = { + sizeof(tdav_consumer_audiounit_t), + tdav_consumer_audiounit_ctor, + tdav_consumer_audiounit_dtor, + tdav_consumer_audio_cmp, }; /* plugin definition*/ -static const tmedia_consumer_plugin_def_t tdav_consumer_audiounit_plugin_def_s = -{ - &tdav_consumer_audiounit_def_s, - - tmedia_audio, - "Apple CoreAudio consumer(AudioUnit)", - - tdav_consumer_audiounit_set, - tdav_consumer_audiounit_prepare, - tdav_consumer_audiounit_start, - tdav_consumer_audiounit_consume, - tdav_consumer_audiounit_pause, - tdav_consumer_audiounit_stop +static const tmedia_consumer_plugin_def_t tdav_consumer_audiounit_plugin_def_s = { + &tdav_consumer_audiounit_def_s, + + tmedia_audio, + "Apple CoreAudio consumer(AudioUnit)", + + tdav_consumer_audiounit_set, + tdav_consumer_audiounit_prepare, + tdav_consumer_audiounit_start, + tdav_consumer_audiounit_consume, + tdav_consumer_audiounit_pause, + tdav_consumer_audiounit_stop }; const tmedia_consumer_plugin_def_t *tdav_consumer_audiounit_plugin_def_t = &tdav_consumer_audiounit_plugin_def_s; diff --git a/tinyDAV/src/audio/coreaudio/tdav_producer_audioqueue.c b/tinyDAV/src/audio/coreaudio/tdav_producer_audioqueue.c index d96fd67..b99b202 100755 --- a/tinyDAV/src/audio/coreaudio/tdav_producer_audioqueue.c +++ b/tinyDAV/src/audio/coreaudio/tdav_producer_audioqueue.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. * @@ -23,7 +23,7 @@ /**@file tdav_producer_audioqueue.c * @brief Audio Producer for MacOSX and iOS platforms using AudioQueue. * - * @authors + * @authors * - Laurent Etiemble <laurent.etiemble(at)gmail.com> * - Mamadou Diop <diopmamadou(at)doubango(dot)org> * @@ -41,18 +41,19 @@ #include "tsk_memory.h" #include "tsk_debug.h" -static void __handle_input_buffer (void *userdata, AudioQueueRef queue, AudioQueueBufferRef buffer, const AudioTimeStamp *start_time, UInt32 number_packet_descriptions, const AudioStreamPacketDescription *packet_descriptions ) { - tdav_producer_audioqueue_t* producer = (tdav_producer_audioqueue_t*)userdata; - +static void __handle_input_buffer (void *userdata, AudioQueueRef queue, AudioQueueBufferRef buffer, const AudioTimeStamp *start_time, UInt32 number_packet_descriptions, const AudioStreamPacketDescription *packet_descriptions ) +{ + tdav_producer_audioqueue_t* producer = (tdav_producer_audioqueue_t*)userdata; + if (!producer->started) { return; } - - // Alert the session that there is new data to send - if(TMEDIA_PRODUCER(producer)->enc_cb.callback) { - TMEDIA_PRODUCER(producer)->enc_cb.callback(TMEDIA_PRODUCER(producer)->enc_cb.callback_data, buffer->mAudioData, buffer->mAudioDataByteSize); - } - + + // Alert the session that there is new data to send + if(TMEDIA_PRODUCER(producer)->enc_cb.callback) { + TMEDIA_PRODUCER(producer)->enc_cb.callback(TMEDIA_PRODUCER(producer)->enc_cb.callback_data, buffer->mAudioData, buffer->mAudioDataByteSize); + } + // Re-enqueue the buffer AudioQueueEnqueueBuffer(producer->queue, buffer, 0, NULL); } @@ -63,24 +64,24 @@ static void __handle_input_buffer (void *userdata, AudioQueueRef queue, AudioQue static int tdav_producer_audioqueue_prepare(tmedia_producer_t* self, const tmedia_codec_t* codec) { OSStatus ret; - tsk_size_t i; - tdav_producer_audioqueue_t* producer = (tdav_producer_audioqueue_t*)self; - - if(!producer || !codec && codec->plugin){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - TMEDIA_PRODUCER(producer)->audio.channels = TMEDIA_CODEC_CHANNELS_AUDIO_ENCODING(codec); - TMEDIA_PRODUCER(producer)->audio.rate = TMEDIA_CODEC_RATE_ENCODING(codec); - TMEDIA_PRODUCER(producer)->audio.ptime = TMEDIA_CODEC_PTIME_AUDIO_ENCODING(codec); - /* codec should have ptime */ - - - // Set audio category + tsk_size_t i; + tdav_producer_audioqueue_t* producer = (tdav_producer_audioqueue_t*)self; + + if(!producer || !codec && codec->plugin) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + TMEDIA_PRODUCER(producer)->audio.channels = TMEDIA_CODEC_CHANNELS_AUDIO_ENCODING(codec); + TMEDIA_PRODUCER(producer)->audio.rate = TMEDIA_CODEC_RATE_ENCODING(codec); + TMEDIA_PRODUCER(producer)->audio.ptime = TMEDIA_CODEC_PTIME_AUDIO_ENCODING(codec); + /* codec should have ptime */ + + + // Set audio category #if TARGET_OS_IPHONE - UInt32 category = kAudioSessionCategory_PlayAndRecord; - AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category); + UInt32 category = kAudioSessionCategory_PlayAndRecord; + AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category); #endif // Create the audio stream description AudioStreamBasicDescription *description = &(producer->description); @@ -93,95 +94,95 @@ static int tdav_producer_audioqueue_prepare(tmedia_producer_t* self, const tmedi description->mBytesPerPacket = description->mBitsPerChannel / 8 * description->mChannelsPerFrame; description->mBytesPerFrame = description->mBytesPerPacket; description->mReserved = 0; - + int packetperbuffer = 1000 / TMEDIA_PRODUCER(producer)->audio.ptime; producer->buffer_size = description->mSampleRate * description->mBytesPerFrame / packetperbuffer; - + // Create the record audio queue ret = AudioQueueNewInput(&(producer->description), - __handle_input_buffer, - producer, - NULL, - kCFRunLoopCommonModes, - 0, - &(producer->queue)); - + __handle_input_buffer, + producer, + NULL, + kCFRunLoopCommonModes, + 0, + &(producer->queue)); + for(i = 0; i < CoreAudioRecordBuffers; i++) { // Create the buffer for the queue ret = AudioQueueAllocateBuffer(producer->queue, producer->buffer_size, &(producer->buffers[i])); if (ret) { break; } - + // Clear the data memset(producer->buffers[i]->mAudioData, 0, producer->buffer_size); producer->buffers[i]->mAudioDataByteSize = producer->buffer_size; - + // Enqueue the buffer ret = AudioQueueEnqueueBuffer(producer->queue, producer->buffers[i], 0, NULL); if (ret) { break; } } - - return 0; + + return 0; } static int tdav_producer_audioqueue_start(tmedia_producer_t* self) { OSStatus ret; - tdav_producer_audioqueue_t* producer = (tdav_producer_audioqueue_t*)self; - - if(!producer){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(producer->started){ - TSK_DEBUG_WARN("Producer already started"); - return 0; - } - - producer->started = tsk_true; + tdav_producer_audioqueue_t* producer = (tdav_producer_audioqueue_t*)self; + + if(!producer) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(producer->started) { + TSK_DEBUG_WARN("Producer already started"); + return 0; + } + + producer->started = tsk_true; ret = AudioQueueStart(producer->queue, NULL); - - return ret; + + return ret; } static int tdav_producer_audioqueue_pause(tmedia_producer_t* self) { OSStatus ret; - tdav_producer_audioqueue_t* producer = (tdav_producer_audioqueue_t*)self; - - if(!producer){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - + tdav_producer_audioqueue_t* producer = (tdav_producer_audioqueue_t*)self; + + if(!producer) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + ret = AudioQueuePause(producer->queue); - - return ret; + + return ret; } static int tdav_producer_audioqueue_stop(tmedia_producer_t* self) { OSStatus ret; - tdav_producer_audioqueue_t* producer = (tdav_producer_audioqueue_t*)self; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - if(!producer->started){ - TSK_DEBUG_WARN("Producer not started"); - return 0; - } - - producer->started = tsk_false; + tdav_producer_audioqueue_t* producer = (tdav_producer_audioqueue_t*)self; + + if(!self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if(!producer->started) { + TSK_DEBUG_WARN("Producer not started"); + return 0; + } + + producer->started = tsk_false; ret = AudioQueueStop(producer->queue, false); - - return ret; + + return ret; } @@ -191,62 +192,60 @@ static int tdav_producer_audioqueue_stop(tmedia_producer_t* self) /* constructor */ static tsk_object_t* tdav_producer_audioqueue_ctor(tsk_object_t * self, va_list * app) { - tdav_producer_audioqueue_t *producer = self; - if(producer){ - /* init base */ - tdav_producer_audio_init(TDAV_PRODUCER_AUDIO(producer)); - /* init self */ - // TODO - } - return self; + tdav_producer_audioqueue_t *producer = self; + if(producer) { + /* init base */ + tdav_producer_audio_init(TDAV_PRODUCER_AUDIO(producer)); + /* init self */ + // TODO + } + return self; } /* destructor */ static tsk_object_t* tdav_producer_audioqueue_dtor(tsk_object_t * self) -{ - tdav_producer_audioqueue_t *producer = self; - if(producer){ - // Stop the producer if not done - if(producer->started){ - tdav_producer_audioqueue_stop(self); - } - - // Free all buffers and dispose the queue +{ + tdav_producer_audioqueue_t *producer = self; + if(producer) { + // Stop the producer if not done + if(producer->started) { + tdav_producer_audioqueue_stop(self); + } + + // Free all buffers and dispose the queue if (producer->queue) { - tsk_size_t i; - - for(i=0; i<CoreAudioRecordBuffers; i++){ - AudioQueueFreeBuffer(producer->queue, producer->buffers[i]); - } + tsk_size_t i; + + for(i=0; i<CoreAudioRecordBuffers; i++) { + AudioQueueFreeBuffer(producer->queue, producer->buffers[i]); + } AudioQueueDispose(producer->queue, true); } - - /* deinit base */ - tdav_producer_audio_deinit(TDAV_PRODUCER_AUDIO(producer)); - } - - return self; + + /* deinit base */ + tdav_producer_audio_deinit(TDAV_PRODUCER_AUDIO(producer)); + } + + return self; } /* object definition */ -static const tsk_object_def_t tdav_producer_audioqueue_def_s = -{ - sizeof(tdav_producer_audioqueue_t), - tdav_producer_audioqueue_ctor, - tdav_producer_audioqueue_dtor, - tdav_producer_audio_cmp, +static const tsk_object_def_t tdav_producer_audioqueue_def_s = { + sizeof(tdav_producer_audioqueue_t), + tdav_producer_audioqueue_ctor, + tdav_producer_audioqueue_dtor, + tdav_producer_audio_cmp, }; /* plugin definition*/ -static const tmedia_producer_plugin_def_t tdav_producer_audioqueue_plugin_def_s = -{ - &tdav_producer_audioqueue_def_s, - - tmedia_audio, - "Apple CoreAudio producer (AudioQueue)", - - tdav_producer_audioqueue_set, - tdav_producer_audioqueue_prepare, - tdav_producer_audioqueue_start, - tdav_producer_audioqueue_pause, - tdav_producer_audioqueue_stop +static const tmedia_producer_plugin_def_t tdav_producer_audioqueue_plugin_def_s = { + &tdav_producer_audioqueue_def_s, + + tmedia_audio, + "Apple CoreAudio producer (AudioQueue)", + + tdav_producer_audioqueue_set, + tdav_producer_audioqueue_prepare, + tdav_producer_audioqueue_start, + tdav_producer_audioqueue_pause, + tdav_producer_audioqueue_stop }; const tmedia_producer_plugin_def_t *tdav_producer_audioqueue_plugin_def_t = &tdav_producer_audioqueue_plugin_def_s; diff --git a/tinyDAV/src/audio/coreaudio/tdav_producer_audiounit.c b/tinyDAV/src/audio/coreaudio/tdav_producer_audiounit.c index a88261e..7f8af7e 100755 --- a/tinyDAV/src/audio/coreaudio/tdav_producer_audiounit.c +++ b/tinyDAV/src/audio/coreaudio/tdav_producer_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. * @@ -35,322 +35,323 @@ #define kRingPacketCount 10 -static OSStatus __handle_input_buffer(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList *ioData) { - OSStatus status = noErr; - tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)inRefCon; - - // holder - AudioBuffer buffer; - buffer.mData = tsk_null; - buffer.mDataByteSize = 0; - buffer.mNumberChannels = TMEDIA_PRODUCER(producer)->audio.channels; - - // list of holders - AudioBufferList buffers; - buffers.mNumberBuffers = 1; - buffers.mBuffers[0] = buffer; - - // render to get frames from the system - status = AudioUnitRender(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), - ioActionFlags, - inTimeStamp, - inBusNumber, - inNumberFrames, - &buffers); - if(status == 0){ +static OSStatus __handle_input_buffer(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList *ioData) +{ + OSStatus status = noErr; + tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)inRefCon; + + // holder + AudioBuffer buffer; + buffer.mData = tsk_null; + buffer.mDataByteSize = 0; + buffer.mNumberChannels = TMEDIA_PRODUCER(producer)->audio.channels; + + // list of holders + AudioBufferList buffers; + buffers.mNumberBuffers = 1; + buffers.mBuffers[0] = buffer; + + // render to get frames from the system + status = AudioUnitRender(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), + ioActionFlags, + inTimeStamp, + inBusNumber, + inNumberFrames, + &buffers); + if(status == 0) { // must not be done on async thread: doing it gives bad audio quality when audio+video call is done with CPU consuming codec (e.g. speex or g729) - speex_buffer_write(producer->ring.buffer, buffers.mBuffers[0].mData, buffers.mBuffers[0].mDataByteSize); + speex_buffer_write(producer->ring.buffer, buffers.mBuffers[0].mData, buffers.mBuffers[0].mDataByteSize); int avail = speex_buffer_get_available(producer->ring.buffer); while (producer->started && avail >= producer->ring.chunck.size) { avail -= speex_buffer_read(producer->ring.buffer, (void*)producer->ring.chunck.buffer, (int)producer->ring.chunck.size); TMEDIA_PRODUCER(producer)->enc_cb.callback(TMEDIA_PRODUCER(producer)->enc_cb.callback_data, - producer->ring.chunck.buffer, producer->ring.chunck.size); + producer->ring.chunck.buffer, producer->ring.chunck.size); } - } - + } + return status; } /* ============ Media Producer Interface ================= */ int tdav_producer_audiounit_set(tmedia_producer_t* self, const tmedia_param_t* param) -{ +{ tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self; - if(param->plugin_type == tmedia_ppt_producer){ - if(param->value_type == tmedia_pvt_int32){ - if (tsk_striequals(param->key, "mute")) { - producer->muted = TSK_TO_INT32((uint8_t*)param->value); - return tdav_audiounit_handle_mute(((tdav_producer_audiounit_t*)self)->audioUnitHandle, producer->muted); - } + if(param->plugin_type == tmedia_ppt_producer) { + if(param->value_type == tmedia_pvt_int32) { + if (tsk_striequals(param->key, "mute")) { + producer->muted = TSK_TO_INT32((uint8_t*)param->value); + return tdav_audiounit_handle_mute(((tdav_producer_audiounit_t*)self)->audioUnitHandle, producer->muted); + } else if (tsk_striequals(param->key, "interrupt")) { - int32_t interrupt = *((uint8_t*)param->value) ? 1 : 0; + int32_t interrupt = *((uint8_t*)param->value) ? 1 : 0; return tdav_audiounit_handle_interrupt(producer->audioUnitHandle, interrupt); } - } - } - return tdav_producer_audio_set(TDAV_PRODUCER_AUDIO(self), param); + } + } + return tdav_producer_audio_set(TDAV_PRODUCER_AUDIO(self), param); } static int tdav_producer_audiounit_prepare(tmedia_producer_t* self, const tmedia_codec_t* codec) { - static UInt32 flagOne = 1; - UInt32 param; - // static UInt32 flagZero = 0; + static UInt32 flagOne = 1; + UInt32 param; + // static UInt32 flagZero = 0; #define kInputBus 1 - - tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self; - OSStatus status = noErr; - AudioStreamBasicDescription audioFormat; - AudioStreamBasicDescription deviceFormat; - - if(!producer || !codec || !codec->plugin){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(!producer->audioUnitHandle){ - if(!(producer->audioUnitHandle = tdav_audiounit_handle_create(TMEDIA_PRODUCER(producer)->session_id))){ - TSK_DEBUG_ERROR("Failed to get audio unit instance for session with id=%lld", TMEDIA_PRODUCER(producer)->session_id); - return -3; - } - } - - // enable - status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), - kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Input, - kInputBus, - &flagOne, - sizeof(flagOne)); - if(status != noErr){ - TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%ld", (signed long)status); - return -4; - } - else { + + tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self; + OSStatus status = noErr; + AudioStreamBasicDescription audioFormat; + AudioStreamBasicDescription deviceFormat; + + if(!producer || !codec || !codec->plugin) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(!producer->audioUnitHandle) { + if(!(producer->audioUnitHandle = tdav_audiounit_handle_create(TMEDIA_PRODUCER(producer)->session_id))) { + TSK_DEBUG_ERROR("Failed to get audio unit instance for session with id=%lld", TMEDIA_PRODUCER(producer)->session_id); + return -3; + } + } + + // enable + status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Input, + kInputBus, + &flagOne, + sizeof(flagOne)); + if(status != noErr) { + TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%ld", (signed long)status); + return -4; + } + else { #if !TARGET_OS_IPHONE // strange: TARGET_OS_MAC is equal to '1' on Smulator - // disable output - param = 0; - status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), - kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Output, - 0, - ¶m, - sizeof(UInt32)); - if(status != noErr){ - TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%ld", (signed long)status); - return -4; - } - - // set default audio device - param = sizeof(AudioDeviceID); - AudioDeviceID inputDeviceID; - status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, ¶m, &inputDeviceID); - if(status != noErr){ - TSK_DEBUG_ERROR("AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice) failed with status=%ld", (signed long)status); - return -4; - } - - // set the current device to the default input unit - status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), - kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Output, - 0, - &inputDeviceID, - sizeof(AudioDeviceID)); - if(status != noErr){ - TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_CurrentDevice) failed with status=%ld", (signed long)status); - return -4; - } + // disable output + param = 0; + status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Output, + 0, + ¶m, + sizeof(UInt32)); + if(status != noErr) { + TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%ld", (signed long)status); + return -4; + } + + // set default audio device + param = sizeof(AudioDeviceID); + AudioDeviceID inputDeviceID; + status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, ¶m, &inputDeviceID); + if(status != noErr) { + TSK_DEBUG_ERROR("AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice) failed with status=%ld", (signed long)status); + return -4; + } + + // set the current device to the default input unit + status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Output, + 0, + &inputDeviceID, + sizeof(AudioDeviceID)); + if(status != noErr) { + TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_CurrentDevice) failed with status=%ld", (signed long)status); + return -4; + } #endif /* TARGET_OS_MAC */ - - /* codec should have ptime */ - TMEDIA_PRODUCER(producer)->audio.channels = TMEDIA_CODEC_CHANNELS_AUDIO_ENCODING(codec); - TMEDIA_PRODUCER(producer)->audio.rate = TMEDIA_CODEC_RATE_ENCODING(codec); - TMEDIA_PRODUCER(producer)->audio.ptime = TMEDIA_CODEC_PTIME_AUDIO_ENCODING(codec); + + /* codec should have ptime */ + TMEDIA_PRODUCER(producer)->audio.channels = TMEDIA_CODEC_CHANNELS_AUDIO_ENCODING(codec); + TMEDIA_PRODUCER(producer)->audio.rate = TMEDIA_CODEC_RATE_ENCODING(codec); + TMEDIA_PRODUCER(producer)->audio.ptime = TMEDIA_CODEC_PTIME_AUDIO_ENCODING(codec); TSK_DEBUG_INFO("AudioUnit producer: channels=%d, rate=%d, ptime=%d", TMEDIA_PRODUCER(producer)->audio.channels, TMEDIA_PRODUCER(producer)->audio.rate, TMEDIA_PRODUCER(producer)->audio.ptime); - - // get device format - param = sizeof(AudioStreamBasicDescription); - status = AudioUnitGetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, - kInputBus, - &deviceFormat, ¶m); - if(status == noErr && deviceFormat.mSampleRate){ + + // get device format + param = sizeof(AudioStreamBasicDescription); + status = AudioUnitGetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + kInputBus, + &deviceFormat, ¶m); + if(status == noErr && deviceFormat.mSampleRate) { #if TARGET_OS_IPHONE - // iOS support 8Khz, 16kHz and 32kHz => do not override the sampleRate + // iOS support 8Khz, 16kHz and 32kHz => do not override the sampleRate #elif TARGET_OS_MAC - // For example, iSight supports only 48kHz - TMEDIA_PRODUCER(producer)->audio.rate = deviceFormat.mSampleRate; + // For example, iSight supports only 48kHz + TMEDIA_PRODUCER(producer)->audio.rate = deviceFormat.mSampleRate; #endif - } - - // set format - audioFormat.mSampleRate = TMEDIA_PRODUCER(producer)->audio.rate; - audioFormat.mFormatID = kAudioFormatLinearPCM; - audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved; - audioFormat.mChannelsPerFrame = TMEDIA_PRODUCER(producer)->audio.channels; - audioFormat.mFramesPerPacket = 1; - audioFormat.mBitsPerChannel = TMEDIA_PRODUCER(producer)->audio.bits_per_sample; - audioFormat.mBytesPerPacket = audioFormat.mBitsPerChannel / 8 * audioFormat.mChannelsPerFrame; - audioFormat.mBytesPerFrame = audioFormat.mBytesPerPacket; - audioFormat.mReserved = 0; - if(audioFormat.mFormatID == kAudioFormatLinearPCM && audioFormat.mChannelsPerFrame == 1){ - audioFormat.mFormatFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; - } - status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, - kInputBus, - &audioFormat, - sizeof(audioFormat)); - if(status){ - TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioUnitProperty_StreamFormat) failed with status=%ld", (signed long)status); - return -5; - } - else { - - // configure - if(tdav_audiounit_handle_configure(producer->audioUnitHandle, tsk_false, TMEDIA_PRODUCER(producer)->audio.ptime, &audioFormat)){ - TSK_DEBUG_ERROR("tdav_audiounit_handle_set_rate(%d) failed", TMEDIA_PRODUCER(producer)->audio.rate); - return -4; - } - - // set callback function - AURenderCallbackStruct callback; - callback.inputProc = __handle_input_buffer; - callback.inputProcRefCon = producer; - status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), - kAudioOutputUnitProperty_SetInputCallback, - kAudioUnitScope_Output, - kInputBus, - &callback, - sizeof(callback)); - if(status){ - TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_SetInputCallback) failed with status=%ld", (signed long)status); - return -6; - } - else { - // disbale buffer allocation as we will provide ours - //status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), - // kAudioUnitProperty_ShouldAllocateBuffer, - // kAudioUnitScope_Output, - // kInputBus, - // &flagZero, - // sizeof(flagZero)); - - producer->ring.chunck.size = (TMEDIA_PRODUCER(producer)->audio.ptime * audioFormat.mSampleRate * audioFormat.mBytesPerFrame) / 1000; - // allocate our chunck buffer - if(!(producer->ring.chunck.buffer = tsk_realloc(producer->ring.chunck.buffer, producer->ring.chunck.size))){ - TSK_DEBUG_ERROR("Failed to allocate new buffer"); - return -7; - } - // create ringbuffer - producer->ring.size = kRingPacketCount * producer->ring.chunck.size; - if(!producer->ring.buffer){ - producer->ring.buffer = speex_buffer_init((int)producer->ring.size); - } - else { - int ret; - if((ret = speex_buffer_resize(producer->ring.buffer, producer->ring.size)) < 0){ - TSK_DEBUG_ERROR("speex_buffer_resize(%d) failed with error code=%d", (int)producer->ring.size, ret); - return ret; - } - } - if(!producer->ring.buffer){ - TSK_DEBUG_ERROR("Failed to create a new ring buffer with size = %d", (int)producer->ring.size); - return -9; - } - } - - } - } - - TSK_DEBUG_INFO("AudioUnit producer prepared"); - return tdav_audiounit_handle_signal_producer_prepared(producer->audioUnitHandle);; + } + + // set format + audioFormat.mSampleRate = TMEDIA_PRODUCER(producer)->audio.rate; + audioFormat.mFormatID = kAudioFormatLinearPCM; + audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved; + audioFormat.mChannelsPerFrame = TMEDIA_PRODUCER(producer)->audio.channels; + audioFormat.mFramesPerPacket = 1; + audioFormat.mBitsPerChannel = TMEDIA_PRODUCER(producer)->audio.bits_per_sample; + audioFormat.mBytesPerPacket = audioFormat.mBitsPerChannel / 8 * audioFormat.mChannelsPerFrame; + audioFormat.mBytesPerFrame = audioFormat.mBytesPerPacket; + audioFormat.mReserved = 0; + if(audioFormat.mFormatID == kAudioFormatLinearPCM && audioFormat.mChannelsPerFrame == 1) { + audioFormat.mFormatFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; + } + status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + kInputBus, + &audioFormat, + sizeof(audioFormat)); + if(status) { + TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioUnitProperty_StreamFormat) failed with status=%ld", (signed long)status); + return -5; + } + else { + + // configure + if(tdav_audiounit_handle_configure(producer->audioUnitHandle, tsk_false, TMEDIA_PRODUCER(producer)->audio.ptime, &audioFormat)) { + TSK_DEBUG_ERROR("tdav_audiounit_handle_set_rate(%d) failed", TMEDIA_PRODUCER(producer)->audio.rate); + return -4; + } + + // set callback function + AURenderCallbackStruct callback; + callback.inputProc = __handle_input_buffer; + callback.inputProcRefCon = producer; + status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), + kAudioOutputUnitProperty_SetInputCallback, + kAudioUnitScope_Output, + kInputBus, + &callback, + sizeof(callback)); + if(status) { + TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_SetInputCallback) failed with status=%ld", (signed long)status); + return -6; + } + else { + // disbale buffer allocation as we will provide ours + //status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), + // kAudioUnitProperty_ShouldAllocateBuffer, + // kAudioUnitScope_Output, + // kInputBus, + // &flagZero, + // sizeof(flagZero)); + + producer->ring.chunck.size = (TMEDIA_PRODUCER(producer)->audio.ptime * audioFormat.mSampleRate * audioFormat.mBytesPerFrame) / 1000; + // allocate our chunck buffer + if(!(producer->ring.chunck.buffer = tsk_realloc(producer->ring.chunck.buffer, producer->ring.chunck.size))) { + TSK_DEBUG_ERROR("Failed to allocate new buffer"); + return -7; + } + // create ringbuffer + producer->ring.size = kRingPacketCount * producer->ring.chunck.size; + if(!producer->ring.buffer) { + producer->ring.buffer = speex_buffer_init((int)producer->ring.size); + } + else { + int ret; + if((ret = speex_buffer_resize(producer->ring.buffer, producer->ring.size)) < 0) { + TSK_DEBUG_ERROR("speex_buffer_resize(%d) failed with error code=%d", (int)producer->ring.size, ret); + return ret; + } + } + if(!producer->ring.buffer) { + TSK_DEBUG_ERROR("Failed to create a new ring buffer with size = %d", (int)producer->ring.size); + return -9; + } + } + + } + } + + TSK_DEBUG_INFO("AudioUnit producer prepared"); + return tdav_audiounit_handle_signal_producer_prepared(producer->audioUnitHandle);; } static int tdav_producer_audiounit_start(tmedia_producer_t* self) { - tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self; - - if(!producer){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(producer->paused){ - producer->paused = tsk_false; - return tsk_false; - } - - int ret; - if(producer->started){ - TSK_DEBUG_WARN("Already started"); - return 0; - } - else { - ret = tdav_audiounit_handle_start(producer->audioUnitHandle); - if(ret){ - TSK_DEBUG_ERROR("tdav_audiounit_handle_start failed with error code=%d", ret); - return ret; - } - } - producer->started = tsk_true; - + tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self; + + if(!producer) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(producer->paused) { + producer->paused = tsk_false; + return tsk_false; + } + + int ret; + if(producer->started) { + TSK_DEBUG_WARN("Already started"); + return 0; + } + else { + ret = tdav_audiounit_handle_start(producer->audioUnitHandle); + if(ret) { + TSK_DEBUG_ERROR("tdav_audiounit_handle_start failed with error code=%d", ret); + return ret; + } + } + producer->started = tsk_true; + // apply parameters (because could be lost when the producer is restarted -handle recreated-) ret = tdav_audiounit_handle_mute(producer->audioUnitHandle, producer->muted); - TSK_DEBUG_INFO("AudioUnit producer started"); - return 0; + TSK_DEBUG_INFO("AudioUnit producer started"); + return 0; } static int tdav_producer_audiounit_pause(tmedia_producer_t* self) { tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self; - if(!producer){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - producer->paused = tsk_true; - TSK_DEBUG_INFO("AudioUnit producer paused"); - return 0; + if(!producer) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + producer->paused = tsk_true; + TSK_DEBUG_INFO("AudioUnit producer paused"); + return 0; } static int tdav_producer_audiounit_stop(tmedia_producer_t* self) { tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self; - - if(!producer){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - if(!producer->started){ - TSK_DEBUG_INFO("Not started"); - return 0; - } - else { - int ret = tdav_audiounit_handle_stop(producer->audioUnitHandle); - if(ret){ - TSK_DEBUG_ERROR("tdav_audiounit_handle_stop failed with error code=%d", ret); - // do not return even if failed => we MUST stop the thread! - } + + if(!producer) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if(!producer->started) { + TSK_DEBUG_INFO("Not started"); + return 0; + } + else { + int ret = tdav_audiounit_handle_stop(producer->audioUnitHandle); + if(ret) { + TSK_DEBUG_ERROR("tdav_audiounit_handle_stop failed with error code=%d", ret); + // do not return even if failed => we MUST stop the thread! + } #if TARGET_OS_IPHONE - //https://devforums.apple.com/thread/118595 - if(producer->audioUnitHandle){ - tdav_audiounit_handle_destroy(&producer->audioUnitHandle); - } + //https://devforums.apple.com/thread/118595 + if(producer->audioUnitHandle) { + tdav_audiounit_handle_destroy(&producer->audioUnitHandle); + } #endif - } - producer->started = tsk_false; - TSK_DEBUG_INFO("AudioUnit producer stoppped"); - return 0; + } + producer->started = tsk_false; + TSK_DEBUG_INFO("AudioUnit producer stoppped"); + return 0; } @@ -360,61 +361,59 @@ static int tdav_producer_audiounit_stop(tmedia_producer_t* self) /* constructor */ static tsk_object_t* tdav_producer_audiounit_ctor(tsk_object_t * self, va_list * app) { - tdav_producer_audiounit_t *producer = self; - if(producer){ - /* init base */ - tdav_producer_audio_init(TDAV_PRODUCER_AUDIO(producer)); - /* init self */ - } - return self; + tdav_producer_audiounit_t *producer = self; + if(producer) { + /* init base */ + tdav_producer_audio_init(TDAV_PRODUCER_AUDIO(producer)); + /* init self */ + } + return self; } /* destructor */ static tsk_object_t* tdav_producer_audiounit_dtor(tsk_object_t * self) -{ - tdav_producer_audiounit_t *producer = self; - if(producer){ - // Stop the producer if not done - if(producer->started){ - tdav_producer_audiounit_stop(self); - } - - // Free all buffers and dispose the queue +{ + tdav_producer_audiounit_t *producer = self; + if(producer) { + // Stop the producer if not done + if(producer->started) { + tdav_producer_audiounit_stop(self); + } + + // Free all buffers and dispose the queue if (producer->audioUnitHandle) { - tdav_audiounit_handle_destroy(&producer->audioUnitHandle); + tdav_audiounit_handle_destroy(&producer->audioUnitHandle); } TSK_FREE(producer->ring.chunck.buffer); - if(producer->ring.buffer){ - speex_buffer_destroy(producer->ring.buffer); - } - /* deinit base */ - tdav_producer_audio_deinit(TDAV_PRODUCER_AUDIO(producer)); - + if(producer->ring.buffer) { + speex_buffer_destroy(producer->ring.buffer); + } + /* deinit base */ + tdav_producer_audio_deinit(TDAV_PRODUCER_AUDIO(producer)); + TSK_DEBUG_INFO("*** AudioUnit Producer destroyed ***"); - } - - return self; + } + + return self; } /* object definition */ -static const tsk_object_def_t tdav_producer_audiounit_def_s = -{ - sizeof(tdav_producer_audiounit_t), - tdav_producer_audiounit_ctor, - tdav_producer_audiounit_dtor, - tdav_producer_audio_cmp, +static const tsk_object_def_t tdav_producer_audiounit_def_s = { + sizeof(tdav_producer_audiounit_t), + tdav_producer_audiounit_ctor, + tdav_producer_audiounit_dtor, + tdav_producer_audio_cmp, }; /* plugin definition*/ -static const tmedia_producer_plugin_def_t tdav_producer_audiounit_plugin_def_s = -{ - &tdav_producer_audiounit_def_s, - - tmedia_audio, - "Apple CoreAudio producer (AudioUnit)", - - tdav_producer_audiounit_set, - tdav_producer_audiounit_prepare, - tdav_producer_audiounit_start, - tdav_producer_audiounit_pause, - tdav_producer_audiounit_stop +static const tmedia_producer_plugin_def_t tdav_producer_audiounit_plugin_def_s = { + &tdav_producer_audiounit_def_s, + + tmedia_audio, + "Apple CoreAudio producer (AudioUnit)", + + tdav_producer_audiounit_set, + tdav_producer_audiounit_prepare, + tdav_producer_audiounit_start, + tdav_producer_audiounit_pause, + tdav_producer_audiounit_stop }; const tmedia_producer_plugin_def_t *tdav_producer_audiounit_plugin_def_t = &tdav_producer_audiounit_plugin_def_s; |