spirc.rs 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  1. use std;
  2. use std::time::{SystemTime, UNIX_EPOCH};
  3. use futures::future;
  4. use futures::sync::{mpsc, oneshot};
  5. use futures::{Async, Future, Poll, Sink, Stream};
  6. use protobuf::{self, Message};
  7. use rand;
  8. use rand::seq::SliceRandom;
  9. use serde_json;
  10. use crate::context::StationContext;
  11. use crate::playback::mixer::Mixer;
  12. use crate::playback::player::Player;
  13. use crate::protocol;
  14. use crate::protocol::spirc::{DeviceState, Frame, MessageType, PlayStatus, State, TrackRef};
  15. use librespot_core::config::ConnectConfig;
  16. use librespot_core::mercury::MercuryError;
  17. use librespot_core::session::Session;
  18. use librespot_core::spotify_id::{SpotifyAudioType, SpotifyId, SpotifyIdError};
  19. use librespot_core::util::SeqGenerator;
  20. use librespot_core::version;
  21. use librespot_core::volume::Volume;
  22. pub struct SpircTask {
  23. player: Player,
  24. mixer: Box<dyn Mixer>,
  25. config: SpircTaskConfig,
  26. sequence: SeqGenerator<u32>,
  27. ident: String,
  28. device: DeviceState,
  29. state: State,
  30. subscription: Box<dyn Stream<Item = Frame, Error = MercuryError>>,
  31. sender: Box<dyn Sink<SinkItem = Frame, SinkError = MercuryError>>,
  32. commands: mpsc::UnboundedReceiver<SpircCommand>,
  33. end_of_track: Box<dyn Future<Item = (), Error = oneshot::Canceled>>,
  34. shutdown: bool,
  35. session: Session,
  36. context_fut: Box<dyn Future<Item = serde_json::Value, Error = MercuryError>>,
  37. autoplay_fut: Box<dyn Future<Item = String, Error = MercuryError>>,
  38. context: Option<StationContext>,
  39. }
  40. pub enum SpircCommand {
  41. Play,
  42. PlayPause,
  43. Pause,
  44. Prev,
  45. Next,
  46. VolumeUp,
  47. VolumeDown,
  48. Shutdown,
  49. }
  50. struct SpircTaskConfig {
  51. linear_volume: bool,
  52. autoplay: bool,
  53. }
  54. const CONTEXT_TRACKS_HISTORY: usize = 10;
  55. const CONTEXT_FETCH_THRESHOLD: u32 = 5;
  56. pub struct Spirc {
  57. commands: mpsc::UnboundedSender<SpircCommand>,
  58. }
  59. fn initial_state() -> State {
  60. let mut frame = protocol::spirc::State::new();
  61. frame.set_repeat(false);
  62. frame.set_shuffle(false);
  63. frame.set_status(PlayStatus::kPlayStatusStop);
  64. frame.set_position_ms(0);
  65. frame.set_position_measured_at(0);
  66. frame
  67. }
  68. fn initial_device_state(config: ConnectConfig) -> DeviceState {
  69. {
  70. let mut msg = DeviceState::new();
  71. msg.set_sw_version(version::version_string());
  72. msg.set_is_active(false);
  73. msg.set_can_play(true);
  74. msg.set_volume(0);
  75. msg.set_name(config.name);
  76. {
  77. let repeated = msg.mut_capabilities();
  78. {
  79. let msg = repeated.push_default();
  80. msg.set_typ(protocol::spirc::CapabilityType::kCanBePlayer);
  81. {
  82. let repeated = msg.mut_intValue();
  83. repeated.push(1)
  84. };
  85. msg
  86. };
  87. {
  88. let msg = repeated.push_default();
  89. msg.set_typ(protocol::spirc::CapabilityType::kDeviceType);
  90. {
  91. let repeated = msg.mut_intValue();
  92. repeated.push(config.device_type as i64)
  93. };
  94. msg
  95. };
  96. {
  97. let msg = repeated.push_default();
  98. msg.set_typ(protocol::spirc::CapabilityType::kGaiaEqConnectId);
  99. {
  100. let repeated = msg.mut_intValue();
  101. repeated.push(1)
  102. };
  103. msg
  104. };
  105. {
  106. let msg = repeated.push_default();
  107. msg.set_typ(protocol::spirc::CapabilityType::kSupportsLogout);
  108. {
  109. let repeated = msg.mut_intValue();
  110. repeated.push(0)
  111. };
  112. msg
  113. };
  114. {
  115. let msg = repeated.push_default();
  116. msg.set_typ(protocol::spirc::CapabilityType::kIsObservable);
  117. {
  118. let repeated = msg.mut_intValue();
  119. repeated.push(1)
  120. };
  121. msg
  122. };
  123. {
  124. let msg = repeated.push_default();
  125. msg.set_typ(protocol::spirc::CapabilityType::kVolumeSteps);
  126. {
  127. let repeated = msg.mut_intValue();
  128. repeated.push(64)
  129. };
  130. msg
  131. };
  132. {
  133. let msg = repeated.push_default();
  134. msg.set_typ(protocol::spirc::CapabilityType::kSupportsPlaylistV2);
  135. {
  136. let repeated = msg.mut_intValue();
  137. repeated.push(64)
  138. };
  139. msg
  140. };
  141. {
  142. let msg = repeated.push_default();
  143. msg.set_typ(protocol::spirc::CapabilityType::kSupportedContexts);
  144. {
  145. let repeated = msg.mut_stringValue();
  146. repeated.push(::std::convert::Into::into("album"));
  147. repeated.push(::std::convert::Into::into("playlist"));
  148. repeated.push(::std::convert::Into::into("search"));
  149. repeated.push(::std::convert::Into::into("inbox"));
  150. repeated.push(::std::convert::Into::into("toplist"));
  151. repeated.push(::std::convert::Into::into("starred"));
  152. repeated.push(::std::convert::Into::into("publishedstarred"));
  153. repeated.push(::std::convert::Into::into("track"))
  154. };
  155. msg
  156. };
  157. {
  158. let msg = repeated.push_default();
  159. msg.set_typ(protocol::spirc::CapabilityType::kSupportedTypes);
  160. {
  161. let repeated = msg.mut_stringValue();
  162. repeated.push(::std::convert::Into::into("audio/local"));
  163. repeated.push(::std::convert::Into::into("audio/track"));
  164. repeated.push(::std::convert::Into::into("audio/episode"));
  165. repeated.push(::std::convert::Into::into("local"));
  166. repeated.push(::std::convert::Into::into("track"))
  167. };
  168. msg
  169. };
  170. };
  171. msg
  172. }
  173. }
  174. fn calc_logarithmic_volume(volume: u16) -> u16 {
  175. // Volume conversion taken from https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2
  176. // Convert the given volume [0..0xffff] to a dB gain
  177. // We assume a dB range of 60dB.
  178. // Use the equation: a * exp(b * x)
  179. // in which a = IDEAL_FACTOR, b = 1/1000
  180. const IDEAL_FACTOR: f64 = 6.908;
  181. let normalized_volume = volume as f64 / std::u16::MAX as f64; // To get a value between 0 and 1
  182. let mut val = std::u16::MAX;
  183. // Prevent val > std::u16::MAX due to rounding errors
  184. if normalized_volume < 0.999 {
  185. let new_volume = (normalized_volume * IDEAL_FACTOR).exp() / 1000.0;
  186. val = (new_volume * std::u16::MAX as f64) as u16;
  187. }
  188. debug!("input volume:{} to mixer: {}", volume, val);
  189. // return the scale factor (0..0xffff) (equivalent to a voltage multiplier).
  190. val
  191. }
  192. fn volume_to_mixer(volume: u16, linear_volume: bool) -> u16 {
  193. if linear_volume {
  194. debug!("linear volume: {}", volume);
  195. volume
  196. } else {
  197. calc_logarithmic_volume(volume)
  198. }
  199. }
  200. impl Spirc {
  201. pub fn new(
  202. config: ConnectConfig,
  203. session: Session,
  204. player: Player,
  205. mixer: Box<dyn Mixer>,
  206. ) -> (Spirc, SpircTask) {
  207. debug!("new Spirc[{}]", session.session_id());
  208. let ident = session.device_id().to_owned();
  209. // Uri updated in response to issue #288
  210. let uri = format!("hm://remote/user/{}/", session.username());
  211. let subscription = session.mercury().subscribe(&uri as &str);
  212. let subscription = subscription
  213. .map(|stream| stream.map_err(|_| MercuryError))
  214. .flatten_stream();
  215. let subscription = Box::new(subscription.map(|response| -> Frame {
  216. let data = response.payload.first().unwrap();
  217. protobuf::parse_from_bytes(data).unwrap()
  218. }));
  219. let sender = Box::new(
  220. session
  221. .mercury()
  222. .sender(uri)
  223. .with(|frame: Frame| Ok(frame.write_to_bytes().unwrap())),
  224. );
  225. let (cmd_tx, cmd_rx) = mpsc::unbounded();
  226. let volume = config.volume;
  227. let task_config = SpircTaskConfig {
  228. linear_volume: config.linear_volume,
  229. autoplay: config.autoplay,
  230. };
  231. let device = initial_device_state(config);
  232. let mut task = SpircTask {
  233. player: player,
  234. mixer: mixer,
  235. config: task_config,
  236. sequence: SeqGenerator::new(1),
  237. ident: ident,
  238. device: device,
  239. state: initial_state(),
  240. subscription: subscription,
  241. sender: sender,
  242. commands: cmd_rx,
  243. end_of_track: Box::new(future::empty()),
  244. shutdown: false,
  245. session: session.clone(),
  246. context_fut: Box::new(future::empty()),
  247. autoplay_fut: Box::new(future::empty()),
  248. context: None,
  249. };
  250. task.set_volume(volume);
  251. let spirc = Spirc { commands: cmd_tx };
  252. task.hello();
  253. (spirc, task)
  254. }
  255. pub fn play(&self) {
  256. let _ = self.commands.unbounded_send(SpircCommand::Play);
  257. }
  258. pub fn play_pause(&self) {
  259. let _ = self.commands.unbounded_send(SpircCommand::PlayPause);
  260. }
  261. pub fn pause(&self) {
  262. let _ = self.commands.unbounded_send(SpircCommand::Pause);
  263. }
  264. pub fn prev(&self) {
  265. let _ = self.commands.unbounded_send(SpircCommand::Prev);
  266. }
  267. pub fn next(&self) {
  268. let _ = self.commands.unbounded_send(SpircCommand::Next);
  269. }
  270. pub fn volume_up(&self) {
  271. let _ = self.commands.unbounded_send(SpircCommand::VolumeUp);
  272. }
  273. pub fn volume_down(&self) {
  274. let _ = self.commands.unbounded_send(SpircCommand::VolumeDown);
  275. }
  276. pub fn shutdown(&self) {
  277. let _ = self.commands.unbounded_send(SpircCommand::Shutdown);
  278. }
  279. }
  280. impl Future for SpircTask {
  281. type Item = ();
  282. type Error = ();
  283. fn poll(&mut self) -> Poll<(), ()> {
  284. loop {
  285. let mut progress = false;
  286. if self.session.is_invalid() {
  287. return Ok(Async::Ready(()));
  288. }
  289. if !self.shutdown {
  290. match self.subscription.poll().unwrap() {
  291. Async::Ready(Some(frame)) => {
  292. progress = true;
  293. self.handle_frame(frame);
  294. }
  295. Async::Ready(None) => {
  296. error!("subscription terminated");
  297. self.shutdown = true;
  298. self.commands.close();
  299. }
  300. Async::NotReady => (),
  301. }
  302. match self.commands.poll().unwrap() {
  303. Async::Ready(Some(command)) => {
  304. progress = true;
  305. self.handle_command(command);
  306. }
  307. Async::Ready(None) => (),
  308. Async::NotReady => (),
  309. }
  310. match self.end_of_track.poll() {
  311. Ok(Async::Ready(())) => {
  312. progress = true;
  313. self.handle_end_of_track();
  314. }
  315. Ok(Async::NotReady) => (),
  316. Err(oneshot::Canceled) => self.end_of_track = Box::new(future::empty()),
  317. }
  318. // TODO: Refactor
  319. match self.context_fut.poll() {
  320. Ok(Async::Ready(value)) => {
  321. let r_context = serde_json::from_value::<StationContext>(value.clone());
  322. self.context = match r_context {
  323. Ok(context) => {
  324. info!(
  325. "Resolved {:?} tracks from <{:?}>",
  326. context.tracks.len(),
  327. self.state.get_context_uri(),
  328. );
  329. Some(context)
  330. }
  331. Err(e) => {
  332. error!("Unable to parse JSONContext {:?}\n{:?}", e, value);
  333. None
  334. }
  335. };
  336. // It needn't be so verbose - can be as simple as
  337. // if let Some(ref context) = r_context {
  338. // info!("Got {:?} tracks from <{}>", context.tracks.len(), context.uri);
  339. // }
  340. // self.context = r_context;
  341. progress = true;
  342. self.context_fut = Box::new(future::empty());
  343. }
  344. Ok(Async::NotReady) => (),
  345. Err(err) => {
  346. self.context_fut = Box::new(future::empty());
  347. error!("ContextError: {:?}", err)
  348. }
  349. }
  350. match self.autoplay_fut.poll() {
  351. Ok(Async::Ready(autoplay_station_uri)) => {
  352. info!("Autoplay uri resolved to <{:?}>", autoplay_station_uri);
  353. self.context_fut = self.resolve_station(&autoplay_station_uri);
  354. progress = true;
  355. self.autoplay_fut = Box::new(future::empty());
  356. }
  357. Ok(Async::NotReady) => (),
  358. Err(err) => {
  359. self.autoplay_fut = Box::new(future::empty());
  360. error!("AutoplayError: {:?}", err)
  361. }
  362. }
  363. }
  364. let poll_sender = self.sender.poll_complete().unwrap();
  365. // Only shutdown once we've flushed out all our messages
  366. if self.shutdown && poll_sender.is_ready() {
  367. return Ok(Async::Ready(()));
  368. }
  369. if !progress {
  370. return Ok(Async::NotReady);
  371. }
  372. }
  373. }
  374. }
  375. impl SpircTask {
  376. fn now_ms(&mut self) -> i64 {
  377. let dur = match SystemTime::now().duration_since(UNIX_EPOCH) {
  378. Ok(dur) => dur,
  379. Err(err) => err.duration(),
  380. };
  381. ((dur.as_secs() as i64 + self.session.time_delta()) * 1000
  382. + (dur.subsec_nanos() / 1000_000) as i64)
  383. }
  384. fn handle_command(&mut self, cmd: SpircCommand) {
  385. let active = self.device.get_is_active();
  386. match cmd {
  387. SpircCommand::Play => {
  388. if active {
  389. self.handle_play();
  390. self.notify(None);
  391. } else {
  392. CommandSender::new(self, MessageType::kMessageTypePlay).send();
  393. }
  394. }
  395. SpircCommand::PlayPause => {
  396. if active {
  397. self.handle_play_pause();
  398. self.notify(None);
  399. } else {
  400. CommandSender::new(self, MessageType::kMessageTypePlayPause).send();
  401. }
  402. }
  403. SpircCommand::Pause => {
  404. if active {
  405. self.handle_pause();
  406. self.notify(None);
  407. } else {
  408. CommandSender::new(self, MessageType::kMessageTypePause).send();
  409. }
  410. }
  411. SpircCommand::Prev => {
  412. if active {
  413. self.handle_prev();
  414. self.notify(None);
  415. } else {
  416. CommandSender::new(self, MessageType::kMessageTypePrev).send();
  417. }
  418. }
  419. SpircCommand::Next => {
  420. if active {
  421. self.handle_next();
  422. self.notify(None);
  423. } else {
  424. CommandSender::new(self, MessageType::kMessageTypeNext).send();
  425. }
  426. }
  427. SpircCommand::VolumeUp => {
  428. if active {
  429. self.handle_volume_up();
  430. self.notify(None);
  431. } else {
  432. CommandSender::new(self, MessageType::kMessageTypeVolumeUp).send();
  433. }
  434. }
  435. SpircCommand::VolumeDown => {
  436. if active {
  437. self.handle_volume_down();
  438. self.notify(None);
  439. } else {
  440. CommandSender::new(self, MessageType::kMessageTypeVolumeDown).send();
  441. }
  442. }
  443. SpircCommand::Shutdown => {
  444. CommandSender::new(self, MessageType::kMessageTypeGoodbye).send();
  445. self.shutdown = true;
  446. self.commands.close();
  447. }
  448. }
  449. }
  450. fn handle_frame(&mut self, frame: Frame) {
  451. debug!(
  452. "{:?} {:?} {} {} {}",
  453. frame.get_typ(),
  454. frame.get_device_state().get_name(),
  455. frame.get_ident(),
  456. frame.get_seq_nr(),
  457. frame.get_state_update_id()
  458. );
  459. if frame.get_ident() == self.ident
  460. || (frame.get_recipient().len() > 0 && !frame.get_recipient().contains(&self.ident))
  461. {
  462. return;
  463. }
  464. match frame.get_typ() {
  465. MessageType::kMessageTypeHello => {
  466. self.notify(Some(frame.get_ident()));
  467. }
  468. MessageType::kMessageTypeLoad => {
  469. if !self.device.get_is_active() {
  470. let now = self.now_ms();
  471. self.device.set_is_active(true);
  472. self.device.set_became_active_at(now);
  473. }
  474. self.update_tracks(&frame);
  475. if self.state.get_track().len() > 0 {
  476. let now = self.now_ms();
  477. self.state
  478. .set_position_ms(frame.get_state().get_position_ms());
  479. self.state.set_position_measured_at(now as u64);
  480. let play = frame.get_state().get_status() == PlayStatus::kPlayStatusPlay;
  481. self.load_track(play);
  482. } else {
  483. info!("No more tracks left in queue");
  484. self.state.set_status(PlayStatus::kPlayStatusStop);
  485. }
  486. self.notify(None);
  487. }
  488. MessageType::kMessageTypePlay => {
  489. self.handle_play();
  490. self.notify(None);
  491. }
  492. MessageType::kMessageTypePlayPause => {
  493. self.handle_play_pause();
  494. self.notify(None);
  495. }
  496. MessageType::kMessageTypePause => {
  497. self.handle_pause();
  498. self.notify(None);
  499. }
  500. MessageType::kMessageTypeNext => {
  501. self.handle_next();
  502. self.notify(None);
  503. }
  504. MessageType::kMessageTypePrev => {
  505. self.handle_prev();
  506. self.notify(None);
  507. }
  508. MessageType::kMessageTypeVolumeUp => {
  509. self.handle_volume_up();
  510. self.notify(None);
  511. }
  512. MessageType::kMessageTypeVolumeDown => {
  513. self.handle_volume_down();
  514. self.notify(None);
  515. }
  516. MessageType::kMessageTypeRepeat => {
  517. self.state.set_repeat(frame.get_state().get_repeat());
  518. self.notify(None);
  519. }
  520. MessageType::kMessageTypeShuffle => {
  521. self.state.set_shuffle(frame.get_state().get_shuffle());
  522. if self.state.get_shuffle() {
  523. let current_index = self.state.get_playing_track_index();
  524. {
  525. let tracks = self.state.mut_track();
  526. tracks.swap(0, current_index as usize);
  527. if let Some((_, rest)) = tracks.split_first_mut() {
  528. let mut rng = rand::thread_rng();
  529. rest.shuffle(&mut rng);
  530. }
  531. }
  532. self.state.set_playing_track_index(0);
  533. } else {
  534. let context = self.state.get_context_uri();
  535. debug!("{:?}", context);
  536. }
  537. self.notify(None);
  538. }
  539. MessageType::kMessageTypeSeek => {
  540. let position = frame.get_position();
  541. let now = self.now_ms();
  542. self.state.set_position_ms(position);
  543. self.state.set_position_measured_at(now as u64);
  544. self.player.seek(position);
  545. self.notify(None);
  546. }
  547. MessageType::kMessageTypeReplace => {
  548. self.update_tracks(&frame);
  549. self.notify(None);
  550. }
  551. MessageType::kMessageTypeVolume => {
  552. self.set_volume(frame.get_volume() as u16);
  553. self.notify(None);
  554. }
  555. MessageType::kMessageTypeNotify => {
  556. if self.device.get_is_active() && frame.get_device_state().get_is_active() {
  557. self.device.set_is_active(false);
  558. self.state.set_status(PlayStatus::kPlayStatusStop);
  559. self.player.stop();
  560. self.mixer.stop();
  561. }
  562. }
  563. _ => (),
  564. }
  565. }
  566. fn handle_play(&mut self) {
  567. if self.state.get_status() == PlayStatus::kPlayStatusPause {
  568. self.mixer.start();
  569. self.player.play();
  570. self.state.set_status(PlayStatus::kPlayStatusPlay);
  571. let now = self.now_ms();
  572. self.state.set_position_measured_at(now as u64);
  573. }
  574. }
  575. fn handle_play_pause(&mut self) {
  576. match self.state.get_status() {
  577. PlayStatus::kPlayStatusPlay => self.handle_pause(),
  578. PlayStatus::kPlayStatusPause => self.handle_play(),
  579. _ => (),
  580. }
  581. }
  582. fn handle_pause(&mut self) {
  583. if self.state.get_status() == PlayStatus::kPlayStatusPlay {
  584. self.player.pause();
  585. self.mixer.stop();
  586. self.state.set_status(PlayStatus::kPlayStatusPause);
  587. let now = self.now_ms() as u64;
  588. let position = self.state.get_position_ms();
  589. let diff = now - self.state.get_position_measured_at();
  590. self.state.set_position_ms(position + diff as u32);
  591. self.state.set_position_measured_at(now);
  592. }
  593. }
  594. fn consume_queued_track(&mut self) -> usize {
  595. // Removes current track if it is queued
  596. // Returns the index of the next track
  597. let current_index = self.state.get_playing_track_index() as usize;
  598. if self.state.get_track()[current_index].get_queued() {
  599. self.state.mut_track().remove(current_index);
  600. return current_index;
  601. }
  602. current_index + 1
  603. }
  604. fn handle_next(&mut self) {
  605. let mut new_index = self.consume_queued_track() as u32;
  606. let mut continue_playing = true;
  607. let tracks_len = self.state.get_track().len() as u32;
  608. debug!(
  609. "At track {:?} of {:?} <{:?}> update [{}]",
  610. new_index,
  611. self.state.get_track().len(),
  612. self.state.get_context_uri(),
  613. tracks_len - new_index < CONTEXT_FETCH_THRESHOLD
  614. );
  615. let context_uri = self.state.get_context_uri().to_owned();
  616. if (context_uri.starts_with("spotify:station:")
  617. || context_uri.starts_with("spotify:dailymix:"))
  618. && ((self.state.get_track().len() as u32) - new_index) < CONTEXT_FETCH_THRESHOLD
  619. {
  620. self.context_fut = self.resolve_station(&context_uri);
  621. self.update_tracks_from_context();
  622. }
  623. if self.config.autoplay && new_index == tracks_len - 1 {
  624. // Extend the playlist
  625. // Note: This doesn't seem to reflect in the UI
  626. // the additional tracks in the frame don't show up as with station view
  627. debug!("Extending playlist <{}>", context_uri);
  628. self.update_tracks_from_context();
  629. }
  630. if new_index >= tracks_len {
  631. new_index = 0; // Loop around back to start
  632. continue_playing = self.state.get_repeat();
  633. }
  634. self.state.set_playing_track_index(new_index);
  635. self.state.set_position_ms(0);
  636. let now = self.now_ms();
  637. self.state.set_position_measured_at(now as u64);
  638. self.load_track(continue_playing);
  639. }
  640. fn handle_prev(&mut self) {
  641. // Previous behaves differently based on the position
  642. // Under 3s it goes to the previous song (starts playing)
  643. // Over 3s it seeks to zero (retains previous play status)
  644. if self.position() < 3000 {
  645. // Queued tracks always follow the currently playing track.
  646. // They should not be considered when calculating the previous
  647. // track so extract them beforehand and reinsert them after it.
  648. let mut queue_tracks = Vec::new();
  649. {
  650. let queue_index = self.consume_queued_track();
  651. let tracks = self.state.mut_track();
  652. while queue_index < tracks.len() && tracks[queue_index].get_queued() {
  653. queue_tracks.push(tracks.remove(queue_index));
  654. }
  655. }
  656. let current_index = self.state.get_playing_track_index();
  657. let new_index = if current_index > 0 {
  658. current_index - 1
  659. } else if self.state.get_repeat() {
  660. self.state.get_track().len() as u32 - 1
  661. } else {
  662. 0
  663. };
  664. // Reinsert queued tracks after the new playing track.
  665. let mut pos = (new_index + 1) as usize;
  666. for track in queue_tracks.into_iter() {
  667. self.state.mut_track().insert(pos, track);
  668. pos += 1;
  669. }
  670. let now = self.now_ms();
  671. self.state.set_playing_track_index(new_index);
  672. self.state.set_position_ms(0);
  673. self.state.set_position_measured_at(now as u64);
  674. self.load_track(true);
  675. } else {
  676. let now = self.now_ms();
  677. self.state.set_position_ms(0);
  678. self.state.set_position_measured_at(now as u64);
  679. self.player.seek(0);
  680. }
  681. }
  682. fn handle_volume_up(&mut self) {
  683. let mut volume: u32 = self.device.get_volume() as u32 + 4096;
  684. if volume > 0xFFFF {
  685. volume = 0xFFFF;
  686. }
  687. self.set_volume(volume as u16);
  688. }
  689. fn handle_volume_down(&mut self) {
  690. let mut volume: i32 = self.device.get_volume() as i32 - 4096;
  691. if volume < 0 {
  692. volume = 0;
  693. }
  694. self.set_volume(volume as u16);
  695. }
  696. fn handle_end_of_track(&mut self) {
  697. self.handle_next();
  698. self.notify(None);
  699. }
  700. fn position(&mut self) -> u32 {
  701. let diff = self.now_ms() as u64 - self.state.get_position_measured_at();
  702. self.state.get_position_ms() + diff as u32
  703. }
  704. fn resolve_station(
  705. &self,
  706. uri: &str,
  707. ) -> Box<dyn Future<Item = serde_json::Value, Error = MercuryError>> {
  708. let radio_uri = format!("hm://radio-apollo/v3/stations/{}", uri);
  709. self.resolve_uri(&radio_uri)
  710. }
  711. fn resolve_autoplay_uri(
  712. &self,
  713. uri: &str,
  714. ) -> Box<dyn Future<Item = String, Error = MercuryError>> {
  715. let query_uri = format!("hm://autoplay-enabled/query?uri={}", uri);
  716. let request = self.session.mercury().get(query_uri);
  717. Box::new(request.and_then(move |response| {
  718. if response.status_code == 200 {
  719. let data = response
  720. .payload
  721. .first()
  722. .expect("Empty autoplay uri")
  723. .to_vec();
  724. let autoplay_uri = String::from_utf8(data).unwrap();
  725. Ok(autoplay_uri)
  726. } else {
  727. warn!("No autoplay_uri found");
  728. Err(MercuryError)
  729. }
  730. }))
  731. }
  732. fn resolve_uri(
  733. &self,
  734. uri: &str,
  735. ) -> Box<dyn Future<Item = serde_json::Value, Error = MercuryError>> {
  736. let request = self.session.mercury().get(uri);
  737. Box::new(request.and_then(move |response| {
  738. let data = response
  739. .payload
  740. .first()
  741. .expect("Empty payload on context uri");
  742. let response: serde_json::Value = serde_json::from_slice(&data).unwrap();
  743. Ok(response)
  744. }))
  745. }
  746. fn update_tracks_from_context(&mut self) {
  747. if let Some(ref context) = self.context {
  748. self.context_fut = self.resolve_uri(&context.next_page_url);
  749. let new_tracks = &context.tracks;
  750. debug!("Adding {:?} tracks from context to frame", new_tracks.len());
  751. let mut track_vec = self.state.take_track().into_vec();
  752. if let Some(head) = track_vec.len().checked_sub(CONTEXT_TRACKS_HISTORY) {
  753. track_vec.drain(0..head);
  754. }
  755. track_vec.extend_from_slice(&new_tracks);
  756. self.state
  757. .set_track(protobuf::RepeatedField::from_vec(track_vec));
  758. // Update playing index
  759. if let Some(new_index) = self
  760. .state
  761. .get_playing_track_index()
  762. .checked_sub(CONTEXT_TRACKS_HISTORY as u32)
  763. {
  764. self.state.set_playing_track_index(new_index);
  765. }
  766. } else {
  767. warn!("No context to update from!");
  768. }
  769. }
  770. fn update_tracks(&mut self, frame: &protocol::spirc::Frame) {
  771. debug!("State: {:?}", frame.get_state());
  772. let index = frame.get_state().get_playing_track_index();
  773. let context_uri = frame.get_state().get_context_uri().to_owned();
  774. let tracks = frame.get_state().get_track();
  775. debug!("Frame has {:?} tracks", tracks.len());
  776. if context_uri.starts_with("spotify:station:")
  777. || context_uri.starts_with("spotify:dailymix:")
  778. {
  779. self.context_fut = self.resolve_station(&context_uri);
  780. } else if self.config.autoplay {
  781. info!("Fetching autoplay context uri");
  782. // Get autoplay_station_uri for regular playlists
  783. self.autoplay_fut = self.resolve_autoplay_uri(&context_uri);
  784. }
  785. self.state.set_playing_track_index(index);
  786. self.state.set_track(tracks.into_iter().cloned().collect());
  787. self.state.set_context_uri(context_uri);
  788. self.state.set_repeat(frame.get_state().get_repeat());
  789. self.state.set_shuffle(frame.get_state().get_shuffle());
  790. }
  791. // should this be a method of SpotifyId directly?
  792. fn get_spotify_id_for_track(&self, track_ref: &TrackRef) -> Result<SpotifyId, SpotifyIdError> {
  793. SpotifyId::from_raw(track_ref.get_gid()).or_else(|_| {
  794. let uri = track_ref.get_uri();
  795. debug!("Malformed or no gid, attempting to parse URI <{}>", uri);
  796. SpotifyId::from_uri(uri)
  797. })
  798. }
  799. fn load_track(&mut self, play: bool) {
  800. let context_uri = self.state.get_context_uri().to_owned();
  801. let mut index = self.state.get_playing_track_index();
  802. let start_index = index;
  803. let tracks_len = self.state.get_track().len() as u32;
  804. debug!(
  805. "Loading context: <{}> index: [{}] of {}",
  806. context_uri, index, tracks_len
  807. );
  808. // Cycle through all tracks, break if we don't find any playable tracks
  809. // TODO: This will panic if no playable tracks are found!
  810. // tracks in each frame either have a gid or uri (that may or may not be a valid track)
  811. // E.g - context based frames sometimes contain tracks with <spotify:meta:page:>
  812. let track = {
  813. let mut track_ref = self.state.get_track()[index as usize].clone();
  814. let mut track_id = self.get_spotify_id_for_track(&track_ref);
  815. while track_id.is_err() || track_id.unwrap().audio_type == SpotifyAudioType::NonPlayable
  816. {
  817. warn!(
  818. "Skipping track <{:?}> at position [{}] of {}",
  819. track_ref.get_uri(),
  820. index,
  821. tracks_len
  822. );
  823. index = if index + 1 < tracks_len { index + 1 } else { 0 };
  824. self.state.set_playing_track_index(index);
  825. if index == start_index {
  826. warn!("No playable track found in state: {:?}", self.state);
  827. break;
  828. }
  829. track_ref = self.state.get_track()[index as usize].clone();
  830. track_id = self.get_spotify_id_for_track(&track_ref);
  831. }
  832. track_id
  833. }
  834. .expect("Invalid SpotifyId");
  835. let position = self.state.get_position_ms();
  836. let end_of_track = self.player.load(track, play, position);
  837. if play {
  838. self.state.set_status(PlayStatus::kPlayStatusPlay);
  839. } else {
  840. self.state.set_status(PlayStatus::kPlayStatusPause);
  841. }
  842. self.end_of_track = Box::new(end_of_track);
  843. }
  844. fn hello(&mut self) {
  845. CommandSender::new(self, MessageType::kMessageTypeHello).send();
  846. }
  847. fn notify(&mut self, recipient: Option<&str>) {
  848. let mut cs = CommandSender::new(self, MessageType::kMessageTypeNotify);
  849. if let Some(s) = recipient {
  850. cs = cs.recipient(&s);
  851. }
  852. cs.send();
  853. }
  854. fn set_volume(&mut self, volume: u16) {
  855. self.device.set_volume(volume as u32);
  856. self.mixer
  857. .set_volume(volume_to_mixer(volume, self.config.linear_volume));
  858. if let Some(cache) = self.session.cache() {
  859. cache.save_volume(Volume { volume })
  860. }
  861. }
  862. }
  863. impl Drop for SpircTask {
  864. fn drop(&mut self) {
  865. debug!("drop Spirc[{}]", self.session.session_id());
  866. }
  867. }
  868. struct CommandSender<'a> {
  869. spirc: &'a mut SpircTask,
  870. frame: protocol::spirc::Frame,
  871. }
  872. impl<'a> CommandSender<'a> {
  873. fn new(spirc: &'a mut SpircTask, cmd: MessageType) -> CommandSender {
  874. let mut frame = protocol::spirc::Frame::new();
  875. frame.set_version(1);
  876. frame.set_protocol_version(::std::convert::Into::into("2.0.0"));
  877. frame.set_ident(spirc.ident.clone());
  878. frame.set_seq_nr(spirc.sequence.get());
  879. frame.set_typ(cmd);
  880. frame.set_device_state(spirc.device.clone());
  881. frame.set_state_update_id(spirc.now_ms());
  882. CommandSender {
  883. spirc: spirc,
  884. frame: frame,
  885. }
  886. }
  887. fn recipient(mut self, recipient: &'a str) -> CommandSender {
  888. self.frame.mut_recipient().push(recipient.to_owned());
  889. self
  890. }
  891. #[allow(dead_code)]
  892. fn state(mut self, state: protocol::spirc::State) -> CommandSender<'a> {
  893. self.frame.set_state(state);
  894. self
  895. }
  896. fn send(mut self) {
  897. if !self.frame.has_state() && self.spirc.device.get_is_active() {
  898. self.frame.set_state(self.spirc.state.clone());
  899. }
  900. let send = self.spirc.sender.start_send(self.frame).unwrap();
  901. assert!(send.is_ready());
  902. }
  903. }