📄 vblasterlid.cxx
字号:
/*
* vblasterlid.cxx
*
* Creative Labs VOIP Blaster codec interface
*
* Open H323 Library
*
* Copyright (c) 2001 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Open H323 Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Contributor(s): ______________________________________.
*
* $Log: vblasterlid.cxx,v $
* Revision 1.3 2007/06/04 16:06:30 joegenbaclor
* *** empty log message ***
*
* Revision 1.2 2006/10/12 05:28:00 joegenbaclor
* fixed compile error in VC 2005
*
* Revision 1.1 2006/06/26 03:03:21 joegenbaclor
* I have decided to include the latest development realease of OPAL tagged Deimos Devel 1 (June 8 2006) as inegrated classes to opensipstack to avoid future version conflicts due to the fast pace in OPAL development. This move is also aimed to reduce the size of projects using OPAL componets such as the soon to be relased OpenSIPPhone.
*
* Revision 2.7 2004/10/06 13:03:42 rjongbloed
* Added "configure" support for known LIDs
* Changed LID GetName() function to be normalised against the GetAllNames()
* return values and fixed the pre-factory registration system.
* Added a GetDescription() function to do what the previous GetName() did.
*
* Revision 2.6 2004/02/19 10:47:05 rjongbloed
* Merged OpenH323 version 1.13.1 changes.
*
* Revision 2.5 2003/03/24 07:18:30 robertj
* Added registration system for LIDs so can work with various LID types by
* name instead of class instance.
*
* Revision 2.4 2002/09/06 07:20:31 robertj
* Fixed previous update, did not port properly.
*
* Revision 2.3 2002/09/04 06:01:49 robertj
* Updated to OpenH323 v1.9.6
*
* Revision 2.2 2002/02/11 09:32:13 robertj
* Updated to openH323 v1.8.0
*
* Revision 2.1 2002/01/22 06:28:43 robertj
* Added voice blaster support
*
* Revision 1.9 2003/12/03 06:58:00 csoutheren
* More vblaster implementation
*
* Revision 1.8 2003/11/10 12:38:20 csoutheren
* Additional fixes for Fobbit Windows driver
*
* Revision 1.7 2002/09/03 06:25:00 robertj
* Cosmetic change to formatting.
*
* Revision 1.6 2002/08/05 10:03:48 robertj
* Cosmetic changes to normalise the usage of pragma interface/implementation.
*
* Revision 1.5 2002/07/09 00:39:08 robertj
* Patches for latest fobbit driver, thanks Jian Yang
*
* Revision 1.4 2002/02/05 06:19:47 craigs
* Changed to use OPAL define rather than strings
*
* Revision 1.3 2002/01/15 07:23:10 craigs
* Added IsDevicePresent command
*
* Revision 1.2 2002/01/15 05:54:16 robertj
* Added bad implementation for GetDeviceNames()
*
* Revision 1.1 2002/01/15 04:16:52 craigs
* Initial version
*
*/
#include <ptlib.h>
#ifdef __GNUC__
#pragma implementation "vblasterlid.h"
#endif
#include <lids/vblasterlid.h>
////////////////////////////////////////////////
/// Get rid of LNK4221: no public symbols found;
/// archive member will be inaccessible
const char * vblasterlid_file_content = NULL;
////////////////////////////////////////////////
#if HAS_VBLASTER
#define STARTUP_TIMEOUT 500
/*
This code uses the VoIPBlaster interface as written by Dave Fobbitt (http://www.fobbit.com).
All of the information about the VoIPBlaster command set and functions was derived directly
from the code made available by Dave. This code requires Dave's USB drivers to be installed
as per the instructions on his site. Thanks to Dave for making this code available for
general use.
Introduction
The interface to the VoIPBlaster (VB) is implemented using two pairs of read/write channels. These
are implemented as four named pipes for Windows, or two sockets for Unix. One channel is used
for sending commands to the VB and reading status, and the other channel is used for sending and
receiving audio data.
Initialisation:
TBD
Commands:
There are 27 different comands recognised by the VB. Each command is one byte.
COMMAND_PHONE_OFF 0x01 drop loop current
COMMAND_PHONE_ON 0x02 used on startup
COMMAND_RING_ON 0x03 start ringing
COMMAND_RING_OFF 0x04 used on startup & to stop ringing
COMMAND_VOUT_START 0x05 start audio output
COMMAND_VOUT_STOP 0x06 stop audio output
COMMAND_VINP_START 0x07 start audio input
COMMAND_VINP_STOP 0x08 stop audio input
COMMAND_UNKNOWN_1 0x09 Unknown (TESTSTART)
COMMAND_UNKNOWN_2 0x0a Unknown (TESTSTOP)
COMMAND_UNKNOWN_3 0x0b Unknown (SENDFAXTONE)
COMMAND_0x0c 0x0c Go offhook for headset
COMMAND_0x0d 0x0d Go onhook for headset
COMMAND_SETUP_MODE 0x0e Unknown(goto setup mode)
COMMAND_VOUT_DONE 0x0f voice in/out off, report output drained
COMMAND_0x10 0x10 Unknown (used in file output, seems ok without)
COMMAND_0x11 0x11 Unknown (used in file output, seems ok without)
COMMAND_MUTE_ON 0x12 Audio mute on
COMMAND_MUTE_OFF 0x13 Audio mute off
COMMAND_VOL_0 0x34 Set volume (min)
COMMAND_VOL_1 0x35 Set volume
COMMAND_VOL_2 0x36 Set volume
COMMAND_VOL_3 0x37 Set volume (default)
COMMAND_VOL_4 0x38 Set volume
COMMAND_VOL_5 0x39 Set volume
COMMAND_VOL_6 0x3a Set volume (max)
Status:
There are 11 different status responses sent by the VB. Each status is one byte.
STATUS_NONE 0x00 No status
STATUS_HOOK_OFF 0x01 Offhook
STATUS_HOOK_ON 0x02 Onhook
STATUS_DEBUG 0x00 Not used (DEBUG)
STATUS_RINGDETECT 0x00 Not used (RINGDETECT)
STATUS_RINGING_ON 0x05 Ring started
STATUS_RINGING_OFF 0x06 Ring stopped
STATUS_HEADSET_IN 0x08 Headset plugged in
STATUS_HEADSET_OUT 0x09 Headset unplugged
STATUS_0x0a 0x0a Unknown (setup accepted?)
STATUS_VOUT_DONE 0x0c Voice output done
Voice:
The VB will accept audio in G.723.1 format at either 6.4kbps frames (24 bytes) or 5.3 kbps
frames (20 bytes). However, it only generates audio data at 5.3 kbps frames (20 bytes)
*/
static BYTE blasterInit1[] =
{
0x3b,0x00,0x40,0x8b // first 2 bytes is length, second 2 bytes is command?
};
static BYTE blasterInit2[] =
{
0x00,0x01,0x00,0x00,0x18,0x02,0x8f,0x00,
0x10,0x00,0x28,0x40,0x03,0x1a,0x0d,0x0c,
0xfa,0x43,0xfd,0xea,0x93,0xfe,0x1a,0x41,
0x00,0x4a,0x93,0xfe,0x2a,0x40,0x00,0x1a,
0x93,0xfe,0x3a,0x0a,0x00,0x1f,0x3c,0x00,
0x8c,0x0d,0x03,0xa3,0x23,0xa2,0xdf,0x0d,
0x0c,0x3a,0x40,0x00,0x2a,0x93,0xfe,0x4a,
0x0a,0x00,0x0f
};
// this gets sent each time the voice output goes idle
static BYTE blasterInit3[] =
{
0x75,0x58,0x9b,0x04,0x72,0x00,0x00,0x11,
0xe0,0x00,0x65,0x82,0x00,0x90,0x00,0x1c,
0x96,0xc1,0x0f,0xf2,0x3d,0x95,0x8e,0x5e,
0xe7,0x66,0xef,0xd4,0xba,0x21,0x0d,0x30,
0xcb,0x1e,0x52,0x35,0x9a,0xb6,0xff,0x7f,
0x74,0x58,0x9b,0x04,0x68,0x08,0x00,0x99,
0x52,0xfa,0x75,0xd7,0x72,0xba,0xdb,0x03,
0x3d,0xdb,0x77,0xd0,0x77,0x03,0x1f,0x05
};
// some silence data, for now only used in 'vblast_ring' to kill the dialtone
static BYTE silence[] =
{
0xd5,0x14,0x0a,0x0d,0x1a,0x00,0x00,0x0a,
0x80,0x00,0xaf,0x06,0x00,0x00,0xfc,0x24,
0x9b,0x70,0xcf,0xc0,0xa1,0x53,0x18,0x00,
0x08,0x04,0xfe,0x50,0x8f,0x12,0x50,0x50,
0x4b,0x32,0x56,0x77,0x15,0xe9,0x0f,0xe8,
0xd5,0xc8,0xad,0x68,0xc8,0x74,0xe4,0x27,
0x71,0xd8,0x87,0x34,0xad,0x60,0x07,0xa8,
0xb6,0x64,0x0f,0x44,0x59,0x02,0xf4,0x00,
0x0e,0x80,0xba,0x68,0x73,0x00,0xe0,0xdf,
0x82,0xf4,0xa3,0x1f,0x18,0xb3,0x70,0x2e,
0xdd,0x1c,0xb1,0x00,0x02,0xfc,0x07,0xde,
0x09,0xc2,0x5e,0x82,0xaf,0xbc,0x5a,0x6c,
0xa2,0x02,0xbb,0xac,0x65,0x47,0x99,0x74,
0xfe,0xf4,0xe5,0xf7,0x70,0x90,0xe7,0x21,
0x15,0x33,0x56,0x8a,0x77,0x50,0xb5,0x42,
0x51,0x17,0xf2,0x4c,0xa8,0xfc,0x10,0x60,
0x82,0x1e,0x50,0x2f,0xa4,0x57,0x31,0x1e,
0xdd,0xc0,0xaf,0x6f,0x4d,0x1f,0xf5,0x08,
0x18,0x90,0x15,0x7f,0x70,0x1e,0x60,0x3e,
0x15,0xfb,0xa0,0x0d,0xbd,0x60,0x90,0x6d,
0x65,0x43,0xb1,0xdc,0xc2,0xd5,0x19,0xe5,
0xe1,0xe8,0x27,0xe4,0xcf,0x82,0x39,0xec,
0x38,0x84,0x3b,0x75,0x51,0x3b,0xb1,0x70,
0xde,0x68,0xba,0x06,0x79,0x0f,0x76,0x18,
0x74,0x53,0x45,0x4f,0x83,0x52,0xa0,0xa0,
0x5d,0xc1,0xed,0xc4,0x9f,0x77,0x27,0x36,
0x83,0xf9,0x07,0x7f,0x28,0xf3,0x41,0x41,
0x85,0x94,0x15,0xc0,0x45,0x13,0xee,0x30,
0x54,0x8c,0xea,0x37,0x03,0xf8,0xae,0x1f,
0x85,0xe7,0xed,0x21,0x58,0x01,0xff,0xe5,
0x75,0xc3,0x09,0x05,0x12,0x00,0x26,0xa7,
0x0b,0x26,0x9f,0x81,0x26,0x50,0x06,0x97,
0x31,0xa4,0x3c,0xca,0x1d,0x97,0xc2,0x9d,
0x42,0x6d,0xcf,0xae,0xe6,0xe5,0x27,0x04,
0x03,0xc2,0x93,0x5d,0xa7,0x62,0xf1,0x87,
0x5d,0x41,0xe5,0x0a,0x0a,0x70,0x69,0x3f,
0xf1,0xf4,0xfe,0x0d,0x4e,0x27,0x97,0x5b,
0xb0,0x0b,0xe5,0x78,0xa5,0x26,0x09,0x49,
0x90,0xfc,0xf1,0x77,0x52,0x0c,0xdf,0xef,
0x7f,0x8d,0x84,0x15,0x48,0xc7,0xff,0x5b,
};
/////////////////////////////////////////////////////////////////////////////
OpalVoipBlasterDevice::OpalVoipBlasterDevice()
: dtmfQueue(DTMFQueueSize)
{
statusThread = NULL;
}
OpalVoipBlasterDevice::~OpalVoipBlasterDevice()
{
Close();
}
BOOL OpalVoipBlasterDevice::Open(const PString & device)
{
Close();
int deviceIndex = device.AsInteger();
readStopped = writeStopped = TRUE;
// open the lowlevel device
if (!vBlaster.OpenCommand(deviceIndex)) {
PTRACE(3, "vBlaster\tCould not open VoipBlaster device \"" << device << '"');
return FALSE;
}
if (!vBlaster.OpenData()) {
PTRACE(3, "vBlaster\tCould not open VoipBlaster data for device \"" << device << '"');
return FALSE;
}
// put device into setup mode
PTRACE(3, "vBlaster\tSending setup command");
// put the handset on hook, which should stop all voice data
vBlaster.WriteCommand(VoipBlasterInterface::Command_HS_ONHOOK);
// flush all input
vBlaster.Flush(STARTUP_TIMEOUT);
vBlaster.WriteCommand(VoipBlasterInterface::Command_SETUP_MODE);
// setup for incoming status
hookState = FALSE;
headset = FALSE;
ringOn = TRUE; // so we can detect ring off
firstTime = FALSE;
//vBlaster.Flush(STARTUP_TIMEOUT);
vBlaster.WriteData(blasterInit1, sizeof(blasterInit1));
//vBlaster.Flush(STARTUP_TIMEOUT);
vBlaster.WriteData(blasterInit2, sizeof(blasterInit2));
//vBlaster.Flush(STARTUP_TIMEOUT);
int status = VoipBlasterInterface::Status_Empty;
int i = 0;
for ( i = 3; ringOn && i > 0; i--) {
vBlaster.WriteCommand(VoipBlasterInterface::Command_VOL_3);
vBlaster.WriteCommand(VoipBlasterInterface::Command_RING_OFF);
vBlaster.WriteCommand(VoipBlasterInterface::Command_PHONE_ON);
PTimer timer(2000);
do {
status = vBlaster.ReadStatus(STARTUP_TIMEOUT);
if (status != VoipBlasterInterface::Status_Empty)
HandleStatus(status);
} while (ringOn && timer.IsRunning());
}
if (i == 0) {
PTRACE(3, "vBlaster\tCould not initialise");
return FALSE;
}
// set up thread to read status pipe
statusRunning = TRUE;
statusThread = PThread::Create(PCREATE_NOTIFIER(StatusHandler), 0,
PThread::NoAutoDeleteThread,
PThread::NormalPriority,
"VbStatus:%x");
// unmute output and set default value
vBlaster.WriteCommand(VoipBlasterInterface::Command_VOL_3);
vBlaster.WriteCommand(VoipBlasterInterface::Command_MUTE_OFF);
vBlaster.WriteCommand(VoipBlasterInterface::Command_VOUT_STOP);
vBlaster.WriteCommand(VoipBlasterInterface::Command_VINP_STOP);
// save the device name
deviceName = device;
PTRACE(3, "vBlaster\tVoipBlaster device \"" << device << "\" opened");
os_handle = deviceIndex;
return TRUE;
}
BOOL OpalVoipBlasterDevice::Close()
{
PWaitAndSignal m(vbMutex);
if (!IsOpen())
return FALSE;
// flag the status thread to stop running on next status byte
statusRunning = FALSE;
// send a command to the phone stat will force a status byte to return
vBlaster.WriteCommand(VoipBlasterInterface::Command_PHONE_OFF);
vBlaster.WriteCommand(VoipBlasterInterface::Command_MUTE_OFF);
vBlaster.WriteCommand(VoipBlasterInterface::Command_VOUT_DONE);
vBlaster.WriteData (blasterInit3, sizeof(blasterInit3));
// close the device - this will stop the status thread for sure!
vBlaster.CloseCommand();
// wait for the status thread to terminate
statusThread->WaitForTermination();
delete statusThread;
statusThread = NULL;
deviceName = PString();
os_handle = -1;
return TRUE;
}
PString OpalVoipBlasterDevice::GetDeviceType() const
{
return OPAL_VBLASTER_TYPE_NAME;
}
PString OpalVoipBlasterDevice::GetDeviceName() const
{
return deviceName;
}
PStringArray OpalVoipBlasterDevice::GetAllNames() const
{
return GetDeviceNames();
}
PString OpalVoipBlasterDevice::GetDescription() const
{
return "Createive Labs VoIP Blaster (" + deviceName + ')';
}
void OpalVoipBlasterDevice::StatusHandler(PThread &, INT)
{
while (statusRunning) {
int status = vBlaster.ReadStatus();
if (status != VoipBlasterInterface::Status_Empty)
HandleStatus(status);
}
}
void OpalVoipBlasterDevice::HandleStatus(int status)
{
switch (status) {
//case VoipBlasterInterface::Status_NONE: // No status
// break;
case VoipBlasterInterface::Status_HOOK_OFF: // Offhook
PTRACE(1, "VB\tHook off");
hookState = TRUE;
headset = FALSE;
break;
case VoipBlasterInterface::Status_HOOK_ON: // Onhook
PTRACE(1, "VB\tHook on");
hookState = FALSE;
headset = FALSE;
break;
case VoipBlasterInterface::Status_RINGING_ON: // Ring started
PTRACE(1, "VB\tRing start");
ringOn = TRUE;
break;
case VoipBlasterInterface::Status_RINGING_OFF: // Ring stopped
PTRACE(1, "VB\tRing end");
ringOn = FALSE;
break;
case VoipBlasterInterface::Status_HEADSET_IN: // Headset plugged in
PTRACE(1, "VB\tHeadset in");
headset = TRUE;
break;
case VoipBlasterInterface::Status_HEADSET_OUT: // Headset unplugged
PTRACE(1, "VB\tHeadset out");
headset = FALSE;
break;
case VoipBlasterInterface::Status_0x0a: // Unknown (setup accepted?)
PTRACE(1, "VB\tStatus 0xa");
// read 17 byte serial number
BYTE serialNumber[17];
memset(serialNumber, 0, sizeof(serialNumber));
vBlaster.ReadData(serialNumber, sizeof(serialNumber), STARTUP_TIMEOUT);
{
PString str;
for (int i = 0; i < sizeof(serialNumber); i++)
str.sprintf("%02x ", serialNumber[i]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -