void audio_unit_check_audio_route(aubio_audio_unit_t *o) { CFStringRef currentRoute; UInt32 val, thissize = sizeof(currentRoute); OSStatus err = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &thissize, ¤tRoute); if (err) { AUBIO_ERR("audio_unit: could not get current route\n"); goto fail; } else { char *route = (char *)CFStringGetCStringPtr ( currentRoute, kCFStringEncodingUTF8); if (route == NULL) { int bufferSize = 25; route = calloc(bufferSize, sizeof(char)); CFStringGetCString ( currentRoute, route, bufferSize, kCFStringEncodingUTF8); } if (o->verbose) { AUBIO_MSG ("audio_unit: current route is %s\n", route); } //free(route); } if( currentRoute ) { if( CFStringCompare( currentRoute, CFSTR("Headset"), 0 ) == kCFCompareEqualTo ) { val = kAudioSessionOverrideAudioRoute_None; } else if( CFStringCompare( currentRoute, CFSTR("Receiver" ), 0 ) == kCFCompareEqualTo ) { val = kAudioSessionOverrideAudioRoute_Speaker; } else if( CFStringCompare( currentRoute, CFSTR("ReceiverAndMicrophone" ), 0 ) == kCFCompareEqualTo ) { val = kAudioSessionOverrideAudioRoute_Speaker; } else if( CFStringCompare( currentRoute, CFSTR("SpeakerAndMicrophone" ), 0 ) == kCFCompareEqualTo ) { val = kAudioSessionOverrideAudioRoute_Speaker; } else if( CFStringCompare( currentRoute, CFSTR("HeadphonesAndMicrophone" ), 0 ) == kCFCompareEqualTo ) { val = kAudioSessionOverrideAudioRoute_None; } else if( CFStringCompare( currentRoute, CFSTR("HeadsetInOut" ), 0 ) == kCFCompareEqualTo ) { val = kAudioSessionOverrideAudioRoute_None; } else { val = kAudioSessionOverrideAudioRoute_None; } o->input_enabled = true; if (val == kAudioSessionOverrideAudioRoute_Speaker) { if (o->prevent_feedback) { o->input_enabled = false; if (o->verbose) { AUBIO_MSG ("audio_unit: disabling input to avoid feedback\n"); } } else { AUBIO_WRN ("audio_unit: input not disabled as prevent_feedback set to 0, risking feedback\n"); } } err = AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(UInt32), &val); if (err) { AUBIO_ERR("audio_unit: could not set session OverrideAudioRoute to Speaker\n"); } } fail: if ( currentRoute ) free((void*)currentRoute); return; }
/* *This function handles a change in the audio's route. *(TODO) this needs some work, should be a member of the class and call setupIO in place of SetupRemoteIO; *(TODO) make sure we don't crash when input becomes unavailable on an iPod Touch. */ void propListener( void * inClientData, AudioSessionPropertyID inID, UInt32 inDataSize, const void *inData ) { //NSLog(@"propListener"); MUEAudioIO *THIS = (MUEAudioIO*)inClientData; if (inID == kAudioSessionProperty_AudioRouteChange) { // if there was a route change, we need to dispose the current rio unit and create a new one AudioComponentInstanceDispose(THIS->rioUnit); //SetupRemoteIO(THIS->rioUnit, THIS->inputProc, THIS->thruFormat); THIS->setupIO(); //(TODO) will this work? UInt32 size = sizeof(THIS->hwSampleRate); AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate, &size, &THIS->hwSampleRate); AudioOutputUnitStart(THIS->rioUnit); //See what the new routing is, and take dependent action... CFStringRef newRoute; size = sizeof(CFStringRef); AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &size, &newRoute); if (newRoute) { CFShow(newRoute); if (CFStringCompare(newRoute, CFSTR("Headset"), NULL) == kCFCompareEqualTo) // headset plugged in { //Do something if you'd like } else if (CFStringCompare(newRoute, CFSTR("Receiver"), NULL) == kCFCompareEqualTo) // headset plugged in { //Do something if you'd like } else //Something else must be plugged in...Third party? { //Do something if you'd like } } } }
float CCoreAudioUnit::GetLatency() { if (!m_audioUnit) return 0.0f; //kAudioSessionProperty_CurrentHardwareIOBufferDuration //kAudioSessionProperty_CurrentHardwareOutputLatency Float32 preferredBufferSize = 0.0f; UInt32 size = sizeof(preferredBufferSize); AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputLatency, &size, &preferredBufferSize); return preferredBufferSize; }
/* *Audio Session Configuration. * Requests an audio session from core audio and configures it for effects processing by default (one input, one output). * <Sam> All major configurations are set for the AudioSession Instance here */ int MUEAudioIO::configureAudioSession() { try { // Initialize and configure the audio session AudioSessionInitialize(NULL, NULL, rioInterruptionListener, this); AudioSessionSetActive(true); //audio should not mix with iPod audio, and we want input and output. UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord; //audio will mix with iPod audio, but we get output only (no input) with this type of session //UInt32 audioCategory = kAudioSessionCategory_AmbientSound; AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory); // The entire purpose of the propListener is to detect a change in signal flow (headphones w/ mic or even third party device) AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, this); //(TODO) make get/set preferred buffer size // This value is in seconds! We want really low latency... preferredBufferSize = .01; // .005 for buffer of 256, .01 for buffer of 512 AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize); // Related to our propListener. When the signal flow changes, sometimes the hardware sample rate can change. You'll notice in the propListener it checks for a new one. UInt32 size = sizeof(hwSampleRate); AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate, &size, &hwSampleRate); } catch (...) { printf("An unknown error occurred in audio session configuration!\n"); //if (url) CFRelease(url); } return 0; }
UInt32 audio_unit_get_audio_session_category () { UInt32 category, thissize; thissize = sizeof(category); OSStatus err = AudioSessionGetProperty(kAudioSessionProperty_AudioCategory, &thissize, &category); if (err) { AUBIO_ERR("audio_unit: could not get audio category (%d)\n", (int)err); return err; } if (category == kAudioSessionCategory_AmbientSound) { AUBIO_MSG("audio_unit: session category is AmbiantSound\n"); } else if (category == kAudioSessionCategory_SoloAmbientSound) { AUBIO_MSG("audio_unit: session category is SoloAmbiantSound\n"); } else if (category == kAudioSessionCategory_MediaPlayback) { AUBIO_MSG("audio_unit: session category is MediaPlayback\n"); } else if (category == kAudioSessionCategory_RecordAudio) { AUBIO_MSG("audio_unit: session category is RecordAudio\n"); } else if (category == kAudioSessionCategory_PlayAndRecord) { AUBIO_MSG("audio_unit: session category is PlayAndRecord\n"); } else if (category == kAudioSessionCategory_AudioProcessing) { AUBIO_MSG("audio_unit: session category is AudioProcessing\n"); } return category; }
sint_t aubio_audio_unit_get_info (aubio_audio_unit_t *o) { UInt32 thissize, input_hw_channels, output_hw_channels, max_fps; Float32 latency, input_latency, output_latency, input_hw_volume, output_hw_volume; Float64 samplerate; OSStatus err = 0; // Show some info about the opened unit /* get sampling rate */ thissize = sizeof(samplerate); err = AudioUnitGetProperty (o->audio_unit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 1, &samplerate, &thissize); if (err) { AUBIO_ERR("audio_unit: could not get audio unit sample rate (%d)\n", (int)err); goto fail; } /* get hardware input channels */ thissize = sizeof(input_hw_channels); err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputNumberChannels, &thissize, &input_hw_channels); if (err) { AUBIO_ERR("audio_unit: could not get hardware input channels (%d)\n", (int)err); goto fail; } /* get hardware output channels */ thissize = sizeof(output_hw_channels); err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputNumberChannels, &thissize, &output_hw_channels); if (err) { AUBIO_ERR("audio_unit: could not get hardware output channels (%d)\n", (int)err); goto fail; } /* get hardware input volume */ thissize = sizeof(input_hw_volume); err = AudioSessionGetProperty(kAudioSessionProperty_InputGainScalar, &thissize, &input_hw_volume); if (err) { AUBIO_ERR("audio_unit: could not get hardware input volume (%d)\n", (int)err); goto fail; } /* get hardware output volume */ thissize = sizeof(output_hw_volume); err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputVolume, &thissize, &output_hw_volume); if (err) { AUBIO_ERR("audio_unit: could not get hardware output volume (%d)\n", (int)err); goto fail; } AUBIO_MSG("audio_unit: opened at %.0fHz, sw channels %din/%dout, hw channels %din/%dout, hw vol %.2fin/%.2fout\n", samplerate, o->sw_input_channels, o->sw_output_channels, (unsigned int)input_hw_channels, (unsigned int)output_hw_channels, input_hw_volume, output_hw_volume); /* get max frames per slice */ thissize = sizeof(max_fps); err = AudioUnitGetProperty (o->audio_unit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &max_fps, &thissize); if (err) { AUBIO_ERR("audio_unit: could not get maximum frames per slice property %d\n", (int)err); goto fail; } /* get hardware latency */ thissize = sizeof(latency); err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &thissize, &latency); if (err) { AUBIO_ERR("audio_unit: could not get hardware latency %d\n", (int)err); goto fail; } /* get input latency */ thissize = sizeof(input_latency); err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputLatency, &thissize, &input_latency); if (err) { AUBIO_ERR("audio_unit: could not get input latency %d\n", (int)err); goto fail; } /* get output harlatency */ thissize = sizeof(output_latency); err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputLatency, &thissize, &output_latency); if (err) { AUBIO_ERR("audio_unit: could not get output latency %d\n", (int)err); goto fail; } AUBIO_MSG("audio_unit: I/O latency: %.2fms, %d frames, (%.2fms, %d frames in, %.2fms %d frames out)\n", latency*1000., (sint_t)round(latency*samplerate), input_latency*1000., (sint_t)ROUND(input_latency*samplerate), output_latency*1000., (sint_t)ROUND(output_latency*samplerate)); fail: return err; }
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; } #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=%ld", 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=%ld", 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); } #endif #endif done: return (status == noErr) ? 0 : -2; }
static void au_configure(AUData *d) { AudioStreamBasicDescription audioFormat; AudioComponentDescription au_description; AudioComponent foundComponent; OSStatus auresult; UInt32 doSetProperty = 1; UInt32 doNotSetProperty = 0; auresult = AudioSessionSetActive(true); check_auresult(auresult,"AudioSessionSetActive"); UInt32 audioCategory =kAudioSessionCategory_PlayAndRecord; auresult =AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory); check_auresult(auresult,"Configuring audio session "); if (d->is_ringer) { auresult=AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,sizeof (doSetProperty),&doSetProperty); check_auresult(auresult,"kAudioSessionProperty_OverrideAudioRoute"); ms_message("Configuring audio session default route to speaker"); } else { ms_message("Configuring audio session default route to receiver"); } if (d->started == TRUE) { //nothing else to do return; } au_description.componentType = kAudioUnitType_Output; au_description.componentSubType = kAudioUnitSubType_VoiceProcessingIO; au_description.componentManufacturer = kAudioUnitManufacturer_Apple; au_description.componentFlags = 0; au_description.componentFlagsMask = 0; foundComponent = AudioComponentFindNext (NULL,&au_description); auresult=AudioComponentInstanceNew (foundComponent, &d->io_unit); check_auresult(auresult,"AudioComponentInstanceNew"); audioFormat.mSampleRate = d->rate; audioFormat.mFormatID = kAudioFormatLinearPCM; audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; audioFormat.mFramesPerPacket = 1; audioFormat.mChannelsPerFrame = d->nchannels; audioFormat.mBitsPerChannel = d->bits; audioFormat.mBytesPerPacket = d->bits / 8; audioFormat.mBytesPerFrame = d->nchannels * d->bits / 8; AudioUnitElement outputBus = 0; AudioUnitElement inputBus = 1; auresult=AudioUnitUninitialize (d->io_unit); check_auresult(auresult,"AudioUnitUninitialize"); //read auresult=AudioUnitSetProperty ( d->io_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input , inputBus, &doSetProperty, sizeof (doSetProperty) ); check_auresult(auresult,"kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Input"); //setup stream format auresult=AudioUnitSetProperty ( d->io_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, outputBus, &audioFormat, sizeof (audioFormat) ); //write //enable output bus auresult =AudioUnitSetProperty ( d->io_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output , outputBus, &doSetProperty, sizeof (doSetProperty) ); check_auresult(auresult,"kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output"); //setup stream format auresult=AudioUnitSetProperty ( d->io_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, inputBus, &audioFormat, sizeof (audioFormat) ); check_auresult(auresult,"kAudioUnitProperty_StreamFormat,kAudioUnitScope_Output"); check_auresult(auresult,"kAudioUnitProperty_StreamFormat,kAudioUnitScope_Input"); //disable unit buffer allocation auresult=AudioUnitSetProperty ( d->io_unit, kAudioUnitProperty_ShouldAllocateBuffer, kAudioUnitScope_Output, outputBus, &doNotSetProperty, sizeof (doNotSetProperty) ); check_auresult(auresult,"kAudioUnitProperty_ShouldAllocateBuffer,kAudioUnitScope_Output"); AURenderCallbackStruct renderCallbackStruct; renderCallbackStruct.inputProc = au_render_cb; renderCallbackStruct.inputProcRefCon = d; auresult=AudioUnitSetProperty ( d->io_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, outputBus, &renderCallbackStruct, sizeof (renderCallbackStruct) ); check_auresult(auresult,"kAudioUnitProperty_SetRenderCallback,kAudioUnitScope_Input"); const Float64 preferredSampleRate = d->rate;//PREFERRED_HW_SAMPLE_RATE; /*optimum to minimize delay, must put a software resampler to deal with 8khz*/ auresult=AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareSampleRate ,sizeof(preferredSampleRate) , &preferredSampleRate); check_auresult(auresult,"kAudioSessionProperty_PreferredHardwareSampleRate"); Float32 preferredBufferSize; switch (d->rate) { case 11025: case 22050: preferredBufferSize= .020; break; default: preferredBufferSize= .015; } auresult=AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration ,sizeof(preferredBufferSize) , &preferredBufferSize); if (auresult != 0) ms_message("kAudioSessionProperty_PreferredHardwareIOBufferDuration returns %i ",auresult); Float64 delay; UInt32 delaySize = sizeof(delay); auresult=AudioUnitGetProperty(d->io_unit ,kAudioUnitProperty_Latency , kAudioUnitScope_Global , 0 , &delay , &delaySize); UInt32 quality; UInt32 qualitySize = sizeof(quality); auresult=AudioUnitGetProperty(d->io_unit ,kAudioUnitProperty_RenderQuality , kAudioUnitScope_Global , 0 , &quality , &qualitySize); ms_message("I/O unit latency [%f], quality [%i]",delay,quality); Float32 hwoutputlatency; UInt32 hwoutputlatencySize=sizeof(hwoutputlatency); auresult=AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputLatency ,&hwoutputlatencySize , &hwoutputlatency); Float32 hwinputlatency; UInt32 hwinputlatencySize=sizeof(hwoutputlatency); auresult=AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputLatency ,&hwinputlatencySize , &hwinputlatency); Float32 hwiobuf; UInt32 hwiobufSize=sizeof(hwiobuf); auresult=AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration ,&hwiobufSize , &hwiobuf); Float64 hwsamplerate; UInt32 hwsamplerateSize=sizeof(hwsamplerate); auresult=AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate ,&hwsamplerateSize ,&hwsamplerate); ms_message("current hw output latency [%f] input [%f] iobuf[%f] sample rate [%f]",hwoutputlatency,hwinputlatency,hwiobuf,hwsamplerate); auresult=AudioOutputUnitStart(d->io_unit); check_auresult(auresult,"AudioOutputUnitStart"); d->started=TRUE; return; }