Use std::thread rather than pthreads for AlsaPlayer
This commit is contained in:
parent
c2b8892b33
commit
1bf6197869
1 changed files with 112 additions and 223 deletions
|
@ -44,128 +44,74 @@
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
#include <libaegisub/make_unique.h>
|
#include <libaegisub/make_unique.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <boost/scope_exit.hpp>
|
||||||
|
#include <chrono>
|
||||||
|
#include <condition_variable>
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
#include <inttypes.h>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
// X11 is the bestest
|
||||||
|
#undef None
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct PlaybackState {
|
enum class Message {
|
||||||
pthread_mutex_t mutex;
|
None,
|
||||||
pthread_cond_t cond;
|
Start,
|
||||||
|
Stop,
|
||||||
bool playing = false;
|
Close
|
||||||
bool alive = false;
|
|
||||||
|
|
||||||
bool signal_start = false;
|
|
||||||
bool signal_stop = false;
|
|
||||||
bool signal_close = false;
|
|
||||||
bool signal_volume = false;
|
|
||||||
|
|
||||||
double volume = 1.0;
|
|
||||||
int64_t start_position = 0;
|
|
||||||
int64_t end_position = 0;
|
|
||||||
|
|
||||||
AudioProvider *provider = nullptr;
|
|
||||||
std::string device_name;
|
|
||||||
|
|
||||||
int64_t last_position = 0;
|
|
||||||
timespec last_position_time;
|
|
||||||
|
|
||||||
PlaybackState()
|
|
||||||
{
|
|
||||||
pthread_mutex_init(&mutex, 0);
|
|
||||||
pthread_cond_init(&cond, 0);
|
|
||||||
memset(&last_position_time, 0, sizeof last_position_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
~PlaybackState()
|
|
||||||
{
|
|
||||||
pthread_cond_destroy(&cond);
|
|
||||||
pthread_mutex_destroy(&mutex);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AlsaPlayer final : public AudioPlayer {
|
class AlsaPlayer final : public AudioPlayer {
|
||||||
PlaybackState ps;
|
std::mutex mutex;
|
||||||
pthread_t thread;
|
std::condition_variable cond;
|
||||||
|
|
||||||
|
std::string device_name = OPT_GET("Player/Audio/ALSA/Device")->GetString();
|
||||||
|
|
||||||
|
Message message = Message::None;
|
||||||
|
|
||||||
|
std::atomic<bool> playing{false};
|
||||||
|
std::atomic<double> volume{1.0};
|
||||||
|
int64_t start_position = 0;
|
||||||
|
std::atomic<int64_t> end_position{0};
|
||||||
|
|
||||||
|
int64_t last_position = 0;
|
||||||
|
timespec last_position_time = {0, 0};
|
||||||
|
|
||||||
|
std::thread thread;
|
||||||
|
|
||||||
|
void PlaybackThread();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AlsaPlayer(AudioProvider *provider);
|
AlsaPlayer(AudioProvider *provider);
|
||||||
~AlsaPlayer();
|
~AlsaPlayer();
|
||||||
|
|
||||||
void Play(int64_t start, int64_t count);
|
void Play(int64_t start, int64_t count) override;
|
||||||
void Stop();
|
void Stop() override;
|
||||||
bool IsPlaying();
|
bool IsPlaying() override { return playing; }
|
||||||
|
|
||||||
int64_t GetStartPosition();
|
void SetVolume(double vol) override { volume = vol; }
|
||||||
int64_t GetEndPosition();
|
int64_t GetEndPosition() override { return end_position; }
|
||||||
int64_t GetCurrentPosition();
|
int64_t GetCurrentPosition() override;
|
||||||
void SetEndPosition(int64_t pos);
|
void SetEndPosition(int64_t pos) override;
|
||||||
void SetCurrentPosition(int64_t pos);
|
|
||||||
|
|
||||||
void SetVolume(double vol);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PthreadMutexLocker {
|
void AlsaPlayer::PlaybackThread()
|
||||||
pthread_mutex_t &mutex;
|
|
||||||
|
|
||||||
PthreadMutexLocker(const PthreadMutexLocker &) = delete;
|
|
||||||
PthreadMutexLocker& operator=(PthreadMutexLocker const&) = delete;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit PthreadMutexLocker(pthread_mutex_t &mutex) : mutex(mutex)
|
|
||||||
{
|
|
||||||
pthread_mutex_lock(&mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
~PthreadMutexLocker()
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaitCondition(pthread_cond_t &cond)
|
|
||||||
{
|
|
||||||
return pthread_cond_wait(&cond, &mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
int WaitConditionTimeout(pthread_cond_t &cond, int ms)
|
|
||||||
{
|
|
||||||
timespec abstime;
|
|
||||||
clock_gettime(CLOCK_REALTIME, &abstime);
|
|
||||||
abstime.tv_nsec += ms * 1000000;
|
|
||||||
return pthread_cond_timedwait(&cond, &mutex, &abstime);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ScopedAliveFlag {
|
|
||||||
bool &flag;
|
|
||||||
|
|
||||||
ScopedAliveFlag(const ScopedAliveFlag &) = delete;
|
|
||||||
ScopedAliveFlag& operator=(ScopedAliveFlag const&) = delete;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ScopedAliveFlag(bool &var) : flag(var) { flag = true; }
|
|
||||||
~ScopedAliveFlag() { flag = false; }
|
|
||||||
};
|
|
||||||
|
|
||||||
void *playback_thread(void *arg)
|
|
||||||
{
|
{
|
||||||
// This is exception-free territory!
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
// Return a pointer to a static string constant describing the error, or 0 on no error
|
|
||||||
auto &ps = *static_cast<PlaybackState *>(arg);
|
|
||||||
|
|
||||||
PthreadMutexLocker ml(ps.mutex);
|
snd_pcm_t *pcm = nullptr;
|
||||||
ScopedAliveFlag alive_flag(ps.alive);
|
if (snd_pcm_open(&pcm, device_name.c_str(), SND_PCM_STREAM_PLAYBACK, 0) != 0)
|
||||||
|
return;
|
||||||
snd_pcm_t *pcm = 0;
|
|
||||||
if (snd_pcm_open(&pcm, ps.device_name.c_str(), SND_PCM_STREAM_PLAYBACK, 0) != 0)
|
|
||||||
return (void*)"snd_pcm_open";
|
|
||||||
LOG_D("audio/player/alsa") << "opened pcm";
|
LOG_D("audio/player/alsa") << "opened pcm";
|
||||||
|
BOOST_SCOPE_EXIT_ALL(&) { snd_pcm_close(pcm); };
|
||||||
|
|
||||||
do_setup:
|
do_setup:
|
||||||
snd_pcm_format_t pcm_format;
|
snd_pcm_format_t pcm_format;
|
||||||
switch (ps.provider->GetBytesPerSample())
|
switch (provider->GetBytesPerSample())
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
LOG_D("audio/player/alsa") << "format U8";
|
LOG_D("audio/player/alsa") << "format U8";
|
||||||
|
@ -176,62 +122,58 @@ do_setup:
|
||||||
pcm_format = SND_PCM_FORMAT_S16_LE;
|
pcm_format = SND_PCM_FORMAT_S16_LE;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
snd_pcm_close(pcm);
|
return;
|
||||||
return (void*)"snd_pcm_format_t";
|
|
||||||
}
|
}
|
||||||
if (snd_pcm_set_params(pcm,
|
if (snd_pcm_set_params(pcm,
|
||||||
pcm_format,
|
pcm_format,
|
||||||
SND_PCM_ACCESS_RW_INTERLEAVED,
|
SND_PCM_ACCESS_RW_INTERLEAVED,
|
||||||
ps.provider->GetChannels(),
|
provider->GetChannels(),
|
||||||
ps.provider->GetSampleRate(),
|
provider->GetSampleRate(),
|
||||||
1, // allow resample
|
1, // allow resample
|
||||||
100*1000 // 100 milliseconds latency
|
100*1000 // 100 milliseconds latency
|
||||||
) != 0)
|
) != 0)
|
||||||
return (void*)"snd_pcm_set_params";
|
return;
|
||||||
LOG_D("audio/player/alsa") << "set pcm params";
|
LOG_D("audio/player/alsa") << "set pcm params";
|
||||||
|
|
||||||
size_t framesize = ps.provider->GetChannels() * ps.provider->GetBytesPerSample();
|
size_t framesize = provider->GetChannels() * provider->GetBytesPerSample();
|
||||||
|
|
||||||
ps.signal_close = false;
|
while (true)
|
||||||
while (ps.signal_close == false)
|
|
||||||
{
|
{
|
||||||
// Wait for condition to trigger
|
// Wait for condition to trigger
|
||||||
if (!ps.signal_start)
|
while (message != Message::Start)
|
||||||
ml.WaitCondition(ps.cond);
|
|
||||||
LOG_D("audio/player/alsa") << "outer loop, condition happened";
|
|
||||||
|
|
||||||
if (ps.signal_start == false || ps.end_position <= ps.start_position)
|
|
||||||
{
|
{
|
||||||
LOG_D("audio/player/alsa") << "nothing to play, rewaiting";
|
cond.wait(lock, [&] { return message != Message::None; });
|
||||||
ps.signal_start = false;
|
if (message == Message::Close)
|
||||||
continue;
|
return;
|
||||||
|
if (message == Message::Start && end_position > start_position)
|
||||||
|
break;
|
||||||
|
// Not playing, so don't need to stop...
|
||||||
|
message = Message::None;
|
||||||
}
|
}
|
||||||
|
message = Message::None;
|
||||||
|
|
||||||
LOG_D("audio/player/alsa") << "starting playback";
|
LOG_D("audio/player/alsa") << "starting playback";
|
||||||
int64_t position = ps.start_position;
|
int64_t position = start_position;
|
||||||
|
|
||||||
// Playback position
|
// Playback position
|
||||||
ps.last_position = position;
|
last_position = position;
|
||||||
clock_gettime(CLOCK_REALTIME, &ps.last_position_time);
|
clock_gettime(CLOCK_REALTIME, &last_position_time);
|
||||||
|
|
||||||
// Initial buffer-fill
|
// Initial buffer-fill
|
||||||
{
|
{
|
||||||
snd_pcm_sframes_t avail = std::min(snd_pcm_avail(pcm), (snd_pcm_sframes_t)(ps.end_position-position));
|
auto avail = std::min(snd_pcm_avail(pcm), (snd_pcm_sframes_t)(end_position-position));
|
||||||
std::unique_ptr<char[]> buf{new char[avail*framesize]};
|
std::unique_ptr<char[]> buf{new char[avail*framesize]};
|
||||||
ps.provider->GetAudioWithVolume(buf.get(), position, avail, ps.volume);
|
provider->GetAudioWithVolume(buf.get(), position, avail, volume);
|
||||||
snd_pcm_sframes_t written = 0;
|
snd_pcm_sframes_t written = 0;
|
||||||
while (written <= 0)
|
while (written <= 0)
|
||||||
{
|
{
|
||||||
written = snd_pcm_writei(pcm, buf.get(), avail);
|
written = snd_pcm_writei(pcm, buf.get(), avail);
|
||||||
if (written == -ESTRPIPE)
|
if (written == -ESTRPIPE)
|
||||||
{
|
|
||||||
snd_pcm_recover(pcm, written, 0);
|
snd_pcm_recover(pcm, written, 0);
|
||||||
}
|
|
||||||
else if (written <= 0)
|
else if (written <= 0)
|
||||||
{
|
{
|
||||||
snd_pcm_close(pcm);
|
|
||||||
LOG_D("audio/player/alsa") << "error filling buffer";
|
LOG_D("audio/player/alsa") << "error filling buffer";
|
||||||
return (void*)"snd_pcm_writei";
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
position += written;
|
position += written;
|
||||||
|
@ -241,22 +183,21 @@ do_setup:
|
||||||
LOG_D("audio/player/alsa") << "initial buffer filled, hitting start";
|
LOG_D("audio/player/alsa") << "initial buffer filled, hitting start";
|
||||||
snd_pcm_start(pcm);
|
snd_pcm_start(pcm);
|
||||||
|
|
||||||
ps.signal_start = false;
|
playing = true;
|
||||||
ps.signal_stop = false;
|
BOOST_SCOPE_EXIT_ALL(&) { playing = false; };
|
||||||
|
while (true)
|
||||||
while (ps.signal_stop == false)
|
|
||||||
{
|
{
|
||||||
int64_t orig_position = position;
|
|
||||||
int64_t orig_ps_end_position = ps.end_position;
|
|
||||||
|
|
||||||
ScopedAliveFlag playing_flag(ps.playing);
|
|
||||||
|
|
||||||
// Sleep a bit, or until an event
|
// Sleep a bit, or until an event
|
||||||
ml.WaitConditionTimeout(ps.cond, 50);
|
cond.wait_for(lock, std::chrono::milliseconds{25});
|
||||||
//LOG_D("audio/player/alsa") << "playback loop, out of wait";
|
|
||||||
|
if (message == Message::Close)
|
||||||
|
{
|
||||||
|
snd_pcm_drop(pcm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for stop signal
|
// Check for stop signal
|
||||||
if (ps.signal_stop == true)
|
if (message == Message::Stop || message == Message::Start)
|
||||||
{
|
{
|
||||||
LOG_D("audio/player/alsa") << "playback loop, stop signal";
|
LOG_D("audio/player/alsa") << "playback loop, stop signal";
|
||||||
snd_pcm_drop(pcm);
|
snd_pcm_drop(pcm);
|
||||||
|
@ -267,8 +208,8 @@ do_setup:
|
||||||
snd_pcm_sframes_t delay;
|
snd_pcm_sframes_t delay;
|
||||||
if (snd_pcm_delay(pcm, &delay) == 0)
|
if (snd_pcm_delay(pcm, &delay) == 0)
|
||||||
{
|
{
|
||||||
ps.last_position = position - delay;
|
last_position = position - delay;
|
||||||
clock_gettime(CLOCK_REALTIME, &ps.last_position_time);
|
clock_gettime(CLOCK_REALTIME, &last_position_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill buffer
|
// Fill buffer
|
||||||
|
@ -278,66 +219,50 @@ do_setup:
|
||||||
if (snd_pcm_recover(pcm, -EPIPE, 1) < 0)
|
if (snd_pcm_recover(pcm, -EPIPE, 1) < 0)
|
||||||
{
|
{
|
||||||
LOG_D("audio/player/alsa") << "failed to recover from underrun";
|
LOG_D("audio/player/alsa") << "failed to recover from underrun";
|
||||||
return (void*)"snd_pcm_avail";
|
return;
|
||||||
}
|
}
|
||||||
tmp_pcm_avail = snd_pcm_avail(pcm);
|
tmp_pcm_avail = snd_pcm_avail(pcm);
|
||||||
}
|
}
|
||||||
avail = std::min(tmp_pcm_avail, (snd_pcm_sframes_t)(ps.end_position-position));
|
auto avail = std::min(tmp_pcm_avail, (snd_pcm_sframes_t)(end_position-position));
|
||||||
if (avail < 0)
|
if (avail < 0)
|
||||||
{
|
|
||||||
printf("\n--------- avail was less than 0: %ld\n", (long)avail);
|
|
||||||
printf("snd_pcm_avail(pcm): %ld\n", (long)tmp_pcm_avail);
|
|
||||||
printf("original position: %" PRId64 "\n", orig_position);
|
|
||||||
printf("current position: %" PRId64 "\n", position);
|
|
||||||
printf("original ps.end_position: %" PRId64 "\n", orig_ps_end_position);
|
|
||||||
printf("current ps.end_position: %" PRId64 "\n", ps.end_position);
|
|
||||||
printf("---------\n\n");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
std::unique_ptr<char[]> buf{new char[avail*framesize]};
|
std::unique_ptr<char[]> buf{new char[avail*framesize]};
|
||||||
ps.provider->GetAudioWithVolume(buf.get(), position, avail, ps.volume);
|
provider->GetAudioWithVolume(buf.get(), position, avail, volume);
|
||||||
snd_pcm_sframes_t written = 0;
|
snd_pcm_sframes_t written = 0;
|
||||||
while (written <= 0)
|
while (written <= 0)
|
||||||
{
|
{
|
||||||
written = snd_pcm_writei(pcm, buf.get(), avail);
|
written = snd_pcm_writei(pcm, buf.get(), avail);
|
||||||
if (written == -ESTRPIPE || written == -EPIPE)
|
if (written == -ESTRPIPE || written == -EPIPE)
|
||||||
{
|
|
||||||
snd_pcm_recover(pcm, written, 0);
|
snd_pcm_recover(pcm, written, 0);
|
||||||
}
|
|
||||||
else if (written == 0)
|
else if (written == 0)
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
else if (written < 0)
|
else if (written < 0)
|
||||||
{
|
{
|
||||||
snd_pcm_close(pcm);
|
|
||||||
LOG_D("audio/player/alsa") << "error filling buffer, written=" << written;
|
LOG_D("audio/player/alsa") << "error filling buffer, written=" << written;
|
||||||
return (void*)"snd_pcm_writei";
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
position += written;
|
position += written;
|
||||||
}
|
}
|
||||||
//LOG_D("audio/player/alsa") << "playback loop, filled buffer";
|
|
||||||
|
|
||||||
// Check for end of playback
|
// Check for end of playback
|
||||||
if (position >= ps.end_position)
|
if (position >= end_position)
|
||||||
{
|
{
|
||||||
LOG_D("audio/player/alsa") << "playback loop, past end, draining";
|
LOG_D("audio/player/alsa") << "playback loop, past end, draining";
|
||||||
snd_pcm_drain(pcm);
|
snd_pcm_drain(pcm);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ps.signal_stop = false;
|
|
||||||
|
playing = false;
|
||||||
LOG_D("audio/player/alsa") << "out of playback loop";
|
LOG_D("audio/player/alsa") << "out of playback loop";
|
||||||
|
|
||||||
switch (snd_pcm_state(pcm))
|
switch (snd_pcm_state(pcm))
|
||||||
{
|
{
|
||||||
case SND_PCM_STATE_OPEN:
|
case SND_PCM_STATE_OPEN:
|
||||||
// no clue what could have happened here, but start over
|
// no clue what could have happened here, but start over
|
||||||
ps.signal_start = false;
|
|
||||||
ps.signal_stop = false;
|
|
||||||
goto do_setup;
|
goto do_setup;
|
||||||
|
|
||||||
case SND_PCM_STATE_SETUP:
|
case SND_PCM_STATE_SETUP:
|
||||||
|
@ -347,80 +272,55 @@ do_setup:
|
||||||
|
|
||||||
case SND_PCM_STATE_DISCONNECTED:
|
case SND_PCM_STATE_DISCONNECTED:
|
||||||
// lost device, close the handle and return error
|
// lost device, close the handle and return error
|
||||||
snd_pcm_close(pcm);
|
return;
|
||||||
return (void*)"SND_PCM_STATE_DISCONNECTED";
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// everything else should either be fine or impossible (here)
|
// everything else should either be fine or impossible (here)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ps.signal_close = false;
|
|
||||||
LOG_D("audio/player/alsa") << "out of outer loop";
|
|
||||||
|
|
||||||
snd_pcm_close(pcm);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AlsaPlayer::AlsaPlayer(AudioProvider *provider)
|
AlsaPlayer::AlsaPlayer(AudioProvider *provider) try
|
||||||
: AudioPlayer(provider)
|
: AudioPlayer(provider)
|
||||||
|
, thread(&AlsaPlayer::PlaybackThread, this)
|
||||||
{
|
{
|
||||||
ps.provider = provider;
|
}
|
||||||
|
catch (std::system_error const&) {
|
||||||
ps.device_name = OPT_GET("Player/Audio/ALSA/Device")->GetString();
|
throw agi::AudioPlayerOpenError("AlsaPlayer: Creating the playback thread failed", 0);
|
||||||
|
|
||||||
if (pthread_create(&thread, 0, &playback_thread, &ps) != 0)
|
|
||||||
throw agi::AudioPlayerOpenError("AlsaPlayer: Creating the playback thread failed", 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AlsaPlayer::~AlsaPlayer()
|
AlsaPlayer::~AlsaPlayer()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
PthreadMutexLocker ml(ps.mutex);
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
ps.signal_stop = true;
|
message = Message::Close;
|
||||||
ps.signal_close = true;
|
cond.notify_all();
|
||||||
LOG_D("audio/player/alsa") << "close stream, stop+close signal";
|
|
||||||
pthread_cond_signal(&ps.cond);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_join(thread, 0); // FIXME: check for errors
|
thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlsaPlayer::Play(int64_t start, int64_t count)
|
void AlsaPlayer::Play(int64_t start, int64_t count)
|
||||||
{
|
{
|
||||||
PthreadMutexLocker ml(ps.mutex);
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
ps.signal_start = true;
|
message = Message::Start;
|
||||||
ps.signal_stop = true; // make sure to stop any ongoing playback first
|
start_position = start;
|
||||||
ps.start_position = start;
|
end_position = start + count;
|
||||||
ps.end_position = start + count;
|
cond.notify_all();
|
||||||
pthread_cond_signal(&ps.cond);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlsaPlayer::Stop()
|
void AlsaPlayer::Stop()
|
||||||
{
|
{
|
||||||
PthreadMutexLocker ml(ps.mutex);
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
ps.signal_stop = true;
|
message = Message::Stop;
|
||||||
LOG_D("audio/player/alsa") << "stop stream, stop signal";
|
cond.notify_all();
|
||||||
pthread_cond_signal(&ps.cond);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AlsaPlayer::IsPlaying()
|
|
||||||
{
|
|
||||||
PthreadMutexLocker ml(ps.mutex);
|
|
||||||
return ps.playing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlsaPlayer::SetEndPosition(int64_t pos)
|
void AlsaPlayer::SetEndPosition(int64_t pos)
|
||||||
{
|
{
|
||||||
PthreadMutexLocker ml(ps.mutex);
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
ps.end_position = pos;
|
end_position = pos;
|
||||||
}
|
|
||||||
|
|
||||||
int64_t AlsaPlayer::GetEndPosition()
|
|
||||||
{
|
|
||||||
PthreadMutexLocker ml(ps.mutex);
|
|
||||||
return ps.end_position;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t AlsaPlayer::GetCurrentPosition()
|
int64_t AlsaPlayer::GetCurrentPosition()
|
||||||
|
@ -430,10 +330,10 @@ int64_t AlsaPlayer::GetCurrentPosition()
|
||||||
int64_t samplerate;
|
int64_t samplerate;
|
||||||
|
|
||||||
{
|
{
|
||||||
PthreadMutexLocker ml(ps.mutex);
|
std::unique_lock<std::mutex> lock(mutex);
|
||||||
lastpos = ps.last_position;
|
lastpos = last_position;
|
||||||
lasttime = ps.last_position_time;
|
lasttime = last_position_time;
|
||||||
samplerate = ps.provider->GetSampleRate();
|
samplerate = provider->GetSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
timespec now;
|
timespec now;
|
||||||
|
@ -445,18 +345,7 @@ int64_t AlsaPlayer::GetCurrentPosition()
|
||||||
double last_sec = lasttime.tv_sec + lasttime.tv_nsec/NANO;
|
double last_sec = lasttime.tv_sec + lasttime.tv_nsec/NANO;
|
||||||
double diff_sec = now_sec - last_sec;
|
double diff_sec = now_sec - last_sec;
|
||||||
|
|
||||||
int64_t pos = lastpos + (int64_t)(diff_sec * samplerate);
|
return lastpos + (int64_t)(diff_sec * samplerate);
|
||||||
//printf("AlsaPlayer: current position = %lld\n", pos);
|
|
||||||
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AlsaPlayer::SetVolume(double vol)
|
|
||||||
{
|
|
||||||
PthreadMutexLocker ml(ps.mutex);
|
|
||||||
ps.volume = vol;
|
|
||||||
ps.signal_volume = true;
|
|
||||||
pthread_cond_signal(&ps.cond);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue