Skip to content

Use Sync Controllers

This guide covers how to create and use sync controllers for maintaining a local PlaybackSnapshot in sync with the native runtime.

Sync controllers are useful when:

  • You need a local snapshot that stays in sync with native playback
  • You want to receive event callbacks without manually registering multiple listeners
  • You’re building a UI component that displays playback state
import { createLegatoSync } from '@ddgutierrezc/legato-capacitor';
const sync = createLegatoSync({
onSnapshot: (snapshot) => {
console.log('State:', snapshot.state);
console.log('Position:', snapshot.position);
console.log('Track:', snapshot.currentTrack?.title);
},
});
await sync.start();
const current = sync.getCurrent();
if (current) {
console.log('Current state:', current.state);
console.log('Current position:', current.position);
}
await sync.resync();
await sync.stop();
import { createLegatoSync } from '@ddgutierrezc/legato-capacitor';
import { audioPlayer } from '@ddgutierrezc/legato-capacitor';
async function initSyncUI() {
const sync = createLegatoSync({
onSnapshot: (snapshot) => {
// Update UI elements
updatePlayPauseButton(snapshot.state === 'playing');
updateProgressBar(snapshot.position, snapshot.duration);
updateTrackInfo(snapshot.currentTrack);
},
onEvent: (eventName, payload) => {
console.log('Event:', eventName);
},
});
// Start sync
await sync.start();
// Add some tracks
await audioPlayer.add({
tracks: [{ id: '1', url: 'https://example.com/audio.mp3', title: 'Demo' }],
});
// Start playback
await audioPlayer.play();
// Return cleanup function
return () => sync.stop();
}
async function updatePlayPauseButton(isPlaying: boolean) {
// Update your UI
}
async function updateProgressBar(position: number, duration: number | null) {
// Update your progress bar
}
async function updateTrackInfo(track: any) {
// Update track info display
}
initSyncUI().then((cleanup) => {
// Call cleanup() when done
});
ActionResult
createLegatoSync()Creates controller with optional callbacks
start()Subscribes to events, returns initial snapshot
getCurrent()Returns current local snapshot or null
resync()Refreshes snapshot from native state
stop()Removes all listeners
import { createAudioPlayerSync } from '@ddgutierrezc/legato-capacitor';
const sync = createAudioPlayerSync({
onSnapshot: (snapshot) => {
console.log('State:', snapshot.state);
},
});
await sync.start();

The sync controller mirrors native state using getSnapshot() and event listeners. Runtime capability projection (e.g., whether seek is supported) is not reflected in the local snapshot fields directly — use audioPlayer.getCapabilities() separately to conditionally enable UI features like seek bars or skip buttons.

const caps = await audioPlayer.getCapabilities();
// Conditionally show/hide UI based on runtime capabilities
if (caps.supported.includes('seek')) {
showSeekBar();
}
if (!caps.supported.includes('skip-next')) {
hideNextButton();
}