📄 av_upnp_ctrl_internal.h
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
//
// Declarations for internal implementation of the UPnP AV toolkit's control point functionality
//
#ifndef __AV_UPNP_CTRL_INTERNAL_H
#define __AV_UPNP_CTRL_INTERNAL_H
#include <hash_map.hxx>
#include <hash_set.hxx>
#include <sync.hxx>
#include <auto_xxx.hxx>
#ifndef UNDER_CE
# include "desktop.h"
#endif
#include "sax.h"
#include "upnp_proxy.h"
#include "av_upnp.h"
namespace av_upnp
{
namespace details
{
extern DWORD AVErrorFromUPnPError(HRESULT hr);
extern bool GetService(IUPnPServices* pServices, LPCWSTR pszServiceID, LPCWSTR pszServiceType, IUPnPService** ppService);
// IEventSourceImpl
template<typename T>
class IEventSourceImpl : public T,
public IEventSink
{
public:
virtual ~IEventSourceImpl()
{
// Every call to Advise must be matched with a call to Unadvise
assert(m_setSink.empty());
}
// av::IEventSource
public:
// Advise
virtual DWORD Advise(
/*[in]*/ IEventSink *pSubscriber)
{
if(!pSubscriber)
return ERROR_AV_POINTER;
ce::gate<ce::critical_section_with_copy> gate(m_csSinkSet);
if(m_setSink.end() != m_setSink.insert(pSubscriber))
return SUCCESS_AV;
else
{
DEBUGMSG(ZONE_AV_ERROR, (AV_TEXT("OOM when inserting subscriber")));
return ERROR_AV_OOM;
}
}
// Unadvise
virtual DWORD Unadvise(
/*[in]*/ IEventSink *pSubscriber)
{
ce::gate<ce::critical_section_with_copy> gate(m_csSinkSet);
if(!m_setSink.erase(pSubscriber))
return ERROR_AV_POINTER;
else
return SUCCESS_AV;
}
// av::IEventSink
public:
virtual DWORD OnStateChanged(
/*[in]*/ LPCWSTR pszStateVariableName,
/*[in]*/ LPCWSTR pszValue)
{
ce::gate<ce::critical_section_with_copy> gate(m_csSinkSet);
for(EventSinkSet::iterator it = m_setSink.begin(), itEnd = m_setSink.end(); it != itEnd; ++it)
(*it)->OnStateChanged(pszStateVariableName, pszValue);
return SUCCESS_AV;
}
virtual DWORD OnStateChanged(
/*[in]*/ LPCWSTR pszStateVariableName,
/*[in]*/ long nValue)
{
ce::gate<ce::critical_section_with_copy> gate(m_csSinkSet);
for(EventSinkSet::iterator it = m_setSink.begin(), itEnd = m_setSink.end(); it != itEnd; ++it)
(*it)->OnStateChanged(pszStateVariableName, nValue);
return SUCCESS_AV;
}
virtual DWORD OnStateChanged(
/*[in]*/ LPCWSTR pszStateVariableName,
/*[in]*/ LPCWSTR pszChannel,
/*[in]*/ long nValue)
{
ce::gate<ce::critical_section_with_copy> gate(m_csSinkSet);
for(EventSinkSet::iterator it = m_setSink.begin(), itEnd = m_setSink.end(); it != itEnd; ++it)
(*it)->OnStateChanged(pszStateVariableName, pszChannel, nValue);
return SUCCESS_AV;
}
protected:
typedef ce::hash_set<IEventSink*> EventSinkSet;
ce::critical_section_with_copy m_csSinkSet;
EventSinkSet m_setSink;
};
//
// IUPnPServiceCallbackImpl
//
class IUPnPServiceCallbackImpl : public IUPnPServiceCallback
{
// IUPnPServiceCallback
public:
// ServiceInstanceDied
STDMETHOD(ServiceInstanceDied)(
/* [in] */ IUPnPService*)
{
return S_OK;
}
// IUnknown
public:
STDMETHOD(QueryInterface)(
/* [in] */ REFIID riid,
/* [in] */ LPVOID* ppv)
{
if(InlineIsEqualGUID(riid, IID_IUnknown) ||
InlineIsEqualGUID(riid, IID_IUPnPServiceCallback))
{
*ppv = this;
return S_OK;
}
else
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)(void)
{return 1; }
STDMETHOD_(ULONG, Release)(void)
{return 1; }
};
//
// ServiceCtrl
//
template<typename T>
class ServiceCtrl : public IEventSourceImpl<T>,
protected IUPnPServiceCallbackImpl
{
public:
~ServiceCtrl()
{
if(m_pCallbackPrivate)
m_pCallbackPrivate->RemoveTransientCallback(m_dwCookie);
}
bool Init(IUPnPService* pService, IUPnPDevice* pDevice)
{
assert(pService);
assert(pDevice);
HRESULT hr;
if(SUCCEEDED(hr = pService->QueryInterface(IID_IUPnPServiceCallbackPrivate, (void**)&m_pCallbackPrivate)))
{
if(FAILED(hr = m_pCallbackPrivate->AddTransientCallback(static_cast<IUPnPServiceCallbackImpl*>(this), &m_dwCookie)))
{
DEBUGMSG(ZONE_AV_ERROR, (AV_TEXT("AddTransientCallback failed with error 0x%08x"), hr));
return false;
}
}
else
{
DEBUGMSG(ZONE_AV_ERROR, (AV_TEXT("QueryInterface(IID_IUPnPServiceCallbackPrivate) failed 0x%08x"), hr));
return false;
}
return true;
}
// IUPnPServiceCallback
public:
// StateVariableChanged
STDMETHOD(StateVariableChanged)(
/* [in] */ IUPnPService*,
/* [in] */ LPCWSTR pcwszStateVarName,
/* [in] */ VARIANT varValue)
{
#ifdef DEBUG
ce::variant varTemp;
if(FAILED(VariantChangeType(&varTemp, &varValue, 0, VT_BSTR)))
varTemp.bstrVal = L"<unknown>";
DEBUGMSG(ZONE_AV_TRACE, (AV_TEXT("Event: %s=%s"), pcwszStateVarName, varTemp.bstrVal));
#endif
if(varValue.vt == VT_BSTR)
{
OnStateChanged(pcwszStateVarName, varValue.bstrVal);
}
else
{
ce::variant varDest;
if(SUCCEEDED(VariantChangeType(&varDest, &varValue, 0, VT_I4)))
{
OnStateChanged(pcwszStateVarName, varDest.lVal);
}
else
{
DEBUGMSG(ZONE_AV_ERROR, (AV_TEXT("Received event of unsupported type %d for variable \"%s\""), varValue.vt, pcwszStateVarName));
}
}
return S_OK;
}
protected:
CComPtr<IUPnPServiceCallbackPrivate> m_pCallbackPrivate;
DWORD m_dwCookie;
};
//
// LastChangeParsing
//
class LastChangeParsing : protected ce::SAXContentHandler
{
public:
LastChangeParsing(LPCWSTR pszNamespace);
// ISAXContentHandler
protected:
virtual HRESULT STDMETHODCALLTYPE startDocument(void);
virtual HRESULT STDMETHODCALLTYPE startElement(
/* [in] */ const wchar_t *pwchNamespaceUri,
/* [in] */ int cchNamespaceUri,
/* [in] */ const wchar_t *pwchLocalName,
/* [in] */ int cchLocalName,
/* [in] */ const wchar_t *pwchQName,
/* [in] */ int cchQName,
/* [in] */ ISAXAttributes *pAttributes);
virtual HRESULT STDMETHODCALLTYPE endElement(
/* [in] */ const wchar_t *pwchNamespaceUri,
/* [in] */ int cchNamespaceUri,
/* [in] */ const wchar_t *pwchLocalName,
/* [in] */ int cchLocalName,
/* [in] */ const wchar_t *pwchQName,
/* [in] */ int cchQName);
protected:
virtual DWORD OnStateChanged(
/*[in]*/ int InstanceID,
/*[in]*/ LPCWSTR pszStateVariableName,
/*[in]*/ LPCWSTR pszValue) = 0;
virtual DWORD OnStateChanged(
/*[in]*/ int InstanceID,
/*[in]*/ LPCWSTR pszStateVariableName,
/*[in]*/ long nValue) = 0;
virtual DWORD OnStateChanged(
/*[in]*/ int InstanceID,
/*[in]*/ LPCWSTR pszStateVariableName,
/*[in]*/ LPCWSTR pszChannel,
/*[in]*/ long nValue) = 0;
protected:
struct StateVar
{
StateVar(bool bNumeric)
: bNumeric(bNumeric)
{}
bool bNumeric;
};
int m_InstanceID;
int m_nLevelsUnderInstanceID;
bool m_bUnderInstanceID;
wstring m_strEventElement;
wstring m_strInstanceElement;
ce::hash_map<wstring, StateVar> m_mapStateVars;
};
//
// IVirtualServiceRefCount
//
class IVirtualServiceRefCount
{
public:
virtual void ReleaseInstance(long InstanceID) = 0;
};
//
// VirtualServiceCtrl
//
template<typename I, typename T>
class VirtualServiceCtrl : private IUPnPServiceCallbackImpl,
private IVirtualServiceRefCount,
private LastChangeParsing
{
public:
VirtualServiceCtrl()
: LastChangeParsing(get_event_namespace<I>())
{}
~VirtualServiceCtrl()
{
// Release must be called on every virtual service instance pointer obtained
assert(m_mapInstances.empty());
if(m_pCallbackPrivate)
m_pCallbackPrivate->RemoveTransientCallback(m_dwCookie);
}
// Init
bool Init(IUPnPService* pService, IUPnPDevice* pDevice)
{
assert(pService);
assert(pDevice);
// For now, hardcode which vars have numeric types in AVTransport and RenderingControl
m_mapStateVars.insert(L"Brightness", true);
m_mapStateVars.insert(L"Contrast", true);
m_mapStateVars.insert(L"Sharpness", true);
m_mapStateVars.insert(L"RedVideoGain", true);
m_mapStateVars.insert(L"GreenVideoGain", true);
m_mapStateVars.insert(L"BlueVideoGain", true);
m_mapStateVars.insert(L"RedVideoBlackLevel", true);
m_mapStateVars.insert(L"GreenVideoBlackLevel", true);
m_mapStateVars.insert(L"BlueVideoBlackLevel", true);
m_mapStateVars.insert(L"ColorTemperature", true);
m_mapStateVars.insert(L"HorizontalKeystone", true);
m_mapStateVars.insert(L"VerticalKeystone", true);
m_mapStateVars.insert(L"Volume", true);
m_mapStateVars.insert(L"VolumeDB", true);
m_mapStateVars.insert(L"NumberOfTracks", true);
m_mapStateVars.insert(L"CurrentTrack", true);
m_pService = pService;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -