2
0

PlayerState.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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. innerFrame.state.track_count = 0;
  29. // Prepare player's capabilities
  30. addCapability(CapabilityType_kCanBePlayer, 1);
  31. addCapability(CapabilityType_kDeviceType, 4);
  32. addCapability(CapabilityType_kGaiaEqConnectId, 1);
  33. addCapability(CapabilityType_kSupportsLogout, 0);
  34. addCapability(CapabilityType_kIsObservable, 1);
  35. addCapability(CapabilityType_kVolumeSteps, 64);
  36. addCapability(CapabilityType_kSupportedContexts, -1,
  37. std::vector<std::string>({"album", "playlist", "search", "inbox",
  38. "toplist", "starred", "publishedstarred", "track"}));
  39. addCapability(CapabilityType_kSupportedTypes, -1,
  40. std::vector<std::string>({"audio/local", "audio/track", "audio/episode", "local", "track"}));
  41. innerFrame.device_state.capabilities_count = 8;
  42. }
  43. PlayerState::~PlayerState() {
  44. pb_release(Frame_fields, &innerFrame);
  45. pb_release(Frame_fields, &remoteFrame);
  46. }
  47. void PlayerState::setPlaybackState(const PlaybackState state)
  48. {
  49. switch (state)
  50. {
  51. case PlaybackState::Loading:
  52. // Prepare the playback at position 0
  53. innerFrame.state.status = PlayStatus_kPlayStatusPause;
  54. innerFrame.state.position_ms = 0;
  55. innerFrame.state.position_measured_at = timeProvider->getSyncedTimestamp();
  56. break;
  57. case PlaybackState::Playing:
  58. innerFrame.state.status = PlayStatus_kPlayStatusPlay;
  59. innerFrame.state.position_measured_at = timeProvider->getSyncedTimestamp();
  60. break;
  61. case PlaybackState::Stopped:
  62. break;
  63. case PlaybackState::Paused:
  64. // Update state and recalculate current song position
  65. innerFrame.state.status = PlayStatus_kPlayStatusPause;
  66. uint32_t diff = timeProvider->getSyncedTimestamp() - innerFrame.state.position_measured_at;
  67. this->updatePositionMs(innerFrame.state.position_ms + diff);
  68. break;
  69. }
  70. }
  71. bool PlayerState::isActive()
  72. {
  73. return innerFrame.device_state.is_active;
  74. }
  75. bool PlayerState::nextTrack()
  76. {
  77. if (innerFrame.state.repeat) return true;
  78. innerFrame.state.playing_track_index++;
  79. if (innerFrame.state.playing_track_index >= innerFrame.state.track_count)
  80. {
  81. innerFrame.state.playing_track_index = 0;
  82. if (!innerFrame.state.repeat)
  83. {
  84. setPlaybackState(PlaybackState::Paused);
  85. return false;
  86. }
  87. }
  88. return true;
  89. }
  90. void PlayerState::prevTrack()
  91. {
  92. if (innerFrame.state.playing_track_index > 0)
  93. {
  94. innerFrame.state.playing_track_index--;
  95. }
  96. else if (innerFrame.state.repeat)
  97. {
  98. innerFrame.state.playing_track_index = innerFrame.state.track_count - 1;
  99. }
  100. }
  101. void PlayerState::setActive(bool isActive)
  102. {
  103. innerFrame.device_state.is_active = isActive;
  104. if (isActive)
  105. {
  106. innerFrame.device_state.became_active_at = timeProvider->getSyncedTimestamp();
  107. innerFrame.device_state.has_became_active_at = true;
  108. }
  109. }
  110. void PlayerState::updatePositionMs(uint32_t position)
  111. {
  112. innerFrame.state.position_ms = position;
  113. innerFrame.state.position_measured_at = timeProvider->getSyncedTimestamp();
  114. }
  115. void PlayerState::updateTracks()
  116. {
  117. CSPOT_LOG(info, "---- Track count %d", remoteFrame.state.track_count);
  118. // free unused tracks
  119. if(innerFrame.state.track_count > remoteFrame.state.track_count)
  120. {
  121. for(uint16_t i = remoteFrame.state.track_count; i < innerFrame.state.track_count; ++i)
  122. {
  123. free(innerFrame.state.track[i].gid);
  124. }
  125. }
  126. // reallocate memory for new tracks
  127. innerFrame.state.track = (TrackRef *) realloc(innerFrame.state.track, sizeof(TrackRef) * remoteFrame.state.track_count);
  128. for(uint16_t i = 0; i < remoteFrame.state.track_count; ++i)
  129. {
  130. uint16_t gid_size = remoteFrame.state.track[i].gid->size;
  131. // allocate if need more tracks
  132. if(i >= innerFrame.state.track_count)
  133. {
  134. innerFrame.state.track[i].gid = (pb_bytes_array_t *) malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(gid_size));
  135. }
  136. memcpy(innerFrame.state.track[i].gid->bytes, remoteFrame.state.track[i].gid->bytes, gid_size);
  137. innerFrame.state.track[i].gid->size = gid_size;
  138. innerFrame.state.track[i].has_queued = remoteFrame.state.track[i].has_queued;
  139. innerFrame.state.track[i].queued = remoteFrame.state.track[i].queued;
  140. // not used?
  141. innerFrame.state.track[i].uri = NULL;
  142. innerFrame.state.track[i].context = NULL;
  143. }
  144. innerFrame.state.context_uri = (char *) realloc(innerFrame.state.context_uri,
  145. strlen(remoteFrame.state.context_uri) + 1);
  146. strcpy(innerFrame.state.context_uri, remoteFrame.state.context_uri);
  147. innerFrame.state.track_count = remoteFrame.state.track_count;
  148. innerFrame.state.has_playing_track_index = true;
  149. innerFrame.state.playing_track_index = remoteFrame.state.playing_track_index;
  150. if (remoteFrame.state.repeat)
  151. {
  152. setRepeat(true);
  153. }
  154. if (remoteFrame.state.shuffle)
  155. {
  156. setShuffle(true);
  157. }
  158. }
  159. void PlayerState::setVolume(uint32_t volume)
  160. {
  161. innerFrame.device_state.volume = volume;
  162. configMan->volume = volume;
  163. configMan->save();
  164. }
  165. void PlayerState::setShuffle(bool shuffle)
  166. {
  167. innerFrame.state.shuffle = shuffle;
  168. if (shuffle)
  169. {
  170. // Put current song at the begining
  171. std::swap(innerFrame.state.track[0], innerFrame.state.track[innerFrame.state.playing_track_index]);
  172. // Shuffle current tracks
  173. for (int x = 1; x < innerFrame.state.track_count - 1; x++)
  174. {
  175. auto j = x + (std::rand() % (innerFrame.state.track_count - x));
  176. std::swap(innerFrame.state.track[j], innerFrame.state.track[x]);
  177. }
  178. innerFrame.state.playing_track_index = 0;
  179. }
  180. }
  181. void PlayerState::setRepeat(bool repeat)
  182. {
  183. innerFrame.state.repeat = repeat;
  184. }
  185. std::shared_ptr<TrackReference> PlayerState::getCurrentTrack()
  186. {
  187. // Wrap current track in a class
  188. return std::make_shared<TrackReference>(&innerFrame.state.track[innerFrame.state.playing_track_index]);
  189. }
  190. std::vector<uint8_t> PlayerState::encodeCurrentFrame(MessageType typ)
  191. {
  192. free(innerFrame.ident);
  193. free(innerFrame.protocol_version);
  194. // Prepare current frame info
  195. innerFrame.version = 1;
  196. innerFrame.ident = strdup(deviceId);
  197. innerFrame.seq_nr = this->seqNum;
  198. innerFrame.protocol_version = strdup(protocolVersion);
  199. innerFrame.typ = typ;
  200. innerFrame.state_update_id = timeProvider->getSyncedTimestamp();
  201. innerFrame.has_version = true;
  202. innerFrame.has_seq_nr = true;
  203. innerFrame.recipient_count = 0;
  204. innerFrame.has_state = true;
  205. innerFrame.has_device_state = true;
  206. innerFrame.has_typ = true;
  207. innerFrame.has_state_update_id = true;
  208. this->seqNum += 1;
  209. return pbEncode(Frame_fields, &innerFrame);
  210. }
  211. // Wraps messy nanopb setters. @TODO: find a better way to handle this
  212. void PlayerState::addCapability(CapabilityType typ, int intValue, std::vector<std::string> stringValue)
  213. {
  214. innerFrame.device_state.capabilities[capabilityIndex].has_typ = true;
  215. this->innerFrame.device_state.capabilities[capabilityIndex].typ = typ;
  216. if (intValue != -1)
  217. {
  218. this->innerFrame.device_state.capabilities[capabilityIndex].intValue[0] = intValue;
  219. this->innerFrame.device_state.capabilities[capabilityIndex].intValue_count = 1;
  220. }
  221. else
  222. {
  223. this->innerFrame.device_state.capabilities[capabilityIndex].intValue_count = 0;
  224. }
  225. for (int x = 0; x < stringValue.size(); x++)
  226. {
  227. pbPutString(stringValue[x], this->innerFrame.device_state.capabilities[capabilityIndex].stringValue[x]);
  228. }
  229. this->innerFrame.device_state.capabilities[capabilityIndex].stringValue_count = stringValue.size();
  230. this->capabilityIndex += 1;
  231. }