📄 vblasterlid.cxx
字号:
BOOL OpalVoipBlasterDevice::GetRemoveDTMF(unsigned)
{
return TRUE;
}
BOOL OpalVoipBlasterDevice::SetRemoveDTMF(unsigned, BOOL /*state*/)
{
return TRUE;
}
unsigned OpalVoipBlasterDevice::IsToneDetected(unsigned /*line*/)
{
return FALSE;
}
BOOL OpalVoipBlasterDevice::PlayTone(unsigned /*line*/, CallProgressTones /*tone*/)
{
return FALSE;
}
BOOL OpalVoipBlasterDevice::IsTonePlaying(unsigned)
{
return FALSE;
}
BOOL OpalVoipBlasterDevice::StopTone(unsigned)
{
return FALSE;
}
DWORD OpalVoipBlasterDevice::GetSerialNumber()
{
return 0;
}
PStringArray OpalVoipBlasterDevice::GetDeviceNames()
{
PStringArray array;
VoipBlasterInterface blaster;
PINDEX i = 0;
while ((i < 16) && blaster.IsDevicePresent(i)) {
array[i] = i;
i++;
}
return array;
}
BOOL OpalVoipBlasterDevice::SetCountryCode(T35CountryCodes /*country*/)
{
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
OpalVoipBlasterDevice::ByteQueue::ByteQueue(PINDEX _qMax)
: qMax(_qMax)
{
qOut = qLen = 0;
queue.SetSize(qMax);
}
int OpalVoipBlasterDevice::ByteQueue::Dequeue()
{
PWaitAndSignal m(mutex);
if (qLen == 0)
return -1;
int v = queue[qOut];
qOut = (qOut % qMax);
qLen--;
return v;
}
BOOL OpalVoipBlasterDevice::ByteQueue::Enqueue(BYTE v)
{
PWaitAndSignal m(mutex);
if (qLen == qMax)
return FALSE;
queue[(qOut + qLen) % qMax] = v;
qLen++;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
#include <initguid.h>
#include <setupapi.h>
#pragma comment(lib, "setupapi.lib")
// {00873FDF-61A8-11d1-AA5E-00C04FB1728B} for VB_USB.SYS
DEFINE_GUID(GUID_CLASS_VOIP_BLASTER,
0x873fdf, 0x61a8, 0x11d1, 0xaa, 0x5e, 0x0, 0xc0, 0x4f, 0xb1, 0x72, 0x8b);
static BOOL GetDeviceInterfacePath(HDEVINFO hDevInfo,
PSP_DEVICE_INTERFACE_DATA pDeviceInterfaceData,
char *dest, DWORD dwMaxLen)
{
PSP_INTERFACE_DEVICE_DETAIL_DATA pDetailData = NULL;
ULONG requiredLength = 0;
// allocate a function class device data structure to receive the
// goods about this particular device.
SetupDiGetInterfaceDeviceDetail(hDevInfo,
pDeviceInterfaceData, //
NULL, // probing so no output buffer yet
0, // probing so output buffer length of zero
&requiredLength, //
NULL); // not interested in the specific dev-node
pDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, requiredLength);
ZeroMemory(pDetailData, requiredLength );
pDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
// Retrieve the information from Plug and Play.
if (!SetupDiGetDeviceInterfaceDetail(hDevInfo,
pDeviceInterfaceData,
pDetailData,
requiredLength,
NULL,
NULL)) {
PTRACE(1, "VB\tError " << GetLastError() << " in GetDeviceInterfacePath");
LocalFree(pDetailData);
return FALSE;
}
strncpy(dest,pDetailData->DevicePath, dwMaxLen);
LocalFree(pDetailData);
return TRUE;
}
static BOOL GetDevicePath( LPGUID pGuid, DWORD dwIndex, char *dest, DWORD dwMaxLen )
{
SP_DEVINFO_DATA DeviceInfoData;
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
BOOL result;
// Create a HDEVINFO with all present devices.
HDEVINFO hDevInfoList = SetupDiGetClassDevs(
pGuid, // this guid only
0, // Enumerator
0,
DIGCF_PRESENT | DIGCF_INTERFACEDEVICE );
if (hDevInfoList == INVALID_HANDLE_VALUE) {
PTRACE(1, "VB\tError " << GetLastError() << " in GetDevicePath:SetupDiGetClassDevs");
return FALSE;
}
// Get the Info for the specific device instance (dwIndex)
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiEnumDeviceInfo(hDevInfoList, dwIndex, &DeviceInfoData)) {
PTRACE(1, "VB\tError " << GetLastError() << " in GetDevicePath:SetupDiEnumDeviceInfo");
SetupDiDestroyDeviceInfoList(hDevInfoList); // Cleanup
return FALSE;
}
// for the desired interface, get the path
ZeroMemory(&DeviceInterfaceData, sizeof(DeviceInterfaceData));
DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);
if(!SetupDiEnumDeviceInterfaces(hDevInfoList, &DeviceInfoData, pGuid, 0, &DeviceInterfaceData)) {
PTRACE(1, "VB\tError " << GetLastError() << " in GetDevicePath:SetupDiEnumDeviceInterfaces");
SetupDiDestroyDeviceInfoList(hDevInfoList); // Cleanup
return FALSE;
}
result = GetDeviceInterfacePath( hDevInfoList, &DeviceInterfaceData, dest, dwMaxLen );
SetupDiDestroyDeviceInfoList(hDevInfoList); // Cleanup
return result;
}
static HANDLE OpenPipe(const PString & filename, DWORD dwIndex)
{
char completeDeviceName[256] = "";
if (!GetDevicePath((LPGUID)&GUID_CLASS_VOIP_BLASTER, dwIndex,
completeDeviceName, sizeof(completeDeviceName))) {
return INVALID_HANDLE_VALUE;
}
strcat(completeDeviceName, "\\" );
strcat(completeDeviceName, filename);
HANDLE h = CreateFile(completeDeviceName,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (h == INVALID_HANDLE_VALUE) {
PTRACE(1, "Failed to open " << completeDeviceName << " : " << GetLastError());
}
return h;
}
/////////////////////////////////////////////////////////////////////////////
VoipBlasterInterface::VoipBlasterInterface()
{
deviceIndex = P_MAX_INDEX;
PINDEX i;
for (i = 0; i < NumPipes; i++)
pipes[i] = INVALID_HANDLE_VALUE;
}
BOOL VoipBlasterInterface::IsDevicePresent(PINDEX deviceIndex)
{
char completeDeviceName[256] = "";
return GetDevicePath((LPGUID)&GUID_CLASS_VOIP_BLASTER, deviceIndex,
completeDeviceName, sizeof(completeDeviceName));
}
BOOL VoipBlasterInterface::OpenCommand(PINDEX _deviceIndex)
{
CloseCommand();
deviceIndex = _deviceIndex;
// open the command and status pipes to the driver
if (!OpenVOIPPipe(CommandPipe)) {
PTRACE(1, "VB\tOpen of command pipe failed");
CloseCommand();
return FALSE;
}
if (!OpenVOIPPipe(StatusPipe)) {
PTRACE(1, "VB\tOpen of status pipe failed");
CloseCommand();
return FALSE;
}
return TRUE;
}
BOOL VoipBlasterInterface::CloseCommand()
{
CloseData();
if (deviceIndex == P_MAX_INDEX)
return FALSE;
CloseHandle(pipes[CommandPipe]);
pipes[CommandPipe] = INVALID_HANDLE_VALUE;
CloseHandle(pipes[StatusPipe]);
pipes[StatusPipe] = INVALID_HANDLE_VALUE;
deviceIndex = P_MAX_INDEX;
return TRUE;
}
BOOL VoipBlasterInterface::OpenData()
{
if (deviceIndex == P_MAX_INDEX)
return FALSE;
// open the data pipes to the driver
if (!OpenVOIPPipe(VoiceOutPipe)) {
PTRACE(1, "VB\tOpen of command pipe failed");
CloseCommand();
return FALSE;
}
if (!OpenVOIPPipe(VoiceInPipe)) {
PTRACE(1, "VB\tOpen of status pipe failed");
CloseCommand();
return FALSE;
}
return TRUE;
}
BOOL VoipBlasterInterface::CloseData()
{
if (deviceIndex == P_MAX_INDEX)
return FALSE;
CloseHandle(pipes[VoiceOutPipe]);
pipes[VoiceOutPipe] = INVALID_HANDLE_VALUE;
CloseHandle(pipes[VoiceInPipe]);
pipes[VoiceInPipe] = INVALID_HANDLE_VALUE;
return TRUE;
}
BOOL VoipBlasterInterface::OpenVOIPPipe(VoipBlasterInterface::Pipe pipeIndex)
{
if (deviceIndex == P_MAX_INDEX)
return FALSE;
return (pipes[pipeIndex] = OpenPipe(psprintf("PIPE%02i", pipeIndex), deviceIndex)) != INVALID_HANDLE_VALUE;
}
BOOL VoipBlasterInterface::WriteCommand(Command cmd)
{
BYTE b = (BYTE)cmd;
return WritePipe(pipes[CommandPipe], &b, 1) == 1;
}
VoipBlasterInterface::Status VoipBlasterInterface::ReadStatus(const PTimeInterval duration)
{
BYTE b;
if (ReadPipe(pipes[StatusPipe], &b, 1, duration) == 1)
return (Status)b;
return Status_Empty;
}
BOOL VoipBlasterInterface::WriteData(const void * data, PINDEX len)
{
return WritePipe(pipes[VoiceOutPipe], data, len) == len;
}
int VoipBlasterInterface::ReadData(void * data, PINDEX len, const PTimeInterval duration)
{
return ReadPipe(pipes[VoiceInPipe], data, len, duration);
}
void VoipBlasterInterface::Flush(const PTimeInterval wait)
{
BYTE buffer[1000];
while (ReadData(buffer, 1000, wait) > 0)
;
while (ReadPipe(pipes[StatusPipe], buffer, 1000, wait) > 0)
;
#if 0
BOOL closeOnEnd = (pipes[VoiceInPipe] == INVALID_HANDLE_VALUE);
if (closeOnEnd && !OpenVOIPPipe(VoiceInPipe)) {
PTRACE(2, "VB\tCould not open voice in pipe for flush");
return;
}
PTimer closeTimer;
closeTimer.SetNotifier(PCREATE_NOTIFIER(CloseTimeout));
closeTimer = wait;
PINDEX count = 0;
for (;;) {
BYTE b;
if (ReadPipe(pipes[VoiceInPipe], &b, 1) != 1)
break;
count++;
closeTimer.Reset();
}
closeTimer.Stop();
PError << "Flushed " << count << " bytes" << endl;
#endif
}
void VoipBlasterInterface::CloseTimeout(PTimer &, INT)
{
if (pipes[VoiceInPipe] != INVALID_HANDLE_VALUE) {
CloseHandle(pipes[VoiceInPipe]);
pipes[VoiceInPipe] = INVALID_HANDLE_VALUE;
}
}
int VoipBlasterInterface::WritePipe(HANDLE handle, const void *bp, DWORD len)
{
DWORD writeCount;
PWin32Overlapped overlap;
ResetEvent(overlap.hEvent);
if (::WriteFile(handle, bp, len, &writeCount, &overlap))
return writeCount;
if (GetLastError() != ERROR_IO_PENDING) {
PTRACE(1, "VB\tWriteFile to pipe failed");
return -1;
}
if (!GetOverlappedResult(handle, &overlap, &writeCount, TRUE)) {
PTRACE(1, "VB\tGetOverlappedResult on pipe failed");
return -1;
}
return writeCount;
}
int VoipBlasterInterface::ReadPipe(HANDLE handle, void *bp, DWORD len, const PTimeInterval duration)
{
DWORD readCount;
PWin32Overlapped overlap;
ResetEvent(overlap.hEvent);
if (::ReadFile(handle, bp, len, &readCount, &overlap))
return readCount;
if (GetLastError() != ERROR_IO_PENDING) {
PTRACE(1, "VB\tReadFile from pipe failed");
return -1;
}
DWORD msecs = (duration == PMaxTimeInterval) ? INFINITE : duration.GetInterval();
if (msecs < 500)
msecs = 500;
switch (WaitForSingleObject(overlap.hEvent, msecs)) {
case WAIT_OBJECT_0:
// do nothing ; the device is ready
break;
case WAIT_TIMEOUT:
// cancel the I/O operation;
CancelIo(handle);
break;
default:
PTRACE(1, "VB\tWaitForSingleObject on pipe failed");
return -1;
}
if (!GetOverlappedResult(handle, &overlap, &readCount, TRUE)) {
PTRACE(1, "VB\tGetOverlappedResult on pipe failed");
return -1;
}
return readCount;
}
#endif // _WIN32
#endif // HAS_VBLASTER
/////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -