Player.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #include "Player.h"
  2. #include "Logger.h"
  3. // #include <valgrind/memcheck.h>
  4. Player::Player(std::shared_ptr<MercuryManager> manager, std::shared_ptr<AudioSink> audioSink): bell::Task("player", 10 * 1024, +0, 1)
  5. {
  6. this->audioSink = audioSink;
  7. this->manager = manager;
  8. startTask();
  9. }
  10. void Player::pause()
  11. {
  12. this->currentTrack->audioStream->isPaused = true;
  13. }
  14. void Player::play()
  15. {
  16. this->currentTrack->audioStream->isPaused = false;
  17. }
  18. void Player::setVolume(uint32_t volume)
  19. {
  20. this->volume = (volume / (double)MAX_VOLUME) * 255;
  21. // Calculate and cache log volume value
  22. auto vol = 255 - this->volume;
  23. uint32_t value = (log10(255 / ((float)vol + 1)) * 105.54571334);
  24. if (value >= 254) value = 256;
  25. logVolume = value << 8; // *256
  26. // Pass volume event to the sink if volume is sink-handled
  27. if (!this->audioSink->softwareVolumeControl)
  28. {
  29. this->audioSink->volumeChanged(volume);
  30. }
  31. }
  32. void Player::seekMs(size_t positionMs)
  33. {
  34. this->currentTrack->audioStream->seekMs(positionMs);
  35. // VALGRIND_DO_LEAK_CHECK;
  36. }
  37. void Player::feedPCM(std::vector<uint8_t>& data)
  38. {
  39. // Simple digital volume control alg
  40. // @TODO actually extract it somewhere
  41. if (this->audioSink->softwareVolumeControl)
  42. {
  43. int16_t* psample;
  44. uint32_t pmax;
  45. psample = (int16_t*)(data.data());
  46. for (int32_t i = 0; i < (data.size() / 2); i++)
  47. {
  48. int32_t temp;
  49. // Offset data for unsigned sinks
  50. if (this->audioSink->usign)
  51. {
  52. temp = ((int32_t)psample[i] + 0x8000) * logVolume;
  53. }
  54. else
  55. {
  56. temp = ((int32_t)psample[i]) * logVolume;
  57. }
  58. psample[i] = (temp >> 16) & 0xFFFF;
  59. }
  60. }
  61. this->audioSink->feedPCMFrames(data);
  62. }
  63. void Player::runTask()
  64. {
  65. std::scoped_lock lock(this->runningMutex);
  66. this->isRunning = true;
  67. while (isRunning)
  68. {
  69. if (this->trackQueue.wpop(currentTrack)) {
  70. currentTrack->audioStream->startPlaybackLoop();
  71. currentTrack->loadedTrackCallback = nullptr;
  72. currentTrack->audioStream->streamFinishedCallback = nullptr;
  73. currentTrack->audioStream->audioSink = nullptr;
  74. currentTrack->audioStream->pcmCallback = nullptr;
  75. } else {
  76. //usleep(100000);
  77. }
  78. }
  79. }
  80. void Player::stop() {
  81. this->isRunning = false;
  82. CSPOT_LOG(info, "Stopping player");
  83. this->trackQueue.clear();
  84. cancelCurrentTrack();
  85. CSPOT_LOG(info, "Track cancelled");
  86. std::scoped_lock lock(this->runningMutex);
  87. CSPOT_LOG(info, "Done");
  88. }
  89. void Player::cancelCurrentTrack()
  90. {
  91. if (currentTrack != nullptr)
  92. {
  93. if (currentTrack->audioStream != nullptr && currentTrack->audioStream->isRunning)
  94. {
  95. currentTrack->audioStream->isRunning = false;
  96. }
  97. }
  98. }
  99. void Player::handleLoad(std::shared_ptr<TrackReference> trackReference, std::function<void()>& trackLoadedCallback, uint32_t position_ms, bool isPaused)
  100. {
  101. std::lock_guard<std::mutex> guard(loadTrackMutex);
  102. cancelCurrentTrack();
  103. pcmDataCallback framesCallback = [=](std::vector<uint8_t>& frames) {
  104. this->feedPCM(frames);
  105. };
  106. auto loadedLambda = trackLoadedCallback;
  107. auto track = std::make_shared<SpotifyTrack>(this->manager, trackReference, position_ms, isPaused);
  108. track->trackInfoReceived = this->trackChanged;
  109. track->loadedTrackCallback = [this, track, framesCallback, loadedLambda]() {
  110. loadedLambda();
  111. track->audioStream->streamFinishedCallback = this->endOfFileCallback;
  112. track->audioStream->audioSink = this->audioSink;
  113. track->audioStream->pcmCallback = framesCallback;
  114. this->trackQueue.push(track);
  115. };
  116. }