Code Monkey home page Code Monkey logo

rust-jack's Introduction

JACK

https://img.shields.io/badge/License-MIT-yellow.svg
https://github.com/RustAudio/rust-jack/workflows/Rust/badge.svg
https://img.shields.io/crates/v/jack.svg
https://docs.rs/jack/badge.svg

Overview

Rust bindings for the [JACK Audio Connection Kit](https://jackaudio.org). These bindings work on every operating system that JACK does.

The JACK server is usually started by the user or system. Clients can request that the JACK server is started on demand when they connect, but this can be disabled by the user and is the recommended configuration.

  • Linux and BSD users may install JACK1, JACK2, or Pipewire JACK from their system package

manager.

  • Windows users may install JACK from the

[official website](http://jackaudio.org/downloads/) or [Chocolatey](https://community.chocolatey.org/packages/jack).

[Homebrew](https://formulae.brew.sh/formula/jack).

[:heart: Sponsor](https://github.com/sponsors/wmedrano)

Refer to the [documentation](https://docs.rs/jack/) for details about the API, building, and packaging. Also take a look at the examples directory for usage.

Testing

Testing requires setting up a dummy server and running the tests using a single thread.

# Set up a dummy server for tests. The script is included in this repository.
./dummy_jack_server.sh &
# Run tests with limited concurrency.
RUST_TEST_THREADS=1 cargo test

**Note:** We use a single thread for tests since too many client instantiations in short periods of time cause the JACK server to become flaky.

Possible Issues

If the tests are failing, a possible gotcha may be timing issues.

  1. Increase the value used by sleep_on_test in client/common.rs.

Another case is that libjack may be broken on your setup. Try switching between libjack and libjack2 (they have the same API and libjack2 isn’t necessarily newer than libjack), or using a different version.

rust-jack's People

Contributors

be-ing avatar benjamin-l avatar cramertj avatar derekdreery avatar e2-71828 avatar est31 avatar igbc avatar ischeinkman avatar javyre avatar kasbah avatar kneitinger avatar mlang avatar mousterian avatar niclashoyer avatar ollpu avatar peterstuart avatar piegamesde avatar rex4539 avatar robbert-vdh avatar srperens avatar windfisch avatar wmedrano avatar x37v avatar yuval-k avatar

Stargazers

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

Watchers

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

rust-jack's Issues

No audio out with sine example

I have copied the sine demo from the examples folder and run it but I get no audio out

Output from the program

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/synth_test`
Enter an integer value to change the frequency of the sine wave.
3000

JACK is running and seems to be set up correct because Ardour is working fine on it.

Cleanup test delays

I have them spread out, but they can be made to run during certain functions when on cfg(test).

Know Problematic Areas
Creating/destroying client
Activating/Deactivating client

midi example not realtime safe?

Am I correct in thinking that the midi example:

let cback = move |_: &jack::Client, ps: &jack::ProcessScope| -> jack::Control {

uses a process callback?
http://jackaudio.org/files/docs/html/group__ClientCallbacks.html#gafb5ec9fb4b736606d676c135fb97888b
which requires that the callback be realtime safe?

but it prints:

println!("{:?}", e);

which isn't realtime safe I assume.

It not I'll write a variation of it and submit a PR that fixes that for jack best practices.

AudioOutPort::new() should take an immutable reference to port

AudioOutPort (such as other Port wrappers) only uses Port.buffer(&self) on the given port. This structure also keeps a mutable reference to it while there is no need for it. (file: src/jack/port/audio.rs:101)

Note: other similar wrapper like AudioInPort don't keep mutable references.

Proposal:

  • change the mutable reference _port in AudioOutPort into an immutable one;
  • update the signature of AudioOutPort::new() accordingly;

Stereo output

Hello!

Thank you for this library.

Following the give example I can output audio to the jack server from my program in mono. I wish to output stereo audio, but I am unsure how.

port_type() returns Ok("32 bit float mono audio"), is there a stereo version? Or is the correct approach to open a pair of ports for a stereo output?

Thanks,
Louis

Delay

There is a noticeable delay just from the example of copying input to output. How can this be avoided?

Sending from a processHandler into a channel.

Hi,

I'm new to rust and so this might not be an issue with the library, but I didn't have this issue in a simple example with just threads.

I am trying to read values from an AudioIn port, process them and send them into a channel.

This code shows roughly what I want to do:

extern crate jack;
use jack::{AudioIn, Client, ProcessScope, Control, ClosureProcessHandler, ClientOptions};
use std::sync::mpsc::channel;


pub fn start_processing() {
    // Setup client
    let client = Client::new("rusty_client",
                             ClientOptions::NO_START_SERVER)
        .unwrap().0;

    // Setup port to read
    let spec = AudioIn::default();
    let audio_in_port = client.register_port("in", spec).unwrap();

    // Setup channel
    let (tx, rx) = channel::<f32>();

    let process_handler = ClosureProcessHandler::new(
        move |_: &Client, _process_scope: &ProcessScope| {
            let audio = audio_in_port.as_slice(_process_scope);
            let val = *audio.first().unwrap();
            tx.send(val).unwrap();  // <-- this line breaks it!
            Control::Continue
        });

    let active_client = client.activate_async((), process_handler).unwrap();
}

If I try to compile it, it gives me an error:

  --> src/minimal.rs:27:32
   |
27 |     let active_client = client.activate_async((), process_handler).unwrap();
   |                                ^^^^^^^^^^^^^^ `std::sync::mpsc::Sender<f32>` cannot be shared between threads safely
   |
   = help: within `jack::ClosureProcessHandler<[closure@src/minimal.rs:20:9: 25:10 audio_in_port:jack::Port<jack::AudioIn>, tx:std::sync::mpsc::Sender<f32>]>`, the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<f32>`
   = note: required because it appears within the type `[closure@src/minimal.rs:20:9: 25:10 audio_in_port:jack::Port<jack::AudioIn>, tx:std::sync::mpsc::Sender<f32>]`
   = note: required because it appears within the type `jack::ClosureProcessHandler<[closure@src/minimal.rs:20:9: 25:10 audio_in_port:jack::Port<jack::AudioIn>, tx:std::sync::mpsc::Sender<f32>]>`

But usually with move the Sender should be captured and it should be fine! The error implies that I want the sender to be shared, I don't actually want that!

I'm posting this here because in my minimal example with pure rust, I couldn't reproduce the issue. This code is structurally similar, the way I understand the library:

use std::thread;
use std::sync::mpsc::channel;

fn main() {
    let (tx, rx) = channel::<&str>();

    let handler = move || {
        tx.send("Hey.").unwrap();
    };
    
    thread::spawn(handler);

    let val = rx.recv().unwrap();
    println!("{}", val);
}

If someone could point me towards a solution that would be great!

Auto-connect to system output

Hi, bit of a Jack development noob here.

Initially I thought this crate was just not working, since I ran sine.rs and heard no output. However, I was messing around with qjackctl and found the "Connections" page, and found that if I manually connected the client's output port to the system:playback_1 and system:playback_2 ports, I could hear the output!

It seems like it doesn't do this by default when I launch the sine example, so I figured I'd try to connect it programmatically at the start of the program. I'm having trouble doing this, though. Here's what I've tried:

let spec = jack::AudioOut::default();
let mut out_port = client.register_port("sine_out_1", spec).unwrap();
let system_out_1 = client.port_by_name("system:playback_1").unwrap();
let connect_result = client.connect_ports(&out_port, &system_out_1);
println!("{:?}", connect_result);

The println just gives me:

Err(PortConnectionError("rust_jack_sine:sine_out_1", "system:playback_1"))

and obviously the program crashes when I try to unwrap it.

Did I do something wrong in setting up the connections? Or is something wrong with my setup somehow, since I assume the sine example just works for most other people?

Bitwig on my system can automatically connect to the jack server and output sound when I start it up, so I think my jack server settings are at least workable.

Not sure what system settings would be useful to debug this... I'm running Arch linux, if it matters. I can provide more details if needed.

PortSpec should be an enum, not a trait

It seems very unnecessary for PortSpec to be a trait.
Since i have to pass PortSpecs around in my code, it would be much easier passing around an enum instead of having to use generics and complicate code.

I dont think it would be too hard to do this:

pub enum PortSpec {
    AudioOut,
    AudioIn,
    MidiOut,
    MidiIn,
    Unowned,
}

impl PortSpec {
    fn jack_port_type(&self) -> &str { ... }

    fn jack_flags(&self) -> PortFlags { ... }

    fn jack_buffer_size(&self) -> libc::c_ulong { ... }
}

Although i understand this would break compatibility with previous versions of the library.
But i think this would be more idiomatic to rust and cleaner in the users code.

EDIT:
Also, something that would become possible to do with this that i need right now is to match PortSpecs:

match spec {
    j::PortSpec::AudioIn => {}
    j::PortSpec::AudioOut => {}
    ...
}

Implement Send for Client and AsyncClient

When I try to pass the Client instance to another thread, the compiler tells me the Send trait is not satisfied.

the trait `std::marker::Send` is not implemented for `*mut jack_sys::Struct__jack_client

Is there a reason for this not being possible? I don't have mutch experience in rust but from what I read, there usually isn't mutch reason to not have Send implemented in most types.

Cannot borrow a variable in the jack process callback

I want to use a variable that I borrow from elsewhere in the process callback.
First method is to use the closure approach (example is a slightly modification of the playback_capture example):

extern crate jack;
use jack::prelude as j;
use std::io;

fn handle_audio(i: &u64) {
    let (client, _status) = j::Client::new("rust_jack_simple", j::client_options::NO_START_SERVER)
        .unwrap();

    let in_a = client.register_port("rust_in_l", j::AudioInSpec::default()).unwrap();
    let mut out_a = client.register_port("rust_out_l", j::AudioOutSpec::default()).unwrap();
    let process_callback = move |_: &j::Client, ps: &j::ProcessScope| -> j::JackControl {
        let mut out_a_p = j::AudioOutPort::new(&mut out_a, ps);
        let in_a_p = j::AudioInPort::new(&in_a, ps);
        out_a_p.clone_from_slice(&in_a_p);
        let k = *i; // Using the reference in the callback is not possible.
        j::JackControl::Continue
    };
    let process = j::ProcessHandler::new(process_callback);
    let active_client = j::AsyncClient::new(client, process).unwrap();
    
    /* ... */

    active_client.deactivate().unwrap();
}

fn main() {
	let i : u64 = 0;
	handle_audio(&i);
}

When I try this, I get the following example:

error[E0477]: the type `[[email protected]:11:28: 17:6 out_a:jack::port::Port<jack::port::AudioOutSpec>, in_a:jack::port::Port<jack::port::AudioInSpec>, i:&u64]` does not fulfill the required lifetime

Second method is to use a struct that implements the JackHandler trait and that borrows the variable (again a slightly modified version of the playback_capture example):

extern crate jack;
use jack::prelude as j;
use std::io;

struct Handler<'a> {
	i: &'a u64, // Borrow a variable in the struct
	out_a: j::Port<j::AudioOutSpec>,
	in_a: j::Port<j::AudioInSpec>,
}

impl<'a> j::JackHandler for Handler<'a> {
	fn process(&self, _: &j::Client, ps: &j::ProcessScope) -> j::JackControl {
		let k = *self.i; // Use the borrowed variable
        let mut out_a_p = j::AudioOutPort::new(&mut self.out_a, ps); // Error: cannot borrow self as mutable
        let in_a_p = j::AudioInPort::new(&self.in_a, ps);
        out_a_p.clone_from_slice(&in_a_p);
        j::JackControl::Continue
	}
}

fn handle_audio(i: &u64) {
    let (client, _status) = j::Client::new("rust_jack_simple", j::client_options::NO_START_SERVER)
        .unwrap();

    let in_a = client.register_port("rust_in_l", j::AudioInSpec::default()).unwrap();
    let mut out_a = client.register_port("rust_out_l", j::AudioOutSpec::default()).unwrap();
    let handler = Handler{i: i, out_a: out_a, in_a: in_a};
    let active_client = j::AsyncClient::new(client, handler).unwrap();

    active_client.deactivate().unwrap();
}

fn main() {
	let i : u64 = 0;
	handle_audio(&i);
}

Here, I get the following error:

error: cannot borrow immutable field `self.out_a` as mutable

I could get around this second error by using interior mutability with a Mutex (RefCell doesn't work because it doesn't implement Sync), but the documentation of rust-jack especially discourages calling functions like pthread_mutex_lock in the process function, so this doesn't seem to be a good idea. For implementing the JackHandler trait for certain closures, an unsafe mutable transmute is used ( rust-jack/src/client/callbacks.rs, line 149), so that's still an option.

Am I missing something else? Is it a good idea to have the process function in the JackHandler take an &mut self parameter instead of &self?

Disable JACK logging?

I am currently writing a TUI application that uses Jack internally. Every time something happens, the Jack will happily spam my client, which will result in a messy wall of text over my UI.

Is there a way to silence these messages?

image

build fails on windows 8.1

Title is self-explanatory, here are the errors from running cargo build:

Compiling jack-sys v0.2.0 (file:///Z:/Dev/rust_libs/rust-jack/jack-sys)
error[E0412]: cannot find type `pthread_t` in module libc
  --> jack-sys\src\lib.rs:16:41
   |
16 | pub type jack_native_thread_t = ::libc::pthread_t;
   |                                         ^^^^^^^^^ not found in `libc`

error[E0412]: cannot find type `pthread_t` in module `libc`
   --> jack-sys\src\lib.rs:247:28
    |
247 |         arg1: *mut ::libc::pthread_t,
    |                            ^^^^^^^^^ not found in `libc`

error[E0412]: cannot find type `pthread_attr_t` in module `libc`
   --> jack-sys\src\lib.rs:248:30
    |
248 |         arg2: *const ::libc::pthread_attr_t,
    |                              ^^^^^^^^^^^^^^ not found in `libc`

error: aborting due to 3 previous errors

error: Could not compile `jack-sys`.

Is there no windows support currently? And if so, that should be mentioned in the README.

`notification_handler` and `process_handler` should be `mut`?

Isn't it a bug that notification_handler and process_handler are not required to be mut when passing them to client.activate_async(...)? Now I can pass in an immutable instance as e.g. process_handler and yet receive it as a &mut self in the process() callback which means I can mutate the context object.. Example:

fn main() {
    let context = Context { // not `mut` !
       foo: String::from("orig"),
    };
    let ac = client.activate_async((), context);
    ...
}

struct Context {
    foo: String,
}

impl ProcessHandler for Context {
    fn process(&mut self, client: &Client, ps: &ProcessScope) -> Control {
        self.foo = String::from("new"); // this is fine?
    }
}

how can I help?

I started this: https://github.com/dpzmick/rust-easyjack a while ago (because I eventually would like to get around to writing a synth) when it looked like this repo would just turn into some simple bindings on the jack api, but I really like what you have been doing here recently.

I'm pretty sure rust doesn't need 3 different incomplete and competing rust bindings:
image

It looks like you two have done some things much better than I have, if you would like I can direct my efforts at this project instead of continuing to work on my own.

JACK control

Implement JACK Control functionality. These are the functions prefixed with jackctl in the C API.

Implement Client::close properly

Client::close currently does nothing.

Edit: to clarify, the real purpose of Client::close is to trigger Drop. As such, it'd be more clear to call drop on self in the method (even though it's technically redundant).

Metadata API

As of the release v1.9.13, both Jack 1 and Jack 2 include the metadata API.

a 32 bit problem?

I'm on ubuntu studio 32 bit and this error appears when doing a basic compilation. I don't see it in another 64 bit system... Is it 32 bit related?

` Compiling jack v0.2.1
error[E0308]: mismatched types
--> /home/bdaemon/.cargo/registry/src/github.com-1ecc6299db9ec823/jack-0.2.1/src/client.rs:195:90
|
195 | let ports = j::jack_get_ports(self.client_ptr(), pnp.as_ptr(), tnp.as_ptr(), flags);
| ^^^^^ expected u32, found u64

error[E0308]: mismatched types
--> /home/bdaemon/.cargo/registry/src/github.com-1ecc6299db9ec823/jack-0.2.1/src/client.rs:482:35
|
482 | port_flags,
| ^^^^^^^^^^ expected u32, found u64

error[E0308]: mismatched types
--> /home/bdaemon/.cargo/registry/src/github.com-1ecc6299db9ec823/jack-0.2.1/src/client.rs:483:35
|
483 | buffer_size)
| ^^^^^^^^^^^ expected u32, found u64

error: aborting due to 3 previous errors

error: Could not compile jack.

`

JACK transport

First of all, I'd like to thank you all for this crate, it's really nice :-)

For a personal project, I need to have JACK transport functionalities, which are not implemented yet here. I might be able to contribute this feature to the crate myself, but I'm not exactly sure where to begin? Anyone knows what needs to be done, in order to add transport?

rust-jack doesn't compile on ARM

Hi I want to use rust-jack for some projects on raspberry pi, but it doesn't compile at present - there's a few places in the code where it uses i8 as a char type, but on ARM char is defined as u8.

Example error:

pi@raspberrypi:~/dev/rust/rust-jack $ cargo build
Compiling jack v0.5.3 (file:///home/pi/dev/rust/rust-jack)
error[E0308]: mismatched types
--> src/client/base.rs:270:26
|
270 | collect_strs(ports)
| ^^^^^ expected i8, found u8
|
= note: expected type *const *const i8
found type *mut *const u8

I think it's quite simple to fix, it looks like should be using libc::c_char which will be defined appropriately on each architecture, so in the case of jack_utils::collect_strs the signature would change from:

pub unsafe fn collect_strs(ptr: *const *const i8) -> Vec<String> {

to:

pub unsafe fn collect_strs(ptr: *const *const libc::c_char) -> Vec<String> {

I have the changes and tests passing locally on raspbian already - how do you guys like to work on this repo - can I raise a pull request, or should I fork the repo?

How to avoid polluting stdout when jack fails to connect?

If Jack is not started when I execute

  // Create client
  let c_res = jack::Client::new("rusty_client", jack::ClientOptions::NO_START_SERVER);

I get these messages on stdout

Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock
JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock

How can I avoid them?

callbacks are unsafe due to panicking

Currently, rust-jack does not catch panics at the FFI boundary, resulting in possible unsafety / undefined behaviour.

(c.f. the docs for std::panic::catch_unwind:)

It is currently undefined behavior to unwind from Rust code into foreign code, so this function is particularly useful when Rust is called from another language (normally C). This can run arbitrary Rust code, capturing a panic and allowing a graceful handling of the error.

Remove "Default" requirement from PortSpec

Hi,

What's the reason that PortSpec is defined with a requirement for Default like so:
pub unsafe trait PortSpec: Default + Sized {

Can the requirement it be removed?
The existing portspecs can have their defaults of course, so this change is backward compatible.

I am trying to use jack with a custom port type that needs to be initialized dynamically at runtime.

RUST_TEST_THREADS=1

Test may hang if RUST_TEST_THREADS is greater than 1.

Solutions:

  1. Configure cargo to always run tests with 1 thread always, tests will run slow.
  2. Make JACK work with multiple threads.

how to access `Client` from `JackHandler` safely

thanks for addressing #44 . I'm trying to use port_by_id() now from within a JackHandler::port_registration() to get the port name but I'm not sure how to access a Client from a JackHandler. what is a safe way to do this?

Merging jack-sys

@wmedrano and myself have been added as owners of the jack-sys crate. We should publish a new version that lives in this repo and has updated bindings (including the fn -> unsafe fn changes that are currently keeping this repo pinned against mine own fork of jack-sys.

JackHandler race condition

It isn't guaranteed that two callbacks can't be called at the same time.

Need to change usage to &mut usage to & within handlers.

Remove Client::thread_id

thread_id is currently unimplemented and feels like an intrinsic that shouldn't be available to the end user. Can this be removed?

Unable to find library when compiling examples

I'm attempting to compile this example but continue to get linker errors about missing libraries. I'm running OpenBSD with stable rust 1.38.0 and I do have JACK installed.

The relevant part of the error is this (if you need more I'm happy to provide):

          cc: error: linker command failed with exit code 1 (use -v to see invocation)

Thank you

libjack-dev dependency installation

Either the README should document that libjack-dev must be installed, or the installation should be done automatically. If automatic installation is provided, it should probably be added to the the upstream crate jack-sys.

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.