diff --git a/build/Aegisub/Aegisub.vcxproj b/build/Aegisub/Aegisub.vcxproj
index c504b4202..0b1dcd629 100644
--- a/build/Aegisub/Aegisub.vcxproj
+++ b/build/Aegisub/Aegisub.vcxproj
@@ -110,13 +110,7 @@
-
-
-
-
-
-
@@ -197,7 +191,6 @@
-
@@ -391,7 +384,6 @@
-
diff --git a/build/Aegisub/Aegisub.vcxproj.filters b/build/Aegisub/Aegisub.vcxproj.filters
index 02e122708..6214b4aa1 100644
--- a/build/Aegisub/Aegisub.vcxproj.filters
+++ b/build/Aegisub/Aegisub.vcxproj.filters
@@ -213,24 +213,6 @@
Config
-
- Audio\Players
-
-
- Audio\Players
-
-
- Audio\Players
-
-
- Audio\Players
-
-
- Audio\Players
-
-
- Audio\Players
-
Audio\Players
@@ -528,9 +510,6 @@
Video\Providers
-
- Utilities
-
Video\Visual tools
@@ -1055,9 +1034,6 @@
Main UI
-
- Utilities
-
Video\Visual tools
diff --git a/src/Makefile b/src/Makefile
index 292ee01e4..f6a38b2d1 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -203,7 +203,6 @@ SRC += \
mkv_wrap.cpp \
pen.cpp \
persist_location.cpp \
- plugin_manager.cpp \
preferences.cpp \
preferences_base.cpp \
resolution_resampler.cpp \
diff --git a/src/audio_player.cpp b/src/audio_player.cpp
index dfe8e8561..9c1b6aaa0 100644
--- a/src/audio_player.cpp
+++ b/src/audio_player.cpp
@@ -35,56 +35,75 @@
#include "config.h"
#include "include/aegisub/audio_player.h"
-#include "audio_player_alsa.h"
-#include "audio_player_dsound.h"
-#include "audio_player_dsound2.h"
-#include "audio_player_openal.h"
-#include "audio_player_oss.h"
-#include "audio_player_portaudio.h"
-#include "audio_player_pulse.h"
#include "audio_controller.h"
+#include "factory_manager.h"
#include "options.h"
+#include
+
AudioPlayer::AudioPlayer(AudioProvider *provider)
: provider(provider)
{
}
+std::unique_ptr CreateAlsaPlayer(AudioProvider *providers);
+std::unique_ptr CreateDirectSoundPlayer(AudioProvider *providers);
+std::unique_ptr CreateDirectSound2Player(AudioProvider *providers);
+std::unique_ptr CreateOpenALPlayer(AudioProvider *providers);
+std::unique_ptr CreatePortAudioPlayer(AudioProvider *providers);
+std::unique_ptr CreatePulseAudioPlayer(AudioProvider *providers);
+std::unique_ptr CreateOSSPlayer(AudioProvider *providers);
+
+namespace {
+ struct factory {
+ const char *name;
+ std::unique_ptr (*create)(AudioProvider *);
+ bool hidden;
+ };
+
+ const factory factories[] = {
+#ifdef WITH_ALSA
+ {"ALSA", CreateAlsaPlayer, false},
+#endif
+#ifdef WITH_DIRECTSOUND
+ {"DirectSound-old", CreateDirectSoundPlayer, false},
+ {"DirectSound", CreateDirectSound2Player, false},
+#endif
+#ifdef WITH_OPENAL
+ {"OpenAL", CreateOpenALPlayer, false},
+#endif
+#ifdef WITH_PORTAUDIO
+ {"PortAudio", CreatePortAudioPlayer, false},
+#endif
+#ifdef WITH_LIBPULSE
+ {"PulseAudio", CreatePulseAudioPlayer, false},
+#endif
+#ifdef WITH_OSS
+ {"OSS", CreateOSSPlayer, false},
+#endif
+ };
+}
+
+std::vector AudioPlayerFactory::GetClasses() {
+ return ::GetClasses(boost::make_iterator_range(std::begin(factories), std::end(factories)));
+}
+
std::unique_ptr AudioPlayerFactory::GetAudioPlayer(AudioProvider *provider) {
- std::vector list = GetClasses(OPT_GET("Audio/Player")->GetString());
- if (list.empty()) throw agi::NoAudioPlayersError("No audio players are available.", nullptr);
+ if (std::distance(std::begin(factories), std::end(factories)) == 0)
+ throw agi::NoAudioPlayersError("No audio players are available.", nullptr);
+
+ auto preferred = OPT_GET("Audio/Player")->GetString();
+ auto sorted = GetSorted(boost::make_iterator_range(std::begin(factories), std::end(factories)), preferred);
std::string error;
- for (auto const& factory_name : list) {
+ for (auto factory : sorted) {
try {
- return Create(factory_name, provider);
+ return factory->create(provider);
}
catch (agi::AudioPlayerOpenError const& err) {
- error += factory_name + " factory: " + err.GetChainedMessage() + "\n";
+ error += std::string(factory->name) + " factory: " + err.GetChainedMessage() + "\n";
}
}
throw agi::AudioPlayerOpenError(error, nullptr);
}
-
-void AudioPlayerFactory::RegisterProviders() {
-#ifdef WITH_ALSA
- Register("ALSA");
-#endif
-#ifdef WITH_DIRECTSOUND
- Register("DirectSound-old");
- Register("DirectSound");
-#endif
-#ifdef WITH_OPENAL
- Register("OpenAL");
-#endif
-#ifdef WITH_PORTAUDIO
- Register("PortAudio");
-#endif
-#ifdef WITH_LIBPULSE
- Register("PulseAudio");
-#endif
-#ifdef WITH_OSS
- Register("OSS");
-#endif
-}
diff --git a/src/audio_player_alsa.cpp b/src/audio_player_alsa.cpp
index 7621a34f1..61f009f07 100644
--- a/src/audio_player_alsa.cpp
+++ b/src/audio_player_alsa.cpp
@@ -35,8 +35,7 @@
#include "config.h"
#ifdef WITH_ALSA
-
-#include "audio_player_alsa.h"
+#include "include/aegisub/audio_player.h"
#include "audio_controller.h"
#include "include/aegisub/audio_provider.h"
@@ -48,15 +47,73 @@
#include
#include
-
+#include
#include
+#include
+
+namespace {
+struct PlaybackState {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+
+ bool playing = false;
+ 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 {
+ PlaybackState ps;
+ pthread_t thread;
+
+public:
+ AlsaPlayer(AudioProvider *provider);
+ ~AlsaPlayer();
+
+ void Play(int64_t start, int64_t count);
+ void Stop();
+ bool IsPlaying();
+
+ int64_t GetStartPosition();
+ int64_t GetEndPosition();
+ int64_t GetCurrentPosition();
+ void SetEndPosition(int64_t pos);
+ void SetCurrentPosition(int64_t pos);
+
+ void SetVolume(double vol);
+};
class PthreadMutexLocker {
pthread_mutex_t &mutex;
- PthreadMutexLocker(const PthreadMutexLocker &); // uncopyable
- PthreadMutexLocker(); // no default
- PthreadMutexLocker& operator=(PthreadMutexLocker const&);
+ PthreadMutexLocker(const PthreadMutexLocker &) = delete;
+ PthreadMutexLocker& operator=(PthreadMutexLocker const&) = delete;
public:
explicit PthreadMutexLocker(pthread_mutex_t &mutex) : mutex(mutex)
@@ -83,78 +140,22 @@ public:
}
};
-
class ScopedAliveFlag {
bool &flag;
- ScopedAliveFlag(const ScopedAliveFlag &); // uncopyable
- ScopedAliveFlag(); // no default
- ScopedAliveFlag& operator=(ScopedAliveFlag const&);
+ ScopedAliveFlag(const ScopedAliveFlag &) = delete;
+ ScopedAliveFlag& operator=(ScopedAliveFlag const&) = delete;
public:
explicit ScopedAliveFlag(bool &var) : flag(var) { flag = true; }
~ScopedAliveFlag() { flag = false; }
};
-
-struct PlaybackState {
- pthread_mutex_t mutex;
- pthread_cond_t cond;
-
- bool playing;
- bool alive;
-
- bool signal_start;
- bool signal_stop;
- bool signal_close;
- bool signal_volume;
-
- double volume;
- int64_t start_position;
- int64_t end_position;
-
- AudioProvider *provider;
- std::string device_name;
-
- int64_t last_position;
- timespec last_position_time;
-
- PlaybackState()
- {
- pthread_mutex_init(&mutex, 0);
- pthread_cond_init(&cond, 0);
-
- Reset();
- volume = 1.0;
- }
-
- ~PlaybackState()
- {
- pthread_cond_destroy(&cond);
- pthread_mutex_destroy(&mutex);
- }
-
- void Reset()
- {
- playing = false;
- alive = false;
- signal_start = false;
- signal_stop = false;
- signal_close = false;
- signal_volume = false;
- start_position = 0;
- end_position = 0;
- last_position = 0;
- memset(&last_position_time, 0, sizeof last_position_time);
- provider = 0;
- }
-};
-
void *playback_thread(void *arg)
{
// This is exception-free territory!
// Return a pointer to a static string constant describing the error, or 0 on no error
- PlaybackState &ps = *(PlaybackState*)arg;
+ auto &ps = *static_cast(arg);
PthreadMutexLocker ml(ps.mutex);
ScopedAliveFlag alive_flag(ps.alive);
@@ -363,73 +364,66 @@ do_setup:
return 0;
}
-
AlsaPlayer::AlsaPlayer(AudioProvider *provider)
: AudioPlayer(provider)
-, ps(agi::util::make_unique())
{
- ps->provider = provider;
+ ps.provider = provider;
- ps->device_name = OPT_GET("Player/Audio/ALSA/Device")->GetString();
+ ps.device_name = OPT_GET("Player/Audio/ALSA/Device")->GetString();
- if (pthread_create(&thread, 0, &playback_thread, ps.get()) != 0)
+ if (pthread_create(&thread, 0, &playback_thread, &ps) != 0)
throw agi::AudioPlayerOpenError("AlsaPlayer: Creating the playback thread failed", 0);
}
-
AlsaPlayer::~AlsaPlayer()
{
{
- PthreadMutexLocker ml(ps->mutex);
- ps->signal_stop = true;
- ps->signal_close = true;
+ PthreadMutexLocker ml(ps.mutex);
+ ps.signal_stop = true;
+ ps.signal_close = true;
LOG_D("audio/player/alsa") << "close stream, stop+close signal";
- pthread_cond_signal(&ps->cond);
+ pthread_cond_signal(&ps.cond);
}
pthread_join(thread, 0); // FIXME: check for errors
}
-
void AlsaPlayer::Play(int64_t start, int64_t count)
{
- PthreadMutexLocker ml(ps->mutex);
- ps->signal_start = true;
- ps->signal_stop = true; // make sure to stop any ongoing playback first
- ps->start_position = start;
- ps->end_position = start + count;
- pthread_cond_signal(&ps->cond);
+ PthreadMutexLocker ml(ps.mutex);
+ ps.signal_start = true;
+ ps.signal_stop = true; // make sure to stop any ongoing playback first
+ ps.start_position = start;
+ ps.end_position = start + count;
+ pthread_cond_signal(&ps.cond);
}
-
void AlsaPlayer::Stop()
{
- PthreadMutexLocker ml(ps->mutex);
- ps->signal_stop = true;
+ PthreadMutexLocker ml(ps.mutex);
+ ps.signal_stop = true;
LOG_D("audio/player/alsa") << "stop stream, stop signal";
- pthread_cond_signal(&ps->cond);
+ pthread_cond_signal(&ps.cond);
}
bool AlsaPlayer::IsPlaying()
{
- PthreadMutexLocker ml(ps->mutex);
- return ps->playing;
+ PthreadMutexLocker ml(ps.mutex);
+ return ps.playing;
}
-
void AlsaPlayer::SetEndPosition(int64_t pos)
{
- PthreadMutexLocker ml(ps->mutex);
- ps->end_position = pos;
+ PthreadMutexLocker ml(ps.mutex);
+ ps.end_position = pos;
}
int64_t AlsaPlayer::GetEndPosition()
{
- PthreadMutexLocker ml(ps->mutex);
- return ps->end_position;
+ PthreadMutexLocker ml(ps.mutex);
+ return ps.end_position;
}
-
int64_t AlsaPlayer::GetCurrentPosition()
{
int64_t lastpos;
@@ -437,10 +431,10 @@ int64_t AlsaPlayer::GetCurrentPosition()
int64_t samplerate;
{
- PthreadMutexLocker ml(ps->mutex);
- lastpos = ps->last_position;
- lasttime = ps->last_position_time;
- samplerate = ps->provider->GetSampleRate();
+ PthreadMutexLocker ml(ps.mutex);
+ lastpos = ps.last_position;
+ lasttime = ps.last_position_time;
+ samplerate = ps.provider->GetSampleRate();
}
timespec now;
@@ -460,10 +454,16 @@ int64_t AlsaPlayer::GetCurrentPosition()
void AlsaPlayer::SetVolume(double vol)
{
- PthreadMutexLocker ml(ps->mutex);
- ps->volume = vol;
- ps->signal_volume = true;
- pthread_cond_signal(&ps->cond);
+ PthreadMutexLocker ml(ps.mutex);
+ ps.volume = vol;
+ ps.signal_volume = true;
+ pthread_cond_signal(&ps.cond);
+}
+}
+
+std::unique_ptr CreateAlsaPlayer(AudioProvider *provider)
+{
+ return agi::util::make_unique(provider);
}
#endif // WITH_ALSA
diff --git a/src/audio_player_alsa.h b/src/audio_player_alsa.h
deleted file mode 100644
index a524f7894..000000000
--- a/src/audio_player_alsa.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2011, Niels Martin Hansen
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of the Aegisub Group nor the names of its contributors
-// may be used to endorse or promote products derived from this software
-// without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Aegisub Project http://www.aegisub.org/
-
-/// @file audio_player_alsa.h
-/// @see audio_player_alsa.cpp
-/// @ingroup audio_output
-///
-
-#ifdef WITH_ALSA
-#include "include/aegisub/audio_player.h"
-
-#include
-#include
-
-struct PlaybackState;
-
-class AlsaPlayer final : public AudioPlayer {
- std::unique_ptr ps;
- pthread_t thread;
-
-public:
- AlsaPlayer(AudioProvider *provider);
- ~AlsaPlayer();
-
- void Play(int64_t start, int64_t count);
- void Stop();
- bool IsPlaying();
-
- int64_t GetStartPosition();
- int64_t GetEndPosition();
- int64_t GetCurrentPosition();
- void SetEndPosition(int64_t pos);
- void SetCurrentPosition(int64_t pos);
-
- void SetVolume(double vol);
-};
-
-#endif
diff --git a/src/audio_player_dsound.cpp b/src/audio_player_dsound.cpp
index c32287834..f5844f294 100644
--- a/src/audio_player_dsound.cpp
+++ b/src/audio_player_dsound.cpp
@@ -35,28 +35,72 @@
#include "config.h"
#ifdef WITH_DIRECTSOUND
-
-#include
+#include "include/aegisub/audio_player.h"
#include "audio_controller.h"
-#include "audio_player_dsound.h"
+#include "include/aegisub/audio_provider.h"
#include "frame_main.h"
#include "main.h"
#include "utils.h"
+#include
+#include
+
+#include
+#include
+
+namespace {
+class DirectSoundPlayer;
+
+class DirectSoundPlayerThread final : public wxThread {
+ DirectSoundPlayer *parent;
+ HANDLE stopnotify;
+
+public:
+ void Stop(); // Notify thread to stop audio playback. Thread safe.
+ DirectSoundPlayerThread(DirectSoundPlayer *parent);
+ ~DirectSoundPlayerThread();
+
+ wxThread::ExitCode Entry();
+};
+
+class DirectSoundPlayer final : public AudioPlayer {
+ friend class DirectSoundPlayerThread;
+
+ volatile bool playing = false;
+ float volume = 1.0f;
+ int offset = 0;
+
+ DWORD bufSize = 0;
+ volatile int64_t playPos = 0;
+ int64_t startPos = 0;
+ volatile int64_t endPos = 0;
+ DWORD startTime = 0;
+
+ IDirectSound8 *directSound = nullptr;
+ IDirectSoundBuffer8 *buffer = nullptr;
+
+ bool FillBuffer(bool fill);
+ DirectSoundPlayerThread *thread = nullptr;
+
+public:
+ DirectSoundPlayer(AudioProvider *provider);
+ ~DirectSoundPlayer();
+
+ void Play(int64_t start,int64_t count);
+ void Stop();
+
+ bool IsPlaying() { return playing; }
+
+ int64_t GetEndPosition() { return endPos; }
+ int64_t GetCurrentPosition();
+ void SetEndPosition(int64_t pos);
+
+ void SetVolume(double vol) { volume = vol; }
+};
+
DirectSoundPlayer::DirectSoundPlayer(AudioProvider *provider)
: AudioPlayer(provider)
-, playing(false)
-, volume(1.0f)
-, offset(0)
-, bufSize(0)
-, playPos(0)
-, startPos(0)
-, endPos(0)
-, startTime(0)
-, directSound(0)
-, buffer(0)
-, thread(0)
{
// Initialize the DirectSound object
HRESULT res;
@@ -105,23 +149,13 @@ DirectSoundPlayer::DirectSoundPlayer(AudioProvider *provider)
DirectSoundPlayer::~DirectSoundPlayer() {
Stop();
- // Unref the DirectSound buffer
- if (buffer) {
+ if (buffer)
buffer->Release();
- buffer = nullptr;
- }
- // Unref the DirectSound object
- if (directSound) {
+ if (directSound)
directSound->Release();
- directSound = nullptr;
- }
}
-/// @brief Fill buffer
-/// @param fill
-/// @return
-///
bool DirectSoundPlayer::FillBuffer(bool fill) {
if (playPos >= endPos) return false;
@@ -181,7 +215,6 @@ RetryLock:
goto RetryLock;
}
- // Error
if (FAILED(res)) return false;
// Convert size to number of samples
@@ -197,19 +230,13 @@ RetryLock:
if (count2) provider->GetAudioWithVolume(ptr2, playPos+count1, count2, volume);
playPos += count1+count2;
- // Unlock
buffer->Unlock(ptr1,count1*bytesps,ptr2,count2*bytesps);
- // Update offset
offset = (offset + count1*bytesps + count2*bytesps) % bufSize;
return playPos < endPos;
}
-/// @brief Play
-/// @param start
-/// @param count
-///
void DirectSoundPlayer::Play(int64_t start,int64_t count) {
// Make sure that it's stopped
Stop();
@@ -245,9 +272,6 @@ void DirectSoundPlayer::Play(int64_t start,int64_t count) {
startTime = GetTickCount();
}
-/// @brief Stop
-/// @param timerToo
-///
void DirectSoundPlayer::Stop() {
// Stop the thread
if (thread) {
@@ -259,7 +283,6 @@ void DirectSoundPlayer::Stop() {
}
// The thread is now guaranteed dead and there are no concurrency problems to worry about
- // Stop
if (buffer) buffer->Stop(); // the thread should have done this already
// Reset variables
@@ -270,16 +293,10 @@ void DirectSoundPlayer::Stop() {
offset = 0;
}
-/// @brief Set end
-/// @param pos
-///
void DirectSoundPlayer::SetEndPosition(int64_t pos) {
if (playing) endPos = pos;
}
-/// @brief Get current position
-/// @return
-///
int64_t DirectSoundPlayer::GetCurrentPosition() {
// Check if buffer is loaded
if (!buffer || !playing) return 0;
@@ -291,23 +308,15 @@ int64_t DirectSoundPlayer::GetCurrentPosition() {
return startPos + tdiff * provider->GetSampleRate() / 1000;
}
-/// @brief Thread constructor
-/// @param par
-///
DirectSoundPlayerThread::DirectSoundPlayerThread(DirectSoundPlayer *par) : wxThread(wxTHREAD_JOINABLE) {
parent = par;
stopnotify = CreateEvent(nullptr, true, false, nullptr);
}
-/// @brief Thread destructor
-///
DirectSoundPlayerThread::~DirectSoundPlayerThread() {
CloseHandle(stopnotify);
}
-/// @brief Thread entry point
-/// @return
-///
wxThread::ExitCode DirectSoundPlayerThread::Entry() {
CoInitialize(0);
@@ -355,12 +364,15 @@ wxThread::ExitCode DirectSoundPlayerThread::Entry() {
return 0;
}
-/// @brief Stop playback thread
-///
void DirectSoundPlayerThread::Stop() {
// Increase the stopnotify by one, causing a wait for it to succeed
SetEvent(stopnotify);
}
+}
+
+std::unique_ptr CreateDirectSoundPlayer(AudioProvider *provider) {
+ return agi::util::make_unique(provider);
+}
#endif // WITH_DIRECTSOUND
diff --git a/src/audio_player_dsound.h b/src/audio_player_dsound.h
deleted file mode 100644
index ec9fd244e..000000000
--- a/src/audio_player_dsound.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2006, Rodrigo Braz Monteiro
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of the Aegisub Group nor the names of its contributors
-// may be used to endorse or promote products derived from this software
-// without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Aegisub Project http://www.aegisub.org/
-
-/// @file audio_player_dsound.h
-/// @see audio_player_dsound.cpp
-/// @ingroup audio_output
-///
-
-#ifdef WITH_DIRECTSOUND
-
-#include
-
-#include
-
-#include "include/aegisub/audio_player.h"
-#include "include/aegisub/audio_provider.h"
-
-class DirectSoundPlayer;
-
-class DirectSoundPlayerThread final : public wxThread {
- DirectSoundPlayer *parent;
- HANDLE stopnotify;
-
-public:
- void Stop(); // Notify thread to stop audio playback. Thread safe.
- DirectSoundPlayerThread(DirectSoundPlayer *parent);
- ~DirectSoundPlayerThread();
-
- wxThread::ExitCode Entry();
-};
-
-class DirectSoundPlayer final : public AudioPlayer {
- friend class DirectSoundPlayerThread;
-
- volatile bool playing;
- float volume;
- int offset;
-
- DWORD bufSize;
- volatile int64_t playPos;
- int64_t startPos;
- volatile int64_t endPos;
- DWORD startTime;
-
- IDirectSound8 *directSound;
- IDirectSoundBuffer8 *buffer;
-
- bool FillBuffer(bool fill);
- DirectSoundPlayerThread *thread;
-
-public:
- DirectSoundPlayer(AudioProvider *provider);
- ~DirectSoundPlayer();
-
- void Play(int64_t start,int64_t count);
- void Stop();
-
- bool IsPlaying() { return playing; }
-
- int64_t GetEndPosition() { return endPos; }
- int64_t GetCurrentPosition();
- void SetEndPosition(int64_t pos);
-
- void SetVolume(double vol) { volume = vol; }
-};
-#endif
diff --git a/src/audio_player_dsound2.cpp b/src/audio_player_dsound2.cpp
index a91c1acfd..9952b4d62 100644
--- a/src/audio_player_dsound2.cpp
+++ b/src/audio_player_dsound2.cpp
@@ -35,7 +35,7 @@
#include "config.h"
#ifdef WITH_DIRECTSOUND
-#include "audio_player_dsound2.h"
+#include "include/aegisub/audio_player.h"
#include "audio_controller.h"
#include "include/aegisub/audio_provider.h"
@@ -52,6 +52,68 @@
#include
#include
+namespace {
+class DirectSoundPlayer2Thread;
+
+/// @class DirectSoundPlayer2
+/// @brief New implementation of DirectSound-based audio player
+///
+/// The core design idea is to have a playback thread that owns the DirectSound COM objects
+/// and performs all playback operations, and use the player object as a proxy to
+/// send commands to the playback thread.
+class DirectSoundPlayer2 final : public AudioPlayer {
+ /// The playback thread
+ std::unique_ptr thread;
+
+ /// Desired length in milliseconds to write ahead of the playback cursor
+ int WantedLatency;
+
+ /// Multiplier for WantedLatency to get total buffer length
+ int BufferLength;
+
+ /// @brief Tell whether playback thread is alive
+ /// @return True if there is a playback thread and it's ready
+ bool IsThreadAlive();
+
+public:
+ /// @brief Constructor
+ DirectSoundPlayer2(AudioProvider *provider);
+ /// @brief Destructor
+ ~DirectSoundPlayer2();
+
+ /// @brief Start playback
+ /// @param start First audio frame to play
+ /// @param count Number of audio frames to play
+ void Play(int64_t start,int64_t count);
+
+ /// @brief Stop audio playback
+ /// @param timerToo Whether to also stop the playback update timer
+ void Stop();
+
+ /// @brief Tell whether playback is active
+ /// @return True if audio is playing back
+ bool IsPlaying();
+
+ /// @brief Get playback end position
+ /// @return Audio frame index
+ ///
+ /// Returns 0 if playback is stopped or there is no playback thread
+ int64_t GetEndPosition();
+ /// @brief Get approximate playback position
+ /// @return Index of audio frame user is currently hearing
+ ///
+ /// Returns 0 if playback is stopped or there is no playback thread
+ int64_t GetCurrentPosition();
+
+ /// @brief Change playback end position
+ /// @param pos New end position
+ void SetEndPosition(int64_t pos);
+
+ /// @brief Change playback volume
+ /// @param vol Amplification factor
+ void SetVolume(double vol);
+};
+
/// @brief RAII support class to init and de-init the COM library
struct COMInitialization {
@@ -157,7 +219,6 @@ class DirectSoundPlayer2Thread {
/// @brief Check for error state and throw exception if one occurred
void CheckError();
-
/// Win32 handle to the thread
Win32KernelHandle thread_handle;
@@ -186,16 +247,16 @@ class DirectSoundPlayer2Thread {
Win32KernelHandle error_happened;
/// Statically allocated error message text describing reason for error_happened being set
- const char *error_message;
+ const char *error_message = nullptr;
/// Playback volume, 1.0 is "unchanged"
- double volume;
+ double volume = 1.0;
/// Audio frame to start playback at
- int64_t start_frame;
+ int64_t start_frame = 0;
/// Audio frame to end playback at
- int64_t end_frame;
+ int64_t end_frame = 0;
/// Desired length in milliseconds to write ahead of the playback cursor
@@ -646,11 +707,6 @@ DirectSoundPlayer2Thread::DirectSoundPlayer2Thread(AudioProvider *provider, int
, buffer_length(BufferLength)
, provider(provider)
{
- error_message = 0;
- volume = 1.0;
- start_frame = 0;
- end_frame = 0;
-
thread_handle = (HANDLE)_beginthreadex(0, 0, ThreadProc, this, 0, 0);
if (!thread_handle)
@@ -904,5 +960,10 @@ void DirectSoundPlayer2::SetVolume(double vol)
LOG_E("audio/player/dsound") << msg;
}
}
+}
+
+std::unique_ptr CreateDirectSound2Player(AudioProvider *provider) {
+ return agi::util::make_unique(provider);
+}
#endif // WITH_DIRECTSOUND
diff --git a/src/audio_player_dsound2.h b/src/audio_player_dsound2.h
deleted file mode 100644
index 62e0b0048..000000000
--- a/src/audio_player_dsound2.h
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright (c) 2008, Niels Martin Hansen
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of the Aegisub Group nor the names of its contributors
-// may be used to endorse or promote products derived from this software
-// without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Aegisub Project http://www.aegisub.org/
-
-/// @file audio_player_dsound2.h
-/// @see audio_player_dsound2.cpp
-/// @ingroup audio_output
-///
-
-#ifdef WITH_DIRECTSOUND
-
-#include "include/aegisub/audio_player.h"
-
-class DirectSoundPlayer2Thread;
-
-/// @class DirectSoundPlayer2
-/// @brief New implementation of DirectSound-based audio player
-///
-/// The core design idea is to have a playback thread that owns the DirectSound COM objects
-/// and performs all playback operations, and use the player object as a proxy to
-/// send commands to the playback thread.
-class DirectSoundPlayer2 final : public AudioPlayer {
- /// The playback thread
- std::unique_ptr thread;
-
- /// Desired length in milliseconds to write ahead of the playback cursor
- int WantedLatency;
-
- /// Multiplier for WantedLatency to get total buffer length
- int BufferLength;
-
- /// @brief Tell whether playback thread is alive
- /// @return True if there is a playback thread and it's ready
- bool IsThreadAlive();
-
-public:
- /// @brief Constructor
- DirectSoundPlayer2(AudioProvider *provider);
- /// @brief Destructor
- ~DirectSoundPlayer2();
-
- /// @brief Start playback
- /// @param start First audio frame to play
- /// @param count Number of audio frames to play
- void Play(int64_t start,int64_t count);
-
- /// @brief Stop audio playback
- /// @param timerToo Whether to also stop the playback update timer
- void Stop();
-
- /// @brief Tell whether playback is active
- /// @return True if audio is playing back
- bool IsPlaying();
-
- /// @brief Get playback end position
- /// @return Audio frame index
- ///
- /// Returns 0 if playback is stopped or there is no playback thread
- int64_t GetEndPosition();
- /// @brief Get approximate playback position
- /// @return Index of audio frame user is currently hearing
- ///
- /// Returns 0 if playback is stopped or there is no playback thread
- int64_t GetCurrentPosition();
-
- /// @brief Change playback end position
- /// @param pos New end position
- void SetEndPosition(int64_t pos);
-
- /// @brief Change playback volume
- /// @param vol Amplification factor
- void SetVolume(double vol);
-};
-#endif
diff --git a/src/audio_player_openal.cpp b/src/audio_player_openal.cpp
index a3dbc75da..b44cb3cd0 100644
--- a/src/audio_player_openal.cpp
+++ b/src/audio_player_openal.cpp
@@ -35,14 +35,29 @@
#include "config.h"
#ifdef WITH_OPENAL
-
-#include
-
-#include "audio_player_openal.h"
+#include "include/aegisub/audio_player.h"
#include "audio_controller.h"
+#include "include/aegisub/audio_provider.h"
#include "utils.h"
+#include
+#include
+
+#ifdef __WINDOWS__
+#include
+#include
+#elif defined(__APPLE__)
+#include
+#include
+#else
+#include
+#include
+#endif
+
+#include
+#include
+
// Auto-link to OpenAL lib for MSVC
#ifdef _MSC_VER
#pragma comment(lib, "openal32.lib")
@@ -50,6 +65,65 @@
DEFINE_SIMPLE_EXCEPTION(OpenALException, agi::AudioPlayerOpenError, "audio/open/player/openal")
+namespace {
+class OpenALPlayer final : public AudioPlayer, wxTimer {
+ /// Number of OpenAL buffers to use
+ static const ALsizei num_buffers = 8;
+
+ bool playing = false; ///< Is audio currently playing?
+
+ float volume = 1.f; ///< Current audio volume
+ ALsizei samplerate; ///< Sample rate of the audio
+ int bpf; ///< Bytes per frame
+
+ int64_t start_frame = 0; ///< First frame of playbacka
+ int64_t cur_frame = 0; ///< Next frame to write to playback buffers
+ int64_t end_frame = 0; ///< Last frame to play
+
+ ALCdevice *device = nullptr; ///< OpenAL device handle
+ ALCcontext *context = nullptr; ///< OpenAL sound context
+ ALuint buffers[num_buffers]; ///< OpenAL sound buffers
+ ALuint source = 0; ///< OpenAL playback source
+
+ /// Index into buffers, first free (unqueued) buffer to be filled
+ ALsizei buf_first_free = 0;
+
+ /// Index into buffers, first queued (non-free) buffer
+ ALsizei buf_first_queued = 0;
+
+ /// Number of free buffers
+ ALsizei buffers_free = 0;
+
+ /// Number of buffers which have been fully played since playback was last started
+ ALsizei buffers_played = 0;
+
+ wxStopWatch playback_segment_timer;
+
+ /// Buffer to decode audio into
+ std::vector decode_buffer;
+
+ /// Fill count OpenAL buffers
+ void FillBuffers(ALsizei count);
+
+protected:
+ /// wxTimer override to periodically fill available buffers
+ void Notify() override;
+
+public:
+ OpenALPlayer(AudioProvider *provider);
+ ~OpenALPlayer();
+
+ void Play(int64_t start,int64_t count) override;
+ void Stop() override;
+ bool IsPlaying() override { return playing; }
+
+ int64_t GetEndPosition() override { return end_frame; }
+ int64_t GetCurrentPosition() override;
+ void SetEndPosition(int64_t pos) override;
+
+ void SetVolume(double vol) override { volume = vol; }
+};
+
OpenALPlayer::OpenALPlayer(AudioProvider *provider)
: AudioPlayer(provider)
, samplerate(provider->GetSampleRate())
@@ -210,5 +284,11 @@ int64_t OpenALPlayer::GetCurrentPosition()
long extra = playback_segment_timer.Time();
return buffers_played * decode_buffer.size() / bpf + start_frame + extra * samplerate / 1000;
}
+}
+
+std::unique_ptr CreateOpenALPlayer(AudioProvider *provider)
+{
+ return agi::util::make_unique(provider);
+}
#endif // WITH_OPENAL
diff --git a/src/audio_player_openal.h b/src/audio_player_openal.h
deleted file mode 100644
index bab9e7137..000000000
--- a/src/audio_player_openal.h
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (c) 2007, Niels Martin Hansen
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of the Aegisub Group nor the names of its contributors
-// may be used to endorse or promote products derived from this software
-// without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Aegisub Project http://www.aegisub.org/
-
-/// @file audio_player_openal.h
-/// @see audio_player_openal.cpp
-/// @ingroup audio_output
-///
-
-#ifdef WITH_OPENAL
-#include "include/aegisub/audio_player.h"
-#include "include/aegisub/audio_provider.h"
-
-#ifdef __WINDOWS__
-#include
-#include
-#elif defined(__APPLE__)
-#include
-#include
-#else
-#include
-#include
-#endif
-
-#include
-
-#include
-
-class OpenALPlayer final : public AudioPlayer, wxTimer {
- /// Number of OpenAL buffers to use
- static const ALsizei num_buffers = 8;
-
- bool playing = false; ///< Is audio currently playing?
-
- float volume = 1.f; ///< Current audio volume
- ALsizei samplerate; ///< Sample rate of the audio
- int bpf; ///< Bytes per frame
-
- int64_t start_frame = 0; ///< First frame of playbacka
- int64_t cur_frame = 0; ///< Next frame to write to playback buffers
- int64_t end_frame = 0; ///< Last frame to play
-
- ALCdevice *device = nullptr; ///< OpenAL device handle
- ALCcontext *context = nullptr; ///< OpenAL sound context
- ALuint buffers[num_buffers]; ///< OpenAL sound buffers
- ALuint source = 0; ///< OpenAL playback source
-
- /// Index into buffers, first free (unqueued) buffer to be filled
- ALsizei buf_first_free = 0;
-
- /// Index into buffers, first queued (non-free) buffer
- ALsizei buf_first_queued = 0;
-
- /// Number of free buffers
- ALsizei buffers_free = 0;
-
- /// Number of buffers which have been fully played since playback was last started
- ALsizei buffers_played = 0;
-
- wxStopWatch playback_segment_timer;
-
- /// Buffer to decode audio into
- std::vector decode_buffer;
-
- /// Fill count OpenAL buffers
- void FillBuffers(ALsizei count);
-
-protected:
- /// wxTimer override to periodically fill available buffers
- void Notify() override;
-
-public:
- OpenALPlayer(AudioProvider *provider);
- ~OpenALPlayer();
-
- void Play(int64_t start,int64_t count) override;
- void Stop() override;
- bool IsPlaying() override { return playing; }
-
- int64_t GetEndPosition() override { return end_frame; }
- int64_t GetCurrentPosition() override;
- void SetEndPosition(int64_t pos) override;
-
- void SetVolume(double vol) override { volume = vol; }
-};
-#endif
diff --git a/src/audio_player_oss.cpp b/src/audio_player_oss.cpp
index 35198cbad..0b7d4f156 100644
--- a/src/audio_player_oss.cpp
+++ b/src/audio_player_oss.cpp
@@ -33,12 +33,7 @@
#include "config.h"
#ifdef WITH_OSS
-
-#include
-
-#include
-
-#include "audio_player_oss.h"
+#include "include/aegisub/audio_player.h"
#include "audio_controller.h"
#include "compat.h"
@@ -46,19 +41,112 @@
#include "options.h"
#include "utils.h"
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#ifdef HAVE_SOUNDCARD_H
+# include
+#elif defined(HAVE_SYS_SOUNDCARD_H)
+# include
+#endif
+
+namespace {
DEFINE_SIMPLE_EXCEPTION(OSSError, agi::AudioPlayerOpenError, "audio/player/open/oss")
+class OSSPlayerThread;
-OSSPlayer::OSSPlayer(AudioProvider *provider)
-: AudioPlayer(provider)
-{
- OpenStream();
-}
+class OSSPlayer final : public AudioPlayer {
+ friend class OSSPlayerThread;
-OSSPlayer::~OSSPlayer()
-{
- Stop();
- ::close(dspdev);
-}
+ /// sample rate of audio
+ unsigned int rate = 0;
+
+ /// Worker thread that does the actual writing
+ OSSPlayerThread *thread = nullptr;
+
+ /// Is the player currently playing?
+ volatile bool playing = false;
+
+ /// Current volume level
+ volatile float volume = 1.f;
+
+ /// first frame of playback
+ volatile unsigned long start_frame = 0;
+
+ /// last written frame + 1
+ volatile unsigned long cur_frame = 0;
+
+ /// last frame to play
+ volatile unsigned long end_frame = 0;
+
+ /// bytes per frame
+ unsigned long bpf = 0;
+
+ /// OSS audio device handle
+ volatile int dspdev = 0;
+
+ void OpenStream();
+
+public:
+ OSSPlayer(AudioProvider *provider)
+ : AudioPlayer(provider)
+ {
+ OpenStream();
+ }
+
+ ~OSSPlayer() {
+ Stop();
+ ::close(dspdev);
+ }
+
+
+ void Play(int64_t start, int64_t count);
+ void Stop();
+ bool IsPlaying() { return playing; }
+
+ int64_t GetEndPosition() { return end_frame; }
+ void SetEndPosition(int64_t pos);
+
+ int64_t GetCurrentPosition();
+
+ void SetVolume(double vol) { volume = vol; }
+};
+
+/// Worker thread to asynchronously write audio data to the output device
+class OSSPlayerThread final : public wxThread {
+ /// Parent player
+ OSSPlayer *parent;
+
+public:
+ /// Constructor
+ /// @param parent Player to get audio data and playback state from
+ OSSPlayerThread(OSSPlayer *parent) : wxThread(wxTHREAD_JOINABLE) , parent(parent) { }
+
+ /// Main thread entry point
+ wxThread::ExitCode Entry() {
+ // Use small enough writes for good timing accuracy with all
+ // timing methods.
+ const unsigned long wsize = parent->rate / 25;
+ void *buf = malloc(wsize * parent->bpf);
+
+ while (!TestDestroy() && parent->cur_frame < parent->end_frame) {
+ int rsize = std::min(wsize, parent->end_frame - parent->cur_frame);
+ parent->provider->GetAudioWithVolume(buf, parent->cur_frame,
+ rsize, parent->volume);
+ int written = ::write(parent->dspdev, buf, rsize * parent->bpf);
+ parent->cur_frame += written / parent->bpf;
+ }
+ free(buf);
+ parent->cur_frame = parent->end_frame;
+
+ LOG_D("player/audio/oss") << "Thread dead";
+ return 0;
+ }
+};
void OSSPlayer::OpenStream()
{
@@ -193,31 +281,10 @@ int64_t OSSPlayer::GetCurrentPosition()
// Return the last written frame, timing will suffer
return cur_frame;
}
-
-OSSPlayerThread::OSSPlayerThread(OSSPlayer *par)
-: wxThread(wxTHREAD_JOINABLE)
-, parent(par)
-{
}
-wxThread::ExitCode OSSPlayerThread::Entry() {
- // Use small enough writes for good timing accuracy with all
- // timing methods.
- const unsigned long wsize = parent->rate / 25;
- void *buf = malloc(wsize * parent->bpf);
-
- while (!TestDestroy() && parent->cur_frame < parent->end_frame) {
- int rsize = std::min(wsize, parent->end_frame - parent->cur_frame);
- parent->provider->GetAudioWithVolume(buf, parent->cur_frame,
- rsize, parent->volume);
- int written = ::write(parent->dspdev, buf, rsize * parent->bpf);
- parent->cur_frame += written / parent->bpf;
- }
- free(buf);
- parent->cur_frame = parent->end_frame;
-
- LOG_D("player/audio/oss") << "Thread dead";
- return 0;
+std::unique_ptr CreateOSSPlayer(AudioProvider *provider) {
+ return agi::util::make_unique(provider);
}
#endif // WITH_OSS
diff --git a/src/audio_player_oss.h b/src/audio_player_oss.h
deleted file mode 100644
index 178054442..000000000
--- a/src/audio_player_oss.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2009, Grigori Goronzy
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of the Aegisub Group nor the names of its contributors
-// may be used to endorse or promote products derived from this software
-// without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Aegisub Project http://www.aegisub.org/
-
-/// @file audio_player_oss.h
-/// @see audio_player_oss.cpp
-/// @ingroup audio_output
-///
-
-#ifdef WITH_OSS
-#include
-
-#include
-
-#include
-#ifdef HAVE_SOUNDCARD_H
-# include
-#else
-# ifdef HAVE_SYS_SOUNDCARD_H
-# include
-# endif
-#endif
-
-#include "include/aegisub/audio_player.h"
-
-class AudioProvider;
-class OSSPlayer;
-
-/// Worker thread to asynchronously write audio data to the output device
-class OSSPlayerThread final : public wxThread {
- /// Parent player
- OSSPlayer *parent;
-
-public:
- /// Constructor
- /// @param parent Player to get audio data and playback state from
- OSSPlayerThread(OSSPlayer *parent);
-
- /// Main thread entry point
- wxThread::ExitCode Entry();
-};
-
-class OSSPlayer final : public AudioPlayer {
- friend class OSSPlayerThread;
-
- /// sample rate of audio
- unsigned int rate = 0;
-
- /// Worker thread that does the actual writing
- OSSPlayerThread *thread = nullptr;
-
- /// Is the player currently playing?
- volatile bool playing = false;
-
- /// Current volume level
- volatile float volume = 1.f;
-
- /// first frame of playback
- volatile unsigned long start_frame = 0;
-
- /// last written frame + 1
- volatile unsigned long cur_frame = 0;
-
- /// last frame to play
- volatile unsigned long end_frame = 0;
-
- /// bytes per frame
- unsigned long bpf = 0;
-
- /// OSS audio device handle
- volatile int dspdev = 0;
-
- void OpenStream();
-
-public:
- OSSPlayer(AudioProvider *provider);
- ~OSSPlayer();
-
- void Play(int64_t start, int64_t count);
- void Stop();
- bool IsPlaying() { return playing; }
-
- int64_t GetEndPosition() { return end_frame; }
- void SetEndPosition(int64_t pos);
-
- int64_t GetCurrentPosition();
-
- void SetVolume(double vol) { volume = vol; }
-};
-#endif
diff --git a/src/audio_player_portaudio.cpp b/src/audio_player_portaudio.cpp
index f99cc7c18..822705fb8 100644
--- a/src/audio_player_portaudio.cpp
+++ b/src/audio_player_portaudio.cpp
@@ -32,13 +32,9 @@
/// @ingroup audio_output
///
-
#include "config.h"
#ifdef WITH_PORTAUDIO
-
-#include
-
#include "audio_player_portaudio.h"
#include "audio_controller.h"
@@ -47,6 +43,9 @@
#include "options.h"
#include "utils.h"
+#include
+#include
+
DEFINE_SIMPLE_EXCEPTION(PortAudioError, agi::AudioPlayerOpenError, "audio/player/open/portaudio")
// Uncomment to enable extremely spammy debug logging
@@ -284,4 +283,8 @@ bool PortAudioPlayer::IsPlaying() {
return !!Pa_IsStreamActive(stream);
}
+std::unique_ptr CreatePortAudioPlayer(AudioProvider *provider) {
+ return agi::util::make_unique(provider);
+}
+
#endif // WITH_PORTAUDIO
diff --git a/src/audio_player_pulse.cpp b/src/audio_player_pulse.cpp
index a6cfb6cda..2d601e48d 100644
--- a/src/audio_player_pulse.cpp
+++ b/src/audio_player_pulse.cpp
@@ -35,18 +35,74 @@
#include "config.h"
#ifdef WITH_LIBPULSE
-
-#include
-
-#include
-
-#include "audio_player_pulse.h"
+#include "include/aegisub/audio_player.h"
#include "audio_controller.h"
#include "include/aegisub/audio_provider.h"
#include "utils.h"
#include
+#include
+
+#include
+#include
+#include
+
+namespace {
+class PulseAudioPlayer final : public AudioPlayer {
+ float volume = 1.f;
+ bool is_playing = false;
+
+ volatile unsigned long start_frame = 0;
+ volatile unsigned long cur_frame = 0;
+ volatile unsigned long end_frame = 0;
+
+ unsigned long bpf = 0; // bytes per frame
+
+ wxSemaphore context_notify{0, 1};
+ wxSemaphore context_success{0, 1};
+ volatile int context_success_val;
+
+ wxSemaphore stream_notify{0, 1};
+ wxSemaphore stream_success{0, 1};
+ volatile int stream_success_val;
+
+ pa_threaded_mainloop *mainloop = nullptr; // pulseaudio mainloop handle
+ pa_context *context = nullptr; // connection context
+ volatile pa_context_state_t cstate;
+
+ pa_stream *stream = nullptr;
+ volatile pa_stream_state_t sstate;
+
+ volatile pa_usec_t play_start_time; // timestamp when playback was started
+
+ int paerror = 0;
+
+ /// Called by PA to notify about contetxt operation completion
+ static void pa_context_success(pa_context *c, int success, PulseAudioPlayer *thread);
+ /// Called by PA to notify about other context-related stuff
+ static void pa_context_notify(pa_context *c, PulseAudioPlayer *thread);
+ /// Called by PA when a stream operation completes
+ static void pa_stream_success(pa_stream *p, int success, PulseAudioPlayer *thread);
+ /// Called by PA to request more data written to stream
+ static void pa_stream_write(pa_stream *p, size_t length, PulseAudioPlayer *thread);
+ /// Called by PA to notify about other stream-related stuff
+ static void pa_stream_notify(pa_stream *p, PulseAudioPlayer *thread);
+
+public:
+ PulseAudioPlayer(AudioProvider *provider);
+ ~PulseAudioPlayer();
+
+ void Play(int64_t start,int64_t count);
+ void Stop();
+ bool IsPlaying() { return is_playing; }
+
+ int64_t GetEndPosition() { return end_frame; }
+ int64_t GetCurrentPosition();
+ void SetEndPosition(int64_t pos);
+
+ void SetVolume(double vol) { volume = vol; }
+};
PulseAudioPlayer::PulseAudioPlayer(AudioProvider *provider) : AudioPlayer(provider) {
// Initialise a mainloop
@@ -277,5 +333,9 @@ void PulseAudioPlayer::pa_stream_notify(pa_stream *p, PulseAudioPlayer *thread)
thread->sstate = pa_stream_get_state(thread->stream);
thread->stream_notify.Post();
}
+}
+std::unique_ptr CreatePulseAudioPlayer(AudioProvider *provider) {
+ return agi::util::make_unique(provider);
+}
#endif // WITH_LIBPULSE
diff --git a/src/audio_player_pulse.h b/src/audio_player_pulse.h
deleted file mode 100644
index 7c190d44b..000000000
--- a/src/audio_player_pulse.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) 2007, Niels Martin Hansen
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// * Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above copyright notice,
-// this list of conditions and the following disclaimer in the documentation
-// and/or other materials provided with the distribution.
-// * Neither the name of the Aegisub Group nor the names of its contributors
-// may be used to endorse or promote products derived from this software
-// without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Aegisub Project http://www.aegisub.org/
-
-/// @file audio_player_pulse.h
-/// @see audio_player_pulse.cpp
-/// @ingroup audio_output
-///
-
-#ifdef WITH_LIBPULSE
-#include
-
-#include "include/aegisub/audio_player.h"
-
-class PulseAudioPlayer;
-
-class PulseAudioPlayer final : public AudioPlayer {
- float volume = 1.f;
- bool is_playing = false;
-
- volatile unsigned long start_frame = 0;
- volatile unsigned long cur_frame = 0;
- volatile unsigned long end_frame = 0;
-
- unsigned long bpf = 0; // bytes per frame
-
-
- wxSemaphore context_notify{0, 1};
- wxSemaphore context_success{0, 1};
- volatile int context_success_val;
-
- wxSemaphore stream_notify{0, 1};
- wxSemaphore stream_success{0, 1};
- volatile int stream_success_val;
-
- pa_threaded_mainloop *mainloop = nullptr; // pulseaudio mainloop handle
- pa_context *context = nullptr; // connection context
- volatile pa_context_state_t cstate;
-
- pa_stream *stream = nullptr;
- volatile pa_stream_state_t sstate;
-
- volatile pa_usec_t play_start_time; // timestamp when playback was started
-
- int paerror = 0;
-
- /// Called by PA to notify about contetxt operation completion
- static void pa_context_success(pa_context *c, int success, PulseAudioPlayer *thread);
- /// Called by PA to notify about other context-related stuff
- static void pa_context_notify(pa_context *c, PulseAudioPlayer *thread);
- /// Called by PA when a stream operation completes
- static void pa_stream_success(pa_stream *p, int success, PulseAudioPlayer *thread);
- /// Called by PA to request more data written to stream
- static void pa_stream_write(pa_stream *p, size_t length, PulseAudioPlayer *thread);
- /// Called by PA to notify about other stream-related stuff
- static void pa_stream_notify(pa_stream *p, PulseAudioPlayer *thread);
-
-public:
- PulseAudioPlayer(AudioProvider *provider);
- ~PulseAudioPlayer();
-
- void Play(int64_t start,int64_t count);
- void Stop();
- bool IsPlaying() { return is_playing; }
-
- int64_t GetEndPosition() { return end_frame; }
- int64_t GetCurrentPosition();
- void SetEndPosition(int64_t pos);
-
- void SetVolume(double vol) { volume = vol; }
-};
-
-#endif
diff --git a/src/factory_manager.h b/src/factory_manager.h
index deb977377..89a20d0ba 100644
--- a/src/factory_manager.h
+++ b/src/factory_manager.h
@@ -14,65 +14,9 @@
//
// Aegisub Project http://www.aegisub.org/
-/// @file factory_manager.h
-/// @brief Template/base-class for factory classes
-/// @ingroup utility
-///
-
-#pragma once
-
-#include
-#include