Giter VIP home page Giter VIP logo

comunidadaylas / vorbis-rs Goto Github PK

View Code? Open in Web Editor NEW
15.0 3.0 4.0 287 KB

πŸ”Š Rust bindings for the best-in-breed C libraries of the Vorbis audio codec and Ogg container encapsulation.

Home Page: https://crates.io/crates/vorbis_rs

License: BSD 3-Clause "New" or "Revised" License

Rust 98.42% Shell 1.58%
audio-encoding lancer rust-ffi-bindings rust-ffi-wrappers vorbis aotuv hacktoberfest

vorbis-rs's Introduction

vorbis-rs logo

vorbis-rs

Rust bindings for the best-in-breed C libraries of the Vorbis audio codec and Ogg container encapsulation.

CI workflow status crates.io latest version docs.rs status

crates.io downloads

The vorbis_rs package in this repository provides updated, well-documented and ergonomic bindings for a modified version of the latest reference Vorbis encoder, available here, with the aoTuV and Lancer patchsets applied to it. These patches are considered to implement significant encoding quality and performance improvements by the community.

The supporting aotuv_lancer_vorbis_sys and ogg_next_sys packages provide automatically-generated low-level bindings used by vorbis_rs.

The minimum supported Rust version (MSRV) for every package in this repository is 1.64. Bumping this version is not considered a breaking change for semantic versioning purposes. We will try to do it only when we estimate that such a bump would not cause widespread inconvenience or breakage.

❓ Motivation

The Rust ecosystem already has bindings for these libraries (see vorbis-sys and vorbis), but the quality and maintenance status of the available crates is problematic in an entangled way that does not seem reasonable to fix via PRs or patching:

  • The high-level vorbis crate was not updated in 6 years, has arguably low code quality (lots of panic! with messages containing e-mail addresses, etc.), and depends on an old version of vorbis-sys. In turn vorbis-sys depends on an old version of the libvorbis C library with known security vulnerabilities. It also lacks APIs to do some operations needed by sensible audio processing applications that are offered by the C libraries.
  • vorbis-sys only contains bindings for libvorbis, but updated bindings for libvorbisenc and vorbisfile are necessary to do meaningful Vorbis stream operations in a sane way. These are not available either.
  • There are several random crates in crates.io depending on several of these unsatisfactory binding projects, and it seems unlikely that their maintainers will promptly accept breaking changes on them, generating ecosystem fragmentation.
  • Like most software libraries, frameworks and even Linux distributions, the existing crates seem to be oblivious to the existence of the aoTuV and Lancer patchsets, even though they are meant to be drop-in replacements. Thus, users may reasonably expect any patches to be mentioned, which is a good reason to do a different set of binding crates anyway.

Given these issues and the need for a better solution for Ogg Vorbis audio processing applications in Rust, it was decided to spend development effort on making new bindings: it was estimated that the upfront cost of fixing the technical debt of the ecosystem was higher than starting bindings from scratch and periodically updating the library bindings from upstream. Rewriting the patched Vorbis encoder in Rust was deemed unfeasible.

βš–οΈ License

