If you are lucky enough to only be using non-variable rate MP3s you could multiply the bitrate by 8 bits and then by the number of seconds the song has been playing.
AudioFileStreamSeek works with packets, not number of bytes. So, what you really need to track is the packet count.
The MyEnqueueBuffer method in Matt's code is where the buffers are sent to AudioQueue for playback. Grab packetsfilled and increment your index variable before packetsfilled is reset to 0:
myData.absolutePackets = myData.absolutePackets + myData->packetsFilled;
My problem is that I cannot AudioFileStreamSeek implemented correctly even with this value. So if you have some sample code of a working seek with Matt's code please share.
Thanks!
I haven't really tried AudioFileStream API for this (we rolled our own internally), but here's a few things you have to take care of.
Asssuming you have no problem random-seeking the byte stream, then you have to keep tracking the relationship between MP3 frame number and the absolute byte stream location, just as Paul says. I assume you can do that in your AudioFileStream_PacketsProc by calling AudioFileStreamSeek along the way.
Here's the trickier part. When you do random seek, you have to reset the internal states of AudioFileStream. Because it might be in some intermediate state expecting the next incoming bytes to complete the current frame. I'm not sure if you can just feed zeros to have it skip the current frame, and start over (that you have to try, as I don't see anything like AudioFileStreamReset in the API; the audio queue itself, however, does have reset function that you can clean up already-queued frame). At any rate you have to take care of your AudioFileStream_PacketsProc too because you're going to parse a part of the byte stream which you already have kept track of.
Note you can't just find the start of a MP3 frame by relying on the second and the bitrate. Even with non-variable rate MP3 stream, there can be paddings every other few frames. So the most accurate information still comes from the parser.
I should quickly add that another way to do random seeking is simply "cache" (store) the parsed packets if you're not playing a really long and large stream. Frame index can be calculated from the frame header info. For non VBR MP3s, frames per second is a constant (e.g. it's 44100/1152 = 38.28125 frames per sec for 44.1 kHz stereo non-VBR MP3; check out MP3 spec for why it's so).
can you use AudioQueueStart with the mSampletime of the place you want to seek to?
so just stop the play.... and start at a different sample time? [just take the current sample time and manipulate it by what you need to?]
inDeviceStartTime The time at which the audio queue should start.
To specify a start time relative to the timeline of the associated audio device, use the mSampleTime field of the AudioTimeStamp structure. Use NULL to indicate that the audio queue should start as soon as possible.
Return Value A result code. See “Audio Queue Result Codes.”
Discussion If the associated audio device is not already running, this function starts it.
Any one find the solution for this? If yes, can you please share your example code?
Thanks, Palanisamy