|
|
#include "priv.h"
#include "sccls.h"
#include <mmsystem.h>
#include <amstream.h>
#include "power.h"
#include "dsound.h"
#include "Zaxxon.h"
#ifndef SAFERELEASE
#define SAFERELEASE(x) if (x) { x->Release(); x = NULL; }
#endif
#define AUDIO_MAXBUFFER 64000
// Which is better?
// 2Megs causes 25% cpu usage every 5 seconds
// 1meg causes 15% cpu usage every 2 seconds
// 100k causes a contant 6% cpu usage
// 64k?
#define EVENT_NONE 0x0
#define EVENT_PLAY 0x1
#define EVENT_STOP 0x2
#define EVENT_PAUSE 0x3
#define EVENT_FORWARD 0x4
#define EVENT_BACKWARD 0x5
#define EVENT_TERMINATE 0x6
#define EVENT_ADDSONG 0x7
#define EVENT_REMOVESONG 0x8
#define EVENT_NEXTSONG 0x9
#define EVENT_PREVSONG 0xA
#define EVENT_REGISTER 0xB
#define EVENT_DEREGISTER 0xC
#define EVENT_CLEARPLAYLIST 0xD
#define EVENT_SETSONG 0xE
struct ZAXXONEVENT { ZAXXONEVENT():_dwEvent(EVENT_NONE), _pNext(NULL) { }
DWORD _dwEvent; ZAXXONEVENT* _pNext;
union { TCHAR szPath[MAX_PATH]; UINT szSeconds; UINT iIndex; HWND hwnd; }; };
typedef struct { HANDLE hThread; CRITICAL_SECTION crit; HANDLE hEvents; ZAXXONEVENT* pEvents; } ZAXXON_ARG;
class CNotifyList { HDSA _hdsa; public: CNotifyList() { _hdsa = DSA_Create(sizeof(HWND), 1); } ~CNotifyList() { if (_hdsa) DSA_Destroy(_hdsa); }
void AddNotify(HWND hwnd) { if (_hdsa) DSA_AppendItem(_hdsa, &hwnd); }
void RemoveNotify(HWND hwnd) { //
}
void SendNotify(UINT uMsg, WPARAM wParam, LPARAM lParam) { for (int i = 0; i < DSA_GetItemCount(_hdsa); i++) { DWORD_PTR l; HWND hwnd = *(HWND*)DSA_GetItemPtr(_hdsa, i); SendMessageTimeout(hwnd, uMsg, wParam, lParam, SMTO_ABORTIFHUNG, 100, &l); } } };
class CPlayList { int iIndex; HDPA _hdpa; static BOOL CALLBACK s_DestroyPlaylist(void* pv, void* pvData) { PWSTR psz = (PWSTR)pv; if (psz) { Str_SetPtr(&psz, NULL); }
return TRUE; }
public: int GetIndex() { return iIndex;} CPlayList() { _hdpa = NULL; iIndex = -1; }
~CPlayList() { Empty(); }
BOOL AddSong(PWSTR psz) { if (!_hdpa) { _hdpa = DPA_Create(4); }
if (!_hdpa) return FALSE;
TCHAR* pszSet = NULL; Str_SetPtr(&pszSet, psz); return DPA_AppendPtr(_hdpa, pszSet) != -1; }
BOOL RemoveSong(int i) { if (!_hdpa) return FALSE;
if (i < iIndex) iIndex--;
TCHAR* pszSet = (TCHAR*)DPA_DeletePtr(_hdpa, i); Str_SetPtr(&pszSet, NULL); return FALSE; }
BOOL GetSong(int i, PWSTR psz, int cch) { if (!_hdpa) return FALSE;
PWSTR pszSong = (PWSTR)DPA_FastGetPtr(_hdpa, i); if (pszSong) { iIndex = i; StrCpyN(psz, pszSong, cch); return TRUE; }
return FALSE; }
BOOL GetNextSong(PWSTR psz, int cch) { if (!_hdpa) return FALSE;
if (iIndex >= DPA_GetPtrCount(_hdpa) - 1) iIndex = -1; return GetSong(++iIndex, psz, cch);
}
BOOL GetPrevSong(PWSTR psz, int cch) { if (!_hdpa) return FALSE;
if (iIndex <= 0) iIndex = DPA_GetPtrCount(_hdpa); return GetSong(--iIndex, psz, cch); }
BOOL Empty() { if (_hdpa) { DPA_DestroyCallback(_hdpa, s_DestroyPlaylist, NULL); } _hdpa = NULL;
return TRUE; } };
HRESULT CreateBuffer(IDirectSound* pds, WAVEFORMATEX* pwfx, DWORD dwBufferSize, IDirectSoundBuffer** ppdsb) { HRESULT hr = S_OK; IDirectSoundBuffer* psbPrimary; // Get the primary buffer
DSBUFFERDESC dsbdesc; ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC)); dsbdesc.dwSize = sizeof(DSBUFFERDESC); dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER; hr = pds->CreateSoundBuffer(&dsbdesc, &psbPrimary, NULL); if (SUCCEEDED(hr)) { hr = psbPrimary->SetFormat(pwfx);
if (SUCCEEDED(hr)) { dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY;
dsbdesc.dwBufferBytes = dwBufferSize; dsbdesc.lpwfxFormat = pwfx;
hr = pds->CreateSoundBuffer(&dsbdesc, ppdsb, NULL); } psbPrimary->Release(); }
return hr; }
HRESULT CreateDirectSound(IDirectSound** ppds) { IDirectSound* pds = NULL; HRESULT hr = CoCreateInstance(CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, IID_IDirectSound, (void**)&pds); if (SUCCEEDED(hr)) { hr = pds->Initialize(NULL); // Don't support more than one at the moment.
if (SUCCEEDED(hr)) { hr = pds->SetCooperativeLevel(GetDesktopWindow(), DSSCL_PRIORITY); } }
if (SUCCEEDED(hr)) { *ppds = pds; pds->AddRef(); }
SAFERELEASE(pds); return hr; }
class CZaxxonPlayingSample { public: CZaxxonPlayingSample(); ~CZaxxonPlayingSample();
HRESULT Open(PWSTR psz); HRESULT SetBuffer(PBYTE pBuf, DWORD dwSize); HRESULT CopySampleData(PBYTE pBuffer1, DWORD dwBytesForBuffer1, PBYTE pBuffer2, DWORD dwBytesForBuffer2, DWORD* pdwBytesLeft1, DWORD* pdwBytesLeft2); HRESULT GetSampleFormat(WAVEFORMATEX* pwfx);
private: void CloseOut(); HRESULT _SetupMediaStream(); TCHAR _szPath[MAX_PATH]; IAMMultiMediaStream *_pMMStream; IMediaStream *_pStream; IAudioStreamSample *_pSample; IAudioMediaStream *_pAudioStream; IAudioData *_pAudioData; WAVEFORMATEX _wfx; HANDLE _hRenderEvent; PBYTE _pBuffer; };
CZaxxonPlayingSample::CZaxxonPlayingSample(): _pMMStream(NULL), _pStream(NULL), _pSample(NULL), _pAudioStream(NULL), _pAudioData(NULL), _hRenderEvent(NULL), _pBuffer(NULL) { ZeroMemory(&_wfx, sizeof(WAVEFORMATEX)); }
CZaxxonPlayingSample::~CZaxxonPlayingSample() { CloseOut(); }
void CZaxxonPlayingSample::CloseOut() { ATOMICRELEASE(_pMMStream); ATOMICRELEASE(_pAudioData); ATOMICRELEASE(_pSample); ATOMICRELEASE(_pStream); ATOMICRELEASE(_pAudioStream); if (_hRenderEvent) { CloseHandle(_hRenderEvent); _hRenderEvent = NULL; } }
HRESULT CZaxxonPlayingSample::Open(PWSTR psz) { CloseOut(); lstrcpy(_szPath, psz); return _SetupMediaStream(); }
HRESULT CZaxxonPlayingSample::SetBuffer(PBYTE pBuf, DWORD dwSize) { if (_pAudioData && _pAudioStream) { _pAudioData->SetBuffer(dwSize, pBuf, 0); _pAudioData->SetFormat(&_wfx);
_pBuffer = pBuf;
return _pAudioStream->CreateSample(_pAudioData, 0, &_pSample); }
return E_FAIL; }
HRESULT CZaxxonPlayingSample::GetSampleFormat(WAVEFORMATEX* pwfx) { CopyMemory(pwfx, &_wfx, sizeof(_wfx)); return S_OK; }
HRESULT CZaxxonPlayingSample::CopySampleData(PBYTE pBuffer1, DWORD dwBytesForBuffer1, PBYTE pBuffer2, DWORD dwBytesForBuffer2, DWORD* pdwBytesLeft1, DWORD* pdwBytesLeft2) { if (!_pSample) return E_FAIL;
HRESULT hr = _pSample->Update(0, _hRenderEvent, NULL, 0); if (FAILED(hr) || MS_S_ENDOFSTREAM == hr) { return hr; }
DWORD dwLength; WaitForSingleObject(_hRenderEvent, INFINITE); _pAudioData->GetInfo(NULL, NULL, &dwLength);
*pdwBytesLeft1 = 0; *pdwBytesLeft2 = 0;
// _pBuffer contains the audio data. Copy.
if (dwLength < dwBytesForBuffer1) { *pdwBytesLeft2 = dwBytesForBuffer2; *pdwBytesLeft1 = dwBytesForBuffer1 - dwLength;
dwBytesForBuffer1 = dwLength; dwBytesForBuffer2 = 0; }
CopyMemory(pBuffer1, _pBuffer, dwBytesForBuffer1); dwLength -= dwBytesForBuffer1;
if (dwBytesForBuffer2 > 0 && dwLength > 0) { CopyMemory(pBuffer2, _pBuffer + dwBytesForBuffer1, dwLength); if (dwLength < dwBytesForBuffer2) *pdwBytesLeft2 = dwBytesForBuffer2 - dwLength; }
return hr; }
HRESULT CZaxxonPlayingSample::_SetupMediaStream() { HRESULT hr = E_INVALIDARG; if (_szPath[0] != 0) { hr = CoCreateInstance(CLSID_AMMultiMediaStream, NULL, CLSCTX_INPROC_SERVER, IID_IAMMultiMediaStream, (void **)&_pMMStream); if (SUCCEEDED(hr)) { _pMMStream->Initialize(STREAMTYPE_READ, AMMSF_NOGRAPHTHREAD, NULL); _pMMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio, 0, NULL); hr = _pMMStream->OpenFile(_szPath, AMMSF_RUN); if (SUCCEEDED(hr)) { hr = CoCreateInstance(CLSID_AMAudioData, NULL, CLSCTX_INPROC_SERVER, IID_IAudioData, (void **)&_pAudioData);
if (SUCCEEDED(hr)) { hr = _pMMStream->GetMediaStream(MSPID_PrimaryAudio, &_pStream); if (SUCCEEDED(hr)) { hr = _pStream->QueryInterface(IID_IAudioMediaStream, (void **)&_pAudioStream); if (SUCCEEDED(hr)) { _pAudioStream->GetFormat(&_wfx); _hRenderEvent = CreateEvent(NULL, NULL, TRUE, NULL); hr = S_OK;
} } } } } }
return hr; }
ZAXXONEVENT* GetZaxxonEvent(ZAXXON_ARG* pza) { ZAXXONEVENT* pz = NULL; if (pza->pEvents) { EnterCriticalSection(&pza->crit); if (pza->pEvents) { pz = pza->pEvents; pza->pEvents = pza->pEvents->_pNext; }
LeaveCriticalSection(&pza->crit); }
return pz; }
HRESULT CopySample(CZaxxonPlayingSample* pzax, IDirectSoundBuffer* pdsb, DWORD dwStart, DWORD dwNumBytes) { HRESULT hr; PBYTE pBuffer1; PBYTE pBuffer2; DWORD dwBytesToCopyToBuffer1; DWORD dwBytesToCopyToBuffer2; DWORD dwBytesLeft1; DWORD dwBytesLeft2;
if (!pdsb) return E_ACCESSDENIED;
hr = pdsb->Lock(dwStart, dwNumBytes, (void**)&pBuffer1, &dwBytesToCopyToBuffer1, (void**)&pBuffer2, &dwBytesToCopyToBuffer2, 0); if (SUCCEEDED(hr)) { hr = pzax->CopySampleData( pBuffer1, dwBytesToCopyToBuffer1, pBuffer2, dwBytesToCopyToBuffer2, &dwBytesLeft1, &dwBytesLeft2);
if (FAILED(hr) || MS_S_ENDOFSTREAM == hr) { pdsb->Stop(); } else { if (dwBytesLeft1 > 0) { ZeroMemory(pBuffer1 + dwBytesToCopyToBuffer1 - dwBytesLeft1, dwBytesLeft1); }
if (dwBytesLeft2 > 0) { ZeroMemory(pBuffer2 + dwBytesToCopyToBuffer2 - dwBytesLeft2, dwBytesLeft2); } }
pdsb->Unlock(pBuffer1, dwBytesToCopyToBuffer1, pBuffer2, dwBytesToCopyToBuffer2);
}
return hr; }
BOOL SetupSample(CZaxxonPlayingSample* pzaxSample, PWSTR psz, PBYTE pBuffer, DSBPOSITIONNOTIFY* rgdsbp, int cdsbpn, IDirectSound* pds, IDirectSoundBuffer** ppdsb) { if (SUCCEEDED(pzaxSample->Open(psz))) { WAVEFORMATEX wfx;
pzaxSample->SetBuffer(pBuffer, AUDIO_MAXBUFFER / 2); pzaxSample->GetSampleFormat(&wfx);
if (SUCCEEDED(CreateBuffer(pds, &wfx, AUDIO_MAXBUFFER, ppdsb))) { IDirectSoundNotify* pdsn; if (SUCCEEDED((*ppdsb)->QueryInterface(IID_IDirectSoundNotify, (void**)&pdsn))) { for (int i = 0; i < cdsbpn; i++) { ResetEvent(rgdsbp[i].hEventNotify); }
pdsn->SetNotificationPositions(cdsbpn, rgdsbp); pdsn->Release(); }
if (SUCCEEDED(CopySample(pzaxSample, *ppdsb, 0, AUDIO_MAXBUFFER / 2))) { (*ppdsb)->SetCurrentPosition(0); (*ppdsb)->Play(0, 0, DSBPLAY_LOOPING);
return TRUE; } else { (*ppdsb)->Release(); *ppdsb = NULL; } } }
return FALSE; }
ULONG CALLBACK AudioRenderThread(LPVOID pvArg) { CPlayList playlist; CNotifyList notifylist; ZAXXON_ARG* pza = (ZAXXON_ARG*)pvArg; HRESULT hr = CoInitialize(NULL); PBYTE pBuffer = (PBYTE)LocalAlloc(LMEM_FIXED, AUDIO_MAXBUFFER); if (SUCCEEDED(hr) && pBuffer) { IDirectSound* pds = NULL; IDirectSoundBuffer* pdsb = NULL;
HANDLE rgEvent[] = { CreateEvent(NULL, FALSE, FALSE, NULL), CreateEvent(NULL, FALSE, FALSE, NULL), pza->hEvents, };
DSBPOSITIONNOTIFY rgdsbp[] = { {0, rgEvent[0]}, {AUDIO_MAXBUFFER / 2, rgEvent[1]}, };
if (SUCCEEDED(CreateDirectSound(&pds))) { CZaxxonPlayingSample zaxSample;
BOOL fPaused = FALSE; BOOL fDone = FALSE; while (!fDone) { DWORD dwEvent = WaitForMultipleObjects(ARRAYSIZE(rgEvent), rgEvent, FALSE, INFINITE); dwEvent -= WAIT_OBJECT_0;
if (dwEvent < 2) { DWORD dwStartByte; if (dwEvent + 1 >= ARRAYSIZE(rgdsbp)) dwStartByte = rgdsbp[0].dwOffset; else dwStartByte = rgdsbp[dwEvent + 1].dwOffset;
hr = CopySample(&zaxSample, pdsb, dwStartByte, AUDIO_MAXBUFFER / 2); if (FAILED(hr) || MS_S_ENDOFSTREAM == hr) { TCHAR pszPath[MAX_PATH]; if (playlist.GetNextSong(pszPath, MAX_PATH)) { ATOMICRELEASE(pdsb); notifylist.SendNotify(WM_SONGCHANGE, (WPARAM)pszPath, 0); SetupSample(&zaxSample, pszPath, pBuffer, rgdsbp, ARRAYSIZE(rgdsbp), pds, &pdsb); } } } else { ZAXXONEVENT* pZaxxonEvent; while ((pZaxxonEvent = GetZaxxonEvent(pza))) { switch (pZaxxonEvent->_dwEvent) { case EVENT_STOP: if (pdsb) pdsb->Stop(); notifylist.SendNotify(WM_SONGSTOP, 0, 0); fPaused = FALSE; break;
case EVENT_ADDSONG: playlist.AddSong(pZaxxonEvent->szPath); break;
case EVENT_REMOVESONG: if (pZaxxonEvent->iIndex == playlist.GetIndex()) { fPaused = FALSE; TCHAR pszPath[MAX_PATH]; if (playlist.GetNextSong(pszPath, MAX_PATH)) { if (pdsb) pdsb->Stop(); ATOMICRELEASE(pdsb); notifylist.SendNotify(WM_SONGCHANGE, (WPARAM)pszPath, 0); SetupSample(&zaxSample, pszPath, pBuffer, rgdsbp, ARRAYSIZE(rgdsbp), pds, &pdsb); } }
playlist.RemoveSong(pZaxxonEvent->iIndex); break;
case EVENT_CLEARPLAYLIST: if (pdsb) pdsb->Stop(); fPaused = FALSE; notifylist.SendNotify(WM_SONGSTOP, 0, 0); playlist.Empty(); break;
case EVENT_REGISTER: notifylist.AddNotify(pZaxxonEvent->hwnd); break; case EVENT_DEREGISTER: notifylist.RemoveNotify(pZaxxonEvent->hwnd); break;
case EVENT_PLAY: if (fPaused) { if (pdsb) pdsb->Play(0, 0, DSBPLAY_LOOPING); fPaused = FALSE; } else { fPaused = FALSE; TCHAR pszPath[MAX_PATH]; if (playlist.GetNextSong(pszPath, MAX_PATH)) { ATOMICRELEASE(pdsb); notifylist.SendNotify(WM_SONGCHANGE, (WPARAM)pszPath, 0); SetupSample(&zaxSample, pszPath, pBuffer, rgdsbp, ARRAYSIZE(rgdsbp), pds, &pdsb); } } break;
case EVENT_NEXTSONG: { fPaused = FALSE; TCHAR pszPath[MAX_PATH]; if (playlist.GetNextSong(pszPath, MAX_PATH)) { if (pdsb) pdsb->Stop(); ATOMICRELEASE(pdsb); notifylist.SendNotify(WM_SONGCHANGE, (WPARAM)pszPath, 0); SetupSample(&zaxSample, pszPath, pBuffer, rgdsbp, ARRAYSIZE(rgdsbp), pds, &pdsb); } } break;
case EVENT_PREVSONG: { fPaused = FALSE; TCHAR pszPath[MAX_PATH]; if (playlist.GetPrevSong(pszPath, MAX_PATH)) { if (pdsb) pdsb->Stop(); ATOMICRELEASE(pdsb); notifylist.SendNotify(WM_SONGCHANGE, (WPARAM)pszPath, 0); SetupSample(&zaxSample, pszPath, pBuffer, rgdsbp, ARRAYSIZE(rgdsbp), pds, &pdsb);
} } break;
case EVENT_SETSONG: { fPaused = FALSE; TCHAR pszPath[MAX_PATH]; if (playlist.GetSong(pZaxxonEvent->iIndex, pszPath, MAX_PATH)) { if (pdsb) pdsb->Stop(); ATOMICRELEASE(pdsb); notifylist.SendNotify(WM_SONGCHANGE, (WPARAM)pszPath, 0); SetupSample(&zaxSample, pszPath, pBuffer, rgdsbp, ARRAYSIZE(rgdsbp), pds, &pdsb);
} }
case EVENT_PAUSE: if (pdsb) pdsb->Stop(); fPaused = TRUE;
break;
case EVENT_TERMINATE: fDone = TRUE; break; }
delete pZaxxonEvent; }
ResetEvent(pza->hEvents); } } }
SAFERELEASE(pdsb); SAFERELEASE(pds);
if (rgEvent[0]) CloseHandle(rgEvent[0]);
if (rgEvent[1]) CloseHandle(rgEvent[1]);
CoUninitialize(); }
if (pBuffer) LocalFree((HLOCAL)pBuffer); return 1; }
class CZaxxonPlayer : public IZaxxonPlayer { ZAXXON_ARG _za; LPTSTR _pszFile; int _cRef; HRESULT _LoadTypeLib(); BOOL _AddPlayEvent(int i); BOOL _AddRemoveEvent(int i); BOOL _AddSongEvent(int iEvent, PWSTR pszFile); BOOL _AddHWNDEvent(int iEvent, HWND hwnd); BOOL _AddPositionEvent(DWORD dwEvent, UINT uSeconds); BOOL _AddEvent(DWORD dwEvent); BOOL _AddEventToList(ZAXXONEVENT* pzEvent); public: CZaxxonPlayer(); virtual ~CZaxxonPlayer();
STDMETHODIMP QueryInterface(REFIID riid, void** ppvObj); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release();
STDMETHODIMP Play(); STDMETHODIMP Stop(); STDMETHODIMP NextSong(); STDMETHODIMP PrevSong(); STDMETHODIMP SetSong(int i); STDMETHODIMP Forward(UINT iSeconds); STDMETHODIMP Backward(UINT iSeconds); STDMETHODIMP Pause(); STDMETHODIMP AddSong(LPWSTR pszFile); STDMETHODIMP RemoveSong(int i); STDMETHODIMP Register(HWND hwnd); STDMETHODIMP DeRegister(HWND hwnd); STDMETHODIMP ClearPlaylist(); };
BOOL CZaxxonPlayer::_AddRemoveEvent(int i) { ZAXXONEVENT* pze = new ZAXXONEVENT; if (pze) { pze->_dwEvent = EVENT_REMOVESONG; pze->iIndex = i; return _AddEventToList(pze); } return FALSE; }
BOOL CZaxxonPlayer::_AddPlayEvent(int i) { ZAXXONEVENT* pze = new ZAXXONEVENT; if (pze) { pze->_dwEvent = EVENT_SETSONG; pze->iIndex = i; return _AddEventToList(pze); } return FALSE; }
BOOL CZaxxonPlayer::_AddPositionEvent(DWORD dwEvent, UINT uSeconds) { return FALSE;
}
BOOL CZaxxonPlayer::_AddHWNDEvent(int iEvent, HWND hwnd) { ZAXXONEVENT* pze = new ZAXXONEVENT; if (pze) { pze->_dwEvent = iEvent; pze->hwnd = hwnd; return _AddEventToList(pze); }
return FALSE; }
BOOL CZaxxonPlayer::_AddSongEvent(int iEvent, PWSTR pszFile) { ZAXXONEVENT* pze = new ZAXXONEVENT; if (pze) { pze->_dwEvent = iEvent; StrCpyN(pze->szPath, pszFile, ARRAYSIZE(pze->szPath)); return _AddEventToList(pze); }
return FALSE; }
BOOL CZaxxonPlayer::_AddEvent(DWORD dwEvent) { ZAXXONEVENT* pze = new ZAXXONEVENT; if (pze) { pze->_dwEvent = dwEvent; return _AddEventToList(pze); } return FALSE; }
BOOL CZaxxonPlayer::_AddEventToList(ZAXXONEVENT* pzEvent) { EnterCriticalSection(&_za.crit); BOOL fRet = FALSE; ZAXXONEVENT** ppza = &_za.pEvents;
while (*ppza) { ppza = &(*ppza)->_pNext; }
*ppza = pzEvent; SetEvent(_za.hEvents);
LeaveCriticalSection(&_za.crit);
return fRet; }
CZaxxonPlayer::CZaxxonPlayer() : _cRef(1) { ZeroMemory(&_za, sizeof(_za)); InitializeCriticalSection(&_za.crit); _za.hEvents = CreateEvent(NULL, TRUE, FALSE, NULL); if (_za.hEvents) { DWORD thread; _za.hThread = CreateThread(NULL, 0, AudioRenderThread, (LPVOID)&_za, 0, &thread); } }
CZaxxonPlayer::~CZaxxonPlayer() { if (_za.hThread) { _AddEvent(EVENT_TERMINATE); WaitForSingleObject(_za.hThread, INFINITE);
CloseHandle(_za.hThread); }
CloseHandle(_za.hEvents);
DeleteCriticalSection(&_za.crit); for (ZAXXONEVENT* pza = GetZaxxonEvent(&_za); pza; pza = GetZaxxonEvent(&_za)) { delete pza; } }
STDMETHODIMP CZaxxonPlayer::QueryInterface(REFIID riid, LPVOID * ppvObj) { static const QITAB qit[] = { QITABENT(CZaxxonPlayer, IZaxxonPlayer), { 0 }, };
return QISearch(this, qit, riid, ppvObj); }
ULONG CZaxxonPlayer::AddRef() { _cRef++; return _cRef; }
ULONG CZaxxonPlayer::Release() { ASSERT(_cRef > 0); _cRef--;
if (_cRef > 0) return _cRef;
delete this; return 0; }
HRESULT CZaxxonPlayer::Play() { _AddEvent(EVENT_PLAY); return S_OK; }
HRESULT CZaxxonPlayer::Stop() { _AddEvent(EVENT_STOP); return E_NOTIMPL; }
HRESULT CZaxxonPlayer::Forward(UINT iSeconds) { return E_NOTIMPL; }
HRESULT CZaxxonPlayer::Backward(UINT iSeconds) { return E_NOTIMPL; }
HRESULT CZaxxonPlayer::Pause() { _AddEvent(EVENT_PAUSE); return S_OK;
}
HRESULT CZaxxonPlayer::AddSong(LPWSTR pszFile) { _AddSongEvent(EVENT_ADDSONG, pszFile);
return S_OK; }
HRESULT CZaxxonPlayer::RemoveSong(int i) { _AddRemoveEvent(i);
return S_OK; }
HRESULT CZaxxonPlayer::NextSong() { _AddEvent(EVENT_NEXTSONG);
return S_OK; }
HRESULT CZaxxonPlayer::PrevSong() { _AddEvent(EVENT_PREVSONG);
return S_OK; }
HRESULT CZaxxonPlayer::SetSong(int i) { _AddPlayEvent(i); return S_OK; }
HRESULT CZaxxonPlayer::Register(HWND hwnd) { _AddHWNDEvent(EVENT_REGISTER, hwnd); return S_OK;
}
HRESULT CZaxxonPlayer::DeRegister(HWND hwnd) { _AddHWNDEvent(EVENT_REGISTER, hwnd); return S_OK; }
HRESULT CZaxxonPlayer::ClearPlaylist() { _AddEvent(EVENT_CLEARPLAYLIST);
return S_OK; }
STDAPI CZaxxonPlayer_CreateInstance(IUnknown *punk, REFIID riid, void **ppv) { HRESULT hr; CZaxxonPlayer *pzax = new CZaxxonPlayer; if (pzax) { hr = pzax->QueryInterface(riid, ppv); pzax->Release(); } else { hr = E_OUTOFMEMORY; *ppv = NULL; } return hr; }
|