The bindings in this repository are licensed under the BSD 3-Clause "New" or "Revised" License (LICENSE or https://opensource.org/licenses/BSD-3-Clause), which is the same permissive license used by the upstream projects.

Contribution license

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in vorbis_rs by you shall be licensed as above, without any additional terms or conditions.

✨ Contributing

This repository started as an ad-hoc solution to address the needs of a Rust application, but it has grown into a project of its own - PRs are welcome!

Cloning & updating

The C libraries sources are managed with submodules, so updating the binding crates with the latest upstream changes should be easy:

  1. Update the submodules.
  2. Run the generate-bindings.sh script on a Unix-like system (Linux, macOS, BSD) with rust-bindgen, or build the project with cargo build --features build-time-bindgen. This will regenerate the low-level FFI bindings according to the latest source code.
  3. Run cargo test. This will execute some basic sanity checks, including encoding and decoding example files, to check that the bindings still work.
  4. Review the changes and/or fix failing tests until there is reasonable confidence that the upgrade was completed successfully.
  5. Commit the changes.

When cloning the repository, remember to also check out the submodules with the vendor code. You can do this by running git submodule update --init --recursive.

Each time vendor code is updated, it will be necessary to release a new version of aotuv_lancer_vorbis_sys and/or ogg_next_sys, so that users of vorbis_rs can download binding crates with the updated vendor code.

🀝 Contact

We welcome friendly talk about the project, including questions, congratulations, and suggestions. Head to the GitHub Discussions page to interact with fellow users, contributors and developers.

πŸ§‘β€πŸ€β€πŸ§‘ Contributors

Thanks goes to these wonderful people (emoji key):

Alejandro GonzΓ‘lez
Alejandro GonzΓ‘lez

πŸ’» πŸ“– πŸ’‘ 🚧 πŸ“†
Vivian
Vivian

πŸ’» πŸ€”
Martin Algesten
Martin Algesten

πŸ’»
Kyle Chen
Kyle Chen

πŸ€”
Daniel Collin
Daniel Collin

πŸ›

This project follows the all-contributors specification. Contributions of any kind welcome!

vorbis-rs's People

Contributors

alextmjugador avatar algesten avatar renovate[bot] avatar vivyir avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

vorbis-rs's Issues

Ergonomics of `VorbisEncoderBuilder`

The way the builder pattern is used for VorbisEncoderBuilder makes constructing a VorbisEncoder slightly awkward. Here's an example of how to go about it currently:

#[allow(unused_results)]

let mut builder = VorbisEncoderBuilder::new(sample_rate, channels, sink)?;

builder.bitrate_management_strategy(VorbisBitrateManagementStrategy::QualityVbr {
    target_quality: 1.0,
});

let encoder = builder.build()?;

I think this would be better:

let encoder = VorbisEncoderBuilder::new(sample_rate, channels, sink)?
    .bitrate_management_strategy(VorbisBitrateManagementStrategy::QualityVbr {
        target_quality: 1.0,
    })
    .build()?;

Methods on builders usually go like this (see the Design Patterns book and reqwest::ClientBuilder for examples):

pub fn foo(mut self, bar: ...) -> Self

but for VorbisEncoderBuilder, the methods look like this:

pub fn foo(&mut self, bar: ...) -> &mut Self

The issue is that VorbisEncoderBuilder::build consumes self when the methods return &mut Self, so you can't chain build with them. I'm also not sure why methods return &mut Self at all. If a user has ownership of the builder struct, getting a &mut Self is trivial. Another smaller issue is that not using the return type (like in the example) triggers the unused_result lint. This can be dealt with, but the workaround should not be needed in the first place.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

This repository currently has no open or pending branches.

Detected dependencies

cargo
Cargo.toml
  • cc 1.0.99
  • bindgen 0.70.0
packages/aotuv_lancer_vorbis_sys/Cargo.toml
packages/ogg_next_sys/Cargo.toml
packages/vorbis_rs/Cargo.toml
  • errno 0.3.9
  • tinyvec 1.6.0
  • thiserror 1.0.61
  • getrandom 0.2.15
git-submodules
.gitmodules
  • vendor/ogg master@0ef384eef978e4346acd1c64830d486aa98c690a
  • vendor/vorbis master@1c49413115971752e360025af58f0e418106e7b9
github-actions
.github/workflows/ci.yml
  • actions/checkout v4@692973e3d937129bcbf40652eb9f2f61becf3332
  • dtolnay/rust-toolchain v1@1482605bfc5719782e1267fd0c0cc350fe7646b8
  • mozilla-actions/sccache-action v0.0.5@89e9040de88b577a072e3760aaf59f585da083af
  • actions/checkout v4@692973e3d937129bcbf40652eb9f2f61becf3332
  • dtolnay/rust-toolchain nightly
  • mozilla-actions/sccache-action v0.0.5@89e9040de88b577a072e3760aaf59f585da083af
  • giraffate/clippy-action v1@13b9d32482f25d29ead141b79e7e04e7900281e0
  • ubuntu 22.04

  • Check this box to trigger a request for Renovate to run again on this repository

Publishing to crates.io? (I'll help!)

Hiya!

I'd love to use your vorbis library in one of my projects (because as you've already mentioned, the current vorbis ecosystem on crates.io is really outdated, has bad code quality and just straight up doesn't even work because of dependency hell in the case of the vorbis crate which is currently on crates.io!); I absolutely love what you've done here, it's really clean, high quality code, all the packages!

In my opinion you should publish these crates to crates.io, maybe under the name of "vorbis-next", "ogg-sys-next", and "vorbis-sys-next" perhaps, your call really, by doing so the ecosystem of rust itself would improve by a lot; Seriously, I spent around 20 hours today (yes I didn't sleep) looking for different lossy audio encoders, vorbis, opus, etc to use in my project, and while I did find an ogg-opus crate it couldn't be played or decoded easily on the web so it was useless for me, I also saw the current vorbis crate and tried to use it but that dependency hell thing got me, your code was really clean however, a breath of fresh air really, while I can continue using your library with git in cargo I think it deserves to be on crates.io, it'd save me and many others like me who are trying to just decode/encode vorbis a lot of time.

If you'd like to publish these crates I can help get them ready by writing nice readmes (in your style) for the packages and also separating the code in the main vorbis bindings so that instead of 1 giant 1k SLOC file it's structured nicely and easier to contribute to/maintain and also writing whatever kind of example I can think of for it, overall just polish them up and then open a PR for it, I'll make sure that the function signatures stay the exact same so your project PackSquash which depends on this library using git won't encounter any problems (I can try building PackSquash from source to confirm as well but I may need your help with that), so this'd only be a change in this library and won't require any change in PackSquash.

Lemme know what you think, if you do approve, lemme know how I can build PackSquash and then I'll get to work!

Return idiomatic error enums instead of low-level library error codes

Currently, the internal macro that converts low-level C library error codes to an user-facing Result just passes through error codes returned by C functions, which users can compare with some crate constants to know the precise error cause:

macro_rules! return_value_to_result {
( $func:ident ( $($arg:expr),* ), $is_ok:expr, $lib_name:literal, $result_to_error_string:expr ) => {{
let return_value = $func($($arg),*) as i32;
if $is_ok(return_value) {
Ok(return_value)
} else {
Err(VorbisError::LibraryError {
__error_message: concat!($lib_name, " error calling ", stringify!($func), ". Reason: ").into(),
__error_reason: $result_to_error_string(return_value).into(),
error_code: return_value
})
}
}};

While this works fine in most cases, it's not an ideal design for several reasons:

  • In theory, the same error code may be used by different C libraries to represent different error causes. Moreover, users can't know which library the error code belongs to, as that information is not meant to be made available on the error struct.
  • A set of error causes is more idiomatically represented in Rust by an enum type, rather than a raw integer.

Therefore, a welcome improvement would be replacing the error_code field with a error_cause field, which relates the library that caused the error with its actual cause. This would complicate the error handling logic significantly, but I think it's worth it for end usage.

Crash trying to encode large buffer

Hi,

First of all thanks for a great crate.

I'm running into a crash when I'm trying to encode a "large" buffer. Here is a small repro case for it.

use vorbis_rs::VorbisEncoderBuilder;
use std::fs::File;

fn main() {
    let mut file = File::create("test.ogg").unwrap();

    let mut encoder = VorbisEncoderBuilder::new(
        core::num::NonZeroU32::new(48000).unwrap(),
        core::num::NonZeroU8::new(1).unwrap(),
        &mut file,
    ).unwrap().build().unwrap();

    let buffer = vec![0f32; 48000 * 100];
    let t = [&buffer];

    encoder.encode_audio_block(&t).unwrap();
    encoder.finish().unwrap();
}

Callstack

* thread #1, name = 'vorbis_test', stop reason = signal SIGSEGV: invalid address (fault address: 0x7ffffedac3a0)
  * frame #0: 0x00005555555832ad vorbis_test`_preextrapolate_helper(v=0x00005555556eaa40) at block.c:450:16
    frame #1: 0x0000555555583778 vorbis_test`vorbis_analysis_wrote(v=0x00005555556eaa40, vals=4800000) at block.c:549:7
    frame #2: 0x0000555555575af6 vorbis_test`vorbis_rs::encoder::encoder_impl::VorbisEncoder$LT$W$GT$::encode_audio_block::h152463b898dee8a7(self=0x00007fffffffd080, audio_block=0x00007fffffffd498) at encoder_impl.rs:369:4
    frame #3: 0x0000555555572cc8 vorbis_test`vorbis_test::main::h08dbc0d2c10d4962 at main.rs:16:5

I can workaround this issue by manually sending smaller chunks of the data to encode_audio_block but I don't see any limitation in the API/docs that would indicate that I have to do that.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.