static int tdav_consumer_audiounit_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec) { tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self; if (!consumer || !codec || !codec->plugin) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } // Initialize the decoder parameters without allocating AudioUnit resourses 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 prepared (ptime=%d, channels=%d, rate=%d)", (int)TMEDIA_CONSUMER(consumer)->audio.ptime, (int)TMEDIA_CONSUMER(consumer)->audio.in.channels, (int)TMEDIA_CONSUMER(consumer)->audio.in.rate); return 0; }
static int tdav_consumer_audiounit_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec) { 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 { #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; } #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); 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(consumer->ring.size); } else { int ret; if((ret = speex_buffer_resize(consumer->ring.buffer, consumer->ring.size)) < 0){ TSK_DEBUG_ERROR("speex_buffer_resize(%d) failed with error code=%d", consumer->ring.size, ret); return ret; } } if(!consumer->ring.buffer){ TSK_DEBUG_ERROR("Failed to create a new ring buffer with size = %d", 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); }
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 #if TARGET_OS_IPHONE 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; description->mFormatID = kAudioFormatLinearPCM; description->mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; description->mChannelsPerFrame = TMEDIA_CONSUMER(consumer)->audio.in.channels; description->mFramesPerPacket = 1; description->mBitsPerChannel = TMEDIA_CONSUMER(consumer)->audio.bits_per_sample; 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, 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; }