Seeking or rewinding

Sep 5, 2012 at 3:15 AM


Thanks for your work on this, it's great to have a fully managed Ogg decoder that works without dependencies. 

I'm using this without NAudio, with OpenTK/OpenAL, to have ogg streaming. Everything works, but having the ability to seek or at least rewind the stream to position 0 would be appreciated. I tried doing naive things like setting the CurrentPosition of the decoder to 0 : 

_decoders[_streamIdx].CurrentPosition = 0;
_sourceStream.Seek(0, SeekOrigin.Begin);

But it keeps playing where it left off.
Is there a simple way to implement this?


Sep 6, 2012 at 1:29 PM


You are absolutely welcome!  Glad someone was able to make use of it...

The seeking implementation is only half baked.  The "naive" thing you tried should have worked, but apparently I missed a detail somewhere.  First guess is that the packet index in the reader isn't getting reset correctly...  I've not tried seeking yet, so it's bound to have lots of wonderful "challenges" left in it.

Sep 20, 2012 at 3:50 PM


I believe I have seeking implemented and working.  Give it a shot and let me know.


Sep 21, 2012 at 2:03 PM


I'm only using seeking for rewinding back to 0 when stop/playing or when looping a sound, but as far as I can tell it works great! Thanks a bunch.

Sep 24, 2012 at 5:57 PM

The SeekTo method of VorbisReader is currently a private member. Is this purposeful?

Sep 24, 2012 at 8:44 PM

Not really...  My usage scenario only requires time-based seeking, so DecodedTime's setter made sense.  I don't like putting complex logic in a property setter, so it was placed in a dedicated method (which will eventually gain "index-based" seek capability for Ogg Skeleton & Matroska).

Thinking about it further, I don't know of any reason why "void SeekTo(long)" couldn't be a public method...  Adding "DecodedSamples" and "TotalSamples" properties would also make life simpler for those doing real-time mixing and such...  I might do that (unless you or someone else would like to send me a patch / pull request).

Thanks for taking a look at the project.  I hope it's helping. :)

Sep 24, 2012 at 10:30 PM

Ah! I didn't notice that DecodedTime had a setter. Testing it out real quick, everything seems to be working fine; just need to tweak my code to catch where the song ends so that I don't fill the latter half of a buffer with silence at the end of each loop.

Also, if you do end up exposing SeekTo as a public method, I'd suggest a public SeekToBeginning() method or something similar since it seems like that would be all a lot of people will be using the seeking for.

Thanks a lot for this project. It's been a real big help.

Sep 25, 2012 at 12:21 AM

Very cool.  I'll probably add some sample-based bits to the public interface.  Not sure about SeekToBeginning(), since SeekTo(0) does the same thing, but I'm not against it.

End of stream is fun.  The return value of ReadSamples(...) is the number of bytes provided, and should equal the number requested until the end of the stream.  If it returns 0, the stream is over and no samples were available to put in the buffer.  You can also watch for DecodedTime == TotalTime after reading samples and checking for 0.

Feel free to make further suggestions. :)

Sep 25, 2012 at 10:44 PM

Yeah, I'm just using ReadSamples and truncating the data as needed before stuffing it into the buffer queue, and I use an "if(DecodedTime >= TotalTime)" to check for the loop. Got it up and organized this afternoon finally and now it's running pretty smoothly.

As for SeekToBeginning() it's obviously not needed that badly; it's longer to type out than SeekTo(0), for one thing. I'm just prone to making a wide array of methods to do the same thing in multiple ways whenever I think someone else might need my code. Not always the best use of my time, to be honest. XD

I do have a question about SeekTo(long), though. I've heard the .ogg format is pretty bad with precision seeking. With SeekTo(long), does it seek to that exact sample location, or does it jump as close as it can?

Sep 25, 2012 at 11:01 PM

Ogg is weird.  The only seek information you get from the file is the sample number of the last completed sample in each page.  Except when the page doesn't complete any samples, in which case you get a "-1" for the seek position.  Just to keep us on our toes, right?

SeekTo() *should* be sample-accurate.  It looks for the right page and the right packet in that page, then decodes the previous packet and the "requested sample's" packet.  It then throws away the "extra" samples before the sample requested.

I think libvorbis doesn't bother with "exact", so most Vorbis decoders don't bother with it either.  I guess I'm just strange.

Sep 26, 2012 at 12:40 AM

If it's sample-accurate then that would save me the trouble of having to split the "intro" of a track off as a separate ogg file (which seems to be a fairly common solution). I'd still have to save the sample position for the loop in a data file somewhere, but I'd have to do that anyway to keep track of which file goes with which intro.