mirror of https://github.com/odrling/Aegisub
Remove AudioPlayer::OpenStream and CloseStream
Instead, just pass the provider to the constructor and let the player worry about when to create its things. The ability to explicitly open and close the playback wasn't actually required for anything, and it complicated the implementations of the players.
This commit is contained in:
parent
6e90d9498d
commit
95a1b7e9b5
|
@ -114,14 +114,24 @@ void AudioController::OnPlaybackTimer(wxTimerEvent &)
|
||||||
void AudioController::OnComputerSuspending(wxPowerEvent &)
|
void AudioController::OnComputerSuspending(wxPowerEvent &)
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
player->CloseStream();
|
delete player;
|
||||||
|
player = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioController::OnComputerResuming(wxPowerEvent &)
|
void AudioController::OnComputerResuming(wxPowerEvent &)
|
||||||
{
|
{
|
||||||
if (provider)
|
if (provider)
|
||||||
player->OpenStream();
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
player = AudioPlayerFactory::GetAudioPlayer(provider);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
CloseAudio();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -135,9 +145,7 @@ void AudioController::OnAudioPlayerChanged()
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
player = AudioPlayerFactory::GetAudioPlayer();
|
player = AudioPlayerFactory::GetAudioPlayer(provider);
|
||||||
player->SetProvider(provider);
|
|
||||||
player->OpenStream();
|
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
@ -238,15 +246,11 @@ void AudioController::OpenAudio(const wxString &url)
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
player = AudioPlayerFactory::GetAudioPlayer();
|
player = AudioPlayerFactory::GetAudioPlayer(provider);
|
||||||
player->SetProvider(provider);
|
|
||||||
player->OpenStream();
|
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
delete player;
|
|
||||||
delete provider;
|
delete provider;
|
||||||
player = 0;
|
|
||||||
provider = 0;
|
provider = 0;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,18 +60,19 @@
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
AudioPlayer::AudioPlayer() {
|
AudioPlayer::AudioPlayer(AudioProvider *provider)
|
||||||
provider = NULL;
|
: provider(provider)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioPlayer* AudioPlayerFactory::GetAudioPlayer() {
|
AudioPlayer* AudioPlayerFactory::GetAudioPlayer(AudioProvider *provider) {
|
||||||
std::vector<std::string> list = GetClasses(OPT_GET("Audio/Player")->GetString());
|
std::vector<std::string> list = GetClasses(OPT_GET("Audio/Player")->GetString());
|
||||||
if (list.empty()) throw agi::NoAudioPlayersError("No audio players are available.", 0);
|
if (list.empty()) throw agi::NoAudioPlayersError("No audio players are available.", 0);
|
||||||
|
|
||||||
std::string error;
|
std::string error;
|
||||||
for (size_t i = 0; i < list.size(); ++i) {
|
for (size_t i = 0; i < list.size(); ++i) {
|
||||||
try {
|
try {
|
||||||
return Create(list[i]);
|
return Create(list[i], provider);
|
||||||
}
|
}
|
||||||
catch (agi::AudioPlayerOpenError const& err) {
|
catch (agi::AudioPlayerOpenError const& err) {
|
||||||
error += list[i] + " factory: " + err.GetChainedMessage() + "\n";
|
error += list[i] + " factory: " + err.GetChainedMessage() + "\n";
|
||||||
|
@ -102,4 +103,4 @@ void AudioPlayerFactory::RegisterProviders() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> AudioPlayerFactory::map *FactoryBase<AudioPlayer *(*)()>::classes = NULL;
|
template<> AudioPlayerFactory::map *FactoryBase<AudioPlayer *(*)(AudioProvider*)>::classes = NULL;
|
||||||
|
|
|
@ -366,42 +366,22 @@ do_setup:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AlsaPlayer::AlsaPlayer()
|
AlsaPlayer::AlsaPlayer(AudioProvider *provider)
|
||||||
: ps(new PlaybackState)
|
: AudioPlayer(provider)
|
||||||
|
, ps(new PlaybackState)
|
||||||
{
|
{
|
||||||
open = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AlsaPlayer::~AlsaPlayer()
|
|
||||||
{
|
|
||||||
CloseStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AlsaPlayer::OpenStream()
|
|
||||||
{
|
|
||||||
if (open) return;
|
|
||||||
|
|
||||||
CloseStream();
|
|
||||||
|
|
||||||
ps->Reset();
|
|
||||||
ps->provider = provider;
|
ps->provider = provider;
|
||||||
|
|
||||||
wxString device_name = lagi_wxString(OPT_GET("Player/Audio/ALSA/Device")->GetString());
|
wxString device_name = lagi_wxString(OPT_GET("Player/Audio/ALSA/Device")->GetString());
|
||||||
ps->device_name = std::string(device_name.utf8_str());
|
ps->device_name = std::string(device_name.utf8_str());
|
||||||
|
|
||||||
if (pthread_create(&thread, 0, &playback_thread, ps.get()) == 0)
|
if (pthread_create(&thread, 0, &playback_thread, ps.get()) != 0)
|
||||||
open = true;
|
|
||||||
else
|
|
||||||
throw agi::AudioPlayerOpenError("AlsaPlayer: Creating the playback thread failed", 0);
|
throw agi::AudioPlayerOpenError("AlsaPlayer: Creating the playback thread failed", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AlsaPlayer::CloseStream()
|
AlsaPlayer::~AlsaPlayer()
|
||||||
{
|
{
|
||||||
if (!open) return;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
PthreadMutexLocker ml(ps->mutex);
|
PthreadMutexLocker ml(ps->mutex);
|
||||||
ps->signal_stop = true;
|
ps->signal_stop = true;
|
||||||
|
@ -411,15 +391,11 @@ void AlsaPlayer::CloseStream()
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_join(thread, 0); // FIXME: check for errors
|
pthread_join(thread, 0); // FIXME: check for errors
|
||||||
|
|
||||||
open = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AlsaPlayer::Play(int64_t start, int64_t count)
|
void AlsaPlayer::Play(int64_t start, int64_t count)
|
||||||
{
|
{
|
||||||
OpenStream();
|
|
||||||
|
|
||||||
PthreadMutexLocker ml(ps->mutex);
|
PthreadMutexLocker ml(ps->mutex);
|
||||||
ps->signal_start = true;
|
ps->signal_start = true;
|
||||||
ps->signal_stop = true; // make sure to stop any ongoing playback first
|
ps->signal_stop = true; // make sure to stop any ongoing playback first
|
||||||
|
@ -431,8 +407,6 @@ void AlsaPlayer::Play(int64_t start, int64_t count)
|
||||||
|
|
||||||
void AlsaPlayer::Stop()
|
void AlsaPlayer::Stop()
|
||||||
{
|
{
|
||||||
if (!open) return;
|
|
||||||
|
|
||||||
PthreadMutexLocker ml(ps->mutex);
|
PthreadMutexLocker ml(ps->mutex);
|
||||||
ps->signal_stop = true;
|
ps->signal_stop = true;
|
||||||
LOG_D("audio/player/alsa") << "stop stream, stop signal";
|
LOG_D("audio/player/alsa") << "stop stream, stop signal";
|
||||||
|
@ -442,13 +416,12 @@ void AlsaPlayer::Stop()
|
||||||
bool AlsaPlayer::IsPlaying()
|
bool AlsaPlayer::IsPlaying()
|
||||||
{
|
{
|
||||||
PthreadMutexLocker ml(ps->mutex);
|
PthreadMutexLocker ml(ps->mutex);
|
||||||
return open && ps->playing;
|
return ps->playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AlsaPlayer::SetEndPosition(int64_t pos)
|
void AlsaPlayer::SetEndPosition(int64_t pos)
|
||||||
{
|
{
|
||||||
if (!open) return;
|
|
||||||
PthreadMutexLocker ml(ps->mutex);
|
PthreadMutexLocker ml(ps->mutex);
|
||||||
ps->end_position = pos;
|
ps->end_position = pos;
|
||||||
}
|
}
|
||||||
|
@ -456,8 +429,6 @@ void AlsaPlayer::SetEndPosition(int64_t pos)
|
||||||
|
|
||||||
void AlsaPlayer::SetCurrentPosition(int64_t pos)
|
void AlsaPlayer::SetCurrentPosition(int64_t pos)
|
||||||
{
|
{
|
||||||
if (!open) return;
|
|
||||||
|
|
||||||
PthreadMutexLocker ml(ps->mutex);
|
PthreadMutexLocker ml(ps->mutex);
|
||||||
|
|
||||||
if (!ps->playing) return;
|
if (!ps->playing) return;
|
||||||
|
@ -471,14 +442,12 @@ void AlsaPlayer::SetCurrentPosition(int64_t pos)
|
||||||
|
|
||||||
int64_t AlsaPlayer::GetStartPosition()
|
int64_t AlsaPlayer::GetStartPosition()
|
||||||
{
|
{
|
||||||
if (!open) return 0;
|
|
||||||
PthreadMutexLocker ml(ps->mutex);
|
PthreadMutexLocker ml(ps->mutex);
|
||||||
return ps->start_position;
|
return ps->start_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t AlsaPlayer::GetEndPosition()
|
int64_t AlsaPlayer::GetEndPosition()
|
||||||
{
|
{
|
||||||
if (!open) return 0;
|
|
||||||
PthreadMutexLocker ml(ps->mutex);
|
PthreadMutexLocker ml(ps->mutex);
|
||||||
return ps->end_position;
|
return ps->end_position;
|
||||||
}
|
}
|
||||||
|
@ -486,8 +455,6 @@ int64_t AlsaPlayer::GetEndPosition()
|
||||||
|
|
||||||
int64_t AlsaPlayer::GetCurrentPosition()
|
int64_t AlsaPlayer::GetCurrentPosition()
|
||||||
{
|
{
|
||||||
if (!open) return 0;
|
|
||||||
|
|
||||||
int64_t lastpos;
|
int64_t lastpos;
|
||||||
timespec lasttime;
|
timespec lasttime;
|
||||||
int64_t samplerate;
|
int64_t samplerate;
|
||||||
|
@ -516,8 +483,6 @@ int64_t AlsaPlayer::GetCurrentPosition()
|
||||||
|
|
||||||
void AlsaPlayer::SetVolume(double vol)
|
void AlsaPlayer::SetVolume(double vol)
|
||||||
{
|
{
|
||||||
if (!open) return;
|
|
||||||
|
|
||||||
PthreadMutexLocker ml(ps->mutex);
|
PthreadMutexLocker ml(ps->mutex);
|
||||||
ps->volume = vol;
|
ps->volume = vol;
|
||||||
ps->signal_volume = true;
|
ps->signal_volume = true;
|
||||||
|
@ -527,8 +492,6 @@ void AlsaPlayer::SetVolume(double vol)
|
||||||
|
|
||||||
double AlsaPlayer::GetVolume()
|
double AlsaPlayer::GetVolume()
|
||||||
{
|
{
|
||||||
if (!open) return 1.0;
|
|
||||||
|
|
||||||
PthreadMutexLocker ml(ps->mutex);
|
PthreadMutexLocker ml(ps->mutex);
|
||||||
return ps->volume;
|
return ps->volume;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,15 +47,11 @@ struct PlaybackState;
|
||||||
class AlsaPlayer : public AudioPlayer {
|
class AlsaPlayer : public AudioPlayer {
|
||||||
agi::scoped_ptr<PlaybackState> ps;
|
agi::scoped_ptr<PlaybackState> ps;
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
bool open;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AlsaPlayer();
|
AlsaPlayer(AudioProvider *provider);
|
||||||
~AlsaPlayer();
|
~AlsaPlayer();
|
||||||
|
|
||||||
void OpenStream();
|
|
||||||
void CloseStream();
|
|
||||||
|
|
||||||
void Play(int64_t start, int64_t count);
|
void Play(int64_t start, int64_t count);
|
||||||
void Stop();
|
void Stop();
|
||||||
bool IsPlaying();
|
bool IsPlaying();
|
||||||
|
|
|
@ -46,30 +46,20 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
/// @brief Constructor
|
DirectSoundPlayer::DirectSoundPlayer(AudioProvider *provider)
|
||||||
///
|
: AudioPlayer(provider)
|
||||||
DirectSoundPlayer::DirectSoundPlayer() {
|
, playing(false)
|
||||||
playing = false;
|
, volume(1.0f)
|
||||||
volume = 1.0f;
|
, offset(0)
|
||||||
playPos = 0;
|
, bufSize(0)
|
||||||
startPos = 0;
|
, playPos(0)
|
||||||
endPos = 0;
|
, startPos(0)
|
||||||
offset = 0;
|
, endPos(0)
|
||||||
|
, startTime(0)
|
||||||
buffer = NULL;
|
, directSound(0)
|
||||||
directSound = NULL;
|
, buffer(0)
|
||||||
thread = NULL;
|
, thread(0)
|
||||||
}
|
{
|
||||||
|
|
||||||
/// @brief Destructor
|
|
||||||
///
|
|
||||||
DirectSoundPlayer::~DirectSoundPlayer() {
|
|
||||||
CloseStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Open stream
|
|
||||||
///
|
|
||||||
void DirectSoundPlayer::OpenStream() {
|
|
||||||
// Initialize the DirectSound object
|
// Initialize the DirectSound object
|
||||||
HRESULT res;
|
HRESULT res;
|
||||||
res = DirectSoundCreate8(&DSDEVID_DefaultPlayback,&directSound,NULL); // TODO: support selecting audio device
|
res = DirectSoundCreate8(&DSDEVID_DefaultPlayback,&directSound,NULL); // TODO: support selecting audio device
|
||||||
|
@ -114,10 +104,7 @@ void DirectSoundPlayer::OpenStream() {
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Close stream
|
DirectSoundPlayer::~DirectSoundPlayer() {
|
||||||
///
|
|
||||||
void DirectSoundPlayer::CloseStream() {
|
|
||||||
// Stop it
|
|
||||||
Stop();
|
Stop();
|
||||||
|
|
||||||
// Unref the DirectSound buffer
|
// Unref the DirectSound buffer
|
||||||
|
|
|
@ -115,42 +115,21 @@ private:
|
||||||
DirectSoundPlayerThread *thread;
|
DirectSoundPlayerThread *thread;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DirectSoundPlayer();
|
DirectSoundPlayer(AudioProvider *provider);
|
||||||
~DirectSoundPlayer();
|
~DirectSoundPlayer();
|
||||||
|
|
||||||
void OpenStream();
|
|
||||||
void CloseStream();
|
|
||||||
|
|
||||||
void Play(int64_t start,int64_t count);
|
void Play(int64_t start,int64_t count);
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
bool IsPlaying() { return playing; }
|
bool IsPlaying() { return playing; }
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
int64_t GetStartPosition() { return startPos; }
|
int64_t GetStartPosition() { return startPos; }
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
int64_t GetEndPosition() { return endPos; }
|
int64_t GetEndPosition() { return endPos; }
|
||||||
int64_t GetCurrentPosition();
|
int64_t GetCurrentPosition();
|
||||||
void SetEndPosition(int64_t pos);
|
void SetEndPosition(int64_t pos);
|
||||||
void SetCurrentPosition(int64_t pos);
|
void SetCurrentPosition(int64_t pos);
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @param vol
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void SetVolume(double vol) { volume = vol; }
|
void SetVolume(double vol) { volume = vol; }
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
double GetVolume() { return volume; }
|
double GetVolume() { return volume; }
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -801,7 +801,8 @@ bool DirectSoundPlayer2Thread::IsDead()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectSoundPlayer2::DirectSoundPlayer2()
|
DirectSoundPlayer2::DirectSoundPlayer2(AudioProvider *provider)
|
||||||
|
: AudioPlayer(provider)
|
||||||
{
|
{
|
||||||
// The buffer will hold BufferLength times WantedLatency milliseconds of audio
|
// The buffer will hold BufferLength times WantedLatency milliseconds of audio
|
||||||
WantedLatency = OPT_GET("Player/Audio/DirectSound/Buffer Latency")->GetInt();
|
WantedLatency = OPT_GET("Player/Audio/DirectSound/Buffer Latency")->GetInt();
|
||||||
|
@ -812,6 +813,16 @@ DirectSoundPlayer2::DirectSoundPlayer2()
|
||||||
WantedLatency = 100;
|
WantedLatency = 100;
|
||||||
if (BufferLength <= 0)
|
if (BufferLength <= 0)
|
||||||
BufferLength = 5;
|
BufferLength = 5;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
thread.reset(new DirectSoundPlayer2Thread(provider, WantedLatency, BufferLength));
|
||||||
|
}
|
||||||
|
catch (const char *msg)
|
||||||
|
{
|
||||||
|
LOG_E("audio/player/dsound") << msg;
|
||||||
|
throw agi::AudioPlayerOpenError(msg, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectSoundPlayer2::~DirectSoundPlayer2()
|
DirectSoundPlayer2::~DirectSoundPlayer2()
|
||||||
|
@ -828,47 +839,10 @@ bool DirectSoundPlayer2::IsThreadAlive()
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectSoundPlayer2::OpenStream()
|
|
||||||
{
|
|
||||||
if (IsThreadAlive()) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
thread.reset(new DirectSoundPlayer2Thread(provider, WantedLatency, BufferLength));
|
|
||||||
}
|
|
||||||
catch (const char *msg)
|
|
||||||
{
|
|
||||||
LOG_E("audio/player/dsound") << msg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DirectSoundPlayer2::CloseStream()
|
|
||||||
{
|
|
||||||
thread.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DirectSoundPlayer2::SetProvider(AudioProvider *new_provider)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (IsThreadAlive() && new_provider != provider)
|
|
||||||
{
|
|
||||||
thread.reset(new DirectSoundPlayer2Thread(new_provider, WantedLatency, BufferLength));
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioPlayer::SetProvider(new_provider);
|
|
||||||
}
|
|
||||||
catch (const char *msg)
|
|
||||||
{
|
|
||||||
LOG_E("audio/player/dsound") << msg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DirectSoundPlayer2::Play(int64_t start,int64_t count)
|
void DirectSoundPlayer2::Play(int64_t start,int64_t count)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
OpenStream();
|
|
||||||
thread->Play(start, count);
|
thread->Play(start, count);
|
||||||
}
|
}
|
||||||
catch (const char *msg)
|
catch (const char *msg)
|
||||||
|
|
|
@ -64,23 +64,10 @@ class DirectSoundPlayer2 : public AudioPlayer {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
DirectSoundPlayer2();
|
DirectSoundPlayer2(AudioProvider *provider);
|
||||||
/// @brief Destructor
|
/// @brief Destructor
|
||||||
~DirectSoundPlayer2();
|
~DirectSoundPlayer2();
|
||||||
|
|
||||||
/// @brief Prepare for playback
|
|
||||||
///
|
|
||||||
/// This means creating the playback thread
|
|
||||||
void OpenStream();
|
|
||||||
/// @brief Shutdown playback
|
|
||||||
void CloseStream();
|
|
||||||
|
|
||||||
/// @brief Change audio provider used
|
|
||||||
/// @param provider New audio provider to use
|
|
||||||
///
|
|
||||||
/// Will re-create the playback thread if the provider changed and playback was open
|
|
||||||
void SetProvider(AudioProvider *provider);
|
|
||||||
|
|
||||||
/// @brief Start playback
|
/// @brief Start playback
|
||||||
/// @param start First audio frame to play
|
/// @param start First audio frame to play
|
||||||
/// @param count Number of audio frames to play
|
/// @param count Number of audio frames to play
|
||||||
|
|
|
@ -52,8 +52,8 @@
|
||||||
|
|
||||||
DEFINE_SIMPLE_EXCEPTION(OpenALException, agi::AudioPlayerOpenError, "audio/open/player/openal")
|
DEFINE_SIMPLE_EXCEPTION(OpenALException, agi::AudioPlayerOpenError, "audio/open/player/openal")
|
||||||
|
|
||||||
OpenALPlayer::OpenALPlayer()
|
OpenALPlayer::OpenALPlayer(AudioProvider *provider)
|
||||||
: open(false)
|
: AudioPlayer(provider)
|
||||||
, playing(false)
|
, playing(false)
|
||||||
, volume(1.f)
|
, volume(1.f)
|
||||||
, samplerate(0)
|
, samplerate(0)
|
||||||
|
@ -64,17 +64,6 @@ OpenALPlayer::OpenALPlayer()
|
||||||
, device(0)
|
, device(0)
|
||||||
, context(0)
|
, context(0)
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
OpenALPlayer::~OpenALPlayer()
|
|
||||||
{
|
|
||||||
CloseStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenALPlayer::OpenStream()
|
|
||||||
{
|
|
||||||
CloseStream();
|
|
||||||
|
|
||||||
bpf = provider->GetChannels() * provider->GetBytesPerSample();
|
bpf = provider->GetChannels() * provider->GetBytesPerSample();
|
||||||
try {
|
try {
|
||||||
// Open device
|
// Open device
|
||||||
|
@ -112,27 +101,16 @@ void OpenALPlayer::OpenStream()
|
||||||
// Determine buffer length
|
// Determine buffer length
|
||||||
samplerate = provider->GetSampleRate();
|
samplerate = provider->GetSampleRate();
|
||||||
decode_buffer.resize(samplerate * bpf / num_buffers / 2); // buffers for half a second of audio
|
decode_buffer.resize(samplerate * bpf / num_buffers / 2); // buffers for half a second of audio
|
||||||
|
|
||||||
// Now ready
|
|
||||||
open = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenALPlayer::CloseStream()
|
OpenALPlayer::~OpenALPlayer()
|
||||||
{
|
{
|
||||||
if (!open) return;
|
|
||||||
|
|
||||||
Stop();
|
Stop();
|
||||||
|
|
||||||
alDeleteSources(1, &source);
|
alDeleteSources(1, &source);
|
||||||
alDeleteBuffers(num_buffers, buffers);
|
alDeleteBuffers(num_buffers, buffers);
|
||||||
alcDestroyContext(context);
|
alcDestroyContext(context);
|
||||||
alcCloseDevice(device);
|
alcCloseDevice(device);
|
||||||
|
|
||||||
context = 0;
|
|
||||||
device = 0;
|
|
||||||
|
|
||||||
// No longer working
|
|
||||||
open = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenALPlayer::Play(int64_t start, int64_t count)
|
void OpenALPlayer::Play(int64_t start, int64_t count)
|
||||||
|
@ -165,7 +143,6 @@ void OpenALPlayer::Play(int64_t start, int64_t count)
|
||||||
|
|
||||||
void OpenALPlayer::Stop()
|
void OpenALPlayer::Stop()
|
||||||
{
|
{
|
||||||
if (!open) return;
|
|
||||||
if (!playing) return;
|
if (!playing) return;
|
||||||
|
|
||||||
// Reset data
|
// Reset data
|
||||||
|
|
|
@ -64,7 +64,6 @@ class OpenALPlayer : public AudioPlayer, wxTimer {
|
||||||
/// Number of OpenAL buffers to use
|
/// Number of OpenAL buffers to use
|
||||||
static const ALsizei num_buffers = 8;
|
static const ALsizei num_buffers = 8;
|
||||||
|
|
||||||
bool open; ///< Is the player ready to play?
|
|
||||||
bool playing; ///< Is audio currently playing?
|
bool playing; ///< Is audio currently playing?
|
||||||
|
|
||||||
float volume; ///< Current audio volume
|
float volume; ///< Current audio volume
|
||||||
|
@ -106,12 +105,9 @@ protected:
|
||||||
void Notify();
|
void Notify();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OpenALPlayer();
|
OpenALPlayer(AudioProvider *provider);
|
||||||
~OpenALPlayer();
|
~OpenALPlayer();
|
||||||
|
|
||||||
void OpenStream();
|
|
||||||
void CloseStream();
|
|
||||||
|
|
||||||
void Play(int64_t start,int64_t count);
|
void Play(int64_t start,int64_t count);
|
||||||
void Stop();
|
void Stop();
|
||||||
bool IsPlaying() { return playing; }
|
bool IsPlaying() { return playing; }
|
||||||
|
|
|
@ -52,25 +52,29 @@
|
||||||
|
|
||||||
DEFINE_SIMPLE_EXCEPTION(OSSError, agi::AudioPlayerOpenError, "audio/player/open/oss")
|
DEFINE_SIMPLE_EXCEPTION(OSSError, agi::AudioPlayerOpenError, "audio/player/open/oss")
|
||||||
|
|
||||||
OSSPlayer::OSSPlayer()
|
OSSPlayer::OSSPlayer(AudioProvider *provider)
|
||||||
|
: AudioPlayer(provider)
|
||||||
|
, rate(0)
|
||||||
|
, thread(0)
|
||||||
|
, playing(false)
|
||||||
|
, volume(1.0f)
|
||||||
|
, start_frame(0)
|
||||||
|
, cur_frame(0)
|
||||||
|
, end_frame(0)
|
||||||
|
, bpf(0)
|
||||||
|
, dspdev(0)
|
||||||
{
|
{
|
||||||
volume = 1.0f;
|
OpenStream();
|
||||||
open = false;
|
|
||||||
playing = false;
|
|
||||||
start_frame = cur_frame = end_frame = bpf = 0;
|
|
||||||
provider = 0;
|
|
||||||
thread = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OSSPlayer::~OSSPlayer()
|
OSSPlayer::~OSSPlayer()
|
||||||
{
|
{
|
||||||
CloseStream();
|
Stop();
|
||||||
|
::close(dspdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OSSPlayer::OpenStream()
|
void OSSPlayer::OpenStream()
|
||||||
{
|
{
|
||||||
CloseStream();
|
|
||||||
|
|
||||||
bpf = provider->GetChannels() * provider->GetBytesPerSample();
|
bpf = provider->GetChannels() * provider->GetBytesPerSample();
|
||||||
|
|
||||||
// Open device
|
// Open device
|
||||||
|
@ -114,20 +118,6 @@ void OSSPlayer::OpenStream()
|
||||||
if (ioctl(dspdev, SNDCTL_DSP_SPEED, &rate) < 0) {
|
if (ioctl(dspdev, SNDCTL_DSP_SPEED, &rate) < 0) {
|
||||||
throw OSSError("OSS player: setting samplerate failed", 0);
|
throw OSSError("OSS player: setting samplerate failed", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now ready
|
|
||||||
open = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OSSPlayer::CloseStream()
|
|
||||||
{
|
|
||||||
if (!open) return;
|
|
||||||
|
|
||||||
Stop();
|
|
||||||
::close(dspdev);
|
|
||||||
|
|
||||||
// No longer working
|
|
||||||
open = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OSSPlayer::Play(int64_t start, int64_t count)
|
void OSSPlayer::Play(int64_t start, int64_t count)
|
||||||
|
@ -146,7 +136,6 @@ void OSSPlayer::Play(int64_t start, int64_t count)
|
||||||
|
|
||||||
void OSSPlayer::Stop()
|
void OSSPlayer::Stop()
|
||||||
{
|
{
|
||||||
if (!open) return;
|
|
||||||
if (!playing) return;
|
if (!playing) return;
|
||||||
|
|
||||||
// Stop the thread
|
// Stop the thread
|
||||||
|
|
|
@ -79,13 +79,10 @@ public:
|
||||||
class OSSPlayer : public AudioPlayer {
|
class OSSPlayer : public AudioPlayer {
|
||||||
friend class OSSPlayerThread;
|
friend class OSSPlayerThread;
|
||||||
|
|
||||||
/// Is the output file handle initialized and ready to be written to?
|
|
||||||
bool open;
|
|
||||||
|
|
||||||
/// sample rate of audio
|
/// sample rate of audio
|
||||||
unsigned int rate;
|
unsigned int rate;
|
||||||
|
|
||||||
/// Worker thread that does the actual writing
|
/// Worker thread that does the actual writing
|
||||||
OSSPlayerThread *thread;
|
OSSPlayerThread *thread;
|
||||||
|
|
||||||
/// Is the player currently playing?
|
/// Is the player currently playing?
|
||||||
|
@ -106,15 +103,14 @@ class OSSPlayer : public AudioPlayer {
|
||||||
/// bytes per frame
|
/// bytes per frame
|
||||||
unsigned long bpf;
|
unsigned long bpf;
|
||||||
|
|
||||||
// OSS audio device handle
|
/// OSS audio device handle
|
||||||
volatile int dspdev;
|
volatile int dspdev;
|
||||||
|
|
||||||
public:
|
|
||||||
OSSPlayer();
|
|
||||||
~OSSPlayer();
|
|
||||||
|
|
||||||
void OpenStream();
|
void OpenStream();
|
||||||
void CloseStream();
|
|
||||||
|
public:
|
||||||
|
OSSPlayer(AudioProvider *provider);
|
||||||
|
~OSSPlayer();
|
||||||
|
|
||||||
void Play(int64_t start, int64_t count);
|
void Play(int64_t start, int64_t count);
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
|
@ -71,9 +71,11 @@ static const PaHostApiTypeId pa_host_api_priority[] = {
|
||||||
};
|
};
|
||||||
static const size_t pa_host_api_priority_count = sizeof(pa_host_api_priority) / sizeof(pa_host_api_priority[0]);
|
static const size_t pa_host_api_priority_count = sizeof(pa_host_api_priority) / sizeof(pa_host_api_priority[0]);
|
||||||
|
|
||||||
PortAudioPlayer::PortAudioPlayer()
|
PortAudioPlayer::PortAudioPlayer(AudioProvider *provider)
|
||||||
: volume(1.0f)
|
: AudioPlayer(provider)
|
||||||
|
, volume(1.0f)
|
||||||
, pa_start(0.0)
|
, pa_start(0.0)
|
||||||
|
, stream(0)
|
||||||
{
|
{
|
||||||
PaError err = Pa_Initialize();
|
PaError err = Pa_Initialize();
|
||||||
|
|
||||||
|
@ -92,6 +94,9 @@ PortAudioPlayer::PortAudioPlayer()
|
||||||
|
|
||||||
if (devices.empty())
|
if (devices.empty())
|
||||||
throw PortAudioError("No PortAudio output devices found", 0);
|
throw PortAudioError("No PortAudio output devices found", 0);
|
||||||
|
|
||||||
|
if (provider)
|
||||||
|
OpenStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortAudioPlayer::GatherDevices(PaHostApiIndex host_idx) {
|
void PortAudioPlayer::GatherDevices(PaHostApiIndex host_idx) {
|
||||||
|
@ -120,6 +125,10 @@ void PortAudioPlayer::GatherDevices(PaHostApiIndex host_idx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PortAudioPlayer::~PortAudioPlayer() {
|
PortAudioPlayer::~PortAudioPlayer() {
|
||||||
|
if (stream) {
|
||||||
|
Stop();
|
||||||
|
Pa_CloseStream(stream);
|
||||||
|
}
|
||||||
Pa_Terminate();
|
Pa_Terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,11 +181,6 @@ void PortAudioPlayer::OpenStream() {
|
||||||
throw PortAudioError("Failed initializing PortAudio stream: " + error, 0);
|
throw PortAudioError("Failed initializing PortAudio stream: " + error, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortAudioPlayer::CloseStream() {
|
|
||||||
Stop();
|
|
||||||
Pa_CloseStream(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortAudioPlayer::paStreamFinishedCallback(void *) {
|
void PortAudioPlayer::paStreamFinishedCallback(void *) {
|
||||||
LOG_D("audio/player/portaudio") << "stopping stream";
|
LOG_D("audio/player/portaudio") << "stopping stream";
|
||||||
}
|
}
|
||||||
|
@ -271,7 +275,7 @@ wxArrayString PortAudioPlayer::GetOutputDevices() {
|
||||||
list.push_back("Default");
|
list.push_back("Default");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PortAudioPlayer player;
|
PortAudioPlayer player(0);
|
||||||
|
|
||||||
for (std::map<std::string, DeviceVec>::iterator it = player.devices.begin(); it != player.devices.end(); ++it)
|
for (std::map<std::string, DeviceVec>::iterator it = player.devices.begin(); it != player.devices.end(); ++it)
|
||||||
list.push_back(lagi_wxString(it->first));
|
list.push_back(lagi_wxString(it->first));
|
||||||
|
|
|
@ -48,6 +48,8 @@ extern "C" {
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class wxArrayString;
|
||||||
|
|
||||||
/// @class PortAudioPlayer
|
/// @class PortAudioPlayer
|
||||||
/// @brief PortAudio Player
|
/// @brief PortAudio Player
|
||||||
///
|
///
|
||||||
|
@ -93,18 +95,15 @@ class PortAudioPlayer : public AudioPlayer {
|
||||||
/// @param host_idx Host API ID
|
/// @param host_idx Host API ID
|
||||||
void GatherDevices(PaHostApiIndex host_idx);
|
void GatherDevices(PaHostApiIndex host_idx);
|
||||||
|
|
||||||
|
void OpenStream();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
PortAudioPlayer();
|
PortAudioPlayer(AudioProvider *provider);
|
||||||
|
|
||||||
/// @brief Destructor
|
/// @brief Destructor
|
||||||
~PortAudioPlayer();
|
~PortAudioPlayer();
|
||||||
|
|
||||||
/// @brief Open stream
|
|
||||||
void OpenStream();
|
|
||||||
/// @brief Close stream
|
|
||||||
void CloseStream();
|
|
||||||
|
|
||||||
/// @brief Play audio.
|
/// @brief Play audio.
|
||||||
/// @param start Start position.
|
/// @param start Start position.
|
||||||
/// @param count Frame count
|
/// @param count Frame count
|
||||||
|
|
|
@ -39,7 +39,9 @@
|
||||||
#ifdef WITH_LIBPULSE
|
#ifdef WITH_LIBPULSE
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
#ifndef AGI_PRE
|
||||||
#include <stdio.h>
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include <wx/thread.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "audio_player_pulse.h"
|
#include "audio_player_pulse.h"
|
||||||
|
@ -48,38 +50,30 @@
|
||||||
#include "include/aegisub/audio_provider.h"
|
#include "include/aegisub/audio_provider.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
PulseAudioPlayer::PulseAudioPlayer()
|
#include <libaegisub/log.h>
|
||||||
: context_notify(0, 1)
|
|
||||||
|
PulseAudioPlayer::PulseAudioPlayer(AudioProvider *provider)
|
||||||
|
: AudioPlayer(provider)
|
||||||
|
, volume(1.0f)
|
||||||
|
, is_playing(false)
|
||||||
|
, start_frame(0)
|
||||||
|
, cur_frame(0)
|
||||||
|
, end_frame(0)
|
||||||
|
, bpf(0)
|
||||||
|
, context_notify(0, 1)
|
||||||
, context_success(0, 1)
|
, context_success(0, 1)
|
||||||
, stream_notify(0, 1)
|
, stream_notify(0, 1)
|
||||||
, stream_success(0, 1)
|
, stream_success(0, 1)
|
||||||
|
, paerror(0)
|
||||||
{
|
{
|
||||||
volume = 1.0f;
|
|
||||||
paerror = 0;
|
|
||||||
open = false;
|
|
||||||
is_playing = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PulseAudioPlayer::~PulseAudioPlayer()
|
|
||||||
{
|
|
||||||
CloseStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PulseAudioPlayer::OpenStream()
|
|
||||||
{
|
|
||||||
if (open) CloseStream();
|
|
||||||
|
|
||||||
// Initialise a mainloop
|
// Initialise a mainloop
|
||||||
//printf("Initialising threaded main loop\n");
|
|
||||||
mainloop = pa_threaded_mainloop_new();
|
mainloop = pa_threaded_mainloop_new();
|
||||||
if (!mainloop) {
|
if (!mainloop)
|
||||||
throw agi::AudioPlayerOpenError("Failed to initialise PulseAudio threaded mainloop object", 0);
|
throw agi::AudioPlayerOpenError("Failed to initialise PulseAudio threaded mainloop object", 0);
|
||||||
}
|
|
||||||
//printf("Starting main loop\n");
|
|
||||||
pa_threaded_mainloop_start(mainloop);
|
pa_threaded_mainloop_start(mainloop);
|
||||||
|
|
||||||
// Create context
|
// Create context
|
||||||
//printf("Creating context\n");
|
|
||||||
context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "Aegisub");
|
context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "Aegisub");
|
||||||
if (!context) {
|
if (!context) {
|
||||||
pa_threaded_mainloop_free(mainloop);
|
pa_threaded_mainloop_free(mainloop);
|
||||||
|
@ -88,8 +82,8 @@ void PulseAudioPlayer::OpenStream()
|
||||||
pa_context_set_state_callback(context, (pa_context_notify_cb_t)pa_context_notify, this);
|
pa_context_set_state_callback(context, (pa_context_notify_cb_t)pa_context_notify, this);
|
||||||
|
|
||||||
// Connect the context
|
// Connect the context
|
||||||
//printf("Connecting context\n");
|
|
||||||
pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
|
pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
|
||||||
|
|
||||||
// Wait for connection
|
// Wait for connection
|
||||||
while (true) {
|
while (true) {
|
||||||
context_notify.Wait();
|
context_notify.Wait();
|
||||||
|
@ -105,7 +99,6 @@ void PulseAudioPlayer::OpenStream()
|
||||||
}
|
}
|
||||||
// otherwise loop once more
|
// otherwise loop once more
|
||||||
}
|
}
|
||||||
//printf("Context connected\n");
|
|
||||||
|
|
||||||
// Set up stream
|
// Set up stream
|
||||||
bpf = provider->GetChannels() * provider->GetBytesPerSample();
|
bpf = provider->GetChannels() * provider->GetBytesPerSample();
|
||||||
|
@ -115,7 +108,7 @@ void PulseAudioPlayer::OpenStream()
|
||||||
ss.channels = provider->GetChannels();
|
ss.channels = provider->GetChannels();
|
||||||
pa_channel_map map;
|
pa_channel_map map;
|
||||||
pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_DEFAULT);
|
pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_DEFAULT);
|
||||||
//printf("Creating stream\n");
|
|
||||||
stream = pa_stream_new(context, "Sound", &ss, &map);
|
stream = pa_stream_new(context, "Sound", &ss, &map);
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
// argh!
|
// argh!
|
||||||
|
@ -129,10 +122,9 @@ void PulseAudioPlayer::OpenStream()
|
||||||
pa_stream_set_write_callback(stream, (pa_stream_request_cb_t)pa_stream_write, this);
|
pa_stream_set_write_callback(stream, (pa_stream_request_cb_t)pa_stream_write, this);
|
||||||
|
|
||||||
// Connect stream
|
// Connect stream
|
||||||
//printf("Connecting playback stream\n");
|
|
||||||
paerror = pa_stream_connect_playback(stream, NULL, NULL, (pa_stream_flags_t)(PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_NOT_MONOTONOUS|PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL);
|
paerror = pa_stream_connect_playback(stream, NULL, NULL, (pa_stream_flags_t)(PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_NOT_MONOTONOUS|PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL);
|
||||||
if (paerror) {
|
if (paerror) {
|
||||||
printf("PulseAudio reported error: %s (%d)\n", pa_strerror(paerror), paerror);
|
LOG_E("audio/player/pulse") << "Stream connection failed: " << pa_strerror(paerror) << "(" << paerror << ")";
|
||||||
throw agi::AudioPlayerOpenError(std::string("PulseAudio reported error: ") + pa_strerror(paerror), 0);
|
throw agi::AudioPlayerOpenError(std::string("PulseAudio reported error: ") + pa_strerror(paerror), 0);
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -141,22 +133,14 @@ void PulseAudioPlayer::OpenStream()
|
||||||
break;
|
break;
|
||||||
} else if (sstate == PA_STREAM_FAILED) {
|
} else if (sstate == PA_STREAM_FAILED) {
|
||||||
paerror = pa_context_errno(context);
|
paerror = pa_context_errno(context);
|
||||||
printf("PulseAudio player: Stream connection failed: %s (%d)\n", pa_strerror(paerror), paerror);
|
LOG_E("audio/player/pulse") << "Stream connection failed: " << pa_strerror(paerror) << "(" << paerror << ")";
|
||||||
throw agi::AudioPlayerOpenError("PulseAudio player: Something went wrong connecting the stream", 0);
|
throw agi::AudioPlayerOpenError("PulseAudio player: Something went wrong connecting the stream", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//printf("Connected playback stream, now playing\n\n");
|
|
||||||
|
|
||||||
// Hopefully this marks success
|
|
||||||
//printf("Finished opening PulseAudio\n\n");
|
|
||||||
open = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PulseAudioPlayer::CloseStream()
|
PulseAudioPlayer::~PulseAudioPlayer()
|
||||||
{
|
{
|
||||||
if (!open) return;
|
|
||||||
//printf("Closing PuseAudio\n");
|
|
||||||
|
|
||||||
if (is_playing) Stop();
|
if (is_playing) Stop();
|
||||||
|
|
||||||
// Hope for the best and just do things as quickly as possible
|
// Hope for the best and just do things as quickly as possible
|
||||||
|
@ -166,16 +150,10 @@ void PulseAudioPlayer::CloseStream()
|
||||||
pa_context_unref(context);
|
pa_context_unref(context);
|
||||||
pa_threaded_mainloop_stop(mainloop);
|
pa_threaded_mainloop_stop(mainloop);
|
||||||
pa_threaded_mainloop_free(mainloop);
|
pa_threaded_mainloop_free(mainloop);
|
||||||
|
|
||||||
//printf("Closed PulseAudio\n");
|
|
||||||
open = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PulseAudioPlayer::Play(int64_t start,int64_t count)
|
void PulseAudioPlayer::Play(int64_t start,int64_t count)
|
||||||
{
|
{
|
||||||
//printf("Starting PulseAudio playback\n");
|
|
||||||
if (!open) OpenStream();
|
|
||||||
|
|
||||||
if (is_playing) {
|
if (is_playing) {
|
||||||
// If we're already playing, do a quick "reset"
|
// If we're already playing, do a quick "reset"
|
||||||
is_playing = false;
|
is_playing = false;
|
||||||
|
@ -187,14 +165,13 @@ void PulseAudioPlayer::Play(int64_t start,int64_t count)
|
||||||
pa_operation_unref(op);
|
pa_operation_unref(op);
|
||||||
if (!stream_success_val) {
|
if (!stream_success_val) {
|
||||||
paerror = pa_context_errno(context);
|
paerror = pa_context_errno(context);
|
||||||
printf("PulseAudio player: Error flushing stream: %s (%d)\n", pa_strerror(paerror), paerror);
|
LOG_E("audio/player/pulse") << "Error flushing stream: " << pa_strerror(paerror) << "(" << paerror << ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start_frame = start;
|
start_frame = start;
|
||||||
cur_frame = start;
|
cur_frame = start;
|
||||||
end_frame = start + count;
|
end_frame = start + count;
|
||||||
//printf("start=%lu end=%lu\n", start_frame, end_frame);
|
|
||||||
|
|
||||||
is_playing = true;
|
is_playing = true;
|
||||||
|
|
||||||
|
@ -202,9 +179,8 @@ void PulseAudioPlayer::Play(int64_t start,int64_t count)
|
||||||
pa_threaded_mainloop_lock(mainloop);
|
pa_threaded_mainloop_lock(mainloop);
|
||||||
paerror = pa_stream_get_time(stream, (pa_usec_t*) &play_start_time);
|
paerror = pa_stream_get_time(stream, (pa_usec_t*) &play_start_time);
|
||||||
pa_threaded_mainloop_unlock(mainloop);
|
pa_threaded_mainloop_unlock(mainloop);
|
||||||
if (paerror) {
|
if (paerror)
|
||||||
printf("PulseAudio player: Error getting stream time: %s (%d)\n", pa_strerror(paerror), paerror);
|
LOG_E("audio/player/pulse") << "Error getting stream time: " << pa_strerror(paerror) << "(" << paerror << ")";
|
||||||
}
|
|
||||||
|
|
||||||
PulseAudioPlayer::pa_stream_write(stream, pa_stream_writable_size(stream), this);
|
PulseAudioPlayer::pa_stream_write(stream, pa_stream_writable_size(stream), this);
|
||||||
|
|
||||||
|
@ -215,14 +191,13 @@ void PulseAudioPlayer::Play(int64_t start,int64_t count)
|
||||||
pa_operation_unref(op);
|
pa_operation_unref(op);
|
||||||
if (!stream_success_val) {
|
if (!stream_success_val) {
|
||||||
paerror = pa_context_errno(context);
|
paerror = pa_context_errno(context);
|
||||||
printf("PulseAudio player: Error triggering stream: %s (%d)\n", pa_strerror(paerror), paerror);
|
LOG_E("audio/player/pulse") << "Error triggering stream: " << pa_strerror(paerror) << "(" << paerror << ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PulseAudioPlayer::Stop()
|
void PulseAudioPlayer::Stop()
|
||||||
{
|
{
|
||||||
if (!is_playing) return;
|
if (!is_playing) return;
|
||||||
//printf("Stopping PulseAudio\n");
|
|
||||||
|
|
||||||
is_playing = false;
|
is_playing = false;
|
||||||
|
|
||||||
|
@ -231,7 +206,6 @@ void PulseAudioPlayer::Stop()
|
||||||
end_frame = 0;
|
end_frame = 0;
|
||||||
|
|
||||||
// Flush the stream of data
|
// Flush the stream of data
|
||||||
//printf("Flushing stream\n");
|
|
||||||
pa_threaded_mainloop_lock(mainloop);
|
pa_threaded_mainloop_lock(mainloop);
|
||||||
pa_operation *op = pa_stream_flush(stream, (pa_stream_success_cb_t)pa_stream_success, this);
|
pa_operation *op = pa_stream_flush(stream, (pa_stream_success_cb_t)pa_stream_success, this);
|
||||||
pa_threaded_mainloop_unlock(mainloop);
|
pa_threaded_mainloop_unlock(mainloop);
|
||||||
|
@ -239,16 +213,8 @@ void PulseAudioPlayer::Stop()
|
||||||
pa_operation_unref(op);
|
pa_operation_unref(op);
|
||||||
if (!stream_success_val) {
|
if (!stream_success_val) {
|
||||||
paerror = pa_context_errno(context);
|
paerror = pa_context_errno(context);
|
||||||
printf("PulseAudio player: Error flushing stream: %s (%d)\n", pa_strerror(paerror), paerror);
|
LOG_E("audio/player/pulse") << "Error flushing stream: " << pa_strerror(paerror) << "(" << paerror << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
// And unref it
|
|
||||||
//printf("Stopped stream\n\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PulseAudioPlayer::IsPlaying()
|
|
||||||
{
|
|
||||||
return is_playing;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PulseAudioPlayer::SetEndPosition(int64_t pos)
|
void PulseAudioPlayer::SetEndPosition(int64_t pos)
|
||||||
|
@ -261,16 +227,6 @@ void PulseAudioPlayer::SetCurrentPosition(int64_t pos)
|
||||||
cur_frame = pos;
|
cur_frame = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t PulseAudioPlayer::GetStartPosition()
|
|
||||||
{
|
|
||||||
return start_frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t PulseAudioPlayer::GetEndPosition()
|
|
||||||
{
|
|
||||||
return end_frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t PulseAudioPlayer::GetCurrentPosition()
|
int64_t PulseAudioPlayer::GetCurrentPosition()
|
||||||
{
|
{
|
||||||
if (!is_playing) return 0;
|
if (!is_playing) return 0;
|
||||||
|
@ -317,7 +273,6 @@ void PulseAudioPlayer::pa_stream_write(pa_stream *p, size_t length, PulseAudioPl
|
||||||
thread->is_playing = false;
|
thread->is_playing = false;
|
||||||
pa_operation *op = pa_stream_drain(p, NULL, NULL);
|
pa_operation *op = pa_stream_drain(p, NULL, NULL);
|
||||||
pa_operation_unref(op);
|
pa_operation_unref(op);
|
||||||
//printf("PA requested more buffer, but no more to stream\n");
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} else if (thread->cur_frame >= thread->end_frame) {
|
} else if (thread->cur_frame >= thread->end_frame) {
|
||||||
|
@ -328,12 +283,10 @@ void PulseAudioPlayer::pa_stream_write(pa_stream *p, size_t length, PulseAudioPl
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("PA requested more buffer, %lu bytes\n", (unsigned long)length);
|
|
||||||
unsigned long bpf = thread->bpf;
|
unsigned long bpf = thread->bpf;
|
||||||
unsigned long frames = length / thread->bpf;
|
unsigned long frames = length / thread->bpf;
|
||||||
unsigned long maxframes = thread->end_frame - thread->cur_frame;
|
unsigned long maxframes = thread->end_frame - thread->cur_frame;
|
||||||
if (frames > maxframes) frames = maxframes;
|
if (frames > maxframes) frames = maxframes;
|
||||||
//printf("Handing it %lu frames\n", frames);
|
|
||||||
void *buf = malloc(frames * bpf);
|
void *buf = malloc(frames * bpf);
|
||||||
thread->provider->GetAudioWithVolume(buf, thread->cur_frame, frames, thread->volume);
|
thread->provider->GetAudioWithVolume(buf, thread->cur_frame, frames, thread->volume);
|
||||||
::pa_stream_write(p, buf, frames*bpf, free, 0, PA_SEEK_RELATIVE);
|
::pa_stream_write(p, buf, frames*bpf, free, 0, PA_SEEK_RELATIVE);
|
||||||
|
|
|
@ -47,14 +47,9 @@ class PulseAudioPlayer;
|
||||||
///
|
///
|
||||||
/// DOCME
|
/// DOCME
|
||||||
class PulseAudioPlayer : public AudioPlayer {
|
class PulseAudioPlayer : public AudioPlayer {
|
||||||
private:
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
float volume;
|
float volume;
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
bool open;
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
bool is_playing;
|
bool is_playing;
|
||||||
|
|
||||||
|
@ -124,18 +119,15 @@ private:
|
||||||
static void pa_stream_notify(pa_stream *p, PulseAudioPlayer *thread);
|
static void pa_stream_notify(pa_stream *p, PulseAudioPlayer *thread);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PulseAudioPlayer();
|
PulseAudioPlayer(AudioProvider *provider);
|
||||||
~PulseAudioPlayer();
|
~PulseAudioPlayer();
|
||||||
|
|
||||||
void OpenStream();
|
|
||||||
void CloseStream();
|
|
||||||
|
|
||||||
void Play(int64_t start,int64_t count);
|
void Play(int64_t start,int64_t count);
|
||||||
void Stop();
|
void Stop();
|
||||||
bool IsPlaying();
|
bool IsPlaying() { return is_playing; }
|
||||||
|
|
||||||
int64_t GetStartPosition();
|
int64_t GetStartPosition() { return start_frame; }
|
||||||
int64_t GetEndPosition();
|
int64_t GetEndPosition() { return end_frame; }
|
||||||
int64_t GetCurrentPosition();
|
int64_t GetCurrentPosition();
|
||||||
void SetEndPosition(int64_t pos);
|
void SetEndPosition(int64_t pos);
|
||||||
void SetCurrentPosition(int64_t pos);
|
void SetCurrentPosition(int64_t pos);
|
||||||
|
|
|
@ -50,12 +50,9 @@ protected:
|
||||||
AudioProvider *provider;
|
AudioProvider *provider;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AudioPlayer();
|
AudioPlayer(AudioProvider *provider);
|
||||||
virtual ~AudioPlayer() { }
|
virtual ~AudioPlayer() { }
|
||||||
|
|
||||||
virtual void OpenStream()=0;
|
|
||||||
virtual void CloseStream()=0;
|
|
||||||
|
|
||||||
virtual void Play(int64_t start,int64_t count)=0; // Play sample range
|
virtual void Play(int64_t start,int64_t count)=0; // Play sample range
|
||||||
virtual void Stop()=0; // Stop playing
|
virtual void Stop()=0; // Stop playing
|
||||||
virtual bool IsPlaying()=0;
|
virtual bool IsPlaying()=0;
|
||||||
|
@ -68,12 +65,10 @@ public:
|
||||||
virtual int64_t GetCurrentPosition()=0;
|
virtual int64_t GetCurrentPosition()=0;
|
||||||
virtual void SetEndPosition(int64_t pos)=0;
|
virtual void SetEndPosition(int64_t pos)=0;
|
||||||
virtual void SetCurrentPosition(int64_t pos)=0;
|
virtual void SetCurrentPosition(int64_t pos)=0;
|
||||||
|
|
||||||
virtual void SetProvider(AudioProvider *new_provider) { provider = new_provider; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AudioPlayerFactory : public Factory0<AudioPlayer> {
|
class AudioPlayerFactory : public Factory1<AudioPlayer, AudioProvider*> {
|
||||||
public:
|
public:
|
||||||
static void RegisterProviders();
|
static void RegisterProviders();
|
||||||
static AudioPlayer *GetAudioPlayer();
|
static AudioPlayer *GetAudioPlayer(AudioProvider *provider);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue