override AEAudioFilePlayer renderCallback
Hi guys,
In a previous iteration of my app, i injected code into the framework to handle some latency issues, specifically grabbing the time when sample first get spit out of the renderCallback in AEAudioFilePlayer.
I'd like to keep the framework untouched, so I have tried using subclass of AEAudioFilePlayer but i can't figure out how to call the super's C function "renderCallback" from a C function in my class.
I can call the method by calling [super renderCallback] from (AEAudioRenderCallback)renderCallback but of course there is no context like "super" in the C style function.
Is this a poor approach? I'm all ears for other ideas.
Jason
Comments
Hmm, latency issues: have you tried automaticLatencyManagement, assuming it's relevant?
You can indeed subclass channel classes - you'll need to call [super renderCallback] from init, and keep that pointer in an instance variable, then use it from the render callback. You can see an example of that within AEAudioFilePlayer itself.
Thanks Michael. Yep, I use auto latency management along with every other trick in the book to handle a couple sticky bits I run into.
Thanks for the pointer, I'll dive into that tomorrow.
That worked wonderfully for the playback timing. I subclassed AEAudioFilePlayer and with very little code (little risk) I intercept some timing when I needed it.
I've done the some in AERecorder, but I need a timestamp at the point in the callback when the buffer size is > 0 (ie it is writing to disk). What I've done is subclassed the AERecorder, and make my own complete callback that mimics the one in AERecorder but sets a variable to a timestamp value at the time I need it to.
I tried using categories and failed, amongst other things. I also toyed with subclassing AEAudioFileWriter instead, as when AEAudioFileWriterAddAudio is called, it's more or less the same time as the timestamp I desire but that opened a whole new can of worms of getting the existing AERecorder to use the subclassed writer; it was more code than the plan I ended up going with.
So while this works, it will rely on me updating this callback if it changes, or switching away from Cocoapod to a fork which implements my change and having to update my fork instead.
Which, in your opinion, is the better method? Or, did I miss something and there's a better way to capture a timestamp when the first time the buffersize is non-zero in AEAudioReceiverCallback in AERecorder?
(To be clear, in the playback solution I was able to capture a timestamp then pass along control to the parent's callback using THIS->_superRenderCallback(..).
However in AERecorder, since I need to capture a timestamp that is in the middle of the logic in the parent callback, I wasn't able to do this, so instead I just recreate the whole callback with the custom code I need.)
Hmm, maybe if you explain what you're goal is, I could suggest an approach? I feel like I'm coming in in the middle here, a bit, so I'm struggling to figure out what's needed
Ha, no problem. I'm recording and playing back at the same time, and syncing. I've achieved perfect sync by:
The second timestamp is easy to get, but the first one required some work in the middle of the AEAudioReceiverCallback in AERecorder. The queue is built up and pulled apart to get the bufferlength. If it's greater than 0 then I grab a timestamp. I subclassed AERecorder to do this and just mimic'ed the whole callback (and the other necessary stuff to get it to work).
For the timestamp in #2, since I can get it at the beginning of the callback, I simple grab the timestamp in my wrapped callback then call the superRenderCallback to call the super's callback. I like that solution. I don't like the solution I've done in AERecorder though. If I wasn't using cocoapods now, I'd fork the repo and add my two lines of code in.
If there's nothing obvious off the top of your head, don't worry about it. What I have works perfectly right now.