CDNAudioFile.h 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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 CDNAudioFile {
  15. public:
  16. CDNAudioFile(const std::string& cdnUrl, const std::vector<uint8_t>& audioKey);
  17. /**
  18. * @brief Opens connection to the provided cdn url, and fetches track metadata.
  19. */
  20. void openStream();
  21. /**
  22. * @brief Read and decrypt part of the cdn stream
  23. *
  24. * @param dst buffer where to read received data to
  25. * @param amount of bytes to read
  26. *
  27. * @returns amount of bytes read
  28. */
  29. size_t readBytes(uint8_t* dst, size_t bytes);
  30. /**
  31. * @brief Returns current position in CDN stream
  32. */
  33. size_t getPosition();
  34. /**
  35. * @brief returns total size of the audio file in bytes
  36. */
  37. size_t getSize();
  38. /**
  39. * @brief Seeks the track to provided position
  40. * @param position position where to seek the track
  41. */
  42. void seek(size_t position);
  43. private:
  44. const int OPUS_HEADER_SIZE = 8 * 1024;
  45. const int OPUS_FOOTER_PREFFERED = 1024 * 12; // 12K should be safe
  46. const int SEEK_MARGIN_SIZE = 1024 * 4;
  47. const int HTTP_BUFFER_SIZE = 1024 * 14;
  48. const int SPOTIFY_OPUS_HEADER = 167;
  49. // Used to store opus metadata, speeds up read
  50. std::vector<uint8_t> header = std::vector<uint8_t>(OPUS_HEADER_SIZE);
  51. std::vector<uint8_t> footer;
  52. // General purpose buffer to read data
  53. std::vector<uint8_t> httpBuffer = std::vector<uint8_t>(HTTP_BUFFER_SIZE);
  54. // AES IV for decrypting the audio stream
  55. const std::vector<uint8_t> audioAESIV = {0x72, 0xe0, 0x67, 0xfb, 0xdd, 0xcb,
  56. 0xcf, 0x77, 0xeb, 0xe8, 0xbc, 0x64,
  57. 0x3f, 0x63, 0x0d, 0x93};
  58. std::unique_ptr<Crypto> crypto;
  59. std::unique_ptr<bell::HTTPClient::Response> httpConnection;
  60. size_t position = 0;
  61. size_t totalFileSize = 0;
  62. size_t lastRequestPosition = 0;
  63. size_t lastRequestCapacity = 0;
  64. bool enableRequestMargin = false;
  65. std::string cdnUrl;
  66. std::vector<uint8_t> audioKey;
  67. void decrypt(uint8_t* dst, size_t nbytes, size_t pos);
  68. };
  69. } // namespace cspot