diff --git a/src/audio_player_alsa.cpp b/src/audio_player_alsa.cpp index dccc65ecb..fa97a4bb4 100644 --- a/src/audio_player_alsa.cpp +++ b/src/audio_player_alsa.cpp @@ -65,6 +65,8 @@ enum class Message { Close }; +using clock = std::chrono::steady_clock; + class AlsaPlayer final : public AudioPlayer { std::mutex mutex; std::condition_variable cond; @@ -78,8 +80,9 @@ class AlsaPlayer final : public AudioPlayer { int64_t start_position = 0; std::atomic end_position{0}; + std::mutex position_mutex; int64_t last_position = 0; - timespec last_position_time = {0, 0}; + clock::time_point last_position_time; std::vector decode_buffer; @@ -87,6 +90,17 @@ class AlsaPlayer final : public AudioPlayer { void PlaybackThread(); + void UpdatePlaybackPosition(snd_pcm_t *pcm, int64_t position) + { + snd_pcm_sframes_t delay; + if (snd_pcm_delay(pcm, &delay) == 0) + { + std::unique_lock playback_lock; + last_position = position - delay; + last_position_time = clock::now(); + } + } + public: AlsaPlayer(AudioProvider *provider); ~AlsaPlayer(); @@ -157,15 +171,12 @@ do_setup: LOG_D("audio/player/alsa") << "starting playback"; int64_t position = start_position; - // Playback position - last_position = position; - clock_gettime(CLOCK_REALTIME, &last_position_time); - // Initial buffer-fill { auto avail = std::min(snd_pcm_avail(pcm), (snd_pcm_sframes_t)(end_position-position)); decode_buffer.resize(avail * framesize); provider->GetAudioWithVolume(decode_buffer.data(), position, avail, volume); + snd_pcm_sframes_t written = 0; while (written <= 0) { @@ -185,6 +196,7 @@ do_setup: LOG_D("audio/player/alsa") << "initial buffer filled, hitting start"; snd_pcm_start(pcm); + UpdatePlaybackPosition(pcm, position); playing = true; BOOST_SCOPE_EXIT_ALL(&) { playing = false; }; while (true) @@ -206,14 +218,6 @@ do_setup: break; } - // Playback position - snd_pcm_sframes_t delay; - if (snd_pcm_delay(pcm, &delay) == 0) - { - last_position = position - delay; - clock_gettime(CLOCK_REALTIME, &last_position_time); - } - // Fill buffer snd_pcm_sframes_t tmp_pcm_avail = snd_pcm_avail(pcm); if (tmp_pcm_avail == -EPIPE) @@ -249,6 +253,8 @@ do_setup: position += written; } + UpdatePlaybackPosition(pcm, position); + // Check for end of playback if (position >= end_position) { @@ -328,26 +334,16 @@ void AlsaPlayer::SetEndPosition(int64_t pos) int64_t AlsaPlayer::GetCurrentPosition() { int64_t lastpos; - timespec lasttime; - int64_t samplerate; + clock::time_point lasttime; { - std::unique_lock lock(mutex); + std::unique_lock playback_lock; lastpos = last_position; lasttime = last_position_time; - samplerate = provider->GetSampleRate(); } - timespec now; - clock_gettime(CLOCK_REALTIME, &now); - - const double NANO = 1000000000; // nano- is 10^-9 - - double now_sec = now.tv_sec + now.tv_nsec/NANO; - double last_sec = lasttime.tv_sec + lasttime.tv_nsec/NANO; - double diff_sec = now_sec - last_sec; - - return lastpos + (int64_t)(diff_sec * samplerate); + auto ms = std::chrono::duration_cast(clock::now() - lasttime).count(); + return lastpos + ms * provider->GetSampleRate() / 1000; } }