Doxygen-document DSound2 audio player

Originally committed to SVN as r4083.
This commit is contained in:
Niels Martin Hansen 2010-02-05 14:51:12 +00:00
parent fe65749623
commit 702739b32e
2 changed files with 126 additions and 161 deletions

View file

@ -55,31 +55,28 @@
#include "utils.h" #include "utils.h"
/// DOCME /// @brief RAII support class to init and de-init the COM library
struct COMInitialization { struct COMInitialization {
/// DOCME /// Flag set if an inited COM library is managed
bool inited; bool inited;
/// @brief DOCME /// @brief Constructor, sets inited false
///
COMInitialization() COMInitialization()
{ {
inited = false; inited = false;
} }
/// @brief DOCME /// @brief Destructor, de-inits COM if it is inited
///
~COMInitialization() ~COMInitialization()
{ {
if (inited) CoUninitialize(); if (inited) CoUninitialize();
} }
/// @brief DOCME /// @brief Initialise the COM library as single-threaded apartment if isn't already inited by us
///
void Init() void Init()
{ {
if (!inited) if (!inited)
@ -92,43 +89,39 @@ struct COMInitialization {
}; };
/// @class COMObjectRetainer
/// @brief Simple auto_ptr-like class for COM objects
template<class T> template<class T>
/// DOCME
struct COMObjectRetainer { struct COMObjectRetainer {
/// DOCME /// Managed object
T *obj; T *obj;
/// @brief DOCME /// @brief Constructor for null object
///
COMObjectRetainer() COMObjectRetainer()
{ {
obj = 0; obj = 0;
} }
/// @brief DOCME /// @brief Constructor to take object immediately
/// @param _obj /// @param _obj Object to manage
///
COMObjectRetainer(T *_obj) COMObjectRetainer(T *_obj)
{ {
obj = _obj; obj = _obj;
} }
/// @brief DOCME /// @brief Destructor, releases object if there is one
///
~COMObjectRetainer() ~COMObjectRetainer()
{ {
if (obj) obj->Release(); if (obj) obj->Release();
} }
/// @brief DOCME /// @brief Dereference the managed object
/// @return /// @return The managed object
///
T * operator -> () T * operator -> ()
{ {
return obj; return obj;
@ -137,11 +130,10 @@ struct COMObjectRetainer {
/// DOCME
/// @class DirectSoundPlayer2Thread /// @class DirectSoundPlayer2Thread
/// @brief DOCME /// @brief Playback thread class for DirectSoundPlayer2
/// ///
/// DOCME /// Not based on wxThread, but uses Win32 threads directly
class DirectSoundPlayer2Thread { class DirectSoundPlayer2Thread {
static unsigned int __stdcall ThreadProc(void *parameter); static unsigned int __stdcall ThreadProc(void *parameter);
void Run(); void Run();
@ -151,64 +143,58 @@ class DirectSoundPlayer2Thread {
void CheckError(); void CheckError();
/// DOCME /// Win32 handle to the thread
HANDLE thread_handle; HANDLE thread_handle;
// Used to signal state-changes to thread /// Event object, world to thread, set to start playback
HANDLE HANDLE event_start_playback;
/// DOCME /// Event object, world to thread, set to stop playback
event_start_playback, HANDLE event_stop_playback;
/// DOCME /// Event object, world to thread, set if playback end time was updated
event_stop_playback, HANDLE event_update_end_time;
/// DOCME /// Event object, world to thread, set if the volume was changed
event_update_end_time, HANDLE event_set_volume;
/// DOCME /// Event object, world to thread, set if the thread should end as soon as possible
event_set_volume, HANDLE event_kill_self;
/// DOCME /// Event object, thread to world, set when the thread has entered its main loop
event_kill_self; HANDLE thread_running;
// Thread communicating back /// Event object, thread to world, set when playback is ongoing
HANDLE HANDLE is_playing;
/// DOCME /// Event object, thread to world, set if an error state has occurred (implies thread is dying)
thread_running, HANDLE error_happened;
/// DOCME /// Statically allocated error message text describing reason for error_happened being set
is_playing,
/// DOCME
error_happened;
/// DOCME
const wxChar *error_message; const wxChar *error_message;
/// DOCME /// Playback volume, 1.0 is "unchanged"
double volume; double volume;
/// DOCME /// Audio frame to start playback at
int64_t start_frame; int64_t start_frame;
/// DOCME /// Audio frame to end playback at
int64_t end_frame; int64_t end_frame;
/// DOCME /// Desired length in milliseconds to write ahead of the playback cursor
int wanted_latency; int wanted_latency;
/// DOCME /// Multiplier for WantedLatency to get total buffer length
int buffer_length; int buffer_length;
/// DOCME /// System millisecond timestamp of last playback start, used to calculate playback position
DWORD last_playback_restart; DWORD last_playback_restart;
/// DOCME /// Audio provider to take sample data from
AudioProvider *provider; AudioProvider *provider;
public: public:
@ -230,9 +216,9 @@ public:
/// @brief DOCME /// @brief Win32 thread entry point
/// @param parameter /// @param parameter Pointer to our thread object
/// @return /// @return Thread return value, always 0 here
/// ///
unsigned int __stdcall DirectSoundPlayer2Thread::ThreadProc(void *parameter) unsigned int __stdcall DirectSoundPlayer2Thread::ThreadProc(void *parameter)
{ {
@ -242,13 +228,11 @@ unsigned int __stdcall DirectSoundPlayer2Thread::ThreadProc(void *parameter)
/// @brief DOCME /// @brief Thread entry point
/// @return
///
void DirectSoundPlayer2Thread::Run() void DirectSoundPlayer2Thread::Run()
{ {
/// DOCME /// Macro used to set error_message, error_happened and end the thread
#define REPORT_ERROR(msg) { error_message = _T("DirectSoundPlayer2Thread: ") _T(msg); SetEvent(error_happened); return; } #define REPORT_ERROR(msg) { error_message = _T("DirectSoundPlayer2Thread: ") _T(msg); SetEvent(error_happened); return; }
COMInitialization COM_library; COMInitialization COM_library;
@ -542,21 +526,19 @@ do_fill_buffer:
} }
} }
/// DOCME
#undef REPORT_ERROR #undef REPORT_ERROR
} }
/// @brief DOCME /// @brief Fill audio data into a locked buffer-pair and unlock the buffers
/// @param buf1 /// @param buf1 First buffer in pair
/// @param buf1sz /// @param buf1sz Byte-size of first buffer in pair
/// @param buf2 /// @param buf2 Second buffer in pair, or null
/// @param buf2sz /// @param buf2sz Byte-size of second buffer in pair
/// @param input_frame /// @param input_frame First audio frame to fill into buffers
/// @param bfr /// @param bfr DirectSound buffer object owning the buffer pair
/// @return /// @return Number of bytes written
/// ///
DWORD DirectSoundPlayer2Thread::FillAndUnlockBuffers(void *buf1, DWORD buf1sz, void *buf2, DWORD buf2sz, int64_t &input_frame, IDirectSoundBuffer8 *bfr) DWORD DirectSoundPlayer2Thread::FillAndUnlockBuffers(void *buf1, DWORD buf1sz, void *buf2, DWORD buf2sz, int64_t &input_frame, IDirectSoundBuffer8 *bfr)
{ {
@ -618,9 +600,7 @@ DWORD DirectSoundPlayer2Thread::FillAndUnlockBuffers(void *buf1, DWORD buf1sz, v
/// @brief DOCME /// @brief Check for error state and throw exception if one occurred
/// @return
///
void DirectSoundPlayer2Thread::CheckError() void DirectSoundPlayer2Thread::CheckError()
{ {
try try
@ -651,11 +631,10 @@ void DirectSoundPlayer2Thread::CheckError()
/// @brief DOCME /// @brief Constructor, creates and starts playback thread
/// @param provider /// @param provider Audio provider to take sample data from
/// @param _WantedLatency /// @param _WantedLatency Desired length in milliseconds to write ahead of the playback cursor
/// @param _BufferLength /// @param _BufferLength Multiplier for WantedLatency to get total buffer length
///
DirectSoundPlayer2Thread::DirectSoundPlayer2Thread(AudioProvider *provider, int _WantedLatency, int _BufferLength) DirectSoundPlayer2Thread::DirectSoundPlayer2Thread(AudioProvider *provider, int _WantedLatency, int _BufferLength)
{ {
event_start_playback = CreateEvent(0, FALSE, FALSE, 0); event_start_playback = CreateEvent(0, FALSE, FALSE, 0);
@ -701,8 +680,7 @@ DirectSoundPlayer2Thread::DirectSoundPlayer2Thread(AudioProvider *provider, int
/// @brief DOCME /// @brief Destructor, waits for thread to have died
///
DirectSoundPlayer2Thread::~DirectSoundPlayer2Thread() DirectSoundPlayer2Thread::~DirectSoundPlayer2Thread()
{ {
SetEvent(event_kill_self); SetEvent(event_kill_self);
@ -711,10 +689,9 @@ DirectSoundPlayer2Thread::~DirectSoundPlayer2Thread()
/// @brief DOCME /// @brief Start audio playback
/// @param start /// @param start Audio frame to start playback at
/// @param count /// @param count Number of audio frames to play
///
void DirectSoundPlayer2Thread::Play(int64_t start, int64_t count) void DirectSoundPlayer2Thread::Play(int64_t start, int64_t count)
{ {
CheckError(); CheckError();
@ -728,8 +705,7 @@ void DirectSoundPlayer2Thread::Play(int64_t start, int64_t count)
/// @brief DOCME /// @brief Stop audio playback
///
void DirectSoundPlayer2Thread::Stop() void DirectSoundPlayer2Thread::Stop()
{ {
CheckError(); CheckError();
@ -739,9 +715,10 @@ void DirectSoundPlayer2Thread::Stop()
/// @brief DOCME /// @brief Change audio playback end point
/// @param new_end_frame /// @param new_end_frame New last audio frame to play
/// ///
/// Playback stops instantly if new_end_frame is before the current playback position
void DirectSoundPlayer2Thread::SetEndFrame(int64_t new_end_frame) void DirectSoundPlayer2Thread::SetEndFrame(int64_t new_end_frame)
{ {
CheckError(); CheckError();
@ -752,9 +729,8 @@ void DirectSoundPlayer2Thread::SetEndFrame(int64_t new_end_frame)
/// @brief DOCME /// @brief Change audio playback volume
/// @param new_volume /// @param new_volume New playback amplification factor, 1.0 is "unchanged"
///
void DirectSoundPlayer2Thread::SetVolume(double new_volume) void DirectSoundPlayer2Thread::SetVolume(double new_volume)
{ {
CheckError(); CheckError();
@ -765,9 +741,8 @@ void DirectSoundPlayer2Thread::SetVolume(double new_volume)
/// @brief DOCME /// @brief Tell whether audio playback is active
/// @return /// @return True if audio is being played back, false if it is not
///
bool DirectSoundPlayer2Thread::IsPlaying() bool DirectSoundPlayer2Thread::IsPlaying()
{ {
CheckError(); CheckError();
@ -791,9 +766,8 @@ bool DirectSoundPlayer2Thread::IsPlaying()
/// @brief DOCME /// @brief Get first audio frame in current playback range
/// @return /// @return Audio frame index
///
int64_t DirectSoundPlayer2Thread::GetStartFrame() int64_t DirectSoundPlayer2Thread::GetStartFrame()
{ {
CheckError(); CheckError();
@ -803,9 +777,10 @@ int64_t DirectSoundPlayer2Thread::GetStartFrame()
/// @brief DOCME /// @brief Get approximate current audio frame being heard by the user
/// @return /// @return Audio frame index
/// ///
/// Returns 0 if not playing
int64_t DirectSoundPlayer2Thread::GetCurrentFrame() int64_t DirectSoundPlayer2Thread::GetCurrentFrame()
{ {
CheckError(); CheckError();
@ -819,9 +794,8 @@ int64_t DirectSoundPlayer2Thread::GetCurrentFrame()
/// @brief DOCME /// @brief Get audio playback end point
/// @return /// @return Audio frame index
///
int64_t DirectSoundPlayer2Thread::GetEndFrame() int64_t DirectSoundPlayer2Thread::GetEndFrame()
{ {
CheckError(); CheckError();
@ -831,9 +805,8 @@ int64_t DirectSoundPlayer2Thread::GetEndFrame()
/// @brief DOCME /// @brief Get current playback volume
/// @return /// @return Audio amplification factor
///
double DirectSoundPlayer2Thread::GetVolume() double DirectSoundPlayer2Thread::GetVolume()
{ {
CheckError(); CheckError();
@ -843,9 +816,8 @@ double DirectSoundPlayer2Thread::GetVolume()
/// @brief DOCME /// @brief Tell whether playback thread has died
/// @return /// @return True if thread is no longer running
///
bool DirectSoundPlayer2Thread::IsDead() bool DirectSoundPlayer2Thread::IsDead()
{ {
switch (WaitForSingleObject(thread_running, 0)) switch (WaitForSingleObject(thread_running, 0))
@ -862,8 +834,7 @@ bool DirectSoundPlayer2Thread::IsDead()
/// @brief DOCME /// @brief Constructor
///
DirectSoundPlayer2::DirectSoundPlayer2() DirectSoundPlayer2::DirectSoundPlayer2()
{ {
thread = 0; thread = 0;
@ -881,8 +852,7 @@ DirectSoundPlayer2::DirectSoundPlayer2()
/// @brief DOCME /// @brief Destructor
///
DirectSoundPlayer2::~DirectSoundPlayer2() DirectSoundPlayer2::~DirectSoundPlayer2()
{ {
CloseStream(); CloseStream();
@ -890,9 +860,8 @@ DirectSoundPlayer2::~DirectSoundPlayer2()
/// @brief DOCME /// @brief Tell whether playback thread is alive
/// @return /// @return True if there is a playback thread and it's ready
///
bool DirectSoundPlayer2::IsThreadAlive() bool DirectSoundPlayer2::IsThreadAlive()
{ {
if (!thread) return false; if (!thread) return false;
@ -909,9 +878,9 @@ bool DirectSoundPlayer2::IsThreadAlive()
/// @brief DOCME /// @brief Prepare for playback
/// @return
/// ///
/// This means creating the playback thread
void DirectSoundPlayer2::OpenStream() void DirectSoundPlayer2::OpenStream()
{ {
if (IsThreadAlive()) return; if (IsThreadAlive()) return;
@ -929,9 +898,7 @@ void DirectSoundPlayer2::OpenStream()
/// @brief DOCME /// @brief Shutdown playback
/// @return
///
void DirectSoundPlayer2::CloseStream() void DirectSoundPlayer2::CloseStream()
{ {
if (!IsThreadAlive()) return; if (!IsThreadAlive()) return;
@ -949,9 +916,10 @@ void DirectSoundPlayer2::CloseStream()
/// @brief DOCME /// @brief Change audio provider used
/// @param provider /// @param provider New audio provider to use
/// ///
/// Will re-create the playback thread if the provider changed and playback was open
void DirectSoundPlayer2::SetProvider(AudioProvider *provider) void DirectSoundPlayer2::SetProvider(AudioProvider *provider)
{ {
try try
@ -972,10 +940,9 @@ void DirectSoundPlayer2::SetProvider(AudioProvider *provider)
/// @brief DOCME /// @brief Start playback
/// @param start /// @param start First audio frame to play
/// @param count /// @param count Number of audio frames to play
///
void DirectSoundPlayer2::Play(int64_t start,int64_t count) void DirectSoundPlayer2::Play(int64_t start,int64_t count)
{ {
try try
@ -993,8 +960,8 @@ void DirectSoundPlayer2::Play(int64_t start,int64_t count)
/// @brief DOCME /// @brief Stop audio playback
/// @param timerToo /// @param timerToo Whether to also stop the playback update timer
/// ///
void DirectSoundPlayer2::Stop(bool timerToo) void DirectSoundPlayer2::Stop(bool timerToo)
{ {
@ -1014,9 +981,8 @@ void DirectSoundPlayer2::Stop(bool timerToo)
/// @brief DOCME /// @brief Tell whether playback is active
/// @return /// @return True if audio is playing back
///
bool DirectSoundPlayer2::IsPlaying() bool DirectSoundPlayer2::IsPlaying()
{ {
try try
@ -1033,9 +999,10 @@ bool DirectSoundPlayer2::IsPlaying()
/// @brief DOCME /// @brief Get first audio frame in playback range
/// @return /// @return Audio frame index
/// ///
/// Returns 0 if playback is stopped or there is no playback thread
int64_t DirectSoundPlayer2::GetStartPosition() int64_t DirectSoundPlayer2::GetStartPosition()
{ {
try try
@ -1052,9 +1019,10 @@ int64_t DirectSoundPlayer2::GetStartPosition()
/// @brief DOCME /// @brief Get playback end position
/// @return /// @return Audio frame index
/// ///
/// Returns 0 if playback is stopped or there is no playback thread
int64_t DirectSoundPlayer2::GetEndPosition() int64_t DirectSoundPlayer2::GetEndPosition()
{ {
try try
@ -1071,9 +1039,10 @@ int64_t DirectSoundPlayer2::GetEndPosition()
/// @brief DOCME /// @brief Get approximate playback position
/// @return /// @return Index of audio frame user is currently hearing
/// ///
/// Returns 0 if playback is stopped or there is no playback thread
int64_t DirectSoundPlayer2::GetCurrentPosition() int64_t DirectSoundPlayer2::GetCurrentPosition()
{ {
try try
@ -1090,9 +1059,8 @@ int64_t DirectSoundPlayer2::GetCurrentPosition()
/// @brief DOCME /// @brief Change playback end position
/// @param pos /// @param pos New end position
///
void DirectSoundPlayer2::SetEndPosition(int64_t pos) void DirectSoundPlayer2::SetEndPosition(int64_t pos)
{ {
try try
@ -1107,9 +1075,10 @@ void DirectSoundPlayer2::SetEndPosition(int64_t pos)
/// @brief DOCME /// @brief Seek playback to new position
/// @param pos /// @param pos New position to seek to
/// ///
/// This is done by simply restarting playback
void DirectSoundPlayer2::SetCurrentPosition(int64_t pos) void DirectSoundPlayer2::SetCurrentPosition(int64_t pos)
{ {
try try
@ -1124,9 +1093,8 @@ void DirectSoundPlayer2::SetCurrentPosition(int64_t pos)
/// @brief DOCME /// @brief Change playback volume
/// @param vol /// @param vol Amplification factor
///
void DirectSoundPlayer2::SetVolume(double vol) void DirectSoundPlayer2::SetVolume(double vol)
{ {
try try
@ -1141,8 +1109,8 @@ void DirectSoundPlayer2::SetVolume(double vol)
/// @brief DOCME /// @brief Get playback volume
/// /// @return Amplification factor
double DirectSoundPlayer2::GetVolume() double DirectSoundPlayer2::GetVolume()
{ {
try try

View file

@ -43,22 +43,23 @@
class DirectSoundPlayer2Thread; class DirectSoundPlayer2Thread;
/// DOCME
/// @class DirectSoundPlayer2 /// @class DirectSoundPlayer2
/// @brief DOCME /// @brief New implementation of DirectSound-based audio player
/// ///
/// DOCME /// 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 : public AudioPlayer { class DirectSoundPlayer2 : public AudioPlayer {
/// DOCME /// The playback thread
DirectSoundPlayer2Thread *thread; DirectSoundPlayer2Thread *thread;
protected: protected:
/// DOCME /// Desired length in milliseconds to write ahead of the playback cursor
int WantedLatency; int WantedLatency;
/// DOCME /// Multiplier for WantedLatency to get total buffer length
int BufferLength; int BufferLength;
bool IsThreadAlive(); bool IsThreadAlive();
@ -88,16 +89,12 @@ public:
/// DOCME
/// @class DirectSoundPlayer2Factory /// @class DirectSoundPlayer2Factory
/// @brief DOCME /// @brief Factory class for DirectSoundPlayer2
///
/// DOCME
class DirectSoundPlayer2Factory : public AudioPlayerFactory { class DirectSoundPlayer2Factory : public AudioPlayerFactory {
public: public:
/// @brief DOCME /// @brief Create a DirectSoundPlayer2 object
///
AudioPlayer *CreatePlayer() { return new DirectSoundPlayer2(); } AudioPlayer *CreatePlayer() { return new DirectSoundPlayer2(); }
}; };