TrackQueue.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #pragma once
  2. #include <stddef.h> // for size_t
  3. #include <atomic>
  4. #include <deque>
  5. #include <mutex>
  6. #include <functional>
  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;
  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. // Will return nullptr if the track is not ready
  46. std::shared_ptr<cspot::CDNAudioFile> getAudioFile();
  47. // --- Steps ---
  48. void stepLoadMetadata(
  49. Track* pbTrack, Episode* pbEpisode, std::mutex& trackListMutex,
  50. std::shared_ptr<bell::WrappedSemaphore> updateSemaphore);
  51. void stepParseMetadata(Track* pbTrack, Episode* pbEpisode);
  52. void stepLoadAudioFile(
  53. std::mutex& trackListMutex,
  54. std::shared_ptr<bell::WrappedSemaphore> updateSemaphore);
  55. void stepLoadCDNUrl(const std::string& accessKey);
  56. void expire();
  57. private:
  58. std::shared_ptr<cspot::Context> ctx;
  59. uint64_t pendingMercuryRequest = 0;
  60. uint32_t pendingAudioKeyRequest = 0;
  61. std::vector<uint8_t> trackId, fileId, audioKey;
  62. std::string cdnUrl;
  63. };
  64. class TrackQueue : public bell::Task {
  65. public:
  66. TrackQueue(std::shared_ptr<cspot::Context> ctx,
  67. std::shared_ptr<cspot::PlaybackState> playbackState);
  68. ~TrackQueue();
  69. enum class SkipDirection { NEXT, PREV };
  70. std::shared_ptr<bell::WrappedSemaphore> playableSemaphore;
  71. std::atomic<bool> notifyPending = false;
  72. void runTask() override;
  73. void stopTask();
  74. bool hasTracks();
  75. bool isFinished();
  76. bool skipTrack(SkipDirection dir, bool expectNotify = true);
  77. void updateTracks(uint32_t requestedPosition = 0, bool initial = false);
  78. TrackInfo getTrackInfo(std::string_view identifier);
  79. std::shared_ptr<QueuedTrack> consumeTrack(
  80. std::shared_ptr<QueuedTrack> prevSong, int& offset);
  81. private:
  82. static const int MAX_TRACKS_PRELOAD = 3;
  83. std::shared_ptr<cspot::AccessKeyFetcher> accessKeyFetcher;
  84. std::shared_ptr<PlaybackState> playbackState;
  85. std::shared_ptr<cspot::Context> ctx;
  86. std::shared_ptr<bell::WrappedSemaphore> processSemaphore;
  87. std::deque<std::shared_ptr<QueuedTrack>> preloadedTracks;
  88. std::vector<TrackReference> currentTracks;
  89. std::mutex tracksMutex, runningMutex;
  90. // PB data
  91. Track pbTrack;
  92. Episode pbEpisode;
  93. std::string accessKey;
  94. int16_t currentTracksIndex = -1;
  95. bool isRunning = false;
  96. void processTrack(std::shared_ptr<QueuedTrack> track);
  97. bool queueNextTrack(int offset = 0, uint32_t positionMs = 0);
  98. };
  99. } // namespace cspot