Background-audio handoff for video + repository/player refactor
Hand video playback off to a native audio-only stream when the app is backgrounded or locked, with no on-device video decode (UR-040). Adds player_enter/exit_background_audio commands, an audio-only stream URL for video items across the repository layer, and the frontend handoff state machine wired into VideoPlayer. Includes accompanying repository/offline/player refactoring and regenerates the traceability matrix.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
//! Tauri commands for playback reporting operations
|
||||
//!
|
||||
//! TRACES: UR-025, UR-019 | IR-015, JA-010, JA-011, JA-012 | DR-028
|
||||
//!
|
||||
//! These commands provide frontend access to the Rust playback reporting system,
|
||||
//! replacing the TypeScript implementation with native Rust reporting.
|
||||
//!
|
||||
@@ -16,7 +18,7 @@ use crate::commands::connectivity::ConnectivityMonitorWrapper;
|
||||
use crate::commands::storage::DatabaseWrapper;
|
||||
use crate::jellyfin::client::JellyfinClient;
|
||||
use crate::jellyfin::JellyfinConfig;
|
||||
use crate::playback_reporting::{PlaybackReporter, PlaybackOperation, PlaybackContext};
|
||||
use crate::playback_reporting::{PlaybackContext, PlaybackOperation, PlaybackReporter};
|
||||
use crate::utils::conversions::seconds_to_ticks;
|
||||
|
||||
/// Tauri state wrapper for PlaybackReporter
|
||||
@@ -61,7 +63,10 @@ pub async fn playback_reporter_init(
|
||||
// Store in wrapper
|
||||
*reporter_wrapper.0.lock().await = Some(reporter);
|
||||
|
||||
log::info!("[PlaybackReporter] Initialized successfully for user: {}", user_id);
|
||||
log::info!(
|
||||
"[PlaybackReporter] Initialized successfully for user: {}",
|
||||
user_id
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -205,7 +210,12 @@ mod tests {
|
||||
};
|
||||
|
||||
// Verify enum variant can be created and pattern matched
|
||||
if let PlaybackOperation::Start { item_id, position_ticks, context } = operation {
|
||||
if let PlaybackOperation::Start {
|
||||
item_id,
|
||||
position_ticks,
|
||||
context,
|
||||
} = operation
|
||||
{
|
||||
assert_eq!(item_id, "item-123");
|
||||
assert_eq!(position_ticks, 15_000_000);
|
||||
assert!(context.is_some());
|
||||
@@ -225,7 +235,10 @@ mod tests {
|
||||
context: None,
|
||||
};
|
||||
|
||||
if let PlaybackOperation::Start { item_id, context, .. } = operation {
|
||||
if let PlaybackOperation::Start {
|
||||
item_id, context, ..
|
||||
} = operation
|
||||
{
|
||||
assert_eq!(item_id, "item-789");
|
||||
assert!(context.is_none());
|
||||
} else {
|
||||
@@ -241,7 +254,12 @@ mod tests {
|
||||
is_paused: true,
|
||||
};
|
||||
|
||||
if let PlaybackOperation::Progress { item_id, position_ticks, is_paused } = operation {
|
||||
if let PlaybackOperation::Progress {
|
||||
item_id,
|
||||
position_ticks,
|
||||
is_paused,
|
||||
} = operation
|
||||
{
|
||||
assert_eq!(item_id, "item-999");
|
||||
assert_eq!(position_ticks, 30_000_000);
|
||||
assert!(is_paused);
|
||||
@@ -272,7 +290,11 @@ mod tests {
|
||||
position_ticks: 120_000_000,
|
||||
};
|
||||
|
||||
if let PlaybackOperation::Stopped { item_id, position_ticks } = operation {
|
||||
if let PlaybackOperation::Stopped {
|
||||
item_id,
|
||||
position_ticks,
|
||||
} = operation
|
||||
{
|
||||
assert_eq!(item_id, "item-111");
|
||||
assert_eq!(position_ticks, 120_000_000);
|
||||
} else {
|
||||
@@ -364,7 +386,10 @@ mod tests {
|
||||
};
|
||||
|
||||
let cloned = operation.clone();
|
||||
if let PlaybackOperation::Progress { item_id, is_paused, .. } = cloned {
|
||||
if let PlaybackOperation::Progress {
|
||||
item_id, is_paused, ..
|
||||
} = cloned
|
||||
{
|
||||
assert_eq!(item_id, "item-clone");
|
||||
assert!(is_paused);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user