
//! @file vpbapi.h
//! @ingroup PublicAPI
//! @brief Voicetronix voice processing board public API
//!
//! This file contains the public API functions for interfacing to @c libvpb.

/*---------------------------------------------------------------------------*\

    AUTHOR..: Voicetronix <support@voicetronix.com.au>
    DATE....: 26/11/97


         Voicetronix Voice Processing Board (VPB) Software
         Copyright (C) 1997-2007 Voicetronix www.voicetronix.com.au

         This library is free software; you can redistribute it and/or
         modify it under the terms of the GNU Lesser General Public
         License as published by the Free Software Foundation; either
         version 2.1 of the License, or (at your option) any later version.

         This library is distributed in the hope that it will be useful,
         but WITHOUT ANY WARRANTY; without even the implied warranty of
         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
         Lesser General Public License for more details.

         You should have received a copy of the GNU Lesser General Public
         License along with this library; if not, write to the Free Software
         Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
         MA  02110-1301  USA

\*---------------------------------------------------------------------------*/

#ifndef __VPBAPI__
#define __VPBAPI__

#include <exception>
#include <string>
#include <vector>
#include <stdint.h>

#include <vt_deprecated.h>

#ifdef WIN32
#define	WINAPI	__stdcall
#else
#define	WINAPI
#endif


 //! @defgroup PublicAPI Public API functions
 //! @brief Public interfaces available to users of @c libvpb.
 //!@{
 //{{{

//! Symbolic type for a handle to an open port on some card.
typedef int VPBPortHandle;

const VPBPortHandle VPB_PORTHANDLE_NULL = -1;


// Return codes
#define	VPB_OK		 0
#define	VPB_NO_EVENTS	-1
#define	VPB_TIME_OUT	-2

// string length
#define	VPB_MAX_STR	256


//! VPB card model types
enum VPB_MODEL
{ //{{{
      //VPB_VPB4   = 0,     //   VPB4 4 port ISA CT card
      //VPB_VPB8L  = 1,     //   VPB8L 8 port logging card
	VPB_V4PCI  = 2,     //!< V4PCI 4 port PCI CT card
	VPB_V4LOG  = 3,     //!< V4LOG 4 port PCI logging card
      //VPB_V12PCI = 4,     //   V12PCI 12 port PCI CT/PBX card
      //VPB_V6PCI  = 5,     //   V6PCI 6 port PCI CT/PBX card
	VPB_PRI    = 6,     //!< Sangoma PRI card
	VPB_OPCI   = 7,	    //!< OpenPCI card
	VPB_OSW    = 8,     //!< OpenSwitch card using vtcore driver

	//! Placeholder for when card type is not yet known.
	VPB_MODEL_UNKNOWN = -1
}; //}}}

//! Analogue port types
enum VPB_PORT
{ //{{{
	VPB_PORT_UNKNOWN = 0,	//!< Placeholder for an unknown port type
	VPB_FXO          = 1,	//!< Trunk port.
	VPB_FXS          = 2	//!< Station port.
}; //}}}


//! @defgroup QueueSize Queue size
//! @note These functions @b must be called prior to the initialisation of the
//!       device structures.  That means before any call to @c vpb_open(),
//!       @c vpb_get_num_cards(), or @c vpb_get_ports_per_card() is made.
//!
//! @exception VpbException will be thrown if they are called after
//!            device initialisation has taken place.
//!
//! If you really must change them after that, you may call @c vpb_close(),
//! (with no arguments) to close all ports and release the existing device
//! structures, then call them before re-opening the desired ports.
//!@{
//{{{

    //! @brief Set the maximum number of events the global @c APIQ may hold.
    void WINAPI vpb_set_global_apiq_size( int size );

    //! @brief Set the maximum number of events per-channel @c APIQ's may hold.
    void WINAPI vpb_set_channel_apiq_size( int size );

//!@} //}}}

//! @defgroup PortInit Port initialisation
//!@{
//{{{

    //! Symbolic type for @c vpb_open() mode flags.
    typedef int VPBOpenMode;

  //! @name mode flags for vpb_open()
  //@{ //{{{

    const VPBOpenMode VPB_OPEN_NONE  = 0x00;    //!< Just open the port.
    const VPBOpenMode VPB_OPEN_RESET = 0x10;    //!< Reset the port state.

    //! The default flags for @c vpb_open().
    const VPBOpenMode VPB_OPEN_DEFAULTS = VPB_OPEN_RESET;

  //@} //}}}


    //! Open a @a port on some @a board for use.
    //{{{
    //! @param board The board number, starting from 0.
    //! @param port  The port number on @a board, starting from 0.
    //! @param flags The @c VPBOpenMode flags which indicate additional
    //!              operations to perform when opening the port.
    //!
    //! @return A handle to pass to other vpbapi functions
    //!         when performing operations on the port.
    //!
    //! @note When @c vpb_open is called to open the first port it performs
    //!       a number of static initialisation tasks that will run in the
    //!       background.  Those tasks may not have completed by the time
    //!       vpb_open returns to the caller.  For most applications, they
    //!       will have had plenty of time to complete by the time any other
    //!       ports have been opened and any app specific initialisation has
    //!       been performed, but for very trivial applications you may need
    //!       to delay briefly before performing subsequent operations on the
    //!       port.  You should likewise avoid repeatedly opening and closing
    //!       single ports in a tight loop.  Such code will perform much more
    //!       efficiently if you simply open all the ports that you require to
    //!       access, then call @c vpb_close() (without any handle parameter)
    //!       to close them all again when you are done with them, as the
    //!       bulk of the initialisation will only be run for the first call
    //!       to @c vpb_open in that case, and will not need to be repeated
    //!       while any ports continue to remain open.
    //}}}
    VPBPortHandle WINAPI vpb_open(unsigned int board,
				  unsigned int port,
				  VPBOpenMode  flags = VPB_OPEN_DEFAULTS);

    //! Reset a port back to its idle state (on-hook, not ringing etc.)
    //{{{
    //! @param handle The handle returned by a call to @c vpb_open().
    //!               If not specified, then all open ports will be reset.
    //!
    //! The precise action performed depends on the type of port that @a handle
    //! refers to, but after this call it should be in the same state as it would
    //! be when initially powered up from a cold start.
    //!
    //! Any hardware gains will be restored to their default levels, or to the
    //! levels specified if configuration files are present.
    //!
    //! The locale specific hardware configuration will be reset according to
    //! (in order of priority):
    //! -# The value explicitly set by a previous call to @c vpb_set_country().
    //! -# A port-specific @c country value specified in the configuration files.
    //! -# The value of the @c VPB_COUNTRY environment variable.
    //! -# The global locale selection specified in the configuration files.
    //! -# The hardcoded default (ie. <tt>AUSTRALIA</tt>).
    //}}}
    void WINAPI vpb_reset(VPBPortHandle handle = VPB_PORTHANDLE_NULL);

    //! Close a previously opened port using the @a handle returned by @c vpb_open().
    //
    //! @param handle The handle returned by a call to @c vpb_open().  If not
    //!               specified, this will close all currently open ports.
    //! @return @c VPB_OK if all goes well.
    //! @exception various exceptions may be thrown in the event of an error.
    int WINAPI vpb_close(VPBPortHandle handle = VPB_PORTHANDLE_NULL);

//!@} //}}}

//! @defgroup CardInfo Card information
//!@{
//{{{

    //! Container type for data returned by @c vpb_get_card_info().
    struct VPB_CARD_INFO
    { //{{{
	char	model[10];	//!< Model
	char	date[16];	//!< Manufacture Date
	char	rev[8];		//!< Revision
	char	sn[10];		//!< Serial Number
    }; //}}}


    //! Return the driver version as a string.
    const char* WINAPI vpb_get_driver_version();

    //! Return the driver version as @a major, @a minor, and @a patchlevel components.
    void WINAPI vpb_get_driver_version(int *major, int *minor, int *patchlevel);

    //! @brief Return the number of cards in the system.
    //! @note  This function may be called prior to @c vpb_open().
    int WINAPI vpb_get_num_cards();

    //! Return the number of ports on @a board.
    //{{{
    //! @param board The board number, starting from 0.
    //! @note This function may be called prior to @c vpb_open().
    //}}}
    int WINAPI vpb_get_ports_per_card(int board);

    //! Return @a detail of the card model and revision for @a board.
    int WINAPI vpb_get_card_info(int board, VPB_CARD_INFO *detail);

    //! Return a string indicating the board model.
    //{{{
    //! @param handle The handle to a port on the board to query.
    //! @return The model string.
    //! @exception VpbException will be thrown if the handle is invalid.
    //! @note You should not rely on any particular value to be returned by
    //!       this function, it is intended for user friendly output only.
    //!       If you need to check the model programmatically, use the
    //!       @c vpb_get_card_type() function instead.
    //}}}
    std::string WINAPI vpb_get_model(VPBPortHandle handle);

    //! Return a string indicating the board model.
    //{{{
    //! @param handle The handle to a port on the board to query.
    //! @param str    The returned model string.
    //! @return @c VPB_OK if the handle is valid.
    //! @exception VpbException may be thrown if the handle is invalid.
    //! @note You should not rely on any particular value to be returned by
    //!       this function, it is intended for user friendly output only.
    //!       If you need to check the model programmatically, use the
    //!       @c vpb_get_card_type() function instead.
    //}}}
    int WINAPI vpb_get_model(VPBPortHandle handle, char *str);

    //! Return a descriptive string for a @c VPB_MODEL type.
    const char *WINAPI vpb_model_desc(VPB_MODEL model);

    //! Return the board model type for @a handle.
    VPB_MODEL WINAPI vpb_get_card_type(VPBPortHandle handle);

    //! Return the @c VPB_PORT type for @a handle.
    VPB_PORT WINAPI vpb_get_port_type(VPBPortHandle handle);

  //! @name Deprecated functions
  //@{ //{{{

    //! This function is deprecated.  Use the more descriptively
    //! named and type-safe @c vpb_get_card_type() function instead.
    VT_DEPRECATED( int WINAPI vpb_get_type(int h) );

    //! This function is deprecated.  Use the version that takes
    //! a board argument in order to know which card to query for.
    VT_DEPRECATED( int WINAPI vpb_get_ports_per_card() );

    //! This function is deprecated.  Use the version that takes a handle argument
    //! as well in order to know which card the model is returned for.
    VT_DEPRECATED( int WINAPI vpb_get_model(char *s) );

    //! This function is deprecated from the public api as it is redundant.
    //! Use the @c vpb_get_port_type() function instead.
    VT_DEPRECATED( int WINAPI vpb_is_station(int handle) );  // 2006, v4.0

  //@} //}}}

//!@} //}}}


//! @defgroup PortControl Port control
//!@{
//{{{

    //! Symbolic hook states.
    enum HookState
    { //{{{

	VPB_ONHOOK      = 0,    //!< Port on-hook.
	VPB_OFFHOOK     = 1,    //!< Port off-hook.
	VPB_FASTOFFHOOK = 2     //!< Port off-hook, no calibration.

    }; //}}}


    //! Return the hook state of a port.
    //{{{
    //! @param handle   The handle of the port to query.
    //! @return @c VPB_ONHOOK or @c VPB_OFFHOOK if the query succeeds.
    //! @exception VpbException will be thrown in the event of an error.
    //! @warning In environments where asynchronous operations may take
    //!          place on @a handle, the real state of the port may have
    //!          already changed again by the time this function returns.
    //!          It is the responsibility of the user application to
    //!          determine how much trust may be placed in the accuracy
    //!          of this value at any point in the code where it is used.
    //}}}
    HookState WINAPI vpb_get_hookstate(VPBPortHandle handle);

    //! Signal a port to set its hook state.  Returns immediately.
    void WINAPI vpb_sethook_async(VPBPortHandle handle, HookState hookstate);

    //! Set the hook state of a port. Waits for it to change before returning.
    void WINAPI vpb_sethook_sync(VPBPortHandle handle, HookState hookstate);

    //! Set the window for detecting flash events on OpenPCI cards.
    //{{{
    //! For FXS ports, this is automatically configured according to the locale
    //! specific values in the @c Country structure.  For FXO ports, flash events
    //! are only generated if this function has been explicitly called (this is
    //! to maintain compatibility with older applications which manually processed
    //! the raw on/off hook events themselves).
    //!
    //! @param handle The handle of the port to configure.
    //! @param min    The minimum on-hook time for a valid flash signal in @c ms.
    //! @param max    The maximum on-hook time for a valid flash signal in @c ms.
    //}}}
    void WINAPI vpb_set_flashtime(VPBPortHandle handle, uint16_t min, uint16_t max);

    // vpb_ring_station_async symbolic cadences
    #define VPB_RING_STATION_ON  -1 //!< Ring station port with default cadence
    #define VPB_RING_STATION_OFF  0 //!< Stop station port ringing

    //! Start or stop a station port ringing.
    //{{{
    //! @param handle   The handle of the port to control.
    //! @param cadence  The ring cadence value.
    //!
    //! If the @a cadence parameter is not specified, the default cadence for
    //! a normal ring according to the port's country setting will be used.
    //! The valid @a cadence values are defined as follows:
    //!
    //! - @c 0   - Stop ringing.
    //! - @c 1   - Ring a guard tone cadence.  Often used before sending caller id.
    //! - @c 2   - Normal ring for Australian phone networks.  (<tt>DR0</tt>)
    //! - @c 3-9 - @c DR1 to @c DR7 of the @c AS/ACIF S002:2001 distinctive ring series.
    //! - @c 10  - US ring cadence.
    //!
    //! There is an additional special ring cadence @c 255, which like @c 0,
    //! stops the station ringing, but in addition will signal an @b OpenPCI
    //! @c FXS port to enter a mode where caller id information can be
    //! transmitted to a handset that is still on hook.  ie. for US style
    //! caller id, you would generate one second of cadence @c 1 tone, stopped
    //! by a cadence @c 255 signal.  The caller id tones can then be sent, and
    //! normal ringing commenced using cadence @c 2 - @c 10.
    //! Convenience functions to do this are provided with the @b CTPort
    //! interface to @b ctserver.
    //!
    //! @note Distinctive ring cadences are not supported by the @b OpenSwitch
    //!       cards at the time of writing.  Values @c 1 - @c 10 will all cause
    //!       its normal ring cadence to be generated.
    //!
    //! @sa vpb_ring_with_cid()
    //}}}
    void WINAPI vpb_ring_station_async(VPBPortHandle handle, int cadence = -1);


    //! Port bridging control flags
    enum BridgeMode
    { //{{{

	VPB_BRIDGE_OFF = 0,     //!< stop bridging
	VPB_BRIDGE_ON  = 1      //!< start bridging

    }; //}}}

    //! Create a full duplex bridge between ports @a h1 and @a h2.
    int WINAPI vpb_bridge(VPBPortHandle h1, VPBPortHandle h2, BridgeMode mode);

    //! Create a half duplex bridge routing audio from @a src to @a dest.
    int WINAPI vpb_listen(VPBPortHandle dest, VPBPortHandle src, BridgeMode mode);

    //XXX Don't use this one.
    int WINAPI vpb_soft_bridge(int h1, int h2, int mode);


    void WINAPI vpb_set_codec_reg(VPBPortHandle handle, uint16_t addr, uint16_t value);

  //! @name Deprecated functions
  //@{ //{{{

    // This function is deprecated.  The resource parameter has been ignored for
    // quite some time now and is determined automatically.  Use the version above
    // that does not require this extra parameter.
    VT_DEPRECATED( int WINAPI vpb_bridge(int h1, int h2, BridgeMode mode, int resource) );

  //@} //}}}

//!@} //}}}


// vpb_conf() modes
#define VPB_CONF_JOIN   1     // Join conference
#define VPB_CONF_LEAVE  0     // Leave conference

// This function is deprecated.  It was only implemented for the obsolete
// vpbhp driver and openswitch cards.  If it is resurrected it will probably
// have a different name and different semantics.  Stay tuned.
VT_DEPRECATED( int WINAPI vpb_conf(int h1,int resource, int mode) );


//! @defgroup Events Event handling
//! An event driven programming model is used by libvpb.  There are primarily
//! two different kinds of events, solicted and unsolicited.
//!
//! @par Solicited events
//! Solicited events are generated as a response to a previous API function
//! call, for example when @c vpb_play_file_async() is called, a solicited
//! event of the type @c VPB_PLAYEND is generated when the file has finished
//! playing.
//!
//! @par Unsolicited events
//! Unsolicited events are generated in response to external conditions,
//! for example when a @c DTMF tone has been detected by the card.
//!@{
//{{{

    //! @c VPB_EVENT type values
    enum VPB_EVT_TYPE
    { //{{{

	//! Invalid event value.  Used where no event is returned from api
	//! functions that take a @c VPB_EVENT return parameter.
	VPB_EVT_NONE		= -1,

	// unsolicited (maskable) events
	// XXX Document all of these explicitly.
	VPB_RING		= 0,
	VPB_DIGIT		= 1,
	VPB_TONEDETECT		= 2,
	VPB_TIMEREXP		= 3,
	VPB_VOXON		= 4,
	VPB_VOXOFF		= 5,
	//VPB_PLAY_UNDERFLOW	= 6,
	//VPB_RECORD_OVERFLOW	= 7,
	VPB_DTMF		= 8,
	VPB_STATION_OFFHOOK	= 9,
	VPB_STATION_ONHOOK	= 10,
	VPB_RING_OFF		= 11,
	VPB_DROP		= 12,
	VPB_STATION_FLASH	= 13,
	VPB_LOOP_OFFHOOK	= 14,
	VPB_LOOP_ONHOOK		= 15,
	VPB_LOOP_POLARITY	= 16,
	VPB_DTMF_DOWN		= 17,
	VPB_LOOP_FLASH		= 18,

	// solicited (non maskable) events
	VPB_PLAYEND		= 100,
	VPB_RECORDEND		= 101,
	VPB_DIALEND		= 102,
	VPB_TONE_DEBUG_END	= 103,
	VPB_CALLEND		= 104,

	VPB_ISDN_ANS		= 110,
	VPB_ISDN_BUSY		= 111,
	VPB_ISDN_CINFO		= 112,
	VPB_ISDN_CALL_FAIL	= 113,
	VPB_ISDN_ANS_FAIL	= 114,
	VPB_ISDN_PROCEEDING	= 115,
	VPB_ISDN_RINGING	= 116,

	//! User defined event message.  Different types of user events may be
	//! differentiated using the @c VPB_EVENT::data or @c VPB_EVENT::extra
	//! fields as appropriate.
	VPB_USER_EVT		= 255

    }; //}}}

    //! Container for VPB event data.
    struct VPB_EVENT
    { //{{{
	VPB_EVT_TYPE  type;     //!< The event type
	int           handle;   //!< The handle of the port that generated the event

	int           data;     //!< Optional data
	unsigned long data1;    //!< Optional long data

	int           lenextra; //!< Support for user defined event data
	void         *extra;    //!< Support for user defined event data
    }; //}}}


  //! @name Event mask values
  //@{ //{{{

    #define VPB_MRING			(1<<VPB_RING)
    #define VPB_MDIGIT     		(1<<VPB_DIGIT)
    #define VPB_MDTMF     		(1<<VPB_DTMF)
    #define VPB_MTONEDETECT		(1<<VPB_TONEDETECT)
    #define VPB_MTIMEREXP		(1<<VPB_TIMEREXP)
    #define VPB_MVOXON			(1<<VPB_VOXON)
    #define VPB_MVOXOFF			(1<<VPB_VOXOFF)
    //#define VPB_MPLAY_UNDERFLOW	(1<<VPB_PLAY_UNDERFLOW)
    //#define VPB_MRECORD_OVERFLOW	(1<<VPB_RECORD_OVERFLOW)
    #define VPB_MSTATION_OFFHOOK	(1<<VPB_STATION_OFFHOOK)
    #define VPB_MSTATION_ONHOOK 	(1<<VPB_STATION_ONHOOK)
    #define VPB_MRING_OFF		(1<<VPB_RING_OFF)
    #define VPB_MDROP			(1<<VPB_DROP)
    #define VPB_MSTATION_FLASH		(1<<VPB_STATION_FLASH)
    #define VPB_MLOOP_OFFHOOK		(1<<VPB_LOOP_OFFHOOK)
    #define VPB_MLOOP_ONHOOK		(1<<VPB_LOOP_ONHOOK)
    #define VPB_MLOOP_POLARITY		(1<<VPB_LOOP_POLARITY)
    #define VPB_MLOOP_FLASH		(1<<VPB_LOOP_FLASH)
    #define VPB_MDTMF_DOWN		(1<<VPB_DTMF_DOWN)
    #define VPB_MALL_EVENTS	        ((unsigned long)-1)

  //@} //}}}

    //! Enable the events specified by @a mask for @a handle.
    //
    //! Events not included in the @a mask are unaffected.
    int WINAPI vpb_enable_event(VPBPortHandle handle, unsigned long mask);

    //! Disable the events specified by @a mask for @a handle.
    //
    //! Events not included in the @a mask are unaffected.
    int WINAPI vpb_disable_event(VPBPortHandle handle, unsigned long mask);

    //! Return the current event mask for @a handle.
    unsigned long WINAPI vpb_get_event_mask(VPBPortHandle handle);

    //! Set the event mask for @a handle.
    int WINAPI vpb_set_event_mask(VPBPortHandle handle, unsigned long mask);

    //! Fetch the next event from the global event queue.
    //{{{
    //! This function will always return immediately whether there is an event
    //! on the queue or not.
    //!
    //! @param event The returned event from the queue, if any.
    //!
    //! @return @c VPB_OK if an event is returned, or @c VPB_NO_EVENTS if the
    //!         queue is currently empty.
    //!
    //! @note Reading events from the global queue does not clear them from the
    //!       port specific queues.  You should excercise caution if reading
    //!       them from both sources.
    //!
    //! @sa vpb_get_event_ch_async(), vpb_get_event_sync(), vpb_get_event_ch_sync()
    //}}}
    int WINAPI vpb_get_event_async(VPB_EVENT *event);

    //! Fetch the next event from a port specific event queue.
    //{{{
    //! This function will always return immediately whether there is an event
    //! on the queue or not.
    //!
    //! @param handle   The handle to the port of interest.
    //! @param event    The returned event from the queue.
    //!
    //! @return @c VPB_OK if an event is returned, or @c VPB_NO_EVENTS if the
    //!         queue is currently empty.
    //!
    //! @note Reading events from the port specific queues does not clear them
    //!       from the global queue.  You should excercise caution if reading
    //!       them from both sources.
    //!
    //! @sa vpb_get_event_async(), vpb_get_event_sync(), vpb_get_event_ch_sync()
    //}}}
    int WINAPI vpb_get_event_ch_async(VPBPortHandle handle, VPB_EVENT *event);

    //! Wait for an event on the global event queue.
    //{{{
    //! This function will return immediately if there is already an event on
    //! the queue, else it will block until one arrives or the time out expires.
    //!
    //! @param event    The returned event from the queue.
    //! @param time_out An optional maximum time to wait, in milliseconds.
    //!                 If the @a time_out is set to 0 this function will
    //!                 block indefinitely until an event arrives.
    //!
    //! @return @c VPB_OK if an event occurred, or @c VPB_TIME_OUT if @a time_out
    //!         elapsed with no event to return.
    //!
    //! @note Reading events from the global queue does not clear them from the
    //!       port specific queues.  You should excercise caution if reading
    //!       them from both sources.
    //!
    //! @sa vpb_get_event_ch_sync(), vpb_get_event_async(), vpb_get_event_ch_async()
    //}}}
    int WINAPI vpb_get_event_sync(VPB_EVENT *event, unsigned int time_out = 0);

    //! Wait for an event on a port specific event queue.
    //{{{
    //! This function will return immediately if there is already an event on
    //! the queue, else it will block until one arrives or the time out expires.
    //!
    //! @param handle   The handle to the port of interest.
    //! @param event    The returned event from the queue.
    //! @param time_out An optional maximum time to wait, in milliseconds.
    //!                 If the @a time_out is set to 0 this function will
    //!                 block indefinitely until an event arrives.
    //!
    //! @return @c VPB_OK if an event occurred, or @c VPB_TIME_OUT if @a time_out
    //!         elapsed with no event to return.
    //!
    //! @note Reading events from the port specific queues does not clear them
    //!       from the global queue.  You should excercise caution if reading
    //!       them from both sources.
    //!
    //! @sa vpb_get_event_sync(), vpb_get_event_async(), vpb_get_event_ch_async()
    //}}}
    int WINAPI vpb_get_event_ch_sync(VPBPortHandle handle, VPB_EVENT *event,
				     unsigned int time_out = 0);

    //! Places an @a event on the global and port specific event queues.
    int WINAPI vpb_put_event(VPB_EVENT *event);

    //! Converts a given @a event into a string describing it.
    //{{{
    //! @param event The event to process.
    //! @param str   The returned string.
    //!
    //! @note The precise form of the returned string should not be relied
    //!       upon and may change with time and different user locales.
    //!       It is intended for user friendly information reporting only.
    //}}}
    void WINAPI vpb_translate_event(VPB_EVENT *event, char *str);

    //! The callback function type for @c vpb_set_event_callback().
    typedef void (WINAPI *vpb_event_callback)(VPB_EVENT *e, void *context);

    //! Sets an event callback function to use instead of the @c APIQ.
    //{{{
    //! @param handle   The handle returned by a call to @c vpb_open().
    //! @param callback A pointer to the function to call, or @c NULL to
    //!                 disable the use of a callback for this port again.
    //! @param context  An optional pointer to user defined data that will be
    //!                 passed to the callback function.
    //!
    //! By default no event callback functions are set, and events are posted
    //!	to the API event queues.  If a callback is set using this function for
    //! some port, it will be called with the event as an argument instead of
    //! placing it in the queue.
    //!
    //! Any event which is @e processed after this function returns will be
    //! subject to the new callback state, however since events are buffered
    //! at the kernel driver level, this may also include some events that
    //! occurred before the call was made, but which had not been processed
    //! at that time.
    //!
    //! @note The @a context data, if any, and the @a callback function must
    //!       be prepared to begin accepting events, before this function is
    //!       called, and may be active when a call to change or remove the
    //!       @a callback is made.  They must remain valid until a call is made
    //!       to the new callback function, or until the next event has been
    //!       posted to the api queue in the event of callbacks being disabled.
    //!
    //! @todo Should this block until it is safe to release the @a context data
    //!       and/or the function definition itself?
    //}}}
    int WINAPI vpb_set_event_callback( VPBPortHandle handle,
				       vpb_event_callback callback,
				       void *context = NULL);

    //! Returns the number of events on the global event queue.
    int WINAPI vpb_get_event_count(void);

    //! Returns the number of events on the port specific event queue for @a handle.
    int WINAPI vpb_get_event_count_ch(VPBPortHandle handle);

    //! Clear all unread events from the queue for @a handle.
    void WINAPI vpb_flush_events(VPBPortHandle handle);

    //! Clear all unread events from the global event queue.
    void WINAPI vpb_flush_events();

//!@} //}}}


//! @defgroup Audio Audio play and record
//! @todo Add appropriate bits of the sgml documentation here.
//!@{
//{{{

    //! return code for @c vpb_play_buf_sync() and @c vpb_record_buf_sync().
    #define VPB_FINISH  1


    //! Port playback parameters
    struct VPB_PLAY
    {//{{{

	//! A string of @c DTMF digits that can terminate playback.
	const char *term_digits;

    }; //}}}

    //! Port recording parameters
    struct VPB_RECORD
    { //{{{

	//! A string of @c DTMF digits that can terminate recording.
	const char   *term_digits;

	//! Max @c ms to record for.  If @c 0, recording will not time out.
	unsigned int  time_out;

    }; //}}}


    //! Audio compression modes
    enum AudioCompress
    { //{{{

	VPB_LINEAR,     //!< 128 kbit/s 16 bit linear
	VPB_ALAW,       //!< 64 kbit/s A-law companded
	VPB_MULAW,      //!< 64 kbit/s mu-law companded
	VPB_OKIADPCM,   //!< 32 kbit/s OKI ADPCM
	VPB_OKIADPCM24, //!< 24 kbit/s OKI ADPCM
	VPB_RAW         //!< Raw data, no encoding

    }; //}}}

    //! play/record state flags
    enum AudioState
    { //{{{

	VPB_AUDIO_IDLE,           //!< No port audio playing
	VPB_AUDIO_PLAYING,        //!< Port audio play in progress
	VPB_AUDIO_RECORDING,      //!< Port audio record in progress
	VPB_AUDIO_TERMINATE,      //!< Async terminate requested
	VPB_AUDIO_TERMINATE_SYNC  //!< Sync terminate requested

    }; //}}}


  //! @name File playback
  //@{ //{{{

    //! Utility function to play a wav file to a port.
    //{{{
    //! This function will not return until playback has completed.
    //!
    //! @param handle     The handle of the port to play to.
    //! @param file_name  The path to the file to play.
    //!
    //! @return @c VPB_OK if playback completed ok.
    //! @exception various exceptions may be thrown if the file cannot be played.
    //}}}
    int WINAPI vpb_play_file_sync(VPBPortHandle handle, const std::string &file_name);

    //! Utility function to play a wav file to a port.
    //{{{
    //! This function returns as soon as playing has started.  It will post a
    //! @c VPB_PLAYEND event on the API event queue when playback has completed.
    //!
    //! @param handle     The handle of the port to play to.
    //! @param file_name  The path to the file to play.
    //! @param data       User defined data to include with the @c VPB_PLAYEND
    //!                   event.
    //!
    //! @return @c VPB_OK if playback was started ok.
    //! @exception various exceptions may be thrown if the file cannot be played.
    //}}}
    int WINAPI vpb_play_file_async(VPBPortHandle handle,
				   const std::string &file_name,
				   int data);

    int WINAPI vpb_play_voxfile_sync(int handle,
				     const std::string &file_name,
				     AudioCompress mode);
    int WINAPI vpb_play_voxfile_async(int handle,
				      const std::string &file_name,
				      AudioCompress mode,
				      int data);

  //@} //}}}

  //! @name Buffer playback
  //@{ //{{{

    //! Prepare and seize a port for playing audio from a buffer.
    //{{{
    //! If audio from a file is playing when this function is called it will
    //! be signalled to terminate.  This function will block until it does so,
    //! or until a previous call to @c vpb_play_buf_start has called
    //! @c vpb_play_buf_finish().
    //!
    //! @param handle The handle to the port to play audio on.
    //! @param mode   The compression mode the audio samples will use.
    //!
    //! @exception various exceptions may be thrown in the event of an error.
    //!
    //! @note You @b must call @c vpb_play_buf_finish() for @a handle when
    //!       you have finished sending audio data to the port.  Between these
    //!       calls you @b must @b not call any @c vpb_play_* function except
    //!       @c vpb_play_buf_sync() or @c vpb_play_buf_async().
    //}}}
    void WINAPI vpb_play_buf_start(VPBPortHandle handle, AudioCompress mode);

    //! %Play a buffer of audio samples to a port.
    //{{{
    //! This function will block until all of the samples in @a buf have been
    //! sent to the hardware driver.  For time critical applications that may
    //! perform some immediate action at the end of playback, it should be
    //! noted that playback will not have fully completed until those internal
    //! buffers have also been processed.  The size of the internal buffers is
    //! hardware dependent.
    //!
    //! @param handle The handle to the port to play audio on.
    //! @param buf    The buffer of samples to play.  It must be encoded
    //!               according to the mode that was specified the preceding
    //!               call to @c vpb_play_buf_start().
    //! @param len    The number of bytes in @a buf.
    //!
    //! @return @c VPB_FINISH if the port has been signalled to terminate
    //!         audio playback.  @c VPB_OK if @a buf was successfully output.
    //!
    //! @exception various exceptions may be thrown in the event of an error.
    //!
    //! @note You @b must call @c vpb_play_buf_start() before making calls to
    //!       this function and you @c must call @c vpb_play_buf_finish() after
    //!       the last buffer full of data has been sent.  This function may be
    //!       called any number of times between those two calls.
    //}}}
    int WINAPI vpb_play_buf_sync(VPBPortHandle handle, const char *buf, size_t len);

    //! %Play a buffer of audio samples to a port.
    //{{{
    //! This function will always return immediately.
    //!
    //! @param handle The handle to the port to play audio on.
    //! @param buf    The buffer of samples to play.  It must be encoded
    //!               according to the mode that was specified the preceding
    //!               call to @c vpb_play_buf_start().
    //! @param len    The number of bytes in @a buf.
    //!
    //! @return @c VPB_FINISH if the port has been signalled to terminate
    //!         audio playback, @c VPB_OK if @a buf was successfully output,
    //!         or @c -EAGAIN if there was insufficient space in the internal
    //!         buffers for @a len bytes to be sent immediately.
    //!
    //! @exception various exceptions may be thrown in the event of an error.
    //!
    //! @note You @b must call @c vpb_play_buf_start() before making calls to
    //!       this function and you @c must call @c vpb_play_buf_finish() after
    //!       the last buffer full of data has been sent.  This function may be
    //!       called any number of times between those two calls.
    //}}}
    int WINAPI vpb_play_buf_async(VPBPortHandle handle, const char *buf, size_t len);

    //! Signal completion of audio playback and release a port for other users.
    //{{{
    //! This function will return immediately, enabling a subsequent or pending
    //! call to @c vpb_play_buf_start() to begin.  The audio samples that were
    //! buffered prior to calling it may not yet have completed playing when it
    //! returns, but new samples will be able to be added to the buffers without
    //! further delay.
    //!
    //! The output may be padded up to the transfer frame size of the hardware
    //! transmitting it (20 - 40ms), so if you require precise timing of any
    //! subsequent samples to be played, you should not release the buffer until
    //! you really have finished with it and are prepared to relinquish it to
    //! another user for output.
    //!
    //! @param handle The handle to the port to complete playback on.
    //!
    //! @exception various exceptions may be thrown in the event of an error.
    //!
    //! @sa vpb_play_buf_finish_sync() if following actions will expect the
    //!     audio already buffered has played to completion.
    //}}}
    void WINAPI vpb_play_buf_finish(VPBPortHandle handle);

    //! Signal completion of audio playback and release a port for other users.
    //{{{
    //! This function will block until any audio remaining in the internal
    //! buffers has been played.
    //!
    //! @param handle The handle to the port to complete playback on.
    //!
    //! @exception various exceptions may be thrown in the event of an error.
    //!
    //! @sa vpb_play_buf_finish() if you do not need to wait for the audio
    //!     to complete, only to signal that no further samples are to be
    //!     transmitted.
    //}}}
    void WINAPI vpb_play_buf_finish_sync(VPBPortHandle handle);

  //@} //}}}

  //! @name Playback termination
  //@{ //{{{

    //! Stop audio playback.
    //{{{
    //! This function does nothing if no audio is currently playing.
    //! Otherwise it will flag the playback to stop as soon as possible
    //! and return immediately.
    //!
    //! @param handle  The handle to the port to cease playback on.
    //!
    //! @return @c VPB_OK if all went well.
    //!
    //! @exception various exceptions may be thrown if things do not go well.
    //!
    //! @sa @c vpb_play_terminate_sync() if you require the audio to have
    //!     definitely ceased playing before proceeding with other operations.
    //}}}
    int WINAPI vpb_play_terminate(int handle);

    //! Stop audio playback.
    //{{{
    //! This function does nothing if no audio is currently playing.
    //! Otherwise it will flag the playback to stop and block until it actually
    //! ceases before returning.
    //!
    //! @param handle  The handle to the port to cease playback on.
    //!
    //! @return @c VPB_OK if all went well.
    //!
    //! @exception various exceptions may be thrown if things do not go well.
    //!
    //! @sa @c vpb_play_terminate() if you do not need to wait for the audio
    //!     to actually cease playing, but only need to signal it to do so.
    //}}}
    int WINAPI vpb_play_terminate_sync(int handle);

  //@} //}}}

  //! @name Playback configuration
  //@{ //{{{

    //! Set playback parameters for a port.
    void WINAPI vpb_play_set(VPBPortHandle handle, const VPB_PLAY &vpb_play);

    inline void WINAPI vpb_play_set(VPBPortHandle handle, const VPB_PLAY *vpb_play)
    { //{{{
	vpb_play_set(handle, *vpb_play);
    } //}}}

    //! Return the current play state of a port.
    //{{{
    //! @param handle The handle to the port to check.
    //! @note The real state of the port may already have changed again by the
    //!       time this function has returned.  Any subsequent code should not
    //!       depend upon this value being correct and must be well behaved
    //!       whatever the real state of the port may be.
    //}}}
    AudioState WINAPI vpb_play_state(int handle);

    //! Set the software play gain component for a port.
    //{{{
    //! This gain will be applied to digital audio data that is sent from
    //! the host PC for output to a hardware port.  The @c vpb_play_file* and
    //! @c vpb_play_buf* functions scale their data according to this level.
    //!
    //! @param handle The handle to the port to adjust.
    //! @param gain   The software gain in @c dB.
    //! @exception VpbException may be thrown if @a handle or @a gain is invalid.
    //}}}
    void WINAPI vpb_play_set_gain(VPBPortHandle handle, float gain);

    //! Return the software play gain for a port.
    float WINAPI vpb_play_get_gain(VPBPortHandle handle);
    inline void WINAPI vpb_play_get_gain(VPBPortHandle handle, float *gain)
    { //{{{
	*gain = vpb_play_get_gain(handle);
    } //}}}

    //! Set the hardware play gain component for a port.
    //{{{
    //! This should be set to match the line reqirements of the device that
    //! is connected to the port.  It should not be used as a general purpose
    //! volume control.  In most cases, the defalt hardware gains should not
    //! need to be adjusted.
    //!
    //! @param handle The handle to the port to adjust.
    //! @param gain   The hardware gain value.  <tt>-12.0 < @a gain < 12.0</tt>
    //! @exception VpbException will be thrown in the event of an error.
    //}}}
    void WINAPI vpb_play_set_hw_gain(VPBPortHandle handle, float gain);

    //! Return the hardware play gain for a port.
    float WINAPI vpb_play_get_hw_gain(VPBPortHandle handle);

  //@} //}}}


  //! @name File recording
  //@{ //{{{

    //! Utility function to record a wav file from a port.
    //{{{
    //! This function will not return until recording has completed.
    //!
    //! @param handle     The handle of the port to record from.
    //! @param file_name  The path to the file to save wav data in.
    //!
    //! @return @c VPB_OK if recording completed ok.
    //! @exception various exceptions may be thrown if the file cannot be
    //!                    recorded.
    //}}}
    int WINAPI vpb_record_file_sync(VPBPortHandle handle,
				    const std::string &file_name,
				    AudioCompress mode);

    //! Utility function to record a wav file from a port.
    //{{{
    //! This function returns as soon as recording has started.  It will post
    //! a @c VPB_RECORDEND event on the API event queue when recording has
    //! completed.
    //!
    //! @param handle     The handle of the port to record from.
    //! @param file_name  The path to the file to save wav data in.
    //! @param mode       The file compression mode to use.
    //!
    //! @return @c VPB_OK if recording was started ok.
    //! @exception various exceptions may be thrown if the file cannot be
    //!                    recorded.
    //}}}
    int WINAPI vpb_record_file_async(VPBPortHandle handle,
				     const std::string &file_name,
				     AudioCompress mode);

    int WINAPI vpb_record_voxfile_sync(int handle,
				       const std::string &file_name,
				       AudioCompress mode);
    int WINAPI vpb_record_voxfile_async(int handle,
					const std::string &file_name,
					AudioCompress mode);

  //@} //}}}

  //! @name Buffer recording
  //@{ //{{{

    //! Prepare and seize a port for recording audio from a buffer.
    //{{{
    //! If audio from a file is recording when this function is called it will
    //! be signalled to terminate.  This function will block until it does so,
    //! or until a previous call to @c vpb_record_buf_start has called
    //! @c vpb_record_buf_finish().
    //!
    //! @param handle The handle to the port to record audio from.
    //! @param mode   The audio compression mode to use.
    //!
    //! @exception various exceptions may be thrown in the event of an error.
    //! @note You @b must call @c vpb_record_buf_finish() for @a handle when
    //!       you have finished recording audio data from the port.  Between
    //!       these calls you @b must @b not call any @c vpb_record_* function
    //!       except @c vpb_record_buf_sync() or @c vpb_record_buf_async().
    //}}}
    void WINAPI vpb_record_buf_start(VPBPortHandle handle, AudioCompress mode);

    //! Record a buffer of audio samples from a port.
    //{{{
    //! This function will block until @a buf has been filled by the hardware
    //! driver.
    //!
    //! @param handle The handle to the port to record audio from.
    //! @param buf    A pointer to storage for the recorded samples.
    //! @param len    The number of bytes to store in @a buf.
    //!
    //! @return @c VPB_FINISH if the port has been signalled to terminate
    //!         audio recording, or if the @c VPB_RECORD time out has elapsed.
    //!         @c VPB_OK if @a buf was successfully filled.
    //!
    //! @exception various exceptions may be thrown in the event of an error.
    //!
    //! @note You @b must call @c vpb_record_buf_start() before making calls to
    //!       this function and you @c must call @c vpb_record_buf_finish()
    //!       after the last buffer full of data has been read.  This function
    //!       may be called any number of times between those two calls.
    //}}}
    int WINAPI vpb_record_buf_sync(VPBPortHandle handle, char *buf, size_t len);

    //! Record a buffer of audio samples from a port.
    //{{{
    //! This function will always return immediately.
    //!
    //! @param handle The handle to the port to record audio from.
    //! @param buf    A pointer to storage for the recorded samples.
    //! @param len    The number of bytes to store in @a buf.
    //!
    //! @return @c VPB_FINISH if the port has been signalled to terminate
    //!         audio recording, or if the @c VPB_RECORD time out has elapsed.
    //!         @c VPB_OK if @a buf was successfully filled.
    //!         @c -EAGAIN if there was insufficient data in the internal
    //!         buffers for @a len bytes to be read immediately.
    //!
    //! @exception various exceptions may be thrown in the event of an error.
    //!
    //! @note You @b must call @c vpb_record_buf_start() before making calls to
    //!       this function and you @c must call @c vpb_record_buf_finish()
    //!       after the last buffer full of data has been read.  This function
    //!       may be called any number of times between those two calls.
    //}}}
    int WINAPI vpb_record_buf_async(VPBPortHandle handle, char *buf, size_t len);

    //! Signal completion of audio recording and release a port for other users.
    //{{{
    //! @param handle The handle to the port to complete recording on.
    //! @exception various exceptions may be thrown in the event of an error.
    //}}}
    void WINAPI vpb_record_buf_finish(VPBPortHandle handle);

  //@} //}}}

  //! @name Recording termination
  //@{ //{{{

    //! Stop audio recording.
    //{{{
    //! This function does nothing if no audio is currently being recorded.
    //! Otherwise it will flag the recording to stop as soon as possible
    //! and return immediately.
    //!
    //! @param handle  The handle to the port to cease recording on.
    //!
    //! @return @c VPB_OK if all went well.
    //!
    //! @exception various exceptions may be thrown if things do not go well.
    //!
    //! @sa @c vpb_record_terminate_sync() if you require the audio to have
    //!     definitely ceased recording before proceeding with other operations.
    //}}}
    int WINAPI vpb_record_terminate(int handle);

    //! Stop audio recording.
    //{{{
    //! This function does nothing if no audio is currently being recorded.
    //! Otherwise it will flag the recording to stop and block until it
    //! actually ceases before returning.
    //!
    //! @param handle  The handle to the port to cease recording on.
    //!
    //! @return @c VPB_OK if all went well.
    //!
    //! @exception various exceptions may be thrown if things do not go well.
    //!
    //! @sa @c vpb_record_terminate() if you do not need to wait for the audio
    //!     to actually cease recording, but only need to signal it to do so.
    //}}}
    int WINAPI vpb_record_terminate_sync(int handle);

  //@} //}}}

  //! @name Recording configuration
  //@{ //{{{

    //! Set recording parameters for a port.
    void WINAPI vpb_record_set(VPBPortHandle handle, const VPB_RECORD &vpb_record);

    inline void WINAPI vpb_record_set(VPBPortHandle handle, const VPB_RECORD *vpb_record)
    { //{{{
	vpb_record_set(handle, *vpb_record);
    } //}}}

    //! Return the current record state of a port.
    //{{{
    //! @param handle The handle to the port to check.
    //! @note The real state of the port may already have changed again by the
    //!       time this function has returned.  Any subsequent code should not
    //!       depend upon this value being correct and must be well behaved
    //!       whatever the real state of the port may be.
    //}}}
    AudioState WINAPI vpb_record_state(int handle);

    //! Set the software record gain component for a port.
    //{{{
    //! This gain will be applied to digital audio data that is received by
    //! the host PC from a hardware port.  The @c vpb_record_file* and
    //! @c vpb_record_buf* functions scale their data according to this level.
    //!
    //! @param handle The handle to the port to adjust.
    //! @param gain   The software gain in @c dB.
    //! @exception VpbException may be thrown if @a handle or @a gain is invalid.
    //}}}
    void WINAPI vpb_record_set_gain(VPBPortHandle handle, float gain);

    //! Return the software record gain for a port.
    float WINAPI vpb_record_get_gain(VPBPortHandle handle);
    inline void WINAPI vpb_record_get_gain(VPBPortHandle handle, float *gain)
    { //{{{
	*gain = vpb_record_get_gain(handle);
    } //}}}

    //! Set the hardware record gain component for a port.
    //{{{
    //! This should be set to match the line conditions presented by the device
    //! connected to the port.  It should not be used as a general purpose
    //! volume control.  In most cases, the defalt hardware gains should not
    //! need to be adjusted.
    //! @param handle The handle to the port to adjust.
    //! @param gain   The hardware gain value.  <tt>-12.0 < @a gain < 12.0</tt>
    //! @exception VpbException will be thrown in the event of an error.
    //}}}
    void WINAPI vpb_record_set_hw_gain(VPBPortHandle handle, float gain);

    //! Return the hardware record gain for a port.
    float WINAPI vpb_record_get_hw_gain(VPBPortHandle handle);

  //@} //}}}


    // record terminating reason outputed during a vpb_record_???_async() in 
    // the data member of the VPBevents

    #define VPB_RECORD_DIGIT       1    // terminated due to Digit String
    #define VPB_RECORD_TIMEOUT     2    // terminated due to record timeout
    #define VPB_RECORD_ENDOFDATA   3    // terminate due to end of data in buffer
    #define VPB_RECORD_MAXDIGIT    4    // terminate due to Maximum digits

//!@} //}}}


//! @defgroup ErrorHandling Error handling
//! @todo Add appropriate bits of the sgml documentation here.
//!@{
//{{{

    //! VPB api runtime exception type
    class VpbException : public std::exception
    { //{{{
    private:

	std::string  m_msg;


    public:

	//! Construct an exception object with a @c printf format message string.
	VpbException(const char *format, ...) __attribute__((format(printf,2,3)));

	//! Destructor.
	~VpbException() throw() {};


      //! @name Error summary
      //@{

	//! Return the message associated with the exception.
	const char *what() const throw()
	{ //{{{
		return m_msg.empty() ? "Unspecified VpbException"
				     : m_msg.c_str();
	} //}}}

      //@}

    }; //}}}


    //! Specify a function to handle @c mprintf() logging output.
    void WINAPI vpb_set_mprintf(void (*func)(const char *format, ...));


    //! @name Run time error manager modes
    //@{
	//! API function error causes program abort. <b>DON'T USE THIS</b>.
	const int VPB_DEVELOPMENT = 0;

	//! API function error returns error code. <b>DON'T USE THIS</b>.
	const int VPB_ERROR_CODE  = 1;

	//! API function error throws a exception
	const int VPB_EXCEPTION   = 2;
    //@}

    // This is deprecated because it does exactly what the VPB_EXCEPTION mode
    // will do to an uncaught exception, except give you the chance to recover
    // when you know you can catch it.  Mostly that's just annoying and will
    // destroy clues useful when debugging.
    VT_DEPRECATED( extern const int VPB_DEVELOPMENT );

    // This is deprecated because there are a few api functions with valid
    // return values that are indistinguishable from an error code.  It's
    // also a mode that lets people write code that does not check for error
    // states, leading to 'mysterious' problems later down the track.  So if
    // you have to already be prepared for exceptions some of the time, and
    // using them all of the time means errors will always be flagged where
    // they really happen, even in places where you figured they wouldn't...
    // then this mode is also just going to make your life harder than it
    // really needs to be.
    VT_DEPRECATED( extern const int VPB_ERROR_CODE );

    // This is deprecated because the only mode that is really safe and useful
    // is already the default.  So if you are changing it, that's probably not
    // what you really want to be doing (anymore).
    //
    // Control the way RunTimeError() handles errors.
    VT_DEPRECATED( int WINAPI vpb_seterrormode(int mode) );

//!@} //}}}


//! @defgroup Dialling Dialling
//!@{
//{{{

    // blind dialling functions

    //! Dials a string of digits on the port for @a handle.
    //{{{
    //! This function will not return until the full string has been dialled.
    //! For channel types that support out of band dialling, and are in a
    //! suitable state to do so, that mechanism will be used to send the dial
    //! string, otherwise @c DTMF tones will be used for signalling.
    //! @param handle  The handle to the port to dial on.
    //! @param dialstr The string of digits to dial.
    //! @par Valid digits
    //! The set of @c DTMF digits is represented by the following characters
    //! in a dial string:
    //! - <tt>0 1 2 3 4 5 6 7 8 9 * # A B C D</tt>
    //! @par
    //! In addition the following characters may also be used in a dial string:
    //! - @c & - Send a hook flash
    //! - @c , - (comma) Pause dialling for 1 second
    //! @sa @c vpb_settone() which permits additional user defined characters
    //!     to be associated with tones and subsequently included in @a dialstr.
    //! @return @c VPB_OK if all goes well.
    //! @exception various exceptions may be thrown in the event of an error.
    //}}}
    int WINAPI vpb_dial_sync(int handle, const std::string &dialstr);

    //! Dials a string of digits on the port for @a handle.
    //{{{
    //! This function will return immediately.  A @c VPB_DIALEND event will
    //! be sent for @a handle when dialling has completed on the port.
    //! For channel types that support out of band dialling, and are in a
    //! suitable state to do so, that mechanism will be used to send the dial
    //! string, otherwise @c DTMF tones will be used for signalling.
    //! @param handle  The handle to the port to dial on.
    //! @param dialstr The string of digits to dial.
    //! @par Valid digits
    //! The set of @c DTMF digits is represented by the following characters
    //! in a dial string:
    //! - <tt>0 1 2 3 4 5 6 7 8 9 * # A B C D</tt>
    //! @par
    //! In addition the following characters may also be used in a dial string:
    //! - @c & - Send a hook flash
    //! - @c , - (comma) Pause dialling for 1 second
    //! @sa @c vpb_settone() which permits additional user defined characters
    //!     to be associated with tones and subsequently included in @a dialstr.
    //! @return @c VPB_OK if all goes well.
    //! @exception various exceptions may be thrown in the event of an error.
    //}}}
    int WINAPI vpb_dial_async(int handle, const std::string &dialstr);

    // Call progress tone ids

    #define VPB_CALL_DISCONNECT	0
    #define VPB_CALL_DIALTONE	1
    #define VPB_CALL_RINGBACK	2
    #define VPB_CALL_BUSY	3
    #define VPB_CALL_GRUNT	4

    typedef struct {
	    unsigned int	tone_id;	// tone detector tone id
	    unsigned int	call_id;	// call progress tone id
	    unsigned int	terminate;	// non zero to terminate list
    } VPB_TONE_MAP;

    #define VPB_MAX_TONE_MAP	10	// maximum number of entries in tone map

    // structure used to store call progress config information

    typedef struct {
      unsigned int	dialtones;		// number of dialtones (eg internal line,
					    // then outside line = 2 dialtones)
      unsigned int	dialtone_timeout;	// wait for dial tone timeout in ms
      unsigned int	ringback_timeout;	// wait for initial ringback in ms
      unsigned int	inter_ringback_timeout;	// if ringback stops for this time (ms),
					    // call is considered connected
      unsigned int	answer_timeout;		// time to wait for answer after ringback
					    // detected in ms
      VPB_TONE_MAP	tone_map[VPB_MAX_TONE_MAP];// maps tone_id to call progress tone
    } VPB_CALL;

    // getting and setting call progress configuration

    int WINAPI vpb_get_call(int handle, VPB_CALL *vpb_call);
    int WINAPI vpb_set_call(int handle, VPB_CALL *vpb_call);

    // call progress return codes

    #define VPB_CALL_CONNECTED		0	 // call connected successfully
    #define VPB_CALL_NO_DIAL_TONE	1	 // dial tone time out
    #define VPB_CALL_NO_RING_BACK	2	 // ring back time out
    //#define VPB_CALL_BUSY		3	 // busy tone - defined else where
    #define VPB_CALL_NO_ANSWER		4	 // no answer time out
    #define VPB_CALL_DISCONNECTED	5	 // no answer time out

    // dialling with call progress

    int WINAPI vpb_call_sync(int handle, char *dialstr);
    int WINAPI vpb_call_async(int handle, char *dialstr);
    int WINAPI vpb_call_async_jp(int handle, char *dialstr);
    int WINAPI vpb_call_sync_jp(int handle, char *dialstr);

//!@} //}}}


//! @defgroup ToneGen Programmable tone generator
//! @todo Add appropriate bits of the sgml documentation here.
//!@{
//{{{

    //! Symbolic identifiers for predefined, localised tones.
    enum VPB_TONE_ID
    { //{{{
	VPB_TONE_DIAL,          //!< Normal dial tone.
	VPB_TONE_RINGING,       //!< Normal ringing tone.
	VPB_TONE_BUSY,          //!< Called number busy tone.
	VPB_TONE_CONGESTION,    //!< Network congestion tone.
	VPB_TONE_UNOBTAINABLE,  //!< Invalid number signal.
	VPB_TONE_CALLWAITING,   //!< Call waiting signal.
	VPB_TONE_STUTTERDIAL,   //!< Voicemail pending signal.

	VPB_TONE_ID_MAX         //!< Indicates the number of defined tone id's.
    }; //}}}

    //! Tone definition structure
    //{{{
    /*! This structure is used to define tone data for the programmable tone
	generator.

	For example:
	@code
	// A single continuous tone
	VPB_TONE au_dial  = { 400, 425, 450, -13, -13, -13, 0, 0, NULL };

	// A two cadence continuous tone
	VPB_TONE au_ring2 = { 400, 425, 450, -13, -13, 0, 400, 2000, &au_ring2 };
	VPB_TONE au_ring  = { 400, 425, 450, -13, -13, 0, 400,  200, &au_ring2 };

	// A three tone one-shot sequence
	VPB_TONE us_sit2  = { 1800, 0, 0, -13, 0, 0, 330, 0, NULL };
	VPB_TONE us_sit1  = { 1400, 0, 0, -13, 0, 0, 330, 0, &us_sit2 };
	VPB_TONE us_sit   = {  950, 0, 0, -13, 0, 0, 330, 0, &us_sit1 };

	vpb_playtone_sync(h, au_dial);
	vpb_playtone_sync(h, au_ring);
	vpb_playtone_sync(h, us_sit);
	@endcode
    */ //}}}
    struct VPB_TONE
    { //{{{

	unsigned short	freq1;	//!< frequency of first tone in @c Hz
	unsigned short	freq2;	//!< frequency of second tone in @c Hz
	unsigned short	freq3;	//!< frequency of third tone in @c Hz
	float		level1;	//!< first tone level in dB, @c -inf to @c 0dB
	float		level2;	//!< second tone level in dB, @c -inf to @c 0dB
	float		level3;	//!< third tone level in dB, @c -inf to @c 0dB
	unsigned long	ton;	//!< on time in @c ms, if 0 tone is continuous
	unsigned long	toff;	//!< off time in @c ms 

	//! Pointer to the next tone in a sequence.
	//{{{
	//! For tone sequences this field should should point to the next tone
	//! definition in the sequence.  It should be @c NULL for a single tone
	//! and for the last tone in a one-shot sequence of tones.  As a special
	//! case for the last tone of a sequence, if this field points to the
	//! object that contains it then the whole sequence will be continuously
	//! repeated until explicitly terminated by the user application.
	//}}}
	VPB_TONE       *next;

    }; //}}}

  //! @name Tone generation
  //@{ //{{{

    //! Start a user defined tone playing and return immediately.
    int WINAPI vpb_playtone_async(int handle, const VPB_TONE &vpb_tone);

    //! Start a user defined tone playing and return immediately.
    int WINAPI vpb_playtone_async(int handle, const VPB_TONE *vpb_tone);

    //! Start a locale specific predefined tone playing and return immediately.
    int WINAPI vpb_playtone_async(int handle, VPB_TONE_ID tone_id);

    //! %Play a user defined tone, return when playback completes.
    int WINAPI vpb_playtone_sync(int handle, const VPB_TONE &vpb_tone);

    //! %Play a user defined tone, return when playback completes.
    int WINAPI vpb_playtone_sync(int handle, const VPB_TONE *vpb_tone);

    //! %Play a locale specific predefined tone, return when playback completes.
    int WINAPI vpb_playtone_sync(int handle, VPB_TONE_ID tone_id);

    //! Terminate a currently playing tone (user defined or dtmf).
    //{{{
    //! @param handle The handle of the port to stop tone playback for.
    //! @return @c VPB_OK if all went well.
    //! @exception various exceptions may be thrown if things go badly.
    //! @note No completion notification will be sent for tones that are
    //!       explicitly terminated using this function.
    //}}}
    int WINAPI vpb_tone_terminate(int handle);

  //@} //}}}

  //! @name Dial string aliases
  //@{ //{{{

    //! Enables user to (re)define the tone associated with a dial string character.
    //{{{
    //! @param ident The dial string character to use for this tone.
    //! @param tone  The @c VPB_TONE structure that defines this tone.
    //!
    //! Any occurrence of @a ident in a dial string sent via @c vpb_dial_sync()
    //! or similar functions will subsequently use the @a tone defined here.
    //!
    //! @return @c VPB_OK if all went well.
    //! @exception various exceptions may be thrown in the event of error.
    //!
    //! @note This must be called @b after @c vpb_open() if you wish to redefine
    //!       the default tones, else your settings for those will be overwritten.
    //}}}
    int WINAPI vpb_settone(char ident, const VPB_TONE *tone);

    //! Get the parameters of the @a tone represented in dial strings by @a ident.
    //{{{
    //! @param ident The dial string character to retrieve tone data for.
    //! @param tone  The returned @c VPB_TONE parameters for @a ident.
    //! @return @c VPB_OK if all went well.
    //! @exception various exceptions may be thrown in the event of error.
    //}}}
    int WINAPI vpb_gettone(char ident, VPB_TONE *tone);

  //@} //}}}

    //! Returns state of play tone (1= playing, 0 = not playing)
    //{{{
    //! @warning It is dangerous to rely on the value returned by this method
    //!          except as an unreliable hint, the state of the tone generator
    //!          may have already changed again by the time it returns.  Any
    //!          following code should be well behaved whatever the state of
    //!          the tone generator really is.
    //! @deprecated This method may be removed in future releases.
    //}}}
    int WINAPI vpb_playtone_state(int handle);

//!@} //}}}


//! @defgroup ToneDet Programmable tone detector
//! @brief More information on the libvpb programmable tone detector is
//!        available @ref ToneDetect "here".
//!@{
//{{{

  //! @name General limits
  //@{

    #define VPB_MD  10  //!< The maximum number of tone detectors per device.
    #define VPB_MS  10  //!< The maximum number of cadence states to match.

  //@}


    //! Tone detector state transition types
    enum ToneStateTransition
    { //{{{

	VPB_TIMER   = 0,
	VPB_RISING  = 1,
	VPB_FALLING = 2,
	VPB_DELAY   = 3

    }; //}}}

    //! Cadence state transition data for @c VPB_DETECT.
    struct VPB_STRAN
    { //{{{

        // NB: The 'type' field here is ostensibly a ToneStateTransition value
        //     however it is assumed elsewhere to be a 16bit value, so we must
        //     preserve the size of this structure over type safety for now.

	uint16_t  type;  //!< @c VPB_TIMER, @c VPB_RISING, or @c VPB_FALLING
	uint16_t  tfire; //!< timer mode only			
	uint16_t  tmin;  //!< minimum tone on/off time (non timer) in ms
	uint16_t  tmax;  //!< maximum tone on/off time (non timer) in ms

    }; //}}}

    //! Container for programmable tone detector parameters.
    struct VPB_DETECT
    { //{{{

       uint16_t	 nstates;	//!< number of cadence states
       uint16_t	 tone_id;	//!< unique ID number for this tone
       uint16_t	 ntones;	//!< number of tones (1 or 2)
       uint16_t	 freq1;		//!< freq of first tone (Hz)
       uint16_t	 bandwidth1;	//!< bandwidth of first tone (Hz)
       uint16_t	 freq2;		//!< freq of first tone (Hz)
       uint16_t  bandwidth2;	//!< bandwidth of second tone (Hz)
       int16_t   minlevel1;	//!< min amp of 1st tone ref 0dBm0
       int16_t   minlevel2;	//!< min amp of 2nd tone ref 0dbm0
       int16_t   twist;		//!< @brief Allowable difference in tone powers
				//!
				//! If (E1/E2 < twist) AND (E2/E1 < twist),
				//! the tone is OK.
       int16_t   snr;		//!< min signal to noise ratio to accept tone
       uint16_t  glitch;        //!< short transitions of glitch ms ignored

       VPB_STRAN stran[VPB_MS]; //!< cadence state transition table

    }; //}}}

  //! @name Built in tone dectector ID's
  //@{

    #define VPB_DIAL		0   //!< dial tone detected (US/Aust/sudio308)
    #define VPB_RINGBACK	1   //!< ringback detected  (US)
    #define VPB_BUSY		2   //!< busy tone detected (US)
    #define VPB_GRUNT		3   //!< grunt detected
    #define VPB_RINGBACK_308	4   //!< ringback detected (studio 308)
    #define VPB_BUSY_308	5   //!< busy tone detected (studio 308)
    #define VPB_FAX		6   //!< fax CNG tone/preamble
    #define VPB_BUSY_AUST	7   //!< busy/disconnect tone detected (Australia)
    #define VPB_RINGBACK_AUS	8   //!< ringback detected (Australia)
    #define VPB_SPARE9		9   //!< Spare

  //@}

  //! @name Tone masks
  //@{

    #define VPB_MDIAL		(1<<VPB_DIAL)
    #define VPB_MRINGBACK	(1<<VPB_RINGBACK)
    #define VPB_MBUSY		(1<<VPB_BUSY)
    #define VPB_MGRUNT		(1<<VPB_GRUNT)
    #define VPB_MRINGBACK_308	(1<<VPB_RINGBACK_308)
    #define VPB_MBUSY_308	(1<<VPB_BUSY_308)
    #define VPB_MFAX		(1<<VPB_FAX)
    #define VPB_MBUSY_AUST	(1<<VPB_BUSY_AUST)
    #define VPB_MRINGBACK_AUS	(1<<VPB_RINGBACK_AUS)
    #define VPB_MSPARE9		(1<<VPB_SPARE9)
    #define VPB_MALL_TONES	((unsigned long)-1)

  //@}


    //! Set or change the parameters for a tone to detect on some port.
    void WINAPI vpb_settonedet(VPBPortHandle handle, const VPB_DETECT &d);
    // XXX Compatibility function ... may be deprecated later.
    inline void WINAPI vpb_settonedet(VPBPortHandle handle, const VPB_DETECT *d)
    { //{{{
        vpb_settonedet(handle, *d);
    } //}}}

    void WINAPI vpb_gettonedet(VPBPortHandle handle, int id, VPB_DETECT *d);

    //! Revove a tone detector from some port.
    void WINAPI vpb_deltonedet(VPBPortHandle handle, const VPB_DETECT &d);
    // XXX Compatibility function ... may be deprecated later.
    inline void WINAPI vpb_deltonedet(VPBPortHandle handle, const VPB_DETECT *d)
    { //{{{
        vpb_deltonedet(handle, *d);
    } //}}}


    int WINAPI vpb_debug_tonedet(VPBPortHandle handle, int id, char file_name[], int sec);
    //int WINAPI vpb_tonedet_make_default(VPB_DETECT *d);

    //! Enable the @c TONE events specified by @a mask for @a handle.
    //
    //! Events not included in the @a mask are unaffected.
    int WINAPI vpb_enable_tone_event(VPBPortHandle handle, unsigned long mask);

    //! Disable the @c TONE events specified by @a mask for @a handle.
    //
    //! Events not included in the @a mask are unaffected.
    int WINAPI vpb_disable_tone_event(VPBPortHandle handle, unsigned long mask);

    //! Return the current @c TONE event mask for @a handle.
    unsigned long WINAPI vpb_get_tone_event_mask(VPBPortHandle handle);

    //! Set the @c TONE event mask.  The previous mask value will be overwritten.
    int WINAPI vpb_set_tone_event_mask(VPBPortHandle handle, unsigned long mask);

//!@} //}}}


//! @defgroup Timers Timer functions
//! @todo Add appropriate bits of the sgml documentation here.
//!@{
//{{{

    int WINAPI vpb_timer_open(void **timer, int handle, int id, unsigned long period);
    int WINAPI vpb_timer_close(void *timer);
    int WINAPI vpb_timer_start(void *timer);
    int WINAPI vpb_timer_stop(void *timer);
    int WINAPI vpb_timer_restart(void *timer);
    int WINAPI vpb_timer_get_unique_timer_id();
    int WINAPI vpb_timer_change_period(void *timer, unsigned long newperiod);

    //! Put the current thread to sleep for some number of milliseconds.
    void WINAPI vpb_sleep(long time_ms);

//!@} //}}}


//! @defgroup I18N Locale selection
//! @sa @ref L10N
//!@{
//{{{

    //! Container type for country specific data.
    struct Country
    { //{{{
	//! Container type for a list of pointers to @c %Country structures.
	typedef std::vector<const Country*>     List;

	const char *name;           //!< Country name.
	int         code;           //!< Country code.

	int         ring_cadence;   //!< Default ring cadence.

	uint16_t    flash_time;     //!< Generated hook flash time in @c ms.
	uint16_t    flash_min;      //!< Min valid hook flash time in @c ms.
	uint16_t    flash_max;      //!< Max valid hook flash time in @c ms.

	uint16_t    lv_onhook;      //!< On hook voltage threshhold in @c V.
	uint16_t    lv_offhook;     //!< Off hook voltage threshhold in @c V.

	uint16_t    drop_time;      //!< Generated loop drop time in @c ms.
	uint16_t    drop_min;       //!< Min valid loop drop time in @c ms.
	uint16_t    drop_max;       //!< Max valid loop drop time in @c ms.

	double      fsk_mark;       //!< Coefficient for cid generation.
	double      fsk_space;      //!< Coefficient for cid generation.

	VPB_TONE   *tone_gen;       //!< Pointer to an array of @c VPB_TONE_ID_MAX tones.
    }; //}}}

    //! Set the global default country specific information.
    //
    //! This data will be used for ports that have not had their country data
    //! set individually.  If @a country is @c NULL it will restore the initial
    //! hardcoded default country settings (ie. <tt>AUSTRALIA</tt>).
    void WINAPI vpb_set_country(const Country *country);

    //! Set the country specific information for an individual port.
    //
    //! This will override the default country data for @a handle. If @a country
    //! is @c NULL, then @a handle will revert to using the global default data.
    int WINAPI vpb_set_country(VPBPortHandle handle, const Country *country);

    //! Get the current country data for port @a handle.
    const Country* WINAPI vpb_get_port_country(VPBPortHandle handle);

    //! Get country specific data by name.
    //
    //! @param name A country name from the list @ref STDElec "here".
    //! @return @c NULL if @a name is not a pre-defined country name.
    const Country* WINAPI vpb_get_country_data(const std::string &name);

    //! @brief Get country specific data by numeric country code.
    //
    //! @param code The ITU-T numeric country calling code.  A comprehensive
    //!             list of the numeric country codes is available here:
    //!             http://wikipedia.org/wiki/List_of_country_calling_codes
    //!
    //! @return @c NULL if @a code is not a pre-defined numeric country code.
    const Country* WINAPI vpb_get_country_data(int code);

//!@} //}}}


/*-------------------------------------------------------------------------*\

				VOX

\*-------------------------------------------------------------------------*/

typedef struct {
   float		onlevel;  // switch on level in dB (0 dB maximum)
   float		offlevel; // switch off level in dB (0 dB maximum)
   unsigned short 	runon;	  // run on time in ms
} VPB_VOX;

int WINAPI vpb_setvox(int handle, VPB_VOX *vox);
int WINAPI vpb_getvox(int handle, VPB_VOX *vox);

/*-------------------------------------------------------------------------*\

			ADPCM CONVERSION FUNCTIONS

\*-------------------------------------------------------------------------*/

