Skip to content

Commit 543277d

Browse files
authored
refactor: split CI into quality, platforms, sanitizers workflows and fix lints (#1056)
1 parent 6179ea2 commit 543277d

File tree

20 files changed

+441
-266
lines changed

20 files changed

+441
-266
lines changed
Lines changed: 205 additions & 195 deletions
Large diffs are not rendered by default.

.github/workflows/quality.yml

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
name: Code Quality
2+
3+
on:
4+
push:
5+
branches: [master]
6+
paths-ignore:
7+
- "**.md"
8+
- "docs/**"
9+
- "LICENSE*"
10+
- ".gitignore"
11+
pull_request:
12+
branches: [master]
13+
paths-ignore:
14+
- "**.md"
15+
- "docs/**"
16+
- "LICENSE*"
17+
- ".gitignore"
18+
19+
jobs:
20+
formatting:
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v5
24+
25+
- name: Install Rust toolchain
26+
uses: dtolnay/rust-toolchain@stable
27+
with:
28+
components: rustfmt
29+
30+
- name: Check formatting
31+
run: cargo fmt --all -- --check
32+
33+
lints-stable:
34+
strategy:
35+
fail-fast: false
36+
matrix:
37+
include:
38+
# Linux - ALSA/JACK backend
39+
- target: x86_64-unknown-linux-gnu
40+
name: Linux
41+
features: --all-features
42+
os: ubuntu-latest
43+
44+
# Windows - WASAPI backend
45+
- target: x86_64-pc-windows-msvc
46+
name: Windows
47+
features: --all-features
48+
os: windows-latest
49+
50+
# macOS - CoreAudio backend
51+
- target: aarch64-apple-darwin
52+
name: macOS
53+
features: --all-features
54+
os: ubuntu-latest
55+
56+
# Android - Oboe backend
57+
- target: armv7-linux-androideabi
58+
name: Android
59+
features: ""
60+
os: ubuntu-latest
61+
62+
# iOS - CoreAudio (iOS) backend
63+
- target: aarch64-apple-ios
64+
name: iOS
65+
features: ""
66+
os: ubuntu-latest
67+
68+
# WASM - wasm-bindgen feature
69+
- target: wasm32-unknown-unknown
70+
name: WASM-bindgen
71+
features: --features wasm-bindgen
72+
os: ubuntu-latest
73+
74+
# WASM - Emscripten
75+
- target: wasm32-unknown-emscripten
76+
name: WASM-emscripten
77+
features: ""
78+
os: ubuntu-latest
79+
80+
# WASM - WASI
81+
- target: wasm32-wasip1
82+
name: WASI
83+
features: ""
84+
os: ubuntu-latest
85+
86+
name: clippy-${{ matrix.name }}
87+
runs-on: ${{ matrix.os }}
88+
steps:
89+
- uses: actions/checkout@v5
90+
91+
- name: Cache Linux audio packages
92+
if: runner.os == 'Linux'
93+
uses: awalsh128/cache-apt-pkgs-action@latest
94+
with:
95+
packages: libasound2-dev libjack-jackd2-dev libjack-jackd2-0 libdbus-1-dev
96+
97+
- name: Setup ASIO SDK
98+
if: runner.os == 'Windows'
99+
run: |
100+
curl -L -o asio.zip https://www.steinberg.net/asiosdk
101+
7z x -oasio asio.zip
102+
move asio\*\* asio\
103+
choco install asio4all
104+
choco install llvm
105+
106+
- name: Install Rust toolchain
107+
uses: dtolnay/rust-toolchain@stable
108+
with:
109+
components: clippy
110+
targets: ${{ matrix.target }}
111+
112+
- name: Rust Cache
113+
uses: Swatinem/rust-cache@v2
114+
with:
115+
key: clippy-${{ matrix.target }}-${{ matrix.name }}
116+
117+
- name: Run clippy
118+
env:
119+
CPAL_ASIO_DIR: ${{ runner.os == 'Windows' && format('{0}/asio', github.workspace) || '' }}
120+
run: cargo clippy --all --target ${{ matrix.target }} ${{ matrix.features }} -- -D warnings
121+
122+
lints-nightly:
123+
name: clippy-WASM-worklet
124+
runs-on: ubuntu-latest
125+
steps:
126+
- uses: actions/checkout@v5
127+
128+
- name: Cache Linux audio packages
129+
uses: awalsh128/cache-apt-pkgs-action@latest
130+
with:
131+
packages: libasound2-dev libjack-jackd2-dev libjack-jackd2-0 libdbus-1-dev
132+
133+
- name: Install Rust toolchain
134+
uses: dtolnay/rust-toolchain@nightly
135+
with:
136+
components: clippy, rust-src
137+
targets: wasm32-unknown-unknown
138+
139+
- name: Rust Cache
140+
uses: Swatinem/rust-cache@v2
141+
with:
142+
key: clippy-wasm32-worklet
143+
144+
- name: Run clippy (web_audio_worklet)
145+
env:
146+
RUSTFLAGS: -C target-feature=+atomics,+bulk-memory,+mutable-globals
147+
run: cargo +nightly clippy --all --target wasm32-unknown-unknown --features web_audio_worklet -Z build-std=std,panic_abort -- -D warnings

src/host/aaudio/java_interface.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@ mod definitions;
44
mod devices_info;
55
mod utils;
66

7-
pub use self::audio_features::*;
87
pub use self::definitions::*;

src/host/aaudio/java_interface/audio_manager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ fn get_frames_per_buffer<'j>(env: &mut JNIEnv<'j>, context: &JObject<'j>) -> JRe
2929
// TODO: Use jni::errors::Error::ParseFailed instead of jni::errors::Error::JniCall once jni > v0.21.1 is released
3030
frames_per_buffer_string
3131
.parse::<i32>()
32-
.map_err(|e| jni::errors::Error::JniCall(jni::errors::JniError::Unknown))
32+
.map_err(|_| jni::errors::Error::JniCall(jni::errors::JniError::Unknown))
3333
}

src/host/aaudio/mod.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,8 @@ unsafe impl Sync for Stream {}
144144
crate::assert_stream_send!(Stream);
145145
crate::assert_stream_sync!(Stream);
146146

147-
pub type SupportedInputConfigs = VecIntoIter<SupportedStreamConfigRange>;
148-
pub type SupportedOutputConfigs = VecIntoIter<SupportedStreamConfigRange>;
149-
pub type Devices = VecIntoIter<Device>;
147+
pub use crate::iter::{SupportedInputConfigs, SupportedOutputConfigs};
148+
pub type Devices = std::vec::IntoIter<Device>;
150149

151150
impl Host {
152151
pub fn new() -> Result<Self, crate::HostUnavailable> {
@@ -206,7 +205,7 @@ fn default_supported_configs() -> VecIntoIter<SupportedStreamConfigRange> {
206205
channels: *channel_count,
207206
min_sample_rate: SampleRate(*sample_rate as u32),
208207
max_sample_rate: SampleRate(*sample_rate as u32),
209-
buffer_size: buffer_size.clone(),
208+
buffer_size,
210209
sample_format: *sample_format,
211210
});
212211
}
@@ -252,7 +251,7 @@ fn device_supported_configs(device: &AudioDeviceInfo) -> VecIntoIter<SupportedSt
252251
channels: cmp::min(*channel_count as u16, 2u16),
253252
min_sample_rate: SampleRate(*sample_rate as u32),
254253
max_sample_rate: SampleRate(*sample_rate as u32),
255-
buffer_size: buffer_size.clone(),
254+
buffer_size,
256255
sample_format: *format,
257256
});
258257
}
@@ -323,6 +322,10 @@ where
323322
(error_callback)(StreamError::from(error))
324323
}))
325324
.open_stream()?;
325+
// SAFETY: Stream implements Send + Sync (see unsafe impl below). Arc<Mutex<AudioStream>>
326+
// is safe because the Mutex provides exclusive access and AudioStream's thread safety
327+
// is documented in the AAudio C API.
328+
#[allow(clippy::arc_with_non_send_sync)]
326329
Ok(Stream::Input(Arc::new(Mutex::new(stream))))
327330
}
328331

