use iceoryx2::port::subscriber::Subscriber;
use iceoryx2::prelude::*;
use iceoryx2::service::ipc::Service;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};
use e_midi_shared::ipc_protocol::PlaySongAtHeartbeat;
pub const E_MIDI_MUSIC_SYNC_SERVICE: &str = "e_midi_music_sync";
#[derive(Debug)]
pub struct MusicSyncSubscriber {
subscriber: Subscriber<Service, PlaySongAtHeartbeat, ()>,
is_active: Arc<AtomicBool>,
last_heartbeat: Instant,
}
impl MusicSyncSubscriber {
pub fn new() -> Result<Self, String> {
let node = NodeBuilder::new()
.create::<Service>()
.map_err(|e| format!("Node creation failed: {e:?}"))?;
let service = node
.service_builder(&ServiceName::new(E_MIDI_MUSIC_SYNC_SERVICE).map_err(|e| format!("Invalid service name: {e:?}"))?)
.publish_subscribe::<PlaySongAtHeartbeat>()
.open_or_create()
.map_err(|e| format!("Failed to create/open service: {e:?}"))?;
let subscriber = service
.subscriber_builder()
.create()
.map_err(|e| format!("Failed to create subscriber: {e:?}"))?;
Ok(Self {
subscriber,
is_active: Arc::new(AtomicBool::new(true)),
last_heartbeat: Instant::now(),
})
}
pub fn try_receive(&mut self) -> Result<Vec<PlaySongAtHeartbeat>, String> {
if !self.is_active.load(Ordering::Relaxed) {
return Ok(Vec::new());
}
let mut messages = Vec::new();
while let Some(sample) = self.subscriber.receive().map_err(|e| format!("Receive error: {e:?}"))? {
messages.push(*sample);
}
if !messages.is_empty() {
self.last_heartbeat = Instant::now();
}
Ok(messages)
}
pub fn deactivate(&self) {
self.is_active.store(false, Ordering::Relaxed);
}
pub fn time_since_last_message(&self) -> Duration {
self.last_heartbeat.elapsed()
}
}
unsafe impl Send for MusicSyncSubscriber {}
unsafe impl Sync for MusicSyncSubscriber {}