+45
-16
src/app.rs
+45
-16
src/app.rs
···
338
) {
339
let new_state = cmd_rx.recv().await.unwrap();
340
341
-
// report metadata to OS
342
send_os_media_controls_command(
343
self.os_media_controls.as_mut(),
344
os_media_controls::Command::SetMetadata(souvlaki::MediaMetadata {
345
-
title: (!new_state.now_playing.is_empty()).then_some(&new_state.now_playing),
346
-
album: (!new_state.name.is_empty()).then_some(&new_state.name),
347
artist: None,
348
cover_url: None,
349
duration: None,
350
}),
351
);
352
-
// report started playing to OS
353
send_os_media_controls_command(
354
self.os_media_controls.as_mut(),
355
os_media_controls::Command::Play,
356
);
357
-
// report volume to OS
358
send_os_media_controls_command(
359
self.os_media_controls.as_mut(),
360
os_media_controls::Command::SetVolume(new_state.volume.volume_ratio() as f64),
361
);
362
363
let new_state = Arc::new(Mutex::new(new_state));
364
-
365
let id = id.to_string();
366
let new_state_clone = new_state.clone();
367
368
-
thread::spawn(move || loop {
369
let rt = tokio::runtime::Runtime::new().unwrap();
370
rt.block_on(async {
371
-
let mut new_state = new_state_clone.lock().unwrap();
372
-
// Get current playing if available, otherwise use state's value
373
-
new_state.now_playing = get_currently_playing(&id).await.unwrap_or_default();
374
-
drop(new_state);
375
-
std::thread::sleep(Duration::from_millis(10000));
376
});
377
});
378
379
let mut fps = 0;
380
let mut framerate = 0;
381
let mut last_poll = Instant::now();
382
383
loop {
384
let channels = if self.graph.pause {
385
None
386
} else {
387
let Ok(audio_frame) = self.frame_rx.recv() else {
388
-
// other thread has closed so application has
389
-
// closed
390
return;
391
};
392
Some(stream_to_matrix(
···
441
size.y += 8;
442
}
443
let chart = Chart::new(datasets.iter().map(|x| x.into()).collect())
444
-
.x_axis(current_display.axis(&self.graph, Dimension::X)) // TODO allow to have axis sometimes?
445
.y_axis(current_display.axis(&self.graph, Dimension::Y));
446
f.render_widget(chart, size)
447
}
448
})
449
.unwrap();
450
}
451
452
while let Some(event) = self
···
481
}
482
}
483
}
484
-
485
fn current_display_mut(&mut self) -> Option<&mut dyn DisplayMode> {
486
match self.mode {
487
CurrentDisplayMode::Oscilloscope => {
···
338
) {
339
let new_state = cmd_rx.recv().await.unwrap();
340
341
+
let now_playing = new_state.now_playing.clone();
342
+
let name = new_state.name.clone();
343
+
// Report initial metadata to OS
344
send_os_media_controls_command(
345
self.os_media_controls.as_mut(),
346
os_media_controls::Command::SetMetadata(souvlaki::MediaMetadata {
347
+
title: (!now_playing.is_empty()).then(|| now_playing.as_str()),
348
+
album: (!name.is_empty()).then(|| name.as_str()),
349
artist: None,
350
cover_url: None,
351
duration: None,
352
}),
353
);
354
+
// Report started playing to OS
355
send_os_media_controls_command(
356
self.os_media_controls.as_mut(),
357
os_media_controls::Command::Play,
358
);
359
+
// Report volume to OS
360
send_os_media_controls_command(
361
self.os_media_controls.as_mut(),
362
os_media_controls::Command::SetVolume(new_state.volume.volume_ratio() as f64),
363
);
364
365
let new_state = Arc::new(Mutex::new(new_state));
366
let id = id.to_string();
367
let new_state_clone = new_state.clone();
368
369
+
// Background thread to update now_playing
370
+
thread::spawn(move || {
371
let rt = tokio::runtime::Runtime::new().unwrap();
372
rt.block_on(async {
373
+
loop {
374
+
let mut new_state = new_state_clone.lock().unwrap();
375
+
// Get current playing if available, otherwise use default
376
+
let now_playing = get_currently_playing(&id).await.unwrap_or_default();
377
+
if new_state.now_playing != now_playing {
378
+
new_state.now_playing = now_playing;
379
+
}
380
+
drop(new_state);
381
+
std::thread::sleep(Duration::from_millis(10000));
382
+
}
383
});
384
});
385
386
let mut fps = 0;
387
let mut framerate = 0;
388
let mut last_poll = Instant::now();
389
+
let mut last_metadata_update = Instant::now();
390
+
let mut last_now_playing = String::new();
391
+
const METADATA_UPDATE_INTERVAL: Duration = Duration::from_secs(1); // Check every second
392
393
loop {
394
let channels = if self.graph.pause {
395
None
396
} else {
397
let Ok(audio_frame) = self.frame_rx.recv() else {
398
+
// other thread has closed so application has closed
399
return;
400
};
401
Some(stream_to_matrix(
···
450
size.y += 8;
451
}
452
let chart = Chart::new(datasets.iter().map(|x| x.into()).collect())
453
+
.x_axis(current_display.axis(&self.graph, Dimension::X))
454
.y_axis(current_display.axis(&self.graph, Dimension::Y));
455
f.render_widget(chart, size)
456
}
457
})
458
.unwrap();
459
+
460
+
// Update metadata only if needed and at a controlled interval
461
+
if last_metadata_update.elapsed() >= METADATA_UPDATE_INTERVAL {
462
+
let state = new_state.lock().unwrap();
463
+
if state.now_playing != last_now_playing {
464
+
let now_playing = state.now_playing.clone();
465
+
let name = state.name.clone();
466
+
send_os_media_controls_command(
467
+
self.os_media_controls.as_mut(),
468
+
os_media_controls::Command::SetMetadata(souvlaki::MediaMetadata {
469
+
title: (!now_playing.is_empty()).then_some(now_playing.as_str()),
470
+
album: (!name.is_empty()).then_some(name.as_str()),
471
+
artist: None,
472
+
cover_url: None,
473
+
duration: None,
474
+
}),
475
+
);
476
+
last_now_playing = state.now_playing.clone();
477
+
}
478
+
last_metadata_update = Instant::now();
479
+
}
480
}
481
482
while let Some(event) = self
···
511
}
512
}
513
}
514
fn current_display_mut(&mut self) -> Option<&mut dyn DisplayMode> {
515
match self.mode {
516
CurrentDisplayMode::Oscilloscope => {
+3
-2
src/play.rs
+3
-2
src/play.rs