@@ -365,6 +368,10 @@ where
365368
(error_callback)(StreamError::from(error))
366369
}))
367370
.open_stream()?;
371+
// SAFETY: Stream implements Send + Sync (see unsafe impl below). Arc<Mutex<AudioStream>>
372+
// is safe because the Mutex provides exclusive access and AudioStream's thread safety
373+
// is documented in the AAudio C API.
374+
#[allow(clippy::arc_with_non_send_sync)]
368375
Ok(Stream::Output(Arc::new(Mutex::new(stream))))
369376
}
370377

src/host/alsa/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,7 @@ fn parse_alsa_description(description: &str) -> Vec<String> {
9292
// (start_threshold = 2 periods), ensuring low latency even with large multi-period ring
9393
// buffers.
9494

95-
pub type SupportedInputConfigs = VecIntoIter<SupportedStreamConfigRange>;
96-
pub type SupportedOutputConfigs = VecIntoIter<SupportedStreamConfigRange>;
95+
pub use crate::iter::{SupportedInputConfigs, SupportedOutputConfigs};
9796

9897
mod enumerate;
9998

src/host/asio/device.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
pub type SupportedInputConfigs = std::vec::IntoIter<SupportedStreamConfigRange>;
2-
pub type SupportedOutputConfigs = std::vec::IntoIter<SupportedStreamConfigRange>;
1+
pub use crate::iter::{SupportedInputConfigs, SupportedOutputConfigs};
32

43
use super::sys;
54
use crate::BackendSpecificError;
65
use crate::ChannelCount;
76
use crate::DefaultStreamConfigError;
87
use crate::DeviceDescription;
98
use crate::DeviceDescriptionBuilder;
10-
use crate::DeviceDirection;
119
use crate::DeviceId;
1210
use crate::DeviceIdError;
1311
use crate::DeviceNameError;

src/host/asio/stream.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ impl Device {
221221
}
222222

223223
(&sys::AsioSampleType::ASIOSTInt24LSB, SampleFormat::I24) => {
224-
process_input_callback_i24::<I24, _>(
224+
process_input_callback_i24(
225225
&mut data_callback,
226226
&mut interleaved,
227227
asio_stream,
@@ -231,7 +231,7 @@ impl Device {
231231
);
232232
}
233233
(&sys::AsioSampleType::ASIOSTInt24MSB, SampleFormat::I24) => {
234-
process_input_callback_i24::<I24, _>(
234+
process_input_callback_i24(
235235
&mut data_callback,
236236
&mut interleaved,
237237
asio_stream,
@@ -326,6 +326,7 @@ impl Device {
326326
/// 2. If required, silence the ASIO buffer.
327327
/// 3. Finally, write the interleaved data to the non-interleaved ASIO buffer,
328328
/// performing endianness conversions as necessary.
329+
#[allow(clippy::too_many_arguments)]
329330
unsafe fn process_output_callback<A, D, F>(
330331
data_callback: &mut D,
331332
interleaved: &mut [u8],
@@ -745,7 +746,7 @@ unsafe fn asio_channel_slice<T>(
745746
) -> &[T] {
746747
let channel_length = requested_channel_length.unwrap_or(asio_stream.buffer_size as usize);
747748
let buff_ptr: *const T =
748-
asio_stream.buffer_infos[channel_index].buffers[buffer_index as usize] as *const _;
749+
asio_stream.buffer_infos[channel_index].buffers[buffer_index] as *const _;
749750
std::slice::from_raw_parts(buff_ptr, channel_length)
750751
}
751752

@@ -760,8 +761,7 @@ unsafe fn asio_channel_slice_mut<T>(
760761
requested_channel_length: Option<usize>,
761762
) -> &mut [T] {
762763
let channel_length = requested_channel_length.unwrap_or(asio_stream.buffer_size as usize);
763-
let buff_ptr: *mut T =
764-
asio_stream.buffer_infos[channel_index].buffers[buffer_index as usize] as *mut _;
764+
let buff_ptr: *mut T = asio_stream.buffer_infos[channel_index].buffers[buffer_index] as *mut _;
765765
std::slice::from_raw_parts_mut(buff_ptr, channel_length)
766766
}
767767

@@ -862,15 +862,14 @@ unsafe fn process_output_callback_i24<D>(
862862
}
863863
}
864864

865-
unsafe fn process_input_callback_i24<A, D>(
865+
unsafe fn process_input_callback_i24<D>(
866866
data_callback: &mut D,
867867
interleaved: &mut [u8],
868868
asio_stream: &sys::AsioStream,
869869
asio_info: &sys::CallbackInfo,
870870
sample_rate: crate::SampleRate,
871871
little_endian: bool,
872872
) where
873-
A: Copy,
874873
D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
875874
{
876875
let format = SampleFormat::I24;

src/host/coreaudio/ios/enumerate.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
use std::vec::IntoIter as VecIntoIter;
22

3-
use crate::DevicesError;
4-
use crate::SupportedStreamConfigRange;
5-
63
use super::Device;
74

8-
pub type SupportedInputConfigs = ::std::vec::IntoIter<SupportedStreamConfigRange>;
9-
pub type SupportedOutputConfigs = ::std::vec::IntoIter<SupportedStreamConfigRange>;
5+
pub use crate::iter::{SupportedInputConfigs, SupportedOutputConfigs};
106

117
// TODO: Support enumerating earpiece vs headset vs speaker etc?
128
pub struct Devices(VecIntoIter<Device>);

src/host/coreaudio/ios/mod.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use std::sync::Mutex;
55
use coreaudio::audio_unit::render_callback::data;
66
use coreaudio::audio_unit::{render_callback, AudioUnit, Element, Scope};
77
use objc2_audio_toolbox::{kAudioOutputUnitProperty_EnableIO, kAudioUnitProperty_StreamFormat};
8-
use objc2_core_audio::kAudioDevicePropertyBufferFrameSize;
98
use objc2_core_audio_types::AudioBuffer;
109

1110
use objc2_avf_audio::AVAudioSession;
@@ -106,15 +105,15 @@ impl Device {
106105
get_supported_stream_configs(true)
107106
.next()
108107
.map(|range| range.with_max_sample_rate())
109-
.ok_or_else(|| DefaultStreamConfigError::StreamTypeNotSupported)
108+
.ok_or(DefaultStreamConfigError::StreamTypeNotSupported)
110109
}
111110

112111
fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
113112
// Get the maximum channel count config from supported configs
114113
get_supported_stream_configs(false)
115114
.last()
116115
.map(|range| range.with_max_sample_rate())
117-
.ok_or_else(|| DefaultStreamConfigError::StreamTypeNotSupported)
116+
.ok_or(DefaultStreamConfigError::StreamTypeNotSupported)
118117
}
119118
}
120119

@@ -380,7 +379,7 @@ fn get_supported_stream_configs(is_input: bool) -> std::vec::IntoIter<SupportedS
380379
channels,
381380
min_sample_rate: SampleRate(sample_rate),
382381
max_sample_rate: SampleRate(sample_rate),
383-
buffer_size: buffer_size.clone(),
382+
buffer_size,
384383
sample_format: SUPPORTED_SAMPLE_FORMAT,
385384
})
386385
.collect();
@@ -439,7 +438,7 @@ unsafe fn extract_audio_buffer(
439438
) -> (AudioBuffer, Data) {
440439
let buffer = if is_input {
441440
// Input: access through buffer array
442-
let ptr = (*args.data.data).mBuffers.as_ptr() as *const AudioBuffer;
441+
let ptr = (*args.data.data).mBuffers.as_ptr();
443442
let len = (*args.data.data).mNumberBuffers as usize;
444443
let buffers: &[AudioBuffer] = slice::from_raw_parts(ptr, len);
445444
buffers[0]
@@ -449,7 +448,7 @@ unsafe fn extract_audio_buffer(
449448
};
450449

451450
let data = buffer.mData as *mut ();
452-
let len = (buffer.mDataByteSize as usize / bytes_per_channel) as usize;
451+
let len = buffer.mDataByteSize as usize / bytes_per_channel;
453452
let data = Data::from_parts(data, len, sample_format);
454453

455454
(buffer, data)

0 commit comments

Comments
 (0)