#include "StdAfx.h"
#include "BackgroundSound.h"
#include "DirectXException.h"
#pragma comment(lib, "shlwapi.lib")
using namespace System::Runtime::InteropServices;
using namespace System::Windows::Forms;
namespace Sunlight
{
namespace DirectX
{
namespace SoundMusic
{
BackgroundSound::BackgroundSound() :
m_pGraphBuilder(NULL),
m_pMediaControl(NULL),
m_pMediaSeeking(NULL),
m_pMediaEventEx(NULL),
m_heventRepeat(NULL),
m_bDirectShow(false),
m_bPlaying(false)
{
m_pRepeatThread = new Threading::Thread(new Threading::ThreadStart(this, OnEndThread));
m_pRepeatThread->Start();
}
BackgroundSound::~BackgroundSound()
{
if (m_pRepeatThread != NULL)
{
m_pRepeatThread->Abort();
m_pRepeatThread = NULL;
}
}
void BackgroundSound::Load()
{
HRESULT h;
try
{
Sound::Load();
GUID guid = GUID_NOTIFICATION_SEGMENT;
m_pSegment->AddNotificationType(guid);
m_heventRepeat = CreateEvent(NULL, FALSE, FALSE, NULL);
m_bDirectShow = false;
}
catch (Exception *)
{
IGraphBuilder __nogc *pBuilder;
h = CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC, IID_IGraphBuilder,
(void **)&pBuilder);
if (FAILED(h))
Marshal::ThrowExceptionForHR(h);
m_pGraphBuilder = pBuilder;
IMediaControl __nogc *pMC;
h = m_pGraphBuilder->QueryInterface(IID_IMediaControl, (void **)&pMC);
if (FAILED(h))
Marshal::ThrowExceptionForHR(h);
m_pMediaControl = pMC;
IMediaSeeking __nogc *pMS;
h = m_pGraphBuilder->QueryInterface(IID_IMediaSeeking, (void **)&pMS);
if (FAILED(h))
Marshal::ThrowExceptionForHR(h);
m_pMediaSeeking = pMS;
IMediaEventEx __nogc *pME;
h = m_pGraphBuilder->QueryInterface(IID_IMediaEventEx, (void **)&pME);
if (FAILED(h))
Marshal::ThrowExceptionForHR(h);
m_pMediaEventEx = pME;
HANDLE hEvent;
h = m_pMediaEventEx->GetEventHandle((OAEVENT *)&hEvent);
if (FAILED(h))
Marshal::ThrowExceptionForHR(h);
m_heventRepeat = hEvent;
LPWSTR wszFilename = (LPWSTR)(void *)Marshal::StringToCoTaskMemUni(m_pFilename);
h = m_pGraphBuilder->RenderFile(wszFilename, NULL);
CoTaskMemFree(wszFilename);
if ((h == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (h == VFW_E_NOT_FOUND))
throw new IO::FileNotFoundException(String::Format(S"Unable to load sound file {0}", m_pFilename), m_pFilename);
else if (FAILED(h))
Marshal::ThrowExceptionForHR(h);
m_bDirectShow = true;
}
__hook(&Form::Closed, DirectMusicObject->ParentWindow, &BackgroundSound::OnFormClosed, this);
__hook(&Form::Activated, DirectMusicObject->ParentWindow, &BackgroundSound::OnFormActivated, this);
__hook(&Form::Deactivate, DirectMusicObject->ParentWindow, &BackgroundSound::OnFormDeactivated, this);
}
void BackgroundSound::Unload()
{
__unhook(&Form::Closed, DirectMusicObject->ParentWindow, &BackgroundSound::OnFormClosed, this);
__unhook(&Form::Activated, DirectMusicObject->ParentWindow, &BackgroundSound::OnFormActivated, this);
__unhook(&Form::Deactivate, DirectMusicObject->ParentWindow, &BackgroundSound::OnFormDeactivated, this);
if (m_bDirectShow)
{
if (m_pMediaEventEx != NULL)
{
m_pMediaEventEx->Release();
m_pMediaEventEx = NULL;
}
if (m_pMediaSeeking != NULL)
{
m_pMediaSeeking->Release();
m_pMediaSeeking = NULL;
}
if (m_pMediaControl != NULL)
{
m_pMediaControl->Release();
m_pMediaControl = NULL;
}
if (m_pGraphBuilder != NULL)
{
m_pGraphBuilder->Release();
m_pGraphBuilder = NULL;
}
}
else
{
Sound::Unload();
CloseHandle(m_heventRepeat);
}
m_heventRepeat = NULL;
}
void BackgroundSound::OnFormActivated(Object *sender, EventArgs *e)
{
if (m_bPlaying)
Play();
}
void BackgroundSound::OnFormDeactivated(Object *sender, EventArgs *e)
{
if (m_bPlaying)
{
Pause();
m_bPlaying = true; }
}
void BackgroundSound::Play()
{
Prepare();
if (m_bDirectShow)
{
m_pMediaControl->Run();
}
else
{
DirectMusicObject->GetPerformance()->SetNotificationHandle(m_heventRepeat, 0);
DirectMusicObject->GetPerformance()->PlaySegment(m_pSegment, 0, 0, NULL);
}
m_bPlaying = true;
}
void BackgroundSound::Stop()
{
if (m_bDirectShow)
{
m_pMediaControl->Stop();
LONGLONG llPos = 0;
m_pMediaSeeking->SetPositions(&llPos, AM_SEEKING_AbsolutePositioning,
&llPos, AM_SEEKING_NoPositioning);
}
else
Sound::Stop();
m_bPlaying = false;
}
void BackgroundSound::Pause()
{
if (m_bDirectShow)
m_pMediaControl->Stop();
else
Sound::Stop();
m_bPlaying = false;
}
void BackgroundSound::OnFormClosed(Object *sender, EventArgs* e)
{
if (m_bPlaying)
Stop();
Unload();
if (m_pRepeatThread != NULL)
m_pRepeatThread->Abort();
}
void BackgroundSound::OnEndThread()
{
long evCode, param1, param2;
HRESULT h;
for (;;)
{
DWORD dwResult = WaitForSingleObject(m_heventRepeat, 200);
if (dwResult == WAIT_OBJECT_0)
{
if (Finished != NULL)
{
if (m_bDirectShow)
{
for (;;)
{
h = m_pMediaEventEx->GetEvent(&evCode, ¶m1, ¶m2, 0);
if (FAILED(h))
break;
if ((evCode == EC_COMPLETE) || (evCode == EC_USERABORT) || (evCode == EC_ERRORABORT))
{
Stop();
__raise Finished(this, new EventArgs());
}
m_pMediaEventEx->FreeEventParams(evCode, param1, param2);
}
}
else
{
DMUS_NOTIFICATION_PMSG *pPmsg;
while (DirectMusicObject->GetPerformance()->GetNotificationPMsg(&pPmsg) == S_OK)
{
if (pPmsg->dwNotificationOption == DMUS_NOTIFICATION_SEGEND)
{
Stop();
__raise Finished(this, new EventArgs());
}
DirectMusicObject->GetPerformance()->FreePMsg((DMUS_PMSG*)pPmsg);
}
}
}
}
else if (dwResult != WAIT_TIMEOUT)
return;
}
}
}
}
}