-
Notifications
You must be signed in to change notification settings - Fork 231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Seeking #176
Comments
Lewton does. Dunno about the other libraries. |
I guess it should first and foremost be implemented on the decoder struct, if the underlying libraries support it (which I'm not sure of). |
Anyone get anywhere with this? |
I couldn't really get it working and gave up on it 😢 |
It's a feature I need too, unfortunately I don't have much time to try to implement it. |
@recapitalverb I only had success with seeking with hound (hound::WavReader::seek) + cpal, fitting this into rodio might be some work, you can probably add a |
@michaelmarconi Yes you can seek any format that way but it'll take a lot of time to parse the whole audio file, it's the best way if you're fine with that |
Yeah it'd be very CPU and RAM intensive and not a good idea. Some people may want to play back 10 hours of background music or something all in one file... |
Aren't (almost) all audio formats streamable? At least that's what I always thought... You could then load an interval of like 1min into RAM and keep it there at any given time and just continuously load new content and drop the old one. |
Already 1 minute of samples at 48000 samples per seconds with 2 bytes per sample would mean 5760k or 6 mb of memory use. If it's an opt-in feature, people can use it if they want but optimally one would have seeking support in all of the libraries that rodio uses, then make rodio abstract over it. |
Eager for the seeking feature for this library, I looked up for each underlying decoder library: MP3
There is a fork that adds a wrapper to the seek function in the original library, last updated on May 2020, a half year ago. The implementation wraps WAV
Vorbis
Related: RustAudio/lewton#73, and maybe RustAudio/lewton#16 as well? Any updates? @est31 FLAC
Some FLAC files have "SEEKTABLE" metadata, so this may help for implementing the feature. Even if there is no such metadata, one can still seek to arbitrary position and look for the frame header, which contains the frame position, so it is easy to implement binary searching. |
I needed seeking for my podcast player build on rodio. I now have it working (in the most basic way possible) for mp3 on my fork. For that I added:
However sources might not support seeking thus we can not simply add
where PS: I forked the fork of minimp3-rs mentioned above, brought it up to date with master and extended it to allow decoding a whole frame. It is used as a git dependency here instead of minimp3-rs on crates.io |
@est31 Any word on @dskleingeld's implementation? @dskleingeld Do you think the seeking method could be added in a PR to the official minimp3-rs? |
Should be doable, it adds a seperate |
Haven't looked at it but in general seeking support would be a great addition. If it needs upstream changes, those need to be upstreamed first before it can be merged in rodio. |
I have a branch here with a number of changes including seeking working. I was getting some strange runtime errors on Windows with the minimp3 fork with seek support (been a while and I can't remember what it was exactly. I think it was an access violation.) so I ended up using Symphonia instead. Symphonia supports MP3, FLAC, and MP4/AAC so I switched the existing MP3 and FLAC decoders over and also gained AAC support as a result. Unfortunately Symphonia doesn't have seek implemented for AAC so I had to fork Symphonia as well and implement it there. The implementation is quick, hacky, and not particularly precise if you need sub-second precision as I don't really know much about audio codecs, but it seems to be fast enough and works okay if you can accept the limitations. I don't think any of my changes are mergeable as is because I haven't thoroughly tested it aside from just using the basic playback capabilities so some features may not work as it is right now. I have been using it in my audio player project and the basic functionality seems to be working at least, but it should be considered very much a POC and not optimized. The other change I added to this branch is discarding the silent samples from the very beginning of the stream to enable psuedo-gapless playback (seems to be gapless enough for the tracks I tested so far). I plan on making that an opt in feature, but haven't gotten around to it yet. I hope I can make all these changes mergeable eventually, but getting a non-hacky seek solution for all the codecs in Symphonia is an obstacle, there's some changes to Lewton that need to be merged first, and I'll need to do a lot more testing on the seek changes in Rodio to check for any regressions. Here are all the changes I made in case anyone's curious: This also required this fork of Lewton with better seek support Anyway, sorry for the essay, but I figured I'd let people know in case they really want this feature right now and are okay with a hacky solution until I can make this better or someone else creates a better solution. |
@aschey This sounds awesome, excited to see progress on it! |
@aschey, seeking support for all formats, that is great! I see you added a seek method to the Source trait, that looks way cleaner then adding a new trait like I did. I thought this would be a problem for sources that can/do not support seeking. However right now these could fake a seek implementation (always returning How can I help get this in rodio? |
@dskleingeld Yeah, that's basically how I handled it. I figured it's fine for a seek to be a no-op on situations where it doesn't make sense like a sine wave. If you want to run my branch and test it out a bit, that'd help me out a lot. PRs are welcome as well if you see something that can be improved. Most of the source implementations are totally untested right now as I only used it for basic playback, none of the fancy effects or looping or anything. I just made my best guess as to how seek might work for the sources that I haven't used so there's a good chance that a lot of them still need tweaking and some definitely need to be cleaned up with proper error handling and whatnot. In terms of getting this in for real, I think this needs to happen in a few phases. I was lazy and put all of this in one branch just to see if it would work at all, so I'll copy the different parts of my changes into new branches so they can be merged separately.
I've got some life stuff going on right now, so I might not make too much progress in the next few weeks, but I'll start working on part 1 and 2. |
I'm positive towards symphonia integration in general, but some users of rodio might have concerns about the copyleft license that symphonia uses (MPL-2.0). Many gamedevs have a disdain towards anything copyleft related, even if it's the weak copyleft of MPL-2.0. I think an optional backend based on symphonia would work (or maybe multiple, idk what's more elegant), but it shouldn't replace any existing "permissively" licensed backends. |
Okay, fair enough. I can probably make them interchangeable and have it opt-in via a feature flag. Seek can just be a no-op for any decoders that don't support it. |
Hey all, developer of Symphonia here. I stumbled across this thanks to @aschey's recent PRs. I'm happy that Symphonia is getting some attention and thought I could address some of your concerns and add a few thoughts. I'll preface this by saying that I am having difficultly finding time to work on Symphonia, hence the low activity on the repo, but I do hope to dedicate a few hours each week to fix bugs, merge PRs, and refactor things as necessary to improve the library and support different users. In the longer term, my goal is to complete the Vorbis decoder, and implement support for Opus. So onto some thoughts:
Cheers! |
Thanks for reaching out @pdeljanov ! To 4: interesting, will keep it in mind. To 5: wrapping lewton might be a good idea anyways, but as I've said above, symphonia should rather be an option instead of a hard dependency. Having it as an option would be awesome. |
Thanks for getting my PRs merged @pdeljanov. Wrapping lewton in a Decoder trait is an interesting idea that I'll definitely take a look at. I have a working branch with optional Symphonia integration here that I plan to make a PR for once the next Symphonia version is released. |
Would want to have seeking support in redlux (which glues together rust-mp4 and fdk-aac c-bindings with rodio) for |
Hey @aschey, just wanted to give you a heads up that I published 0.3.0 which includes your changes. @probablykasper, for basic (non-fragmented) MP4 files, all you have to do is use the STTS atom to convert a sample timestamp to a sample number. Once you have the sample number, you just need to start reading from that sample number forward. I implemented seeking in MP4 (and ADTS) for v0.3 of Symphonia so you could get some inspiration from that albeit it's a bit more complicated because it also supports fragmented streams. |
Great, thanks for the heads up! Just created the PR to add Symphonia integration here: #376. Happy to accept feedback if you have ideas for improvements. I did briefly look into wrapping Lewton in a decoder trait, but it didn't seem like Lewton's API would be compatible with the way the decoder trait works since Lewton requires access to the underlying read/seek source. Bringing this back to the intent of the original issue, I'll work on another PR to expose Symphonia's seek functionality to Rodio once the previously mentioned PR is merged. |
Lewton has two different APIs. A high level one in the inside_ogg module that indeed needs Read/Seek, as well as a lower level one which only needs access to |
Patching Lewton might no longer be necessary, since Symphonia now has a Vorbis decoder. It's 100% safe code and is at around 10% slower than ffmpeg. Correctness should be quite good as well - I've tested it against the reference implementation on over 200Gb of Vorbis from various sources, and all the mismatches with the reference implementation have been fixed. |
I've been wondering why have rodio at all, given that symphonia exists, has more codecs, etc. Why not use symphonia directly? There is one big difference: Symphonia has a copyleft license. For some people that's good. But I think many don't like copyleft. So the target market of rodio is everything that's left. People who want to use copyleft free licensing. This is a big thing in e.g. games for example. This extends to the libraries that rodio is using. So whatever libraries rodio uses, they should be patched, if possible. Generally it seems that symphonia has more maintainer momentum right now than rodio and related projects. The approach of having a monorepo is quite interesting, compared to rodio's approach of one-codec-per-crate. I still think that, beyond inertia, it's still valuable to maintain rodio and the libraries that rodio uses. |
Naturally. I just wanted to point out that patching every single crate is not strictly necessary to provide some seeking support. Ideally all backends should support it, of course. |
True, but Symphonia is licensed under the MPL, which is a weak copyleft license. Unlike GPL, it can be used in commercial/proprietary projects just fine. It is not infectious, even when statically linking. You only have to disclose changes you made to the library itself (if you made any). |
I use Rodio as it is higher level then symphonia, Rodio's basic example is 11 lines of code whereas symphonia's getting started example comes in at 103 lines. Getting back to the issue at hand, rodio should have seeking in files, this issue has been open for 5 years. We have a working fork (by aschey using symphonia as decoder). Since then symphonia has become an optional/default decoder for Rodio. To me the next step seems a PR integrating aschey changes into Rodio. Seeking methods would be kept behind the same feature flag as the symphonia backends. Possibly even behind an extra unstable flag (like done in tokio) to allow the API change later. @est31 you seem the maintainer of rodio atm, would you be open to such a PR? |
Hey, sorry for abandoning this a while ago. I ended up using Symphonia directly rather than going through Rodio as I needed some additional functionality (unrelated to seeking) that would've been difficult to integrate with Rodio's architecture. Anyone's welcome to pick up my branch here and continue it. It's definitely a bit of a mess and has unrelated changes so you'd be better off just copying over the useful bits into a fresh branch. As mentioned previously, I only got basic playback functionality working though and I didn't really test any of the other features that were affected so I wouldn't assume anything in there beyond basic playback is in a working state. Alternatively, it may be better to avoid adding the seek method to the |
I'm fine with seeking additions. Ideally they'd be in a way that any backend can opt into it. lewton already has partial seeking as well, but it needs to be polished (to be nice). Given that there is a 0.15 cpal upgrade, we'll likely have to do a semver breaking update anyways. |
No worries. Off topic, I wonder what other functionality you needed. I am building a podcast player I think I only need seeking and pause/play but I might have missed something there. Unless any one else works on it (let us know here please!) I will probably work on this in one or two months. I will need seeking anyway and I rather add seeking to Rodio (where I will get some code review and feedback) then throw something together. |
I think you're good. Don't want to spam this thread so I'm happy to discuss more elsewhere, but I'm working on a music player daemon similar to MPD and I needed a way to retrieve the exact playback position of the stream in order to keep multiple clients synchronized. |
I'm gonna give this one ago, Ill open a draft PR soon. |
Cleaned up my implementation build upon years old hacks, got a bit unhappy about the design. So lets discuss our options there. Right now I see 4:
I have a start on this as my current implementation, though to me this design seems to lead to a high amount of new code bloat. I am thinking of abandon it in favor of one of the others. edit 2023-10-02: There is a way to get a clean API but it needs the now still unstable Specialization feature.
Combined with
That is doable but will add some complexity to
The rust API guidelines specify features should be additive, adding a decoder should not remove seeking. To me a merge between 3 and 4 seems like a good option. Switch to an API with runtime errors when you add a feature which enables a decoder that does not support seek. If we plan to add more features only supported by some decoders a good implementation of 1 on which we can build might make more sense. edit 2023-10-02: |
The PR is ready now, it got pretty big, please help the maintainers out by reviewing it. |
#513 updated to latest commit. |
Its merged 🥳 |
Looks like seeking isn't supported for now. Do the used libraries allow seeking in general?
It's a feature I would need for an application and I would be willing to try to implement it. Not sure where though. The sink looks like a good place for it.
The text was updated successfully, but these errors were encountered: