PlayerState.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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. // Prepare default state
  8. innerFrame.state.emplace();
  9. innerFrame.state->position_ms = 0;
  10. innerFrame.state->status = PlayStatus::kPlayStatusStop;
  11. innerFrame.state->position_measured_at = 0;
  12. innerFrame.state->shuffle = false;
  13. innerFrame.state->repeat = false;
  14. innerFrame.device_state.emplace();
  15. innerFrame.device_state->sw_version = swVersion;
  16. innerFrame.device_state->is_active = false;
  17. innerFrame.device_state->can_play = true;
  18. innerFrame.device_state->volume = configMan->volume;
  19. innerFrame.device_state->name = configMan->deviceName;
  20. // Prepare player's capabilities
  21. innerFrame.device_state->capabilities = std::vector<Capability>();
  22. addCapability(CapabilityType::kCanBePlayer, 1);
  23. addCapability(CapabilityType::kDeviceType, 4);
  24. addCapability(CapabilityType::kGaiaEqConnectId, 1);
  25. addCapability(CapabilityType::kSupportsLogout, 0);
  26. addCapability(CapabilityType::kIsObservable, 1);
  27. addCapability(CapabilityType::kVolumeSteps, 64);
  28. addCapability(CapabilityType::kSupportedContexts, -1,
  29. std::vector<std::string>({"album", "playlist", "search", "inbox",
  30. "toplist", "starred", "publishedstarred", "track"}));
  31. addCapability(CapabilityType::kSupportedTypes, -1,
  32. std::vector<std::string>({"audio/local", "audio/track", "audio/episode", "local", "track"}));
  33. }
  34. void PlayerState::setPlaybackState(const PlaybackState state)
  35. {
  36. switch (state)
  37. {
  38. case PlaybackState::Loading:
  39. // Prepare the playback at position 0
  40. innerFrame.state->status = PlayStatus::kPlayStatusPause;
  41. innerFrame.state->position_ms = 0;
  42. innerFrame.state->position_measured_at = timeProvider->getSyncedTimestamp();
  43. break;
  44. case PlaybackState::Playing:
  45. innerFrame.state->status = PlayStatus::kPlayStatusPlay;
  46. innerFrame.state->position_measured_at = timeProvider->getSyncedTimestamp();
  47. break;
  48. case PlaybackState::Stopped:
  49. break;
  50. case PlaybackState::Paused:
  51. // Update state and recalculate current song position
  52. innerFrame.state->status = PlayStatus::kPlayStatusPause;
  53. uint32_t diff = timeProvider->getSyncedTimestamp() - innerFrame.state->position_measured_at.value();
  54. this->updatePositionMs(innerFrame.state->position_ms.value() + diff);
  55. break;
  56. }
  57. }
  58. bool PlayerState::isActive()
  59. {
  60. return innerFrame.device_state->is_active.value();
  61. }
  62. bool PlayerState::nextTrack()
  63. {
  64. innerFrame.state->playing_track_index.value()++;
  65. if (innerFrame.state->playing_track_index >= innerFrame.state->track.size())
  66. {
  67. innerFrame.state->playing_track_index = 0;
  68. if (!innerFrame.state->repeat)
  69. {
  70. setPlaybackState(PlaybackState::Paused);
  71. return false;
  72. }
  73. }
  74. return true;
  75. }
  76. void PlayerState::prevTrack()
  77. {
  78. if (innerFrame.state->playing_track_index > 0)
  79. {
  80. innerFrame.state->playing_track_index.value()--;
  81. }
  82. else if (innerFrame.state->repeat)
  83. {
  84. innerFrame.state->playing_track_index = innerFrame.state->track.size() - 1;
  85. }
  86. }
  87. void PlayerState::setActive(bool isActive)
  88. {
  89. innerFrame.device_state->is_active = isActive;
  90. if (isActive)
  91. {
  92. innerFrame.device_state->became_active_at = timeProvider->getSyncedTimestamp();
  93. }
  94. }
  95. void PlayerState::updatePositionMs(uint32_t position)
  96. {
  97. innerFrame.state->position_ms = position;
  98. innerFrame.state->position_measured_at = timeProvider->getSyncedTimestamp();
  99. }
  100. void PlayerState::updateTracks()
  101. {
  102. CSPOT_LOG(info, "---- Track count %d", remoteFrame.state->track.size());
  103. // innerFrame.state->context_uri = remoteFrame.state->context_uri == nullptr ? nullptr : strdup(otherFrame->state->context_uri);
  104. innerFrame.state->track = remoteFrame.state->track;
  105. innerFrame.state->playing_track_index = remoteFrame.state->playing_track_index;
  106. if (remoteFrame.state->repeat.value())
  107. {
  108. setRepeat(true);
  109. }
  110. if (remoteFrame.state->shuffle.value())
  111. {
  112. setShuffle(true);
  113. }
  114. }
  115. void PlayerState::setVolume(uint32_t volume)
  116. {
  117. innerFrame.device_state->volume = volume;
  118. configMan->volume = volume;
  119. configMan->save();
  120. }
  121. void PlayerState::setShuffle(bool shuffle)
  122. {
  123. innerFrame.state->shuffle = shuffle;
  124. if (shuffle)
  125. {
  126. // Put current song at the begining
  127. auto tmp = innerFrame.state->track.at(0);
  128. innerFrame.state->track.at(0) = innerFrame.state->track.at(innerFrame.state->playing_track_index.value());
  129. innerFrame.state->track.at(innerFrame.state->playing_track_index.value()) = tmp;
  130. // Shuffle current tracks
  131. for (int x = 1; x < innerFrame.state->track.size() - 1; x++)
  132. {
  133. auto j = x + (std::rand() % (innerFrame.state->track.size() - x));
  134. tmp = innerFrame.state->track.at(j);
  135. innerFrame.state->track.at(j) = innerFrame.state->track.at(x);
  136. innerFrame.state->track.at(x) = tmp;
  137. }
  138. innerFrame.state->playing_track_index = 0;
  139. }
  140. }
  141. void PlayerState::setRepeat(bool repeat)
  142. {
  143. innerFrame.state->repeat = repeat;
  144. }
  145. std::shared_ptr<TrackReference> PlayerState::getCurrentTrack()
  146. {
  147. // Wrap current track in a class
  148. return std::make_shared<TrackReference>(&innerFrame.state->track.at(innerFrame.state->playing_track_index.value()));
  149. }
  150. std::vector<uint8_t> PlayerState::encodeCurrentFrame(MessageType typ)
  151. {
  152. // Prepare current frame info
  153. innerFrame.version = 1;
  154. innerFrame.ident = deviceId;
  155. innerFrame.seq_nr = this->seqNum;
  156. innerFrame.protocol_version = protocolVersion;
  157. innerFrame.typ = typ;
  158. innerFrame.state_update_id = timeProvider->getSyncedTimestamp();
  159. this->seqNum += 1;
  160. auto fram = encodePb(innerFrame);
  161. return fram;
  162. }
  163. // Wraps messy nanopb setters. @TODO: find a better way to handle this
  164. void PlayerState::addCapability(CapabilityType typ, int intValue, std::vector<std::string> stringValue)
  165. {
  166. auto capability = Capability();
  167. capability.typ = typ;
  168. if (intValue != -1)
  169. {
  170. capability.intValue = std::vector<int64_t>({intValue});
  171. }
  172. capability.stringValue = stringValue;
  173. innerFrame.device_state->capabilities.push_back(capability);
  174. }