int  WINAPI vpb_adpcm_open(void **adpcm);
void WINAPI vpb_adpcm_reset(void *adpcm);
void WINAPI vpb_adpcm_close(void *adpcm);
int  WINAPI vpb_adpcm_encode(void  *adpcm,
			    char  adpcmbuf[],   unsigned short *nadpcmbytes,
			    short linearbuf[],  unsigned short nlinear);
int  WINAPI vpb_adpcm_decode(void  *adpcm,
			    short linearbuf[],  unsigned short *nlinear,
			    char  adpcmbuf[] ,  unsigned short nadpcmbytes);


//! @defgroup WavAudio Wav audio support
//! @todo Add appropriate bits of the sgml documentation here.
//!@{
//{{{

    //! May be added to the Wave file mode to include a @c VPB_VLOG chunk when recording.
    #define VPB_VLOG_CHUNK	0x4000

    //! Additional data that may be included in a wav file.
    struct VPB_VLOG
    { //{{{
	short	channel;        //!< Channel number
	char	inout[4];       //!< Call Direction
	char	statime[16];    //!< Record Start Time yyyymmddHHMMSS
	char	endtime[16];    //!< Record End Time yyyymmddHHMMSS
	char	filename[256];  //!< Original Filename
	char	cidn[128];      //!< CID number ascii
	char	cidt[128];      //!< CID TEXT ascii
	char	term[64];       //!< Termination reason TEXT ascii
    }; //}}}

    struct WFILE;


  //! @name Wave file output
  //@{ //{{{

    //! Open a @c RIFF wave file for writing.
    //{{{
    //! @param wav      Pointer to a pointer where encoding state may be stored.
    //!                 This pointer should be passed to other @c vpb_wave_*
    //!                 functions that will operate on the opened file.
    //! @param filename The full path to the file to write.
    //! @param mode     The @c AudioCompress mode to use for the file.  It may
    //!                 optionally be or'd with @c VPB_VLOG_CHUNK to record
    //!                 additional data in the wav file headers.
    //!
    //! @exception various exceptions may be thrown in the event of an error.
    //}}}
    void WINAPI vpb_wave_open_write(WFILE **wav, const std::string &filename, int mode);

    //! Write a block of audio samples to a @c RIFF wave file.
    //{{{
    //! @param wav The pointer returned by a call to @c vpb_wave_open_write().
    //! @param buf The buffer of samples to write.
    //! @param n   The number of bytes to write.
    //!
    //! @return The number of bytes actually written.
    //}}}
    int WINAPI vpb_wave_write(WFILE *wav, const char *buf, long n);

    //! @brief Close a @c RIFF wave file after writing.
    //! @param wav The pointer returned by a call to @c vpb_wave_open_write().
    void WINAPI vpb_wave_close_write(WFILE *wav);

  //@} //}}}

  //! @name Wave file input
  //@{ //{{{

    //! Open a @c RIFF wave file for reading.
    //{{{
    //! @param wav      Pointer to a pointer where encoding state may be stored.
    //!                 This pointer should be passed to other @c vpb_wave_*
    //!                 functions that will operate on the opened file.
    //! @param filename The full path to the file to read.
    //!
    //! @exception various exceptions may be thrown in the event of an error.
    //}}}
    void WINAPI vpb_wave_open_read(WFILE **wav, const std::string &filename);

    //! Read a block of audio samples from a @c RIFF wave file.
    //{{{
    //! @param wav The pointer returned by a call to @c vpb_wave_open_read().
    //! @param buf The buffer to store samples in.
    //! @param n   The size of the buffer in bytes.
    //!
    //! @return The number of bytes actually stored in @a buf.
    //}}}
    int WINAPI vpb_wave_read(WFILE *wav, char *buf, unsigned long n);

    //! @brief Close a @c RIFF wave file after reading.
    //! @param wav The pointer returned by a call to @c vpb_wave_open_read().
    void WINAPI vpb_wave_close_read(WFILE *wav);

  //@} //}}}

  //! @name Miscellaneous wave file operations
  //@{ //{{{

    //! Return the size of wave file data in bytes.
    size_t vpb_wave_get_size(WFILE *wav);

    //! Return the compression mode of @a wav.
    AudioCompress WINAPI vpb_wave_get_mode(WFILE *wav);

    //! Change the sample rate of a wav file.
    //{{{
    //! @param wav  The pointer returned by a call to @c vpb_wave_open_*.
    //! @param rate The new sampling rate to use.
    //}}}
    void WINAPI vpb_wave_set_sample_rate(WFILE *wav, unsigned short rate);

    //! Move the wave pointer to a specified location in the samples.
    //{{{
    //! @param wav    The pointer returned by a call to @c vpb_wave_open_*.
    //! @param offset The offset from the start of the audio samples.
    //!
    //! @return @c VPB_OK if the operation succeeded.  Otherwise @c -1 will be
    //!         returned and @c errno will be set to indicate the error.
    //}}}
    int WINAPI vpb_wave_seek(WFILE *wav, long offset);

  //@} //}}}

  //! @name Wave file VLOG data
  //@{ //{{{

    //! Set @c VPB_VLOG information for inclusion in a wave file.
    //{{{
    //! @param wav The pointer returned by a call to @c vpb_wave_open_write().
    //! @param buf The @c VPB_VLOG data to include.
    //!
    //! @return @c VPB_OK if successful, else a non-zero error code.
    //}}}
    int WINAPI vpb_wave_set_vlog(WFILE *wav, VPB_VLOG *buf);

    //! Get @c VPB_VLOG information from a wave file.
    //{{{
    //! @param wav The pointer returned by a call to @c vpb_wave_open_*
    //! @param buf A pointer to storage for the @c VPB_VLOG data.
    //!
    //! @return @c VPB_OK if successful, else a non-zero error code.
    //}}}
    int WINAPI vpb_wave_get_vlog(WFILE *wav, VPB_VLOG *buf);

  //@} //}}}

//!@} //}}}


//! @defgroup DTMFCollect DTMF digit collection
//!@{
//{{{

    //! Digit collection parameters
    struct VPB_DIGITS
    { //{{{

	//! A list of specific digits that may terminate collection.
	const char    *term_digits;

	//! The maximum number of digits to collect.
	unsigned short max_digits;

	//! The maximum time in @c ms to wait for digits.
	unsigned long  digit_time_out;

	//! The maximum time in @c ms to wait for further digits once collection begins.
	unsigned long  inter_digit_time_out;

    }; //}}}


    //! The termination reason passed in the @c VPB_EVENT::data field of a @c VPB_DIGIT event.
    enum CollectEndReason
    { //{{{

        //! A termination digit was collected.
	VPB_DIGIT_TERM                 = 0,

        //! The specified maximum number of digits were collected.
	VPB_DIGIT_MAX                  = 1,

        //! The specified time for collecting digits expired.
	VPB_DIGIT_TIME_OUT             = 2,

        //! The specified time for collecting further digits expired.
	VPB_DIGIT_INTER_DIGIT_TIME_OUT = 3,

    }; //}}}


    //! Clears the internal digit buffer for @a handle.
    //{{{
    //! This function is often called before commencing collection if any
    //! digits entered prior to that time should be discarded.
    //}}}
    int WINAPI vpb_flush_digits(int handle);

    //! Get a buffer of @c DTMF digits.
    //{{{
    //! This function will return immediately and post a @c VPB_DIGIT event
    //! for @a handle when collection is completed.  If it is called while
    //! collection is already in progress for @a handle, the process is reset
    //! and any digits collected prior to that will be discarded.
    //!
    //! @param handle The handle to the port to collect digits from.
    //! @param digits The conditions defining how digits are collected.
    //! @param digbuf A pointer to storage for at least
    //!               <tt>VPB_DIGITS::max_digits + 1</tt> characters.
    //!               The returned string of digits will be @c NULL terminated.
    //!
    //! @return @c VPB_OK if collection starts successfully.
    //!
    //! @exception various exceptions may be thrown in the event of an error.
    //}}}
    int WINAPI vpb_get_digits_async(int handle, VPB_DIGITS *digits, char *digbuf);

    //! Get a buffer of @c DTMF digits.
    //{{{
    //! This function will block until collection is completed.  If it is
    //! called while async collection is already in progress for @a handle,
    //! the process is reset and any digits collected prior to that will be
    //! discarded.  If it is called while synchronous collection is already
    //! in progress an exception will be thrown.  If it is interrupted by a
    //! call to start async collection an exception will be thrown.
    //!
    //! @param handle The handle to the port to collect digits from.
    //! @param digits The conditions defining how digits are collected.
    //! @param digbuf A pointer to storage for at least
    //!               <tt>VPB_DIGITS::max_digits + 1</tt> characters.
    //!               The returned string of digits will be @c NULL terminated.
    //!
    //! @return The @c CollectEndReason indicating why collection was terminated.
    //!
    //! @exception various exceptions may be thrown in the event of an error.
    //!
    //! @note In most cases, this probably isn't the function you want and you
    //!       should use @c vpb_get_digits_async() instead.  This function does
    //!       <b>no checking</b> for other events (such as hangup) while it is
    //!       waiting for digits and there is no graceful way to interrupt it
    //!       if you are checking for them elsewhere in some other thread.
    //!       Most code should integrate the async digit collection with its
    //!       normal event processing loop, as the cases where DTMF digits
    //!       really are the @a only thing you need to be watching for tend to
    //!       be the exception rather than the rule.
    //}}}
    CollectEndReason WINAPI vpb_get_digits_sync(int handle, VPB_DIGITS *digits, char *digbuf);

//!@} //}}}


