"Learning Core Audio" Corrections for January 23, 2013 page 108 Listing 6.16 Reads: } AudioConverterDispose(audioConverter); } Should Read: } AudioConverterDispose(audioConverter); free (outputBuffer); } Sixth paragraph Reads: The while(1) will break when AudioConverterFillComplexBuffer() gets 0 packets. Then the loop exits. All you need to do at that point is dispose of the converter, as in Listing 6.16. Should read: The while(1) will break when AudioConverterFillComplexBuffer() gets 0 packets. Then the loop exits. All you need to do at that point is dispose of the converter and the outputBuffer, as in Listing 6.16. ------------- page 144 Listing 7.20 Reads: cleanup: AUGraphStop (player.graph); AUGraphUninitialize (player.graph); AUGraphClose(player.graph); return 0; } Should read: cleanup: AUGraphStop (player.graph); AUGraphUninitialize (player.graph); AUGraphClose(player.graph); DisposeAUGraph(player.graph); return 0; } -------------- page 167 Replace all of footnote 1 with the following text "The CARingBuffer class has moved around in recent releases, and this has caused lots of problems. In Xcode 4.2 and earlier, it was installed in /Developer/Extras/CoreAudio/PublicUtility, but some versions were buggy. Apple Techincal Q&A 1665, "Core Audio PublicUtility -- Installing the CARingBuffer Update" explains the problem and links to an updated version. Xcode 4.3 and 4.4 don't install the PublicUtility classes, and instead require you to download it from the "Audio Tools for Xcode" package on developer.apple.com. Starting in Xcode 4.5, the PublicUtility classes are no longer in this download; they're now in a Sample Code project called "Core Audio Public Utility", which you can find with Xcode's documentation browser. A Readme.rtf file in this project now directs you to install the classes at /Library/Developer/CoreAudio/PublicUtility, and the downloadable version of the book's code has been updated to look for CARingBuffer's .h and .cpp files on this path." ------------- p. 177 First paragraph Reads: Now you get to work. When you created the struct, you set up some “offset” time fields. Now you start using them in Listing 8.16. You have these because the input and output units might be using totally different schemes for their time stamps. One might be using real-world “wall clock” time, whereas the other might be counting seconds since your application launched. This matters because the CARingBuffer keeps track of the time stamps of the samples added to it. If they’re wildly different, you won’t get any sound. You can deal with this by noticing the first time stamp provided by each unit and, when you have both, calculating the difference (or offset) between them. Should read (just adds new final sentence): Now you get to work. When you created the struct, you set up some “offset” time fields. Now you start using them in Listing 8.16. You have these because the input and output units might be using totally different schemes for their time stamps. One might be using real-world “wall clock” time, whereas the other might be counting seconds since your application launched. This matters because the CARingBuffer keeps track of the time stamps of the samples added to it. If they’re wildly different, you won’t get any sound. You can deal with this by noticing the first time stamp provided by each unit and, when you have both, calculating the difference (or offset) between them. To notice when you get the first output time stamp, you'll want to initially set it to a flag value like -1 (you already set firstInputSampleTime to -1 back in Listing 8.14, and will similarly initialize firstOutputSampleTime later, in Listing 8.20). Listing 8.16 Reads: // have we ever logged input timing? (for offset calculation) if (player->firstInputSampleTime < 0.0) { player->firstInputSampleTime = inTimeStamp->mSampleTime; if ((player->firstOutputSampleTime > 0.0) && (player->inToOutSampleTimeOffset < 0.0)) { player->inToOutSampleTimeOffset = player->firstInputSampleTime - player->firstOutputSampleTime; } } Should read: // have we ever logged input timing? (for offset calculation) if (player->firstInputSampleTime < 0.0) { player->firstInputSampleTime = inTimeStamp->mSampleTime; if ((player->firstOutputSampleTime > -1.0) && (player->inToOutSampleTimeOffset < 0.0)) { player->inToOutSampleTimeOffset = player->firstInputSampleTime - player->firstOutputSampleTime; } } --------------- p. 181 Listing 8.21 Reads: OSStatus GraphRenderProc(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData) { MyAUGraphPlayer *player = (MyAUGraphPlayer*) inRefCon; // have we ever logged output timing? (for offset calculation) if (player->firstOutputSampleTime < 0.0) { player->firstOutputSampleTime = inTimeStamp->mSampleTime; if ((player->firstInputSampleTime > 0.0) && (player->inToOutSampleTimeOffset < 0.0)) { player->inToOutSampleTimeOffset = player->firstInputSampleTime - player->firstOutputSampleTime; } } Should read: OSStatus GraphRenderProc(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData) { MyAUGraphPlayer *player = (MyAUGraphPlayer*) inRefCon; // have we ever logged output timing? (for offset calculation) if (player->firstOutputSampleTime < 0.0) { player->firstOutputSampleTime = inTimeStamp->mSampleTime; if ((player->firstInputSampleTime > -1.0) && (player->inToOutSampleTimeOffset < 0.0)) { player->inToOutSampleTimeOffset = player->firstInputSampleTime - player->firstOutputSampleTime; } } Third paragraph Reads: As before, this offset calculation needs to run only once, the first time in either callback that both firstInputSampleTime and firstOutputSampleTime have values other than the -1 flag value you initialized them with. Should read: As before, this offset calculation needs to run only once, the first time in either callback that both firstInputSampleTime and firstOutputSampleTime have values other than the -1 flag value you initialized them with (in Listings 8.14 and 8.20, respectively).