254 lines
9.2 KiB
C++
254 lines
9.2 KiB
C++
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright © Microsoft Corporation. All rights reserved
|
|
|
|
// SpAudioPlug.h: Definition of the SpAudioPlug class
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#if !defined(AFX_SPAUDIOPLUG_H__AD57CF29_3B4A_40A9_BB01_9BE69043E1DF__INCLUDED_)
|
|
#define AFX_SPAUDIOPLUG_H__AD57CF29_3B4A_40A9_BB01_9BE69043E1DF__INCLUDED_
|
|
|
|
#if _MSC_VER > 1000
|
|
#pragma once
|
|
#endif // _MSC_VER > 1000
|
|
|
|
#include "resource.h" // main symbols
|
|
|
|
|
|
//The queue object itself is thread safe. Different threads could call the different methods on the same object.
|
|
//The queue object uses contiguous memory block for queue operation.
|
|
|
|
template <class T>
|
|
class CCriticalSectionLock
|
|
{
|
|
private:
|
|
T* m_pObject;
|
|
|
|
public:
|
|
CCriticalSectionLock(T* pObject)
|
|
{
|
|
m_pObject = pObject;
|
|
m_pObject->Lock();
|
|
}
|
|
~CCriticalSectionLock()
|
|
{
|
|
m_pObject->Unlock();
|
|
}
|
|
};
|
|
|
|
|
|
template <class T>
|
|
class CBasicQueueByArray
|
|
{
|
|
private:
|
|
typedef CCriticalSectionLock< CBasicQueueByArray<T> > CRITICAL_SECTION_AUTO_LOCK;
|
|
|
|
T* m_pCoMemAlloc;
|
|
ULONG m_ulQueueSize; //In terms of the number of element of T in the queue, not the total bytes
|
|
ULONG m_ulHeader; //In terms of the number of element offset from the beginning of memory, range from 0 to m_ulQueueSize - 1
|
|
ULONG m_ulTail; //In terms of the number of element offset from the beginning of memory, range from 0 to m_ulQueueSize - 1
|
|
ULONGLONG m_ullTotalOut; //the total bytes read out of the queue by RemoveTail
|
|
ULONGLONG m_ullTotalIn; //the total bytes put into the queue by InsertHead
|
|
|
|
CRITICAL_SECTION m_CriticalSection;
|
|
HANDLE m_hSpaceAvailable; //signalled when the queue has space
|
|
HANDLE m_hDataAvailable; //signalled when the the queue has m_ulNotifySize or more data
|
|
ULONG m_ulSpaceNotifySize; //when the available space is equal or more than this amount, we need to signal m_hSpaceAvailable
|
|
ULONG m_ulDataNotifySize; //when the available data is equal or more than this amount, we need to signal m_hDataAvailable
|
|
|
|
void _Clear();
|
|
|
|
ULONG _SpaceSize();
|
|
ULONG _DataSize();
|
|
|
|
|
|
public:
|
|
CBasicQueueByArray();
|
|
CBasicQueueByArray(ULONG ulQueueSize, HRESULT *phr);
|
|
~CBasicQueueByArray()
|
|
{
|
|
DeleteCriticalSection(&m_CriticalSection);
|
|
if (m_pCoMemAlloc)
|
|
{
|
|
::CoTaskMemFree(m_pCoMemAlloc);
|
|
}
|
|
}
|
|
|
|
void Lock()
|
|
{
|
|
EnterCriticalSection(&m_CriticalSection);
|
|
}
|
|
|
|
void Unlock()
|
|
{
|
|
LeaveCriticalSection(&m_CriticalSection);
|
|
}
|
|
|
|
|
|
HRESULT Resize(ULONG ulNewQueueSize);
|
|
|
|
HRESULT Init
|
|
(ULONG ulQueueSize, HANDLE hSpaceAvailable, HANDLE hDataAvailable, ULONG ulSpaceNotifySize, ULONG ulDataNotifySize);
|
|
ULONG QueueSize();
|
|
|
|
void InsertHead(T* pElements, ULONG ulCount, ULONG * pulReturnCount);
|
|
void RemoveTail(T* pElements, ULONG ulCount, ULONG * pulReturnCount);
|
|
void ResetPos();
|
|
ULONGLONG GetTotalOut()
|
|
{
|
|
CRITICAL_SECTION_AUTO_LOCK csl(this);
|
|
return m_ullTotalOut;
|
|
}
|
|
ULONGLONG GetTotalIn()
|
|
{
|
|
CRITICAL_SECTION_AUTO_LOCK csl(this);
|
|
return m_ullTotalIn;
|
|
}
|
|
ULONG DataSize()
|
|
{
|
|
CRITICAL_SECTION_AUTO_LOCK csl(this);
|
|
return _DataSize();
|
|
}
|
|
|
|
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// SpAudioPlug
|
|
|
|
class SpAudioPlug :
|
|
public ISpAudio,
|
|
public ISpEventSource,
|
|
public ISpEventSink,
|
|
public CComObjectRootEx<CComMultiThreadModel>,
|
|
public CComCoClass<SpAudioPlug,&CLSID_SpAudioPlug>,
|
|
public IDispatchImpl<ISpAudioPlug, &IID_ISpAudioPlug, &LIBID_SIMPLEAUDIOLib>,
|
|
public IDispatchImpl<ISpeechAudio, &IID_ISpeechAudio, &LIBID_SIMPLEAUDIOLib>
|
|
|
|
{
|
|
public:
|
|
SpAudioPlug();
|
|
HRESULT FinalConstruct();
|
|
void FinalRelease();
|
|
|
|
BEGIN_COM_MAP(SpAudioPlug)
|
|
COM_INTERFACE_ENTRY(ISpAudioPlug)
|
|
COM_INTERFACE_ENTRY(ISequentialStream)
|
|
COM_INTERFACE_ENTRY(IStream)
|
|
COM_INTERFACE_ENTRY(ISpStreamFormat)
|
|
COM_INTERFACE_ENTRY(ISpAudio)
|
|
COM_INTERFACE_ENTRY(ISpNotifySource)
|
|
COM_INTERFACE_ENTRY(ISpEventSource)
|
|
COM_INTERFACE_ENTRY(ISpEventSink)
|
|
COM_INTERFACE_ENTRY2(IDispatch, ISpeechAudio)
|
|
COM_INTERFACE_ENTRY(ISpeechAudio)
|
|
COM_INTERFACE_ENTRY(ISpeechBaseStream)
|
|
END_COM_MAP()
|
|
//DECLARE_NOT_AGGREGATABLE(SpAudioPlug)
|
|
// Remove the comment from the line above if you don't want your object to
|
|
// support aggregation.
|
|
|
|
DECLARE_REGISTRY_RESOURCEID(IDR_SpAudioPlug)
|
|
|
|
// ISpAudioPlug
|
|
STDMETHODIMP Init(VARIANT_BOOL fWrite, SpeechAudioFormatType FormatType);
|
|
STDMETHODIMP SetData(VARIANT vData, long * pWritten);
|
|
STDMETHODIMP GetData(VARIANT* vData);
|
|
|
|
|
|
//--- ISequentialStream ---
|
|
STDMETHODIMP Read(void * pv, ULONG cb, ULONG *pcbRead);
|
|
STDMETHODIMP Write(const void * pv, ULONG cb, ULONG *pcbWritten);
|
|
|
|
//--- IStream ---
|
|
STDMETHODIMP Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER __RPC_FAR *plibNewPosition);
|
|
STDMETHODIMP SetSize(ULARGE_INTEGER libNewSize);
|
|
STDMETHODIMP CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten);
|
|
STDMETHODIMP Commit(DWORD grfCommitFlags);
|
|
STDMETHODIMP Revert(void);
|
|
STDMETHODIMP LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType);
|
|
STDMETHODIMP UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType);
|
|
STDMETHODIMP Stat(STATSTG *pstatstg, DWORD grfStatFlag);
|
|
STDMETHODIMP Clone(IStream **ppstm);
|
|
|
|
//--- ISpStreamFormat ---
|
|
STDMETHODIMP GetFormat(GUID * pguidFormatId, WAVEFORMATEX ** ppCoMemWaveFormatEx);
|
|
|
|
//--- ISpAudio ---
|
|
STDMETHODIMP SetState(SPAUDIOSTATE NewState, ULONGLONG ullReserved );
|
|
STDMETHODIMP SetFormat(REFGUID rguidFmtId, const WAVEFORMATEX * pWaveFormatEx);
|
|
STDMETHODIMP GetStatus(SPAUDIOSTATUS *pStatus);
|
|
STDMETHODIMP SetBufferInfo(const SPAUDIOBUFFERINFO * pInfo);
|
|
STDMETHODIMP GetBufferInfo(SPAUDIOBUFFERINFO * pInfo);
|
|
STDMETHODIMP GetDefaultFormat(GUID * pFormatId, WAVEFORMATEX ** ppCoMemWaveFormatEx);
|
|
STDMETHODIMP_(HANDLE) EventHandle();
|
|
STDMETHODIMP GetVolumeLevel(ULONG *pLevel);
|
|
STDMETHODIMP SetVolumeLevel(ULONG Level);
|
|
STDMETHODIMP GetBufferNotifySize(ULONG *pcbSize);
|
|
STDMETHODIMP SetBufferNotifySize(ULONG cbSize);
|
|
|
|
//--- ISpNotifySource ---
|
|
//--- ISpEventSource ---
|
|
CSpEventSource m_SpEventSource;
|
|
DECLARE_SPEVENTSOURCE_METHODS(m_SpEventSource)
|
|
|
|
//--- ISpEventSink ---
|
|
STDMETHODIMP AddEvents(const SPEVENT* pEventArray, ULONG ulCount);
|
|
STDMETHODIMP GetEventInterest(ULONGLONG * pullEventInterest);
|
|
|
|
//--- ISpeechBaseStream ----------------------------------------
|
|
STDMETHODIMP get_Format(ISpeechAudioFormat** ppStreamFormat) { return E_NOTIMPL; };
|
|
STDMETHODIMP putref_Format(ISpeechAudioFormat* pFormat) { return E_NOTIMPL; };
|
|
STDMETHODIMP Read(VARIANT* pvtBuffer, long NumBytes, long* pRead) { return E_NOTIMPL;}
|
|
STDMETHODIMP Write(VARIANT vtBuffer, long* pWritten) { return E_NOTIMPL;}
|
|
STDMETHODIMP Seek(VARIANT Pos, SpeechStreamSeekPositionType Origin, VARIANT* pNewPosition) { return E_NOTIMPL; };
|
|
|
|
//--- ISpeechAudio ----------------------------------
|
|
STDMETHODIMP SetState( SpeechAudioState State ) { return E_NOTIMPL; };
|
|
STDMETHODIMP get_Status( ISpeechAudioStatus** ppStatus ) { return E_NOTIMPL; };
|
|
STDMETHODIMP get_BufferInfo(ISpeechAudioBufferInfo** ppBufferInfo) { return E_NOTIMPL; };
|
|
STDMETHODIMP get_DefaultFormat(ISpeechAudioFormat** ppStreamFormat) { return E_NOTIMPL; };
|
|
STDMETHODIMP get_Volume(long* pVolume) { return E_NOTIMPL; };
|
|
STDMETHODIMP put_Volume(long Volume) { return E_NOTIMPL; };
|
|
STDMETHODIMP get_BufferNotifySize(long* pBufferNotifySize) { return E_NOTIMPL; };
|
|
STDMETHODIMP put_BufferNotifySize(long BufferNotifySize) { return E_NOTIMPL; };
|
|
STDMETHODIMP get_EventHandle(long* pEventHandle) { return E_NOTIMPL; };
|
|
|
|
void Lock()
|
|
{
|
|
EnterCriticalSection(&m_CriticalSection);
|
|
}
|
|
|
|
void Unlock()
|
|
{
|
|
LeaveCriticalSection(&m_CriticalSection);
|
|
}
|
|
|
|
|
|
private:
|
|
SPAUDIOSTATE m_State;
|
|
CSpStreamFormat m_Format;
|
|
CBasicQueueByArray<BYTE> m_Queue;
|
|
SPAUDIOBUFFERINFO m_BufferInfo;
|
|
ULONG m_cbEventBias;
|
|
BOOL m_fWrite;
|
|
HANDLE m_hQueueHasDataEvent; //The event is signaled by SetData/GetData thread or SAPI SetState thread. Read/Write thread waits for this event.
|
|
HANDLE m_hQueueHasSpaceEvent; //The event is signaled by Read/Write thread or SAPI SetState thread , SetData/GetData thread waits for this event.
|
|
|
|
ULONG m_ulBufferNotifySize;
|
|
HANDLE m_autohAPIEvent; //When there are m_ulBufferNotifySize data available
|
|
BOOL m_fautohAPIEventSet;
|
|
CRITICAL_SECTION m_CriticalSection;
|
|
|
|
void _ProcessEvent();
|
|
|
|
};
|
|
|
|
#define SPAUTO_OBJ_LOCK CCriticalSectionLock< SpAudioPlug > lck(this)
|
|
|
|
#endif // !defined(AFX_SPAUDIOPLUG_H__AD57CF29_3B4A_40A9_BB01_9BE69043E1DF__INCLUDED_)
|