spirc.rs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. use futures::future;
  2. use futures::sync::{oneshot, mpsc};
  3. use futures::{Future, Stream, Sink, Async, Poll};
  4. use protobuf::{self, Message};
  5. use core::config::ConnectConfig;
  6. use core::mercury::MercuryError;
  7. use core::session::Session;
  8. use core::util::{now_ms, SpotifyId, SeqGenerator};
  9. use core::version;
  10. use protocol;
  11. use protocol::spirc::{PlayStatus, State, MessageType, Frame, DeviceState};
  12. use mixer::Mixer;
  13. use player::Player;
  14. use rand;
  15. use rand::Rng;
  16. pub struct SpircTask {
  17. player: Player,
  18. mixer: Box<Mixer>,
  19. sequence: SeqGenerator<u32>,
  20. ident: String,
  21. device: DeviceState,
  22. state: State,
  23. subscription: Box<Stream<Item = Frame, Error = MercuryError>>,
  24. sender: Box<Sink<SinkItem = Frame, SinkError = MercuryError>>,
  25. commands: mpsc::UnboundedReceiver<SpircCommand>,
  26. end_of_track: Box<Future<Item = (), Error = oneshot::Canceled>>,
  27. shutdown: bool,
  28. session: Session,
  29. }
  30. pub enum SpircCommand {
  31. Play,
  32. PlayPause,
  33. Pause,
  34. Prev,
  35. Next,
  36. VolumeUp,
  37. VolumeDown,
  38. Shutdown
  39. }
  40. pub struct Spirc {
  41. commands: mpsc::UnboundedSender<SpircCommand>,
  42. }
  43. fn initial_state() -> State {
  44. protobuf_init!(protocol::spirc::State::new(), {
  45. repeat: false,
  46. shuffle: false,
  47. status: PlayStatus::kPlayStatusStop,
  48. position_ms: 0,
  49. position_measured_at: 0,
  50. })
  51. }
  52. fn initial_device_state(config: ConnectConfig, volume: u16) -> DeviceState {
  53. protobuf_init!(DeviceState::new(), {
  54. sw_version: version::version_string(),
  55. is_active: false,
  56. can_play: true,
  57. volume: volume as u32,
  58. name: config.name,
  59. capabilities => [
  60. @{
  61. typ: protocol::spirc::CapabilityType::kCanBePlayer,
  62. intValue => [1]
  63. },
  64. @{
  65. typ: protocol::spirc::CapabilityType::kDeviceType,
  66. intValue => [config.device_type as i64]
  67. },
  68. @{
  69. typ: protocol::spirc::CapabilityType::kGaiaEqConnectId,
  70. intValue => [1]
  71. },
  72. @{
  73. typ: protocol::spirc::CapabilityType::kSupportsLogout,
  74. intValue => [0]
  75. },
  76. @{
  77. typ: protocol::spirc::CapabilityType::kIsObservable,
  78. intValue => [1]
  79. },
  80. @{
  81. typ: protocol::spirc::CapabilityType::kVolumeSteps,
  82. intValue => [64]
  83. },
  84. @{
  85. typ: protocol::spirc::CapabilityType::kSupportedContexts,
  86. stringValue => [
  87. "album",
  88. "playlist",
  89. "search",
  90. "inbox",
  91. "toplist",
  92. "starred",
  93. "publishedstarred",
  94. "track",
  95. ]
  96. },
  97. @{
  98. typ: protocol::spirc::CapabilityType::kSupportedTypes,
  99. stringValue => [
  100. "audio/local",
  101. "audio/track",
  102. "local",
  103. "track",
  104. ]
  105. }
  106. ],
  107. })
  108. }
  109. impl Spirc {
  110. pub fn new(config: ConnectConfig, session: Session, player: Player, mixer: Box<Mixer>)
  111. -> (Spirc, SpircTask)
  112. {
  113. debug!("new Spirc[{}]", session.session_id());
  114. let ident = session.device_id().to_owned();
  115. let uri = format!("hm://remote/3/user/{}/", session.username());
  116. let subscription = session.mercury().subscribe(&uri as &str);
  117. let subscription = subscription.map(|stream| stream.map_err(|_| MercuryError)).flatten_stream();
  118. let subscription = Box::new(subscription.map(|response| -> Frame {
  119. let data = response.payload.first().unwrap();
  120. protobuf::parse_from_bytes(data).unwrap()
  121. }));
  122. let sender = Box::new(session.mercury().sender(uri).with(|frame: Frame| {
  123. Ok(frame.write_to_bytes().unwrap())
  124. }));
  125. let (cmd_tx, cmd_rx) = mpsc::unbounded();
  126. let volume = config.volume as u16;
  127. let device = initial_device_state(config, volume);
  128. mixer.set_volume(volume as u16);
  129. let mut task = SpircTask {
  130. player: player,
  131. mixer: mixer,
  132. sequence: SeqGenerator::new(1),
  133. ident: ident,
  134. device: device,
  135. state: initial_state(),
  136. subscription: subscription,
  137. sender: sender,
  138. commands: cmd_rx,
  139. end_of_track: Box::new(future::empty()),
  140. shutdown: false,
  141. session: session.clone(),
  142. };
  143. let spirc = Spirc {
  144. commands: cmd_tx,
  145. };
  146. task.hello();
  147. (spirc, task)
  148. }
  149. pub fn play(&self) {
  150. let _ = mpsc::UnboundedSender::send(&self.commands, SpircCommand::Play);
  151. }
  152. pub fn play_pause(&self) {
  153. let _ = mpsc::UnboundedSender::send(&self.commands, SpircCommand::PlayPause);
  154. }
  155. pub fn pause(&self) {
  156. let _ = mpsc::UnboundedSender::send(&self.commands, SpircCommand::Pause);
  157. }
  158. pub fn prev(&self) {
  159. let _ = mpsc::UnboundedSender::send(&self.commands, SpircCommand::Prev);
  160. }
  161. pub fn next(&self) {
  162. let _ = mpsc::UnboundedSender::send(&self.commands, SpircCommand::Next);
  163. }
  164. pub fn volume_up(&self) {
  165. let _ = mpsc::UnboundedSender::send(&self.commands, SpircCommand::VolumeUp);
  166. }
  167. pub fn volume_down(&self) {
  168. let _ = mpsc::UnboundedSender::send(&self.commands, SpircCommand::VolumeDown);
  169. }
  170. pub fn shutdown(&self) {
  171. let _ = mpsc::UnboundedSender::send(&self.commands, SpircCommand::Shutdown);
  172. }
  173. }
  174. impl Future for SpircTask {
  175. type Item = ();
  176. type Error = ();
  177. fn poll(&mut self) -> Poll<(), ()> {
  178. loop {
  179. let mut progress = false;
  180. if !self.shutdown {
  181. match self.subscription.poll().unwrap() {
  182. Async::Ready(Some(frame)) => {
  183. progress = true;
  184. self.handle_frame(frame);
  185. }
  186. Async::Ready(None) => panic!("subscription terminated"),
  187. Async::NotReady => (),
  188. }
  189. match self.commands.poll().unwrap() {
  190. Async::Ready(Some(command)) => {
  191. progress = true;
  192. self.handle_command(command);
  193. }
  194. Async::Ready(None) => (),
  195. Async::NotReady => (),
  196. }
  197. match self.end_of_track.poll() {
  198. Ok(Async::Ready(())) => {
  199. progress = true;
  200. self.handle_end_of_track();
  201. }
  202. Ok(Async::NotReady) => (),
  203. Err(oneshot::Canceled) => {
  204. self.end_of_track = Box::new(future::empty())
  205. }
  206. }
  207. }
  208. let poll_sender = self.sender.poll_complete().unwrap();
  209. // Only shutdown once we've flushed out all our messages
  210. if self.shutdown && poll_sender.is_ready() {
  211. return Ok(Async::Ready(()));
  212. }
  213. if !progress {
  214. return Ok(Async::NotReady);
  215. }
  216. }
  217. }
  218. }
  219. impl SpircTask {
  220. fn handle_command(&mut self, cmd: SpircCommand) {
  221. let active = self.device.get_is_active();
  222. match cmd {
  223. SpircCommand::Play => {
  224. if active {
  225. self.handle_play();
  226. self.notify(None);
  227. } else {
  228. CommandSender::new(self, MessageType::kMessageTypePlay).send();
  229. }
  230. }
  231. SpircCommand::PlayPause => {
  232. if active {
  233. self.handle_play_pause();
  234. self.notify(None);
  235. } else {
  236. CommandSender::new(self, MessageType::kMessageTypePlayPause).send();
  237. }
  238. }
  239. SpircCommand::Pause => {
  240. if active {
  241. self.handle_pause();
  242. self.notify(None);
  243. } else {
  244. CommandSender::new(self, MessageType::kMessageTypePause).send();
  245. }
  246. }
  247. SpircCommand::Prev => {
  248. if active {
  249. self.handle_prev();
  250. self.notify(None);
  251. } else {
  252. CommandSender::new(self, MessageType::kMessageTypePrev).send();
  253. }
  254. }
  255. SpircCommand::Next => {
  256. if active {
  257. self.handle_next();
  258. self.notify(None);
  259. } else {
  260. CommandSender::new(self, MessageType::kMessageTypeNext).send();
  261. }
  262. }
  263. SpircCommand::VolumeUp => {
  264. if active {
  265. self.handle_volume_up();
  266. self.notify(None);
  267. } else {
  268. CommandSender::new(self, MessageType::kMessageTypeVolumeUp).send();
  269. }
  270. }
  271. SpircCommand::VolumeDown => {
  272. if active {
  273. self.handle_volume_down();
  274. self.notify(None);
  275. } else {
  276. CommandSender::new(self, MessageType::kMessageTypeVolumeDown).send();
  277. }
  278. }
  279. SpircCommand::Shutdown => {
  280. CommandSender::new(self, MessageType::kMessageTypeGoodbye).send();
  281. self.shutdown = true;
  282. self.commands.close();
  283. }
  284. }
  285. }
  286. fn handle_frame(&mut self, frame: Frame) {
  287. debug!("{:?} {:?} {} {} {}",
  288. frame.get_typ(),
  289. frame.get_device_state().get_name(),
  290. frame.get_ident(),
  291. frame.get_seq_nr(),
  292. frame.get_state_update_id());
  293. if frame.get_ident() == self.ident ||
  294. (frame.get_recipient().len() > 0 && !frame.get_recipient().contains(&self.ident)) {
  295. return;
  296. }
  297. match frame.get_typ() {
  298. MessageType::kMessageTypeHello => {
  299. self.notify(Some(frame.get_ident()));
  300. }
  301. MessageType::kMessageTypeLoad => {
  302. if !self.device.get_is_active() {
  303. self.device.set_is_active(true);
  304. self.device.set_became_active_at(now_ms());
  305. }
  306. self.update_tracks(&frame);
  307. if self.state.get_track().len() > 0 {
  308. self.state.set_position_ms(frame.get_state().get_position_ms());
  309. self.state.set_position_measured_at(now_ms() as u64);
  310. let play = frame.get_state().get_status() == PlayStatus::kPlayStatusPlay;
  311. self.load_track(play);
  312. } else {
  313. self.state.set_status(PlayStatus::kPlayStatusStop);
  314. }
  315. self.notify(None);
  316. }
  317. MessageType::kMessageTypePlay => {
  318. self.handle_play();
  319. self.notify(None);
  320. }
  321. MessageType::kMessageTypePlayPause => {
  322. self.handle_play_pause();
  323. self.notify(None);
  324. }
  325. MessageType::kMessageTypePause => {
  326. self.handle_pause();
  327. self.notify(None);
  328. }
  329. MessageType::kMessageTypeNext => {
  330. self.handle_next();
  331. self.notify(None);
  332. }
  333. MessageType::kMessageTypePrev => {
  334. self.handle_prev();
  335. self.notify(None);
  336. }
  337. MessageType::kMessageTypeVolumeUp => {
  338. self.handle_volume_up();
  339. self.notify(None);
  340. }
  341. MessageType::kMessageTypeVolumeDown => {
  342. self.handle_volume_down();
  343. self.notify(None);
  344. }
  345. MessageType::kMessageTypeRepeat => {
  346. self.state.set_repeat(frame.get_state().get_repeat());
  347. self.notify(None);
  348. }
  349. MessageType::kMessageTypeShuffle => {
  350. self.state.set_shuffle(frame.get_state().get_shuffle());
  351. if self.state.get_shuffle()
  352. {
  353. let current_index = self.state.get_playing_track_index();
  354. {
  355. let tracks = self.state.mut_track();
  356. tracks.swap(0, current_index as usize);
  357. if let Some((_, rest)) = tracks.split_first_mut() {
  358. rand::thread_rng().shuffle(rest);
  359. }
  360. }
  361. self.state.set_playing_track_index(0);
  362. } else {
  363. let context = self.state.get_context_uri();
  364. debug!("{:?}", context);
  365. }
  366. self.notify(None);
  367. }
  368. MessageType::kMessageTypeSeek => {
  369. let position = frame.get_position();
  370. self.state.set_position_ms(position);
  371. self.state.set_position_measured_at(now_ms() as u64);
  372. self.player.seek(position);
  373. self.notify(None);
  374. }
  375. MessageType::kMessageTypeReplace => {
  376. self.update_tracks(&frame);
  377. self.notify(None);
  378. }
  379. MessageType::kMessageTypeVolume => {
  380. let volume = frame.get_volume();
  381. self.device.set_volume(volume);
  382. self.mixer.set_volume(frame.get_volume() as u16);
  383. self.notify(None);
  384. }
  385. MessageType::kMessageTypeNotify => {
  386. if self.device.get_is_active() &&
  387. frame.get_device_state().get_is_active()
  388. {
  389. self.device.set_is_active(false);
  390. self.state.set_status(PlayStatus::kPlayStatusStop);
  391. self.player.stop();
  392. self.mixer.stop();
  393. }
  394. }
  395. _ => (),
  396. }
  397. }
  398. fn handle_play(&mut self) {
  399. if self.state.get_status() == PlayStatus::kPlayStatusPause {
  400. self.mixer.start();
  401. self.player.play();
  402. self.state.set_status(PlayStatus::kPlayStatusPlay);
  403. self.state.set_position_measured_at(now_ms() as u64);
  404. }
  405. }
  406. fn handle_play_pause(&mut self) {
  407. match self.state.get_status() {
  408. PlayStatus::kPlayStatusPlay => self.handle_pause(),
  409. PlayStatus::kPlayStatusPause => self.handle_play(),
  410. _ => (),
  411. }
  412. }
  413. fn handle_pause(&mut self) {
  414. if self.state.get_status() == PlayStatus::kPlayStatusPlay {
  415. self.player.pause();
  416. self.mixer.stop();
  417. self.state.set_status(PlayStatus::kPlayStatusPause);
  418. let now = now_ms() as u64;
  419. let position = self.state.get_position_ms();
  420. let diff = now - self.state.get_position_measured_at();
  421. self.state.set_position_ms(position + diff as u32);
  422. self.state.set_position_measured_at(now);
  423. }
  424. }
  425. fn handle_next(&mut self) {
  426. let current_index = self.state.get_playing_track_index();
  427. let num_tracks = self.state.get_track().len() as u32;
  428. let new_index = (current_index + 1) % num_tracks;
  429. let mut was_last_track = (current_index + 1) >= num_tracks;
  430. if self.state.get_repeat() {
  431. was_last_track = false;
  432. }
  433. self.state.set_playing_track_index(new_index);
  434. self.state.set_position_ms(0);
  435. self.state.set_position_measured_at(now_ms() as u64);
  436. self.load_track(!was_last_track);
  437. }
  438. fn handle_prev(&mut self) {
  439. // Previous behaves differently based on the position
  440. // Under 3s it goes to the previous song
  441. // Over 3s it seeks to zero
  442. if self.position() < 3000 {
  443. let current_index = self.state.get_playing_track_index();
  444. let new_index = if current_index == 0 {
  445. self.state.get_track().len() as u32 - 1
  446. } else {
  447. current_index - 1
  448. };
  449. self.state.set_playing_track_index(new_index);
  450. self.state.set_position_ms(0);
  451. self.state.set_position_measured_at(now_ms() as u64);
  452. self.load_track(true);
  453. } else {
  454. self.state.set_position_ms(0);
  455. self.state.set_position_measured_at(now_ms() as u64);
  456. self.player.seek(0);
  457. }
  458. }
  459. fn handle_volume_up(&mut self) {
  460. let mut volume: u32 = self.mixer.volume() as u32 + 4096;
  461. if volume > 0xFFFF {
  462. volume = 0xFFFF;
  463. }
  464. self.device.set_volume(volume);
  465. self.mixer.set_volume(volume as u16);
  466. }
  467. fn handle_volume_down(&mut self) {
  468. let mut volume: i32 = self.mixer.volume() as i32 - 4096;
  469. if volume < 0 {
  470. volume = 0;
  471. }
  472. self.device.set_volume(volume as u32);
  473. self.mixer.set_volume(volume as u16);
  474. }
  475. fn handle_end_of_track(&mut self) {
  476. self.handle_next();
  477. self.notify(None);
  478. }
  479. fn position(&mut self) -> u32 {
  480. let diff = now_ms() as u64 - self.state.get_position_measured_at();
  481. self.state.get_position_ms() + diff as u32
  482. }
  483. fn update_tracks(&mut self, frame: &protocol::spirc::Frame) {
  484. let index = frame.get_state().get_playing_track_index();
  485. let tracks = frame.get_state().get_track();
  486. self.state.set_playing_track_index(index);
  487. self.state.set_track(tracks.into_iter().cloned().collect());
  488. }
  489. fn load_track(&mut self, play: bool) {
  490. let index = self.state.get_playing_track_index();
  491. let track = {
  492. let gid = self.state.get_track()[index as usize].get_gid();
  493. SpotifyId::from_raw(gid)
  494. };
  495. let position = self.state.get_position_ms();
  496. let end_of_track = self.player.load(track, play, position);
  497. if play {
  498. self.state.set_status(PlayStatus::kPlayStatusPlay);
  499. } else {
  500. self.state.set_status(PlayStatus::kPlayStatusPause);
  501. }
  502. self.end_of_track = Box::new(end_of_track);
  503. }
  504. fn hello(&mut self) {
  505. CommandSender::new(self, MessageType::kMessageTypeHello).send();
  506. }
  507. fn notify(&mut self, recipient: Option<&str>) {
  508. let mut cs = CommandSender::new(self, MessageType::kMessageTypeNotify);
  509. if let Some(s) = recipient {
  510. cs = cs.recipient(&s);
  511. }
  512. cs.send();
  513. }
  514. }
  515. impl Drop for SpircTask {
  516. fn drop(&mut self) {
  517. debug!("drop Spirc[{}]", self.session.session_id());
  518. }
  519. }
  520. struct CommandSender<'a> {
  521. spirc: &'a mut SpircTask,
  522. frame: protocol::spirc::Frame,
  523. }
  524. impl<'a> CommandSender<'a> {
  525. fn new(spirc: &'a mut SpircTask, cmd: MessageType) -> CommandSender {
  526. let frame = protobuf_init!(protocol::spirc::Frame::new(), {
  527. version: 1,
  528. protocol_version: "2.0.0",
  529. ident: spirc.ident.clone(),
  530. seq_nr: spirc.sequence.get(),
  531. typ: cmd,
  532. device_state: spirc.device.clone(),
  533. state_update_id: now_ms(),
  534. });
  535. CommandSender {
  536. spirc: spirc,
  537. frame: frame,
  538. }
  539. }
  540. fn recipient(mut self, recipient: &'a str) -> CommandSender {
  541. self.frame.mut_recipient().push(recipient.to_owned());
  542. self
  543. }
  544. #[allow(dead_code)]
  545. fn state(mut self, state: protocol::spirc::State) -> CommandSender<'a> {
  546. self.frame.set_state(state);
  547. self
  548. }
  549. fn send(mut self) {
  550. if !self.frame.has_state() && self.spirc.device.get_is_active() {
  551. self.frame.set_state(self.spirc.state.clone());
  552. }
  553. let send = self.spirc.sender.start_send(self.frame).unwrap();
  554. assert!(send.is_ready());
  555. }
  556. }