Player.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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, -2, 1)
  5. {
  6. this->audioSink = audioSink;
  7. this->manager = manager;
  8. startTask();
  9. }
  10. void Player::pause()
  11. {
  12. if (currentTrack != nullptr)
  13. {
  14. if (currentTrack->audioStream != nullptr)
  15. {
  16. this->currentTrack->audioStream->isPaused = true;
  17. }
  18. }
  19. }
  20. void Player::play()
  21. {
  22. if (currentTrack != nullptr)
  23. {
  24. if (currentTrack->audioStream != nullptr)
  25. {
  26. this->currentTrack->audioStream->isPaused = false;
  27. }
  28. }
  29. }
  30. void Player::setVolume(uint32_t volume)
  31. {
  32. this->volume = (volume / (double)MAX_VOLUME) * 255;
  33. // Calculate and cache log volume value
  34. auto vol = 255 - this->volume;
  35. uint32_t value = (log10(255 / ((float)vol + 1)) * 105.54571334);
  36. if (value >= 254) value = 256;
  37. logVolume = value << 8; // *256
  38. // Pass volume event to the sink if volume is sink-handled
  39. if (!this->audioSink->softwareVolumeControl)
  40. {
  41. this->audioSink->volumeChanged(volume);
  42. }
  43. }
  44. void Player::seekMs(size_t positionMs)
  45. {
  46. if (currentTrack != nullptr)
  47. {
  48. if (currentTrack->audioStream != nullptr)
  49. {
  50. this->currentTrack->audioStream->seekMs(positionMs);
  51. }
  52. }
  53. // VALGRIND_DO_LEAK_CHECK;
  54. }
  55. void Player::feedPCM(uint8_t *data, size_t len)
  56. {
  57. // Simple digital volume control alg
  58. // @TODO actually extract it somewhere
  59. if (this->audioSink->softwareVolumeControl)
  60. {
  61. int16_t* psample;
  62. int32_t temp;
  63. psample = (int16_t*)(data);
  64. size_t half_len = len / 2;
  65. for (uint32_t i = 0; i < half_len; i++)
  66. {
  67. // Offset data for unsigned sinks
  68. if (this->audioSink->usign)
  69. {
  70. temp = ((int32_t)psample[i] + 0x8000) * logVolume;
  71. }
  72. else
  73. {
  74. temp = ((int32_t)psample[i]) * logVolume;
  75. }
  76. psample[i] = (temp >> 16) & 0xFFFF;
  77. }
  78. }
  79. this->audioSink->feedPCMFrames(data, len);
  80. }
  81. void Player::runTask()
  82. {
  83. uint8_t *pcmOut = (uint8_t *) malloc(4096 / 4);
  84. std::scoped_lock lock(this->runningMutex);
  85. this->isRunning = true;
  86. while (isRunning)
  87. {
  88. if(nextTrack != nullptr && nextTrack->loaded)
  89. {
  90. this->nextTrackMutex.lock();
  91. currentTrack = this->nextTrack;
  92. this->nextTrack = nullptr;
  93. this->nextTrackMutex.unlock();
  94. currentTrack->audioStream->startPlaybackLoop(pcmOut, 4096 / 4);
  95. currentTrack->loadedTrackCallback = nullptr;
  96. currentTrack->audioStream->streamFinishedCallback = nullptr;
  97. currentTrack->audioStream->audioSink = nullptr;
  98. currentTrack->audioStream->pcmCallback = nullptr;
  99. delete currentTrack;
  100. currentTrack = nullptr;
  101. }
  102. else
  103. {
  104. usleep(20000);
  105. }
  106. }
  107. free(pcmOut);
  108. }
  109. void Player::stop() {
  110. CSPOT_LOG(info, "Trying to stop");
  111. this->isRunning = false;
  112. cancelCurrentTrack();
  113. std::scoped_lock lock(this->runningMutex);
  114. if(this->nextTrack != nullptr)
  115. {
  116. delete this->nextTrack;
  117. }
  118. this->isRunning = false;
  119. CSPOT_LOG(info, "Track cancelled");
  120. cancelCurrentTrack();
  121. CSPOT_LOG(info, "Stopping player");
  122. }
  123. void Player::cancelCurrentTrack()
  124. {
  125. if (currentTrack != nullptr)
  126. {
  127. if (currentTrack->audioStream != nullptr && currentTrack->audioStream->isRunning)
  128. {
  129. currentTrack->audioStream->isRunning = false;
  130. }
  131. }
  132. }
  133. void Player::handleLoad(std::shared_ptr<TrackReference> trackReference, std::function<void(bool)>& trackLoadedCallback, uint32_t position_ms, bool isPaused)
  134. {
  135. std::lock_guard<std::mutex> guard(loadTrackMutex);
  136. pcmDataCallback framesCallback = [=](uint8_t *frames, size_t len) {
  137. this->feedPCM(frames, len);
  138. };
  139. this->nextTrackMutex.lock();
  140. if(this->nextTrack != nullptr)
  141. {
  142. delete this->nextTrack;
  143. this->nextTrack = nullptr;
  144. }
  145. this->nextTrack = new SpotifyTrack(this->manager, trackReference, position_ms, isPaused);
  146. this->nextTrack->trackInfoReceived = this->trackChanged;
  147. this->nextTrack->loadedTrackCallback = [this, framesCallback, trackLoadedCallback]() {
  148. bool needFlush = currentTrack != nullptr && currentTrack->audioStream != nullptr && currentTrack->audioStream->isRunning;
  149. cancelCurrentTrack();
  150. trackLoadedCallback(needFlush);
  151. this->nextTrackMutex.lock();
  152. this->nextTrack->audioStream->streamFinishedCallback = this->endOfFileCallback;
  153. this->nextTrack->audioStream->audioSink = this->audioSink;
  154. this->nextTrack->audioStream->pcmCallback = framesCallback;
  155. this->nextTrack->loaded = true;
  156. this->nextTrackMutex.unlock();
  157. };
  158. this->nextTrackMutex.unlock();
  159. }