Ability to read ogg from non-seekable (i.e. realtime incoming) InputStream


#1

I have a use-case whereby I'm loading ogg-compressed data from an InputStream which is some realtime incoming data-stream (i.e. no ability to know the size of the stream or jump around in it). I implemented setPosition in my inputstream to always return false, however internally in the juce ogg wrapping code, when ogg does the test to check whether the stream is seekable, it nevertheless determines that it is seekable (because the oggSeekCallback function doesn't test the return value of setPosition).

The problem being that if ogg determines the stream is seekable (which it tests in the first line of _ov_open1()), then it will try to read the end of the stream / etc, which this stream doesn't support, and basically gets stuck in an infinite loop of trying to read more data which the stream can't provide yet.

A solution I initially used was to comment-out the line in the OggReader constructor where it sets callbacks.seek_func. This caused everything to work as desired, proving that it can work. But since I don't want to depend on hacks to the juce code, it would be good if juce would support this scenario (for the case of ogg, and this may well apply to other file-formats as well).

Note - the cleaner solution that as I understand things seems a good general fix for the issue (and may be just fixing what may well just be  a simple bug), which I am now using and also works for me, is fixing the oggSeekCallback() function in juce_OggVorbisAudioFormat.cpp such that if setPosition() returns false when it calls it, then it correspondingly returns the -1 error code that ogg is expecting if seeking is not supported, i.e.:

return in->setPosition(offset) ? 0 : -1;

 


#2

i.e. https://github.com/mbevin/JUCE/commit/64a94cde9cb75e07820e94a4a028a3904dc0b78b


#3

Yeah, this is a bit tricky, because the audio reader classes were never designed with streaming in mind, so really don't fit well with this use-case.

It's a good feature request, and definitely something we should support, but to do it properly would mean some fundamental redesigns of the base classes, which we don't have time to work on right now. Can't promise when we'll look at it, but I'll add it to our backlog...


#4

Thanks for the response ... a somewhat related issue, is that some juce streaming-related objects like OggReader (returned by OggVorbisAudioFormat::createReaderFor()) insist on deleting the (here InputStream) stream-object given to them when destroyed (i.e. there's no way to say de-register the reader when done to avoid this deletion or signal that it shouldn't be deleted) ... 

This behaviour doesn't seem to fit how I find myself wanting to use the classes, i.e. in this instance neccessitated for me the creation of an intermediary input-stream-inheriting class and object just so I can safely pass an object to juce which I'm happy to have auto-deleted (the object I would have prefered to be able to pass, but couldn't due to this deletion-on-destruction, happens to be the owner of this reader) ...


#5

Well yes - it's done that way around because it's very easy to create an intermediate non-owning class like you did, but it'd be impossible to do the opposite, and to hand over ownership of the stream to a reader object if all it did was hold a raw pointer.

FWIW these stream classes are very very old! if I were to design them today, I'd probably use reference-counting to manage their lifetimes. If we can find a way to refactor them into that form without breaking too much user code, it's something I'd like to do!