2
0

TrackQueue.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #pragma once
  2. #include <stddef.h> // for size_t
  3. #include <atomic>
  4. #include <deque>
  5. #include <functional>
  6. #include <mutex>
  7. #include "BellTask.h"
  8. #include "PlaybackState.h"
  9. #include "TrackReference.h"
  10. #include "protobuf/metadata.pb.h" // for Track, _Track, AudioFile, Episode
  11. namespace bell {
  12. class WrappedSemaphore;
  13. };
  14. namespace cspot {
  15. struct Context;
  16. class AccessKeyFetcher;
  17. class CDNAudioFile;
  18. // Used in got track info event
  19. struct TrackInfo {
  20. std::string name, album, artist, imageUrl, trackId;
  21. uint32_t duration, number, discNumber;
  22. void loadPbTrack(Track* pbTrack, const std::vector<uint8_t>& gid);
  23. void loadPbEpisode(Episode* pbEpisode, const std::vector<uint8_t>& gid);
  24. };
  25. class QueuedTrack {
  26. public:
  27. QueuedTrack(TrackReference& ref, std::shared_ptr<cspot::Context> ctx,
  28. uint32_t requestedPosition = 0);
  29. ~QueuedTrack();
  30. enum class State {
  31. QUEUED,
  32. PENDING_META,
  33. KEY_REQUIRED,
  34. PENDING_KEY,
  35. CDN_REQUIRED,
  36. READY,
  37. FAILED
  38. };
  39. std::shared_ptr<bell::WrappedSemaphore> loadedSemaphore;
  40. State state = State::QUEUED; // Current state of the track
  41. TrackReference ref; // Holds GID, URI and Context
  42. TrackInfo trackInfo; // Full track information fetched from spotify, name etc
  43. uint32_t requestedPosition;
  44. std::string identifier;
  45. bool loading = false;
  46. // Will return nullptr if the track is not ready
  47. std::shared_ptr<cspot::CDNAudioFile> getAudioFile();
  48. // --- Steps ---
  49. void stepLoadMetadata(
  50. Track* pbTrack, Episode* pbEpisode, std::mutex& trackListMutex,
  51. std::shared_ptr<bell::WrappedSemaphore> updateSemaphore);
  52. void stepParseMetadata(Track* pbTrack, Episode* pbEpisode);
  53. void stepLoadAudioFile(
  54. std::mutex& trackListMutex,
  55. std::shared_ptr<bell::WrappedSemaphore> updateSemaphore);
  56. void stepLoadCDNUrl(const std::string& accessKey);
  57. void expire();
  58. private:
  59. std::shared_ptr<cspot::Context> ctx;
  60. uint64_t pendingMercuryRequest = 0;
  61. uint32_t pendingAudioKeyRequest = 0;
  62. std::vector<uint8_t> trackId, fileId, audioKey;
  63. std::string cdnUrl;
  64. };
  65. class TrackQueue : public bell::Task {
  66. public:
  67. TrackQueue(std::shared_ptr<cspot::Context> ctx,
  68. std::shared_ptr<cspot::PlaybackState> playbackState);
  69. ~TrackQueue();
  70. enum class SkipDirection { NEXT, PREV };
  71. std::shared_ptr<bell::WrappedSemaphore> playableSemaphore;
  72. std::atomic<bool> notifyPending = false;
  73. void runTask() override;
  74. void stopTask();
  75. bool hasTracks();
  76. bool isFinished();
  77. bool skipTrack(SkipDirection dir, bool expectNotify = true);
  78. bool updateTracks(uint32_t requestedPosition = 0, bool initial = false);
  79. TrackInfo getTrackInfo(std::string_view identifier);
  80. std::shared_ptr<QueuedTrack> consumeTrack(
  81. std::shared_ptr<QueuedTrack> prevSong, int& offset);
  82. private:
  83. static const int MAX_TRACKS_PRELOAD = 3;
  84. std::shared_ptr<cspot::AccessKeyFetcher> accessKeyFetcher;
  85. std::shared_ptr<PlaybackState> playbackState;
  86. std::shared_ptr<cspot::Context> ctx;
  87. std::shared_ptr<bell::WrappedSemaphore> processSemaphore;
  88. std::deque<std::shared_ptr<QueuedTrack>> preloadedTracks;
  89. std::vector<TrackReference> currentTracks;
  90. std::mutex tracksMutex, runningMutex;
  91. // PB data
  92. Track pbTrack;
  93. Episode pbEpisode;
  94. std::string accessKey;
  95. int16_t currentTracksIndex = -1;
  96. bool isRunning = false;
  97. void processTrack(std::shared_ptr<QueuedTrack> track);
  98. bool queueNextTrack(int offset = 0, uint32_t positionMs = 0);
  99. };
  100. } // namespace cspot