Skip to content

Commit 09c19cc

Browse files
committed
[add] tests for inactive instances, update comments, and fix dead code placement.
1 parent 13f8dc6 commit 09c19cc

File tree

1 file changed

+41
-11
lines changed

1 file changed

+41
-11
lines changed

crates/lambda-rs/src/audio/playback.rs

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ const PLAYBACK_COMMAND_CAPACITY: usize = 256;
4242
/// # Safety
4343
/// This type is only sound when used as SPSC (exactly one producer thread and
4444
/// one consumer thread).
45-
#[allow(dead_code)]
4645
struct CommandQueue<T, const CAPACITY: usize> {
4746
buffer: [UnsafeCell<MaybeUninit<T>>; CAPACITY],
4847
head: AtomicUsize,
@@ -52,7 +51,6 @@ struct CommandQueue<T, const CAPACITY: usize> {
5251
unsafe impl<T: Send, const CAPACITY: usize> Send for CommandQueue<T, CAPACITY> {}
5352
unsafe impl<T: Send, const CAPACITY: usize> Sync for CommandQueue<T, CAPACITY> {}
5453

55-
#[allow(dead_code)]
5654
impl<T, const CAPACITY: usize> CommandQueue<T, CAPACITY> {
5755
/// Create a new empty queue.
5856
///
@@ -219,7 +217,6 @@ impl GainRamp {
219217
///
220218
/// This scheduler is designed to run inside a real-time audio callback and
221219
/// MUST NOT allocate or block while rendering audio.
222-
#[allow(dead_code)]
223220
struct PlaybackScheduler {
224221
state: PlaybackState,
225222
looping: bool,
@@ -231,7 +228,6 @@ struct PlaybackScheduler {
231228
last_frame_samples: [f32; MAX_PLAYBACK_CHANNELS],
232229
}
233230

234-
#[allow(dead_code)]
235231
impl PlaybackScheduler {
236232
/// Create a scheduler configured for a fixed output channel count.
237233
///
@@ -240,6 +236,7 @@ impl PlaybackScheduler {
240236
///
241237
/// # Returns
242238
/// A scheduler initialized to `Stopped` with no buffer.
239+
#[allow(dead_code)]
243240
fn new(channels: usize) -> Self {
244241
return Self::new_with_ramp_frames(channels, DEFAULT_GAIN_RAMP_FRAMES);
245242
}
@@ -333,6 +330,7 @@ impl PlaybackScheduler {
333330
///
334331
/// # Returns
335332
/// The cursor position as an interleaved sample index.
333+
#[allow(dead_code)]
336334
fn cursor_samples(&self) -> usize {
337335
return self.cursor_samples;
338336
}
@@ -426,7 +424,6 @@ impl PlaybackScheduler {
426424

427425
/// Commands produced by `SoundInstance` transport operations.
428426
#[derive(Debug)]
429-
#[allow(dead_code)]
430427
enum PlaybackCommand {
431428
StopCurrent,
432429
SetBuffer {
@@ -546,14 +543,12 @@ fn playback_state_from_u8(value: u8) -> PlaybackState {
546543
/// A callback-safe controller that drains transport commands and renders audio.
547544
///
548545
/// This type is intended to be owned by the platform audio callback closure.
549-
#[allow(dead_code)]
550546
struct PlaybackController<const COMMAND_CAPACITY: usize> {
551547
command_queue: Arc<CommandQueue<PlaybackCommand, COMMAND_CAPACITY>>,
552548
shared_state: Arc<PlaybackSharedState>,
553549
scheduler: PlaybackScheduler,
554550
}
555551

556-
#[allow(dead_code)]
557552
impl<const COMMAND_CAPACITY: usize> PlaybackController<COMMAND_CAPACITY> {
558553
/// Create a controller configured for a fixed output channel count.
559554
///
@@ -563,6 +558,7 @@ impl<const COMMAND_CAPACITY: usize> PlaybackController<COMMAND_CAPACITY> {
563558
///
564559
/// # Returns
565560
/// A controller initialized to `Stopped` with no active buffer.
561+
#[allow(dead_code)]
566562
fn new(
567563
channels: usize,
568564
command_queue: Arc<CommandQueue<PlaybackCommand, COMMAND_CAPACITY>>,
@@ -804,10 +800,6 @@ impl SoundInstance {
804800
}
805801

806802
/// A playback context owning an output device and one active playback slot.
807-
///
808-
/// This type is a placeholder API surface used while sound playback is under
809-
/// active development. It is expected to become fully functional in a
810-
/// subsequent change set.
811803
pub struct AudioContext {
812804
_output_device: AudioOutputDevice,
813805
command_queue: Arc<PlaybackCommandQueue>,
@@ -1344,4 +1336,42 @@ mod tests {
13441336
assert!(writer.max_abs() <= f32::EPSILON);
13451337
return;
13461338
}
1339+
1340+
/// `SoundInstance` methods MUST be no-ops when the instance is inactive.
1341+
#[test]
1342+
fn sound_instance_is_no_op_when_inactive() {
1343+
let command_queue: Arc<PlaybackCommandQueue> =
1344+
Arc::new(CommandQueue::new());
1345+
let shared_state = Arc::new(PlaybackSharedState::new());
1346+
1347+
shared_state.set_active_instance_id(1);
1348+
shared_state.set_state(PlaybackState::Playing);
1349+
1350+
let mut instance = SoundInstance {
1351+
instance_id: 1,
1352+
command_queue: command_queue.clone(),
1353+
shared_state: shared_state.clone(),
1354+
};
1355+
1356+
assert_eq!(instance.state(), PlaybackState::Playing);
1357+
assert!(instance.is_playing());
1358+
assert!(!instance.is_paused());
1359+
assert!(!instance.is_stopped());
1360+
1361+
shared_state.set_active_instance_id(2);
1362+
shared_state.set_state(PlaybackState::Paused);
1363+
1364+
assert_eq!(instance.state(), PlaybackState::Stopped);
1365+
assert!(!instance.is_playing());
1366+
assert!(!instance.is_paused());
1367+
assert!(instance.is_stopped());
1368+
1369+
instance.play();
1370+
instance.pause();
1371+
instance.stop();
1372+
instance.set_looping(true);
1373+
1374+
assert!(command_queue.pop().is_none());
1375+
return;
1376+
}
13471377
}

0 commit comments

Comments
 (0)