PlayerState.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. #include "PlayerState.h"
  2. #include "Logger.h"
  3. #include "ConfigJSON.h"
  4. PlayerState::PlayerState(std::shared_ptr<TimeProvider> timeProvider)
  5. {
  6. this->timeProvider = timeProvider;
  7. innerFrame = {};
  8. remoteFrame = {};
  9. // Prepare default state
  10. innerFrame.state.has_position_ms = true;
  11. innerFrame.state.position_ms = 0;
  12. innerFrame.state.status = PlayStatus_kPlayStatusStop;
  13. innerFrame.state.has_status = true;
  14. innerFrame.state.position_measured_at = 0;
  15. innerFrame.state.has_position_measured_at = true;
  16. innerFrame.state.shuffle = false;
  17. innerFrame.state.has_shuffle = true;
  18. innerFrame.state.repeat = false;
  19. innerFrame.state.has_repeat = true;
  20. innerFrame.device_state.sw_version = strdup(swVersion);
  21. innerFrame.device_state.is_active = false;
  22. innerFrame.device_state.has_is_active = true;
  23. innerFrame.device_state.can_play = true;
  24. innerFrame.device_state.has_can_play = true;
  25. innerFrame.device_state.volume = configMan->volume;
  26. innerFrame.device_state.has_volume = true;
  27. innerFrame.device_state.name = strdup(configMan->deviceName.c_str());
  28. // Prepare player's capabilities
  29. addCapability(CapabilityType_kCanBePlayer, 1);
  30. addCapability(CapabilityType_kDeviceType, 4);
  31. addCapability(CapabilityType_kGaiaEqConnectId, 1);
  32. addCapability(CapabilityType_kSupportsLogout, 0);
  33. addCapability(CapabilityType_kIsObservable, 1);
  34. addCapability(CapabilityType_kVolumeSteps, 64);
  35. addCapability(CapabilityType_kSupportedContexts, -1,
  36. std::vector<std::string>({"album", "playlist", "search", "inbox",
  37. "toplist", "starred", "publishedstarred", "track"}));
  38. addCapability(CapabilityType_kSupportedTypes, -1,
  39. std::vector<std::string>({"audio/local", "audio/track", "audio/episode", "local", "track"}));
  40. innerFrame.device_state.capabilities_count = 8;
  41. }
  42. PlayerState::~PlayerState() {
  43. pb_release(Frame_fields, &innerFrame);
  44. pb_release(Frame_fields, &remoteFrame);
  45. }
  46. void PlayerState::setPlaybackState(const PlaybackState state)
  47. {
  48. switch (state)
  49. {
  50. case PlaybackState::Loading:
  51. // Prepare the playback at position 0
  52. innerFrame.state.status = PlayStatus_kPlayStatusPause;
  53. innerFrame.state.position_ms = 0;
  54. innerFrame.state.position_measured_at = timeProvider->getSyncedTimestamp();
  55. break;
  56. case PlaybackState::Playing:
  57. innerFrame.state.status = PlayStatus_kPlayStatusPlay;
  58. innerFrame.state.position_measured_at = timeProvider->getSyncedTimestamp();
  59. break;
  60. case PlaybackState::Stopped:
  61. break;
  62. case PlaybackState::Paused:
  63. // Update state and recalculate current song position
  64. innerFrame.state.status = PlayStatus_kPlayStatusPause;
  65. uint32_t diff = timeProvider->getSyncedTimestamp() - innerFrame.state.position_measured_at;
  66. this->updatePositionMs(innerFrame.state.position_ms + diff);
  67. break;
  68. }
  69. }
  70. bool PlayerState::isActive()
  71. {
  72. return innerFrame.device_state.is_active;
  73. }
  74. bool PlayerState::nextTrack()
  75. {
  76. if (innerFrame.state.repeat) return true;
  77. innerFrame.state.playing_track_index++;
  78. if (innerFrame.state.playing_track_index >= innerFrame.state.track_count)
  79. {
  80. innerFrame.state.playing_track_index = 0;
  81. if (!innerFrame.state.repeat)
  82. {
  83. setPlaybackState(PlaybackState::Paused);
  84. return false;
  85. }
  86. }
  87. return true;
  88. }
  89. void PlayerState::prevTrack()
  90. {
  91. if (innerFrame.state.playing_track_index > 0)
  92. {
  93. innerFrame.state.playing_track_index--;
  94. }
  95. else if (innerFrame.state.repeat)
  96. {
  97. innerFrame.state.playing_track_index = innerFrame.state.track_count - 1;
  98. }
  99. }
  100. void PlayerState::setActive(bool isActive)
  101. {
  102. innerFrame.device_state.is_active = isActive;
  103. if (isActive)
  104. {
  105. innerFrame.device_state.became_active_at = timeProvider->getSyncedTimestamp();
  106. innerFrame.device_state.has_became_active_at = true;
  107. }
  108. }
  109. void PlayerState::updatePositionMs(uint32_t position)
  110. {
  111. innerFrame.state.position_ms = position;
  112. innerFrame.state.position_measured_at = timeProvider->getSyncedTimestamp();
  113. }
  114. void PlayerState::updateTracks()
  115. {
  116. CSPOT_LOG(info, "---- Track count %d", remoteFrame.state.track_count);
  117. std::swap(innerFrame.state.context_uri, remoteFrame.state.context_uri);
  118. std::swap(innerFrame.state.track, remoteFrame.state.track);
  119. innerFrame.state.track_count = remoteFrame.state.track_count;
  120. innerFrame.state.has_playing_track_index = true;
  121. innerFrame.state.playing_track_index = remoteFrame.state.playing_track_index;
  122. if (remoteFrame.state.repeat)
  123. {
  124. setRepeat(true);
  125. }
  126. if (remoteFrame.state.shuffle)
  127. {
  128. setShuffle(true);
  129. }
  130. }
  131. void PlayerState::setVolume(uint32_t volume)
  132. {
  133. innerFrame.device_state.volume = volume;
  134. configMan->volume = volume;
  135. configMan->save();
  136. }
  137. void PlayerState::setShuffle(bool shuffle)
  138. {
  139. innerFrame.state.shuffle = shuffle;
  140. if (shuffle)
  141. {
  142. // Put current song at the begining
  143. std::swap(innerFrame.state.track[0], innerFrame.state.track[innerFrame.state.playing_track_index]);
  144. // Shuffle current tracks
  145. for (int x = 1; x < innerFrame.state.track_count - 1; x++)
  146. {
  147. auto j = x + (std::rand() % (innerFrame.state.track_count - x));
  148. std::swap(innerFrame.state.track[j], innerFrame.state.track[x]);
  149. }
  150. innerFrame.state.playing_track_index = 0;
  151. }
  152. }
  153. void PlayerState::setRepeat(bool repeat)
  154. {
  155. innerFrame.state.repeat = repeat;
  156. }
  157. std::shared_ptr<TrackReference> PlayerState::getCurrentTrack()
  158. {
  159. // Wrap current track in a class
  160. return std::make_shared<TrackReference>(&innerFrame.state.track[innerFrame.state.playing_track_index]);
  161. }
  162. std::vector<uint8_t> PlayerState::encodeCurrentFrame(MessageType typ)
  163. {
  164. free(innerFrame.ident);
  165. free(innerFrame.protocol_version);
  166. // Prepare current frame info
  167. innerFrame.version = 1;
  168. innerFrame.ident = strdup(deviceId);
  169. innerFrame.seq_nr = this->seqNum;
  170. innerFrame.protocol_version = strdup(protocolVersion);
  171. innerFrame.typ = typ;
  172. innerFrame.state_update_id = timeProvider->getSyncedTimestamp();
  173. innerFrame.has_version = true;
  174. innerFrame.has_seq_nr = true;
  175. innerFrame.recipient_count = 0;
  176. innerFrame.has_state = true;
  177. innerFrame.has_device_state = true;
  178. innerFrame.has_typ = true;
  179. innerFrame.has_state_update_id = true;
  180. this->seqNum += 1;
  181. return pbEncode(Frame_fields, &innerFrame);
  182. }
  183. // Wraps messy nanopb setters. @TODO: find a better way to handle this
  184. void PlayerState::addCapability(CapabilityType typ, int intValue, std::vector<std::string> stringValue)
  185. {
  186. innerFrame.device_state.capabilities[capabilityIndex].has_typ = true;
  187. this->innerFrame.device_state.capabilities[capabilityIndex].typ = typ;
  188. if (intValue != -1)
  189. {
  190. this->innerFrame.device_state.capabilities[capabilityIndex].intValue[0] = intValue;
  191. this->innerFrame.device_state.capabilities[capabilityIndex].intValue_count = 1;
  192. }
  193. else
  194. {
  195. this->innerFrame.device_state.capabilities[capabilityIndex].intValue_count = 0;
  196. }
  197. for (int x = 0; x < stringValue.size(); x++)
  198. {
  199. pbPutString(stringValue[x], this->innerFrame.device_state.capabilities[capabilityIndex].stringValue[x]);
  200. }
  201. this->innerFrame.device_state.capabilities[capabilityIndex].stringValue_count = stringValue.size();
  202. this->capabilityIndex += 1;
  203. }