//! @defgroup CID Caller id
//!@{
//{{{

    //! Symbolic CID call types.
    enum CidCallType
    { //{{{

	VPB_CID_CT_UNKNOWN = 0x00,  //!< Unknown call type
	VPB_CID_CT_VOICE   = 0x01,  //!< Voice Call
	VPB_CID_CT_RBWF    = 0x02,  //!< Ring back When free
	VPB_CID_CT_MW      = 0x81   //!< Message waiting

    }; //}}}

    //! Container type for caller id data.
    struct VPB_CID
    { //{{{

	CidCallType call_type;	    //!< Call type designator

	char	    cldn[19];	    //!< Calling line directory number
	char	    ra_cldn[2];	    //!< Reason for absence of @c cldn, @c O or @c P
	char	    cn[21];	    //!< Caller name
	char	    ra_cn[2];	    //!< Reason for absence of @c cn, @c O or @c P
	char	    cdn[19];	    //!< Called directory number
	char	    date_time[9];   //!< Time of call
	int	    nmss;	    //!< Network message system status, (0-255 calls waiting)

	char	    pres[256];	    //!< Storage for presentation layer data

	//! Default constructor.
	VPB_CID() { clear(); }

	//! Clear all data members their initialisation state.
	void clear()
	{ //{{{

	    call_type    = VPB_CID_CT_UNKNOWN;
	    cldn[0]      = '\0';
	    ra_cldn[0]   = 'O';
	    ra_cldn[1]   = '\0';
	    cn[0]        = '\0';
	    ra_cn[0]     = 'O';
	    ra_cn[1]     = '\0';
	    cdn[0]       = '\0';
	    date_time[0] = '\0';
	    nmss         = 0;
	    pres[0]      = '\0';

	} //}}}

    }; //}}}

  //! @defgroup CIDDecode Caller id decoding
  //!@{
  //{{{

    //! Attempt to extract a caller's number from a buffer of samples.
    //{{{
    //! @param cid_number Pointer to string storage for the returned number.
    //! @param in         Buffer of audio samples to decode.
    //! @param n          The number of sample in the input buffer.
    //! @return @c VPB_OK if a number was retrieved, @c -1 if none could be
    //!         decoded.
    //! @exception various exceptions may be thrown in the case of other errors.
    //}}}
    int WINAPI vpb_cid_decode(char *cid_number, const short *in, int n);

    //! Attempt to extract all caller id information from a buffer of samples.
    //{{{
    //! @param cli_struct Pointer to storage for the returned data.
    //! @param in         Buffer of audio samples to decode.
    //! @param n          The number of sample in the input buffer.
    //! @return @c VPB_OK if no error occurred while retrieving data, @c -1 if
    //!         some error was detected.
    //}}}
    int WINAPI vpb_cid_decode2(VPB_CID *cli_struct, const short *in, int n);


    //! Enable debugging of the CID decoder.
    //{{{
    //! Causes lots of debug information to be written to the text file
    //! @a debug_file_name.
    //}}}
    void WINAPI vpb_cid_debug_on(const char *debug_file_name);

  //!@} //}}}

  //! @defgroup CIDGen Caller id generation
  //!@{
  //{{{

    //! Maximum size of CID wav data
    #define VPB_CID_MAX_BUF	20400

    //! Maximum size of CID dlp data
    #define VPB_CID_MAX_DLP	256

    //!	Field type identifiers for CID data
    enum CidDataType
    { //{{{

	VPB_CID_EMPTY           = 0,    //!< Flag to clear CID data fields.
	VPB_CID_DATE_TIME       = 1,    //!< Timestamp
	VPB_CID_CALLING_LINE_DN = 2,    //!< Caller directory number
	VPB_CID_CALLED_DN       = 3,    //!< Called directory number
	VPB_CID_RFA_CLDN        = 4,    //!< Reason for absence of caller number
	VPB_CID_CALLER_NAME     = 7,    //!< Caller name
	VPB_CID_RFA_CN          = 8,    //!< Reason for absence of caller name
	VPB_CID_CALL_TYPE       = 0x11, //!< Call type indicator
	VPB_CID_NMSS            = 0x13  //!< Network message system status

    }; //}}}

   //! @name High level functions
   //@{

    //! Set a field in the @a cid data structure.
    //{{{
    //! @param cid   The @c VPB_CID structure to initialise.
    //! @param field The @c VPB_CID field to set.  If @c VPB_CID_EMPTY is
    //!              passed here, then @a value will be ignored and all fields
    //!              will be reset to their default values.
    //! @param value The value to set @a field to.
    //! @return @c 0 upon success, @c -1 in the event of error or an invalid
    //!         @a value.
    //! @note Setting some fields may reset other dependent fields to
    //!       appropriate values.
    //}}}
    int WINAPI vpb_cid_set(VPB_CID *cid, CidDataType field, void *value);

    //! Start @a handle ringing and send type 1 caller id information.
    //{{{
    //! This function will return once the normal ring cadence has begun.
    //! That may be several seconds from the time it is first called.
    //!
    //! @param handle The handle to a station port to ring.
    //! @param cid    The called id information to transmit.
    //! @param cadence The ring cadence to use.  If not specified, the
    //!                normal ring cadence for the country associated with
    //!                @a handle will be used.
    //! @exception various exceptions may be thrown in the event of an error.
    //! @sa vpb_ring_station_async()
    //}}}
    void WINAPI vpb_ring_with_cid(int handle, const VPB_CID &cid, int cadence = -1);

    //! Send type 2 caller id information to @a handle.
    void WINAPI vpb_send_cid_t2_sync(int handle, const VPB_CID &cid);

   //@}

   //! @name Low level functions
   //@{

    //! Create a data link packet from a @c VPB_CID structure.
    //{{{
    //! @param cid The @c VPB_CID structure to send.
    //! @param dlp Pointer to storage for the returned data packet.
    //! @return The number of bytes in the @a dlp.
    //}}}
    int WINAPI vpb_cid_compose_dlp(const VPB_CID &cid, char *dlp);
    int WINAPI vpb_cid_compose_dlp(const VPB_CID *cid, char *dlp);

    //! Encode a data link packet into CP-FSK wav data for type 1 CID.
    //{{{
    //! The resulting wav includes the required CSS and MSS headers.
    //! @param dlp     Data link layer packet (as created by @c vpb_cid_compose_dlp())
    //! @param dlp_len The length of the dlp data (as returned by @c vpb_cid_compose_dlp())
    //! @param wav_buf Pointer to storage for the returned wav data.
    //! @param wav_len Pointer to storage for the wav data sample count.
    //! @param country Locale specific data about the modulation to use.
    //}}}
    void WINAPI vpb_cid_compose_wav(const char *dlp, int dlp_len,
				    short *wav_buf, int *wav_len,
				    const Country *country = NULL);

    //! Encode a data link packet into CP-FSK wav data for type 2 CID.
    //{{{
    //! The resulting wav includes the required MSS headers.
    //! @param dlp     Data link layer packet (as created by @c vpb_cid_compose_dlp())
    //! @param dlp_len The length of the dlp data (as returned by @c vpb_cid_compose_dlp())
    //! @param wav_buf Pointer to storage for the returned wav data.
    //! @param wav_len Pointer to storage for the wav data sample count.
    //! @param country Locale specific data about the modulation to use.
    //}}}
    void WINAPI vpb_cid_t2_compose_wav(const char *dlp, int dlp_len,
				       short *wav_buf, int *wav_len,
				       const Country *country = NULL);
   //@}

  //!@} //}}}

  //! @defgroup CIDDecodeJP Japanese caller id
  //! @brief Additional support for the Japanese caller id standard.
  //!@{
  //{{{

    #define VPB_DID_OTN		2
    #define VPB_DID_OTNRA	4
    #define VPB_DID_OTNEXP	0x21
    #define VPB_DID_CND		9
    #define VPB_DID_CNDEXP	0x22

    typedef struct {
	    char    raw[130];		// Raw bytes decoded, inc parity
	    int     raw_size;		// Raw data byte count
	    char    otn[21];		// Originators Telephone Number
	    char    otnra[31];		// OTA Reason for Absence
	    char    otnexp[4];		// OTA Expansion Data
	    char    cnd[21];		// DID Called Number Data
	    char    cndexp[4];		// DID Expansion Data
    } VPB_CID_JP;

    int WINAPI vpb_cid_jp_decode(VPB_CID_JP *jpcid, short *in, int n);

  //!@} //}}}

//!@} //}}}


//! @defgroup CallLogging Call logging and monitoring
//! These functions are only applicable to hardware using the VTCore driver.
//!
//! For best results with them, @b OpenPCI hardware is recommended.
//! Due to on-board buffering, some loss of synchronisation between incoming
//! and outgoing streams is likely to occur with @b OpenSwitch cards.
//!@{
//{{{

    //! Log full duplex audio from handle @a h to @a filename.
    void WINAPI vpb_log_to_file(VPBPortHandle h, const std::string &filename);

    //! Stop full duplex logging on handle @a h.
    void WINAPI vpb_log_terminate(VPBPortHandle h);

    //! Tap full duplex audio from @a src to @a dest.
    void WINAPI vpb_monitor_audio(VPBPortHandle dest, VPBPortHandle src);

    //! Cancel a tap to handle @a h created with @c vpb_monitor_audio().
    //{{{
    //! @param h Is the handle that was passed as the @a dest parameter
    //!          when the tap was created.
    //}}}
    void WINAPI vpb_monitor_terminate(VPBPortHandle h);

//!@} //}}}


//! @defgroup EchoCan Echo cancelling
//!@{
//{{{

    //! Turns on software loop-back of tx->rx in the kernel.
    //{{{
    //! Useful for echo testing.
    //!
    //! @param handle The handle of the port to enable loopback operations.
    //! @return @c VPB_OK if all went well.
    //! @exception various exceptions may be thrown if all did not go well.
    //! @note This function is not supported for all hardware types.
    //! @sa vpb_loopback_off()
    //}}}
    int WINAPI vpb_loopback_on(int handle);

    //! Turns off software loop-back of tx->rx in the kernel.
    //{{{
    //! Useful for echo testing.
    //!
    //! @param handle The handle of the port to disable loopback operations.
    //! @return @c VPB_OK if all went well.
    //! @exception various exceptions may be thrown if all did not go well.
    //! @note This function is not supported for all hardware types.
    //! @sa vpb_loopback_on()
    //}}}
    int WINAPI vpb_loopback_off(int handle);

    //! Enable the host echo canceller for @a handle.
    int WINAPI vpb_hostecho_on(int handle);

    //! Disable the host echo canceller for @a handle.
    int WINAPI vpb_hostecho_off(int handle);

    int WINAPI vpb_echo_canc_force_adapt_on();
    int WINAPI vpb_echo_canc_force_adapt_off();
    int WINAPI vpb_echo_canc_enable();
    int WINAPI vpb_echo_canc_disable();


    //! Get the current echo suppressor threshold.
    //{{{
    //! This threshold is the same for all channels on all cards.
    //! @param handle A handle to an open port on the card.
    //! @param thresh The returned echo suppressor threshold value.
    //!
    //! @note This function is only supported for @c V4PCI cards.
    //! @exception VpbException will be thrown in the event of an error.
    //}}}
    int WINAPI vpb_echo_canc_get_sup_thresh(int handle, short *thresh);

    //! Set the echo suppressor threshold.
    //{{{
    //! This threshold is the same for all channels on all cards.
    //! @param handle A handle to an open port on the card.
    //! @param thresh The echo suppressor threshold value.
    //!               @c 0x1000 gives @c -18db, @c 0x800 gives @c -24db,
    //!               @c 0x0 for no suppressor.
    //!
    //! @note This function is only supported for @c V4PCI cards.
    //! @exception VpbException will be thrown in the event of an error.
    //}}}
    int WINAPI vpb_echo_canc_set_sup_thresh(int handle, short *thresh);

//!@} //}}}


//! @defgroup LoopVolt Loop voltage sensing
//!@{
//{{{

  #ifndef __FreeBSD__
    int WINAPI vpb_loopvolt_get(int h, short *volts);
    int WINAPI vpb_loopvolt_get_threshold(int h, short *volts);
    int WINAPI vpb_loopvolt_set_threshold(int h, short volts);
    int WINAPI vpb_loopvolt_get_lowlimit(int h, short *volts);
    int WINAPI vpb_loopvolt_set_lowlimit(int h, short volts);
    int WINAPI vpb_loop_get_onhookwindow(int h, int *ms);
    int WINAPI vpb_loop_set_onhookwindow(int h, int ms);
    int WINAPI vpb_loop_get_offhookwindow(int h, int *ms);
    int WINAPI vpb_loop_set_offhookwindow(int h, int ms);
  #endif

//!@} //}}}


//! @defgroup ISDN ISDN support
//!@{
//{{{

    typedef struct {
	    int callingplan;
	    int callingpres;
	    char callingnum[256];
	    char callingname[256];
	    char callingsubaddr[256];
	    char calledsubaddr[256];
	    char callednum[256];
	    int calledplan;
    } VPB_CALL_INFO;

    int WINAPI vpb_isdn_call(int h, char *number, char *cid, int layer1,
			     int transcap, unsigned char *lowlayercompatibility = NULL);
    int WINAPI vpb_isdn_get_cinfo(int h, VPB_CALL_INFO *cinfo);
    int WINAPI vpb_isdn_get_layer1(int h);
    int WINAPI vpb_isdn_get_transcap(int h);
    int WINAPI vpb_isdn_get_lowlayercompatibility(int h,unsigned char *lowlayercompatibility);
    int WINAPI vpb_isdn_get_cause(int h);
    int WINAPI vpb_isdn_proceeding(int h);

//!@} //}}}


 //!@} //}}}  group PublicAPI

#endif	// #ifndef __VPBAPI__	

