123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- #include "Player.h"
- #include "Logger.h"
- // #include <valgrind/memcheck.h>
- Player::Player(std::shared_ptr<MercuryManager> manager, std::shared_ptr<AudioSink> audioSink): bell::Task("player", 10 * 1024, +0, 1)
- {
- this->audioSink = audioSink;
- this->manager = manager;
- startTask();
- }
- void Player::pause()
- {
- this->currentTrack->audioStream->isPaused = true;
- }
- void Player::play()
- {
- this->currentTrack->audioStream->isPaused = false;
- }
- void Player::setVolume(uint32_t volume)
- {
- this->volume = (volume / (double)MAX_VOLUME) * 255;
- // Calculate and cache log volume value
- auto vol = 255 - this->volume;
- uint32_t value = (log10(255 / ((float)vol + 1)) * 105.54571334);
- if (value >= 254) value = 256;
- logVolume = value << 8; // *256
- // Pass volume event to the sink if volume is sink-handled
- if (!this->audioSink->softwareVolumeControl)
- {
- this->audioSink->volumeChanged(volume);
- }
- }
- void Player::seekMs(size_t positionMs)
- {
- this->currentTrack->audioStream->seekMs(positionMs);
- // VALGRIND_DO_LEAK_CHECK;
- }
- void Player::feedPCM(std::vector<uint8_t>& data)
- {
- // Simple digital volume control alg
- // @TODO actually extract it somewhere
- if (this->audioSink->softwareVolumeControl)
- {
- int16_t* psample;
- uint32_t pmax;
- psample = (int16_t*)(data.data());
- for (int32_t i = 0; i < (data.size() / 2); i++)
- {
- int32_t temp;
- // Offset data for unsigned sinks
- if (this->audioSink->usign)
- {
- temp = ((int32_t)psample[i] + 0x8000) * logVolume;
- }
- else
- {
- temp = ((int32_t)psample[i]) * logVolume;
- }
- psample[i] = (temp >> 16) & 0xFFFF;
- }
- }
- this->audioSink->feedPCMFrames(data);
- }
- void Player::runTask()
- {
- std::scoped_lock lock(this->runningMutex);
- this->isRunning = true;
- while (isRunning)
- {
- if (this->trackQueue.wpop(currentTrack)) {
- currentTrack->audioStream->startPlaybackLoop();
- currentTrack->loadedTrackCallback = nullptr;
- currentTrack->audioStream->streamFinishedCallback = nullptr;
- currentTrack->audioStream->audioSink = nullptr;
- currentTrack->audioStream->pcmCallback = nullptr;
- } else {
- //usleep(100000);
- }
- }
- }
- void Player::stop() {
- this->isRunning = false;
- CSPOT_LOG(info, "Stopping player");
- this->trackQueue.clear();
- cancelCurrentTrack();
- CSPOT_LOG(info, "Track cancelled");
- std::scoped_lock lock(this->runningMutex);
- CSPOT_LOG(info, "Done");
- }
- void Player::cancelCurrentTrack()
- {
- if (currentTrack != nullptr)
- {
- if (currentTrack->audioStream != nullptr && currentTrack->audioStream->isRunning)
- {
- currentTrack->audioStream->isRunning = false;
- }
- }
- }
- void Player::handleLoad(std::shared_ptr<TrackReference> trackReference, std::function<void()>& trackLoadedCallback, uint32_t position_ms, bool isPaused)
- {
- std::lock_guard<std::mutex> guard(loadTrackMutex);
- cancelCurrentTrack();
- pcmDataCallback framesCallback = [=](std::vector<uint8_t>& frames) {
- this->feedPCM(frames);
- };
- auto loadedLambda = trackLoadedCallback;
- auto track = std::make_shared<SpotifyTrack>(this->manager, trackReference, position_ms, isPaused);
- track->trackInfoReceived = this->trackChanged;
- track->loadedTrackCallback = [this, track, framesCallback, loadedLambda]() {
- loadedLambda();
- track->audioStream->streamFinishedCallback = this->endOfFileCallback;
- track->audioStream->audioSink = this->audioSink;
- track->audioStream->pcmCallback = framesCallback;
- this->trackQueue.push(track);
- };
- }
|