1use std::{
2 fmt::{Debug, Display},
3 sync::{atomic::Ordering, mpsc::Sender},
4};
5
6use blake3::Hash;
7use rand::{rng, seq::SliceRandom};
8
9use crate::{
10 PlayerEvent,
11 decoder::{DecoderEvent, DecoderTx},
12 event_handler::EventTx,
13 player::{Player, PlayerError, PlayerQueryFlags, QueryResult},
14 playlist::{LoopMode, Playable, PlayableTrack, PlaybackStatus, ShuffleMode},
15};
16
17#[derive(Debug, Clone)]
18pub enum PlayerCommand {
19 Flush {
21 callback: Sender<()>,
22 },
23
24 Play {
26 playable: Playable,
27 },
28 Next,
29 Previous,
30 SetIsPlaying {
31 is_playing: bool,
32 },
33 TogglePlaying {
34 callback: Option<Sender<PlaybackStatus>>,
35 },
36 Stop,
37 SetVolume {
38 volume: f32,
39 increment: bool,
40 callback: Option<Sender<f32>>,
41 },
42 Seek {
43 seconds: f64,
44 increment: bool,
45 callback: Option<Sender<Option<f64>>>,
46 },
47
48 QueueExtend {
50 with: Vec<Playable>,
51 },
52 QueueSet {
53 to: Vec<Playable>,
54 expected_state: Hash,
55 callback: Option<Sender<bool>>,
56 },
57 QueueShuffle,
58 QueueClear,
59
60 PlaylistExtend {
62 with: Vec<Playable>,
63 },
64 PlaylistSet {
65 playables: Vec<Playable>,
66 expected_state: Hash,
67 callback: Option<Sender<bool>>,
68 },
69 PlaylistClear,
70 PlaylistSetShuffleMode {
71 shuffle_mode: ShuffleMode,
72 },
73 PlaylistSetLoopMode {
74 loop_mode: LoopMode,
75 },
76
77 TracklistSeek {
79 index: isize,
80 increment: bool,
81 callback: Option<Sender<usize>>,
82 },
83 TracklistRebuild,
84
85 GetState {
87 flags: PlayerQueryFlags,
88 callback: Sender<QueryResult>,
89 },
90}
91
92impl Display for PlayerCommand {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 match self {
95 PlayerCommand::Flush { .. } => f.write_str("Flush"),
96 PlayerCommand::Play { .. } => f.write_str("Play"),
97 PlayerCommand::Next => f.write_str("Next"),
98 PlayerCommand::Previous => f.write_str("Previous"),
99 PlayerCommand::SetIsPlaying { .. } => f.write_str("SetIsPlaying"),
100 PlayerCommand::TogglePlaying { .. } => f.write_str("TogglePlaying"),
101 PlayerCommand::Stop => f.write_str("Stop"),
102 PlayerCommand::SetVolume { .. } => f.write_str("SetVolume"),
103 PlayerCommand::Seek { .. } => f.write_str("Seek"),
104 PlayerCommand::QueueExtend { .. } => f.write_str("QueueExtend"),
105 PlayerCommand::QueueSet { .. } => f.write_str("QueueSet"),
106 PlayerCommand::QueueShuffle => f.write_str("QueueShuffle"),
107 PlayerCommand::QueueClear => f.write_str("QueueClear"),
108 PlayerCommand::PlaylistExtend { .. } => f.write_str("PlaylistExtend"),
109 PlayerCommand::PlaylistSet { .. } => f.write_str("PlaylistSet"),
110 PlayerCommand::PlaylistClear => f.write_str("PlaylistClear"),
111 PlayerCommand::PlaylistSetShuffleMode { .. } => f.write_str("PlaylistSetShuffleMode"),
112 PlayerCommand::PlaylistSetLoopMode { .. } => f.write_str("PlaylistSetLoopMode"),
113 PlayerCommand::TracklistSeek { .. } => f.write_str("TracklistSeek"),
114 PlayerCommand::TracklistRebuild => f.write_str("TracklistRebuild"),
115 PlayerCommand::GetState { .. } => f.write_str("GetState"),
116 }
117 }
118}
119
120pub enum PlayerRequest {
121 DecoderEvent(DecoderEvent),
122 Command(Box<PlayerCommand>),
123}
124
125pub trait PlayerTx {
126 fn decoder_event(&self, event: DecoderEvent) -> Result<(), PlayerError>;
127 fn command(&self, command: PlayerCommand) -> Result<(), PlayerError>;
128}
129
130impl PlayerTx for Sender<PlayerRequest> {
131 fn decoder_event(&self, event: DecoderEvent) -> Result<(), PlayerError> {
132 self.send(PlayerRequest::DecoderEvent(event))?;
133 Ok(())
134 }
135
136 fn command(&self, command: PlayerCommand) -> Result<(), PlayerError> {
137 self.send(PlayerRequest::Command(Box::new(command)))?;
138 Ok(())
139 }
140}
141
142impl Player {
143 pub(crate) fn run_command(&mut self, command: PlayerCommand) -> Result<(), PlayerError> {
144 match command {
145 PlayerCommand::Flush { callback } => {
147 let _ = callback.send(());
148 }
149
150 PlayerCommand::GetState { flags, callback } => {
152 let mut query = QueryResult::default();
153
154 if flags.contains(PlayerQueryFlags::PLAYBACK_STATE) {
155 query.playback_state = Some(self.playback_state.load(Ordering::SeqCst));
156 }
157
158 if flags.intersects(
159 PlayerQueryFlags::CURRENTLY_PLAYING | PlayerQueryFlags::CURRENTLY_PLAYING_RAW,
160 ) {
161 let currently_playing = self.decoder_tx.get_playing()?;
162
163 if flags.contains(PlayerQueryFlags::CURRENTLY_PLAYING) {
164 query.currently_playing =
165 Some(currently_playing.as_ref().map(|t| t.track.id()).into());
166 }
167
168 if flags.contains(PlayerQueryFlags::CURRENTLY_PLAYING_RAW) {
169 query.currently_playing_raw = Some(currently_playing.into())
170 }
171 }
172
173 if flags.contains(PlayerQueryFlags::VOLUME) {
174 query.volume = Some(f32::from_bits(self.volume.load(Ordering::SeqCst)));
175 }
176
177 if flags.contains(PlayerQueryFlags::TIME) {
178 query.time = Some(self.decoder_tx.get_time()?.into());
179 }
180
181 if flags.contains(PlayerQueryFlags::QUEUE) {
182 query.queue = Some(self.playlist.queue.iter().map(PlayableTrack::id).collect());
183 }
184
185 if flags.contains(PlayerQueryFlags::QUEUE_RAW) {
186 query.queue_raw = Some(self.playlist.queue.iter().cloned().collect());
187 }
188
189 if flags.contains(PlayerQueryFlags::QUEUE_STATE) {
190 query.queue_state = Some(self.playlist.queue_hash());
191 }
192
193 if flags.contains(PlayerQueryFlags::PLAYLIST) {
194 query.playlist = Some(
195 self.playlist
196 .playlist()
197 .iter()
198 .map(Playable::to_collectable)
199 .collect(),
200 );
201 }
202
203 if flags.contains(PlayerQueryFlags::PLAYLIST_RAW) {
204 query.playlist_raw = Some(self.playlist.playlist().to_vec());
205 }
206
207 if flags.contains(PlayerQueryFlags::TRACKLIST) {
208 query.tracklist = Some(
209 self.playlist
210 .tracklist()
211 .iter()
212 .map(PlayableTrack::id)
213 .collect(),
214 )
215 }
216
217 if flags.contains(PlayerQueryFlags::TRACKLIST_RAW) {
218 query.tracklist_raw = Some(self.playlist.tracklist().to_vec())
219 }
220
221 if flags.contains(PlayerQueryFlags::TRACKLIST_POSITION) {
222 query.tracklist_position = Some(self.playlist.position())
223 }
224
225 if flags.contains(PlayerQueryFlags::PLAYLIST_STATE) {
226 query.playlist_state = Some(self.playlist.playlist_hash());
227 }
228
229 if flags.contains(PlayerQueryFlags::SHUFFLE_MODE) {
230 query.shuffle_mode = Some(self.playlist.shuffle_mode);
231 }
232
233 if flags.contains(PlayerQueryFlags::LOOP_MODE) {
234 query.loop_mode = Some(self.playlist.loop_mode);
235 }
236
237 let _ = callback.send(query);
238 }
239
240 PlayerCommand::Play { playable } => {
242 self.playlist.set_playlist(std::iter::once(playable));
243
244 let loaded = self.replace_decoders(true)?;
245
246 if loaded {
247 self.decoder_tx.set_playing(true)?;
248 }
249 }
250 PlayerCommand::SetIsPlaying { is_playing } => {
251 self.decoder_tx.set_playing(is_playing)?;
252 }
253 PlayerCommand::TogglePlaying { callback } => {
254 let state = self.decoder_tx.toggle_playing()?;
255 if let Some(callback) = callback {
256 let _ = callback.send(state);
257 }
258 }
259 PlayerCommand::Stop => {
260 self.decoder_tx.stop()?;
261 }
262 PlayerCommand::SetVolume {
263 volume,
264 increment,
265 callback,
266 } => {
267 let vol = self.set_volume(volume, increment);
268 if let Some(callback) = callback {
269 let _ = callback.send(vol);
270 }
271 }
272 PlayerCommand::Seek {
273 seconds,
274 increment,
275 callback,
276 } => {
277 let time = self.decoder_tx.seek(seconds, increment)?;
278 if let Some(callback) = callback {
279 let _ = callback.send(time);
280 }
281 }
282
283 PlayerCommand::QueueSet {
285 expected_state,
286 to,
287 callback,
288 } => {
289 let equals = expected_state == self.playlist.queue_hash();
290 if equals {
291 self.playlist.queue = to
292 .into_iter()
293 .flat_map(super::super::playlist::Playable::flatten)
294 .collect();
295 }
296 if let Some(callback) = callback {
297 let _ = callback.send(equals);
298 }
299 }
300 PlayerCommand::QueueExtend { with } => self.playlist.queue_extend(with),
301 PlayerCommand::QueueShuffle => {
302 let mut shuffled: Vec<_> = self.playlist.queue.drain(..).collect();
303 shuffled.shuffle(&mut rng());
304 self.playlist.queue = shuffled.into();
305 }
306 PlayerCommand::QueueClear => self.playlist.queue.clear(),
307
308 PlayerCommand::PlaylistSet {
310 expected_state,
311 playables,
312 callback,
313 } => {
314 let equals = expected_state == self.playlist.playlist_hash();
315 if equals {
316 self.playlist.set_playlist(playables);
317 }
318
319 if let Some(callback) = callback {
320 let _ = callback.send(equals);
321 }
322 }
323 PlayerCommand::PlaylistExtend { with } => self.playlist.extend(with),
324 PlayerCommand::PlaylistClear => self.playlist.clear(),
325 PlayerCommand::PlaylistSetShuffleMode { shuffle_mode } => {
326 self.playlist.shuffle_mode = shuffle_mode;
327 self.playlist.rebuild_tracklist();
328
329 self.event_tx
330 .event(PlayerEvent::ShuffleModeChanged { shuffle_mode });
331 }
332 PlayerCommand::PlaylistSetLoopMode { loop_mode } => {
333 self.playlist.loop_mode = loop_mode;
334 self.event_tx
335 .event(PlayerEvent::LoopModeChanged { loop_mode });
336 }
337
338 PlayerCommand::TracklistSeek {
340 index,
341 increment,
342 callback,
343 } => {
344 let position = self.playlist.tracklist_seek(index, increment);
345 self.replace_decoders(false)?;
346 if let Some(callback) = callback {
347 let _ = callback.send(position);
348 }
349 }
350 PlayerCommand::Next => {
351 self.decoder_tx.skip()?;
352 }
353 PlayerCommand::Previous => {
354 self.playlist.tracklist_seek(-1, true);
355 self.replace_decoders(false)?;
356 }
357 PlayerCommand::TracklistRebuild => self.playlist.rebuild_tracklist(),
358 }
359 Ok(())
360 }
361}