1

I have a problem in my applications where I am using AudioUnits. All of the applications Audio (including audio not played through AudioUnits) will start skipping after exiting to Springboard and returning to the applications.

I broke out the problem into a new separate test app. Here are the steps to repeat it:

  • Start an Audio file playing using an AVAudioPlayer.
  • Create, Delete, then again Create an AudioUnit
  • Exit to Springboard
  • Return to the app
  • The Audio from the AvAudioPlayer will start skipping

Here is some of the code I used:

- (IBAction)restartAudioUnit {

    MySoundStream* audioUnitClass;
    audioUnitClass = Load();
    [audioUnitClass release];
    audioUnitClass = Load();

}

Forgive the long code dump but AudioUnits are complex and I am fairly sure I am just setting them up or taking them down incorrectly.

The MySoundStream class:

OSStatus UnitRenderCB(void* pRefCon, AudioUnitRenderActionFlags* flags, const AudioTimeStamp* timeStamp, UInt32 busNum, UInt32 numFrames, AudioBufferList*  pData){

    OSStatus tErr = noErr;

    //Do Nothing

    return tErr;
}

@implementation MySoundStream

-(void) dealloc {

    [self Unload];

    [super dealloc];
}

-(void) Unload {

    OSStatus tErr = noErr; 
    tErr = AudioUnitUninitialize(OutUnit);
}

@end

MySoundStream* Load()
{
    OSStatus tErr = noErr;
    AudioComponentInstance tRIO;
    AudioComponentDescription tRIOCD;
    AURenderCallbackStruct tRIOCB;
    AudioStreamBasicDescription tAUF;

    tRIOCD.componentType = kAudioUnitType_Output;
    tRIOCD.componentSubType = kAudioUnitSubType_RemoteIO;
    tRIOCD.componentManufacturer = kAudioUnitManufacturer_Apple;
    tRIOCD.componentFlags = 0;
    tRIOCD.componentFlagsMask = 0;

    AudioComponent tRIOC = AudioComponentFindNext(NULL, &tRIOCD);
    tErr = AudioComponentInstanceNew(tRIOC, &tRIO);
    if (tErr != noErr) return NULL;

    int tOutEnable = 1;

    tErr = AudioUnitSetProperty(tRIO, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &tOutEnable, sizeof(tOutEnable));
    if (tErr != noErr) return NULL; 

    tAUF.mSampleRate = 44100.00;
    tAUF.mFormatID = kAudioFormatLinearPCM;
    tAUF.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    tAUF.mFramesPerPacket = 1;
    tAUF.mChannelsPerFrame = 2;
    tAUF.mBitsPerChannel = 16;
    tAUF.mBytesPerPacket = 4;
    tAUF.mBytesPerFrame = 4;

    tErr = AudioUnitSetProperty(tRIO, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &tAUF, sizeof(tAUF));
    if (tErr != noErr) return false;

    MySoundStream* pRet = [MySoundStream alloc];

    tRIOCB.inputProc = UnitRenderCB;
    tRIOCB.inputProcRefCon = pRet;
    tErr = AudioUnitSetProperty(tRIO, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &tRIOCB, sizeof(tRIOCB));
    if (tErr != noErr){ delete pRet; return NULL; }

    tErr = AudioUnitInitialize(tRIO);
    if (tErr != noErr){ delete pRet; return NULL; }

    pRet->OutUnit = tRIO;

    return pRet;
}

If anyone can see anything I am doing wrong with this AudioUnit, that woudl be very helpful.

Edit: Upload the complete source. Here

  1. Press Play Sound (may need headphones)
  2. Press RestartAudioUnit
  3. Return to Springboard
  4. Re-enter TestAudioUnit app

Audio will skip

TurqMage
  • 3,321
  • 2
  • 31
  • 52

2 Answers2

1

You are calling AudioUnitInitialize() when the app is re-initialized, which is not good. You need to call AudioUnitInitialize() only once when your app starts, and you should not have to build the entire AU graph every time your app enters the foreground.

Nik Reiman
  • 39,067
  • 29
  • 104
  • 160
  • Sorry if I wasn't clear. I call AudioUnitInitialize, then Uninit, then Init again while the app is running. As if I am shutting down the Unit, reconfiguring it, and starting it again. Is that not allowed? Then after its reconfigured I exit to Spring and return, no calls to AudioUnit anything. – TurqMage Jun 03 '11 at 15:44
  • I might have found my bug while looking into this. There is an AudioSessionInitialize that I wasn't calling, which the docs say should be called once then never again, was this what you were referring to? – TurqMage Jun 03 '11 at 15:50
  • Added source in update, AudioSessionInitialize is being called. – TurqMage Jun 03 '11 at 16:13
  • @TurqMage Yes, you should only call AudioSessionInitialize *once* in your program's initialization. Calling it multiple times (ie, when your application enters the foreground or restarts the audio subsystem) is not good. Make a single call to it in `didFinishLaunchingWithOptions` in your delegate and nowhere else. – Nik Reiman Jun 09 '11 at 07:57
0

Switched to using an AUGraph to setups my Audio Unit path and I had better luck.

TurqMage
  • 3,321
  • 2
  • 31
  • 52