CDNTrackStream.h 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #pragma once
  2. #include <cstddef> // for size_t
  3. #include <cstdint> // for uint8_t
  4. #include <memory> // for shared_ptr, unique_ptr
  5. #include <string> // for string
  6. #include <vector> // for vector
  7. #include "Crypto.h" // for Crypto
  8. #include "HTTPClient.h" // for HTTPClient
  9. namespace bell {
  10. class WrappedSemaphore;
  11. } // namespace bell
  12. namespace cspot {
  13. class AccessKeyFetcher;
  14. class CDNTrackStream {
  15. public:
  16. CDNTrackStream(std::shared_ptr<cspot::AccessKeyFetcher>);
  17. ~CDNTrackStream();
  18. enum class Status { INITIALIZING, HAS_DATA, HAS_URL, FAILED };
  19. struct TrackInfo {
  20. std::string trackId;
  21. std::string name;
  22. std::string album;
  23. std::string artist;
  24. std::string imageUrl;
  25. int duration;
  26. };
  27. TrackInfo trackInfo;
  28. Status status;
  29. std::unique_ptr<bell::WrappedSemaphore> trackReady;
  30. void fetchFile(const std::vector<uint8_t>& trackId,
  31. const std::vector<uint8_t>& audioKey);
  32. void fail();
  33. void openStream();
  34. size_t readBytes(uint8_t* dst, size_t bytes);
  35. size_t getPosition();
  36. size_t getSize();
  37. void seek(size_t position);
  38. private:
  39. const int OPUS_HEADER_SIZE = 8 * 1024;
  40. const int OPUS_FOOTER_PREFFERED = 1024 * 12; // 12K should be safe
  41. const int SEEK_MARGIN_SIZE = 1024 * 4;
  42. const int HTTP_BUFFER_SIZE = 1024 * 14;
  43. const int SPOTIFY_OPUS_HEADER = 167;
  44. // Used to store opus metadata, speeds up read
  45. std::vector<uint8_t> header = std::vector<uint8_t>(OPUS_HEADER_SIZE);
  46. std::vector<uint8_t> footer;
  47. // General purpose buffer to read data
  48. std::vector<uint8_t> httpBuffer = std::vector<uint8_t>(HTTP_BUFFER_SIZE);
  49. // AES IV for decrypting the audio stream
  50. const std::vector<uint8_t> audioAESIV = {0x72, 0xe0, 0x67, 0xfb, 0xdd, 0xcb,
  51. 0xcf, 0x77, 0xeb, 0xe8, 0xbc, 0x64,
  52. 0x3f, 0x63, 0x0d, 0x93};
  53. std::unique_ptr<Crypto> crypto;
  54. std::shared_ptr<cspot::AccessKeyFetcher> accessKeyFetcher;
  55. std::unique_ptr<bell::HTTPClient::Response> httpConnection;
  56. bool isConnected = false;
  57. size_t position = 0; // Spotify header size
  58. size_t totalFileSize = 0;
  59. size_t lastRequestPosition = 0;
  60. size_t lastRequestCapacity = 0;
  61. bool enableRequestMargin = false;
  62. std::string cdnUrl;
  63. std::vector<uint8_t> trackId;
  64. std::vector<uint8_t> audioKey;
  65. void decrypt(uint8_t* dst, size_t nbytes, size_t pos);
  66. };
  67. } // namespace cspot