123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- #include "PlayerState.h"
- #include "Logger.h"
- #include "ConfigJSON.h"
- PlayerState::PlayerState(std::shared_ptr<TimeProvider> timeProvider)
- {
- this->timeProvider = timeProvider;
- // Prepare default state
- innerFrame.state.emplace();
- innerFrame.state->position_ms = 0;
- innerFrame.state->status = PlayStatus::kPlayStatusStop;
- innerFrame.state->position_measured_at = 0;
- innerFrame.state->shuffle = false;
- innerFrame.state->repeat = false;
- innerFrame.device_state.emplace();
- innerFrame.device_state->sw_version = swVersion;
- innerFrame.device_state->is_active = false;
- innerFrame.device_state->can_play = true;
- innerFrame.device_state->volume = configMan->volume;
- innerFrame.device_state->name = configMan->deviceName;
- // Prepare player's capabilities
- innerFrame.device_state->capabilities = std::vector<Capability>();
- addCapability(CapabilityType::kCanBePlayer, 1);
- addCapability(CapabilityType::kDeviceType, 4);
- addCapability(CapabilityType::kGaiaEqConnectId, 1);
- addCapability(CapabilityType::kSupportsLogout, 0);
- addCapability(CapabilityType::kIsObservable, 1);
- addCapability(CapabilityType::kVolumeSteps, 64);
- addCapability(CapabilityType::kSupportedContexts, -1,
- std::vector<std::string>({"album", "playlist", "search", "inbox",
- "toplist", "starred", "publishedstarred", "track"}));
- addCapability(CapabilityType::kSupportedTypes, -1,
- std::vector<std::string>({"audio/local", "audio/track", "audio/episode", "local", "track"}));
- }
- void PlayerState::setPlaybackState(const PlaybackState state)
- {
- switch (state)
- {
- case PlaybackState::Loading:
- // Prepare the playback at position 0
- innerFrame.state->status = PlayStatus::kPlayStatusPause;
- innerFrame.state->position_ms = 0;
- innerFrame.state->position_measured_at = timeProvider->getSyncedTimestamp();
- break;
- case PlaybackState::Playing:
- innerFrame.state->status = PlayStatus::kPlayStatusPlay;
- innerFrame.state->position_measured_at = timeProvider->getSyncedTimestamp();
- break;
- case PlaybackState::Stopped:
- break;
- case PlaybackState::Paused:
- // Update state and recalculate current song position
- innerFrame.state->status = PlayStatus::kPlayStatusPause;
- uint32_t diff = timeProvider->getSyncedTimestamp() - innerFrame.state->position_measured_at.value();
- this->updatePositionMs(innerFrame.state->position_ms.value() + diff);
- break;
- }
- }
- bool PlayerState::isActive()
- {
- return innerFrame.device_state->is_active.value();
- }
- bool PlayerState::nextTrack()
- {
- innerFrame.state->playing_track_index.value()++;
- if (innerFrame.state->playing_track_index >= innerFrame.state->track.size())
- {
- innerFrame.state->playing_track_index = 0;
- if (!innerFrame.state->repeat)
- {
- setPlaybackState(PlaybackState::Paused);
- return false;
- }
- }
- return true;
- }
- void PlayerState::prevTrack()
- {
- if (innerFrame.state->playing_track_index > 0)
- {
- innerFrame.state->playing_track_index.value()--;
- }
- else if (innerFrame.state->repeat)
- {
- innerFrame.state->playing_track_index = innerFrame.state->track.size() - 1;
- }
- }
- void PlayerState::setActive(bool isActive)
- {
- innerFrame.device_state->is_active = isActive;
- if (isActive)
- {
- innerFrame.device_state->became_active_at = timeProvider->getSyncedTimestamp();
- }
- }
- void PlayerState::updatePositionMs(uint32_t position)
- {
- innerFrame.state->position_ms = position;
- innerFrame.state->position_measured_at = timeProvider->getSyncedTimestamp();
- }
- void PlayerState::updateTracks()
- {
- CSPOT_LOG(info, "---- Track count %d", remoteFrame.state->track.size());
- // innerFrame.state->context_uri = remoteFrame.state->context_uri == nullptr ? nullptr : strdup(otherFrame->state->context_uri);
- innerFrame.state->track = remoteFrame.state->track;
- innerFrame.state->playing_track_index = remoteFrame.state->playing_track_index;
- if (remoteFrame.state->repeat.value())
- {
- setRepeat(true);
- }
- if (remoteFrame.state->shuffle.value())
- {
- setShuffle(true);
- }
- }
- void PlayerState::setVolume(uint32_t volume)
- {
- innerFrame.device_state->volume = volume;
- configMan->volume = volume;
- configMan->save();
- }
- void PlayerState::setShuffle(bool shuffle)
- {
- innerFrame.state->shuffle = shuffle;
- if (shuffle)
- {
- // Put current song at the begining
- auto tmp = innerFrame.state->track.at(0);
- innerFrame.state->track.at(0) = innerFrame.state->track.at(innerFrame.state->playing_track_index.value());
- innerFrame.state->track.at(innerFrame.state->playing_track_index.value()) = tmp;
- // Shuffle current tracks
- for (int x = 1; x < innerFrame.state->track.size() - 1; x++)
- {
- auto j = x + (std::rand() % (innerFrame.state->track.size() - x));
- tmp = innerFrame.state->track.at(j);
- innerFrame.state->track.at(j) = innerFrame.state->track.at(x);
- innerFrame.state->track.at(x) = tmp;
- }
- innerFrame.state->playing_track_index = 0;
- }
- }
- void PlayerState::setRepeat(bool repeat)
- {
- innerFrame.state->repeat = repeat;
- }
- std::shared_ptr<TrackReference> PlayerState::getCurrentTrack()
- {
- // Wrap current track in a class
- return std::make_shared<TrackReference>(&innerFrame.state->track.at(innerFrame.state->playing_track_index.value()));
- }
- std::vector<uint8_t> PlayerState::encodeCurrentFrame(MessageType typ)
- {
- // Prepare current frame info
- innerFrame.version = 1;
- innerFrame.ident = deviceId;
- innerFrame.seq_nr = this->seqNum;
- innerFrame.protocol_version = protocolVersion;
- innerFrame.typ = typ;
- innerFrame.state_update_id = timeProvider->getSyncedTimestamp();
- this->seqNum += 1;
- auto fram = encodePb(innerFrame);
- return fram;
- }
- // Wraps messy nanopb setters. @TODO: find a better way to handle this
- void PlayerState::addCapability(CapabilityType typ, int intValue, std::vector<std::string> stringValue)
- {
- auto capability = Capability();
- capability.typ = typ;
- if (intValue != -1)
- {
- capability.intValue = std::vector<int64_t>({intValue});
- }
- capability.stringValue = stringValue;
- innerFrame.device_state->capabilities.push_back(capability);
- }
|