Can't believe it's only been two days, because I feel like I've been battling with iPhone audio forever. I was trying to set it up, but somehow my callback was never called and I was starting to lose hope. I tried to keep things minimal, but turned out I was keeping it too minimal because I was neglecting to prime my sound buffers. I thought I wouldn't need to prime it, that I could just start the playback and then fill the buffers as they are requested from the callback function. Turns out the callback is only called when a buffer runs out, and since I had added no buffers it never got called!
To keep the callback function simple, I thought I would just create noise with rand() and fill the buffer with that instead of reading from a file. Again I neglected something important: setting bufferReference->mAudioDataByteSize. It was 0 by default, so the sound system must have figured there is no more sound to play. After fixing that I heard the sweetest sound ever: white noise being played from my phone!
Next up: learning how to use picker view to select sound waveform.