Skip to content

Commit 4d9c4f8

Browse files
authored
Log before JACK library calls commence. (#208)
* Enable jack logging sooner. - Make `log` crate an optional dependency. - Write documentation for available features. * Bump version.
1 parent 23ac4a5 commit 4d9c4f8

File tree

15 files changed

+322
-117
lines changed

15 files changed

+322
-117
lines changed

.github/workflows/linting.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ jobs:
1515
- name: Checkout
1616
uses: actions/checkout@v2
1717
- name: Install dependencies
18-
run: sudo apt update && sudo apt install jackd libjack0 libjack-dev
18+
run: sudo apt update && sudo apt install jackd2 libjack-jackd2-0 libjack-jackd2-dev
1919
- name: Lint (No Features)
20-
run: cargo clippy --all-targets --no-default-features -- -D clippy::all
20+
run: cargo clippy --all-targets -- -D clippy::all
2121
- name: Lint (metadata)
2222
run: cargo clippy --all-targets --no-default-features --features metadata -- -D clippy::all
2323
- name: Cargo Fmt

Cargo.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ license = "MIT"
88
name = "jack"
99
readme = "README.md"
1010
repository = "https://github.com/RustAudio/rust-jack"
11-
version = "0.12.1"
11+
version = "0.12.2"
1212

1313
[dependencies]
1414
bitflags = "2"
1515
jack-sys = {version = "0.5", path = "./jack-sys"}
1616
lazy_static = "1.4"
1717
libc = "0.2"
18-
log = "0.4"
18+
log = { version = "0.4", optional = true}
1919

2020
[dev-dependencies]
2121
crossbeam-channel = "0.5"
2222

2323
[features]
24-
default = ["dynamic_loading"]
25-
metadata = []
26-
dynamic_loading = ["jack-sys/dynamic_loading"]
24+
default = ["dynamic_loading", "log"]
25+
dynamic_loading = ["jack-sys/dynamic_loading"]
26+
metadata = []

docs/features.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
layout: page
3+
title: Features
4+
permalink: /features
5+
nav_order: 1
6+
---
7+
8+
# Features
9+
10+
The Rust features for the `jack` crate are defined in
11+
<https://github.com/RustAudio/rust-jack/blob/main/Cargo.toml>. To see the
12+
documentation for Rust features in general, see the [Rust
13+
Book](https://doc.rust-lang.org/cargo/reference/features.html).
14+
15+
## Disabling Default Features
16+
17+
The `jack` crate ships with a reasonable set of default features. To enable just
18+
a subset of features, set `default-features` to false and select only the
19+
desired features.
20+
21+
```toml
22+
jack = { version = "..", default-features = false, features = ["log"] }
23+
```
24+
25+
## `log`
26+
27+
Default: Yes
28+
29+
If the [`log` crate](https://crates.io/crates/log) should be used to handle JACK
30+
logging. Requires setting up a logging implementation to make messages
31+
available.
32+
33+
## `dynamic_loading`
34+
35+
Default: Yes
36+
37+
Load `libjack` at runtime as opposed to the standard dynamic linking. This is
38+
preferred as it allows `pw-jack` to intercept the loading at runtime to provide
39+
the Pipewire JACK server implementation.
40+
41+
## `metadata`
42+
43+
Default: No
44+
45+
Provides access to the metadata API. This is experimental. Details on the JACK
46+
metadata API can be found at <https://jackaudio.org/metadata/>.

docs/logging.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
layout: page
3+
title: Logging
4+
permalink: /logging
5+
nav_order: 2
6+
---
7+
8+
# Logging
9+
10+
JACK can communicate info and error messages. By default, the [log
11+
crate](https://github.com/rust-lang/log) is hooked up to output
12+
messages. However, other logging methods can be used with the
13+
[`set_logger`](https://docs.rs/jack/latest/jack/fn.set_logger.html) function.
14+
15+
## No Logging
16+
17+
Logging from `jack` can be disabled entirely by setting the logger to `None`.
18+
19+
```rust
20+
jack::set_logger(jack::LoggerType::None);
21+
```
22+
23+
## Log Crate (default)
24+
25+
The log crate is the default logger if the `log` feature is enabled, which is
26+
enabled by default. The `log` crate provides a *facade* for logging; it provides
27+
macros to perform logging, but another mechanism or crate is required to
28+
actually perform the logging.
29+
30+
In the example below, we use the [`env_logger` crate]() to display logging for
31+
info and error severity level messages.
32+
33+
```rust
34+
env_logger::builder().filter(None, log::LevelFilter::Info).init();
35+
36+
// JACK may log things to `info!` or `error!`.
37+
let (client, _status) =
38+
jack::Client::new("rust_jack_simple", jack::ClientOptions::NO_START_SERVER).unwrap();
39+
```
40+
41+
42+
## Stdio
43+
44+
If the `log` feature is not enabled, then `jack` will log info messages to
45+
`stdout` and error messages to `stderr`. These usually show up in the terminal.
46+
47+
```rust
48+
jack::set_logger(jack::LoggerType::Stdio);
49+
```

docs/quickstart.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
layout: page
33
title: Quickstart
44
permalink: /
5+
nav_order: 0
56
---
67

78
# Quickstart

examples/playback_capture.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,24 @@ use std::io;
44

55
fn main() {
66
// Create client
7+
jack::set_logger(jack::LoggerType::Stdio);
78
let (client, _status) =
89
jack::Client::new("rust_jack_simple", jack::ClientOptions::NO_START_SERVER).unwrap();
910

1011
// Register ports. They will be used in a callback that will be
1112
// called when new data is available.
12-
let in_a = client.register_port("rust_in_l", jack::AudioIn).unwrap();
13-
let in_b = client.register_port("rust_in_r", jack::AudioIn).unwrap();
14-
let mut out_a = client.register_port("rust_out_l", jack::AudioOut).unwrap();
15-
let mut out_b = client.register_port("rust_out_r", jack::AudioOut).unwrap();
13+
let in_a = client
14+
.register_port("rust_in_l", jack::AudioIn::default())
15+
.unwrap();
16+
let in_b = client
17+
.register_port("rust_in_r", jack::AudioIn::default())
18+
.unwrap();
19+
let mut out_a = client
20+
.register_port("rust_out_l", jack::AudioOut::default())
21+
.unwrap();
22+
let mut out_b = client
23+
.register_port("rust_out_r", jack::AudioOut::default())
24+
.unwrap();
1625
let process_callback = move |_: &jack::Client, ps: &jack::ProcessScope| -> jack::Control {
1726
let out_a_p = out_a.as_mut_slice(ps);
1827
let out_b_p = out_b.as_mut_slice(ps);

examples/sine.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ fn main() {
1111
jack::Client::new("rust_jack_sine", jack::ClientOptions::NO_START_SERVER).unwrap();
1212

1313
// 2. register port
14-
let mut out_port = client.register_port("sine_out", jack::AudioOut).unwrap();
14+
let mut out_port = client
15+
.register_port("sine_out", jack::AudioOut::default())
16+
.unwrap();
1517

1618
// 3. define process callback handler
1719
let mut frequency = 220.0;

src/client/async_client.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ where
5252
/// `notification_handler` and `process_handler` are consumed, but they are returned when
5353
/// `Client::deactivate` is called.
5454
pub fn new(client: Client, notification_handler: N, process_handler: P) -> Result<Self, Error> {
55-
let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().unwrap();
55+
let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().ok();
5656
unsafe {
5757
sleep_on_test();
5858
let mut callback_context = Box::new(CallbackContext {
@@ -107,7 +107,7 @@ impl<N, P> AsyncClient<N, P> {
107107
// Helper function for deactivating. Any function that calls this should
108108
// have ownership of self and no longer use it after this call.
109109
unsafe fn maybe_deactivate(&mut self) -> Result<Box<CallbackContext<N, P>>, Error> {
110-
let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().unwrap();
110+
let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().ok();
111111
if self.callback.is_none() {
112112
return Err(Error::ClientIsNoLongerAlive);
113113
}

src/client/client_impl.rs

Lines changed: 4 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use jack_sys as j;
22
use std::fmt::Debug;
3-
use std::panic::catch_unwind;
43
use std::sync::Arc;
54
use std::{ffi, fmt, ptr};
65

@@ -51,7 +50,7 @@ impl Client {
5150
/// Although the client may be successful in opening, there still may be some errors minor
5251
/// errors when attempting to opening. To access these, check the returned `ClientStatus`.
5352
pub fn new(client_name: &str, options: ClientOptions) -> Result<(Self, ClientStatus), Error> {
54-
let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().unwrap();
53+
let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().ok();
5554

5655
// All of the jack_sys functions below assume the client library is loaded and will panic if
5756
// it is not
@@ -60,10 +59,7 @@ impl Client {
6059
return Err(Error::LibraryError(err.to_string()));
6160
}
6261

63-
unsafe {
64-
jack_sys::jack_set_error_function(Some(silent_handler));
65-
jack_sys::jack_set_info_function(Some(silent_handler));
66-
}
62+
crate::logging::maybe_init_logging();
6763
sleep_on_test();
6864
let mut status_bits = 0;
6965
let client = unsafe {
@@ -75,10 +71,6 @@ impl Client {
7571
if client.is_null() {
7672
Err(Error::ClientError(status))
7773
} else {
78-
unsafe {
79-
jack_sys::jack_set_error_function(Some(error_handler));
80-
jack_sys::jack_set_info_function(Some(info_handler));
81-
}
8274
sleep_on_test();
8375
Ok((Client(client, Arc::default(), None), status))
8476
}
@@ -552,7 +544,7 @@ impl Client {
552544
source_port: &Port<A>,
553545
destination_port: &Port<B>,
554546
) -> Result<(), Error> {
555-
let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().unwrap();
547+
let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().ok();
556548
self.connect_ports_by_name(&source_port.name()?, &destination_port.name()?)
557549
}
558550

@@ -670,7 +662,7 @@ impl Client {
670662
/// Close the client.
671663
impl Drop for Client {
672664
fn drop(&mut self) {
673-
let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().unwrap();
665+
let _m = CREATE_OR_DESTROY_CLIENT_MUTEX.lock().ok();
674666
debug_assert!(!self.raw().is_null()); // Rep invariant
675667
// Close the client
676668
sleep_on_test();
@@ -790,27 +782,3 @@ pub struct CycleTimes {
790782
pub next_usecs: Time,
791783
pub period_usecs: libc::c_float,
792784
}
793-
794-
unsafe extern "C" fn error_handler(msg: *const libc::c_char) {
795-
let res = catch_unwind(|| match std::ffi::CStr::from_ptr(msg).to_str() {
796-
Ok(msg) => log::error!("{}", msg),
797-
Err(err) => log::error!("failed to log to JACK error: {:?}", err),
798-
});
799-
if let Err(err) = res {
800-
eprintln!("{err:?}");
801-
std::mem::forget(err);
802-
}
803-
}
804-
805-
unsafe extern "C" fn info_handler(msg: *const libc::c_char) {
806-
let res = catch_unwind(|| match std::ffi::CStr::from_ptr(msg).to_str() {
807-
Ok(msg) => log::info!("{}", msg),
808-
Err(err) => log::error!("failed to log to JACK info: {:?}", err),
809-
});
810-
if let Err(err) = res {
811-
eprintln!("{err:?}");
812-
std::mem::forget(err);
813-
}
814-
}
815-
816-
unsafe extern "C" fn silent_handler(_msg: *const libc::c_char) {}

src/client/test_callback.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,14 @@ fn client_cback_reports_xruns() {
211211
#[test]
212212
fn client_cback_calls_port_registered() {
213213
let ac = active_test_client("client_cback_cpr");
214-
let _pa = ac.as_client().register_port("pa", AudioIn).unwrap();
215-
let _pb = ac.as_client().register_port("pb", AudioIn).unwrap();
214+
let _pa = ac
215+
.as_client()
216+
.register_port("pa", AudioIn::default())
217+
.unwrap();
218+
let _pb = ac
219+
.as_client()
220+
.register_port("pb", AudioIn::default())
221+
.unwrap();
216222
let counter = ac.deactivate().unwrap().1;
217223
assert_eq!(
218224
counter.port_register_history.len(),
@@ -228,8 +234,14 @@ fn client_cback_calls_port_registered() {
228234
#[test]
229235
fn client_cback_calls_port_unregistered() {
230236
let ac = active_test_client("client_cback_cpr");
231-
let pa = ac.as_client().register_port("pa", AudioIn).unwrap();
232-
let pb = ac.as_client().register_port("pb", AudioIn).unwrap();
237+
let pa = ac
238+
.as_client()
239+
.register_port("pa", AudioIn::default())
240+
.unwrap();
241+
let pb = ac
242+
.as_client()
243+
.register_port("pb", AudioIn::default())
244+
.unwrap();
233245
ac.as_client().unregister_port(pa).unwrap();
234246
ac.as_client().unregister_port(pb).unwrap();
235247
let counter = ac.deactivate().unwrap().1;

0 commit comments

Comments
 (0)