Player.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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. 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(uint8_t *data, size_t len)
  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);
  46. for (int32_t i = 0; i < (len / 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, len);
  62. }
  63. void Player::runTask()
  64. {
  65. uint8_t *pcmOut = (uint8_t *) malloc(4096 / 4);
  66. std::scoped_lock lock(this->runningMutex);
  67. this->isRunning = true;
  68. while (isRunning)
  69. {
  70. if (this->trackQueue.wpop(currentTrack)) {
  71. currentTrack->audioStream->startPlaybackLoop(pcmOut, 4096 / 4);
  72. currentTrack->loadedTrackCallback = nullptr;
  73. currentTrack->audioStream->streamFinishedCallback = nullptr;
  74. currentTrack->audioStream->audioSink = nullptr;
  75. currentTrack->audioStream->pcmCallback = nullptr;
  76. } else {
  77. usleep(100);
  78. }
  79. }
  80. free(pcmOut);
  81. }
  82. void Player::stop() {
  83. this->isRunning = false;
  84. CSPOT_LOG(info, "Stopping player");
  85. this->trackQueue.clear();
  86. cancelCurrentTrack();
  87. CSPOT_LOG(info, "Track cancelled");
  88. std::scoped_lock lock(this->runningMutex);
  89. CSPOT_LOG(info, "Done");
  90. }
  91. void Player::cancelCurrentTrack()
  92. {
  93. if (currentTrack != nullptr)
  94. {
  95. if (currentTrack->audioStream != nullptr && currentTrack->audioStream->isRunning)
  96. {
  97. currentTrack->audioStream->isRunning = false;
  98. }
  99. }
  100. }
  101. void Player::handleLoad(std::shared_ptr<TrackReference> trackReference, std::function<void()>& trackLoadedCallback, uint32_t position_ms, bool isPaused)
  102. {
  103. std::lock_guard<std::mutex> guard(loadTrackMutex);
  104. cancelCurrentTrack();
  105. pcmDataCallback framesCallback = [=](uint8_t *frames, size_t len) {
  106. this->feedPCM(frames, len);
  107. };
  108. auto loadedLambda = trackLoadedCallback;
  109. auto track = std::make_shared<SpotifyTrack>(this->manager, trackReference, position_ms, isPaused);
  110. track->trackInfoReceived = this->trackChanged;
  111. track->loadedTrackCallback = [this, track, framesCallback, loadedLambda]() {
  112. loadedLambda();
  113. track->audioStream->streamFinishedCallback = this->endOfFileCallback;
  114. track->audioStream->audioSink = this->audioSink;
  115. track->audioStream->pcmCallback = framesCallback;
  116. this->trackQueue.push(track);
  117. };
  118. }