Data-Over-Voice
An experimental feature to send and receive an identification over voice channel. If a party answers, the ID is transmitted some seconds afterwards. The calling party listens 30 seconds after receiving an answer message for the ID. Add to your extension's settings file: dov_ident <id string without white spaces> dov_log /path/to/log/file dov_type pwm|pcm dov_level 0|level 'pwm' survives analog transcoding. 'pcm' is fast and will almost not be recognised. 'level' can be used to alter default signal amplitude (100..30000).
This commit is contained in:
parent
a1c8b8d89f
commit
034d3a9140
|
@ -186,7 +186,7 @@ lcr_SOURCES = \
|
|||
$(MISDN_SOURCE) $(GSM_SOURCE) $(SS5_SOURCE) $(SIP_SOURCE) $(VOOTP_SOURCE) \
|
||||
endpoint.cpp endpointapp.cpp \
|
||||
appbridge.cpp apppbx.cpp route.c action.cpp action_efi.cpp action_vbox.cpp extension.c mail.c \
|
||||
join.cpp joinpbx.cpp
|
||||
join.cpp joinpbx.cpp dov.cpp
|
||||
|
||||
lcr_LDADD = $(LIBCRYPTO) $(MISDN_LIB) -lpthread $(GSM_LIB) $(SIP_LIB) $(VOOTP_LIB)
|
||||
|
||||
|
|
141
apppbx.cpp
141
apppbx.cpp
|
@ -1970,6 +1970,16 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
|
|||
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
|
||||
message->param.audiopath = 1;
|
||||
message_put(message);
|
||||
if (e_ext.dov_ident[0]) {
|
||||
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DOV_REQUEST);
|
||||
SPRINT(message->param.dov.data, "%08x ", lcr_random);
|
||||
SCAT(message->param.dov.data, e_ext.dov_ident);
|
||||
message->param.dov.length = strlen((char *)message->param.dov.data);
|
||||
message->param.dov.type = e_ext.dov_type;
|
||||
message->param.dov.level = e_ext.dov_level;
|
||||
dov_msg_write(&message->param, 1);
|
||||
message_put(message);
|
||||
}
|
||||
} else if (!e_adminid) {
|
||||
/* callback */
|
||||
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
|
||||
|
@ -2440,6 +2450,18 @@ void EndpointAppPBX::port_disable_dejitter(struct port_list *portlist, int messa
|
|||
message_put(message);
|
||||
}
|
||||
|
||||
/* port MESSAGE_DOV_INDICATION */
|
||||
void EndpointAppPBX::port_dov_indication(struct port_list *portlist, int message_type, union parameter *param)
|
||||
{
|
||||
struct lcr_msg *message;
|
||||
|
||||
logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
|
||||
|
||||
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DOV_INDICATION);
|
||||
memcpy(&message->param, param, sizeof(union parameter));
|
||||
message_put(message);
|
||||
}
|
||||
|
||||
|
||||
/* port MESSAGE_UPDATEBRIDGE */
|
||||
void EndpointAppPBX::port_updatebridge(struct port_list *portlist, int message_type, union parameter *param)
|
||||
|
@ -2665,6 +2687,11 @@ void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, uni
|
|||
port_vootp(portlist, message_type, param);
|
||||
break;
|
||||
|
||||
/* PORT indivated Data-Over-Voice */
|
||||
case MESSAGE_DOV_INDICATION:
|
||||
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') indicates Data-Over-Voice.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
|
||||
port_dov_indication(portlist, message_type, param);
|
||||
break;
|
||||
|
||||
default:
|
||||
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received a wrong message: %d\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, message_type);
|
||||
|
@ -2884,6 +2911,13 @@ void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type,
|
|||
message_put(message);
|
||||
time(&now);
|
||||
e_start = now;
|
||||
|
||||
/* if the remote answered, we listen to DOV message */
|
||||
if (e_ext.dov_log[0]) {
|
||||
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DOV_LISTEN);
|
||||
message->param.dov.type = e_ext.dov_type;
|
||||
message_put(message);
|
||||
}
|
||||
}
|
||||
|
||||
/* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
|
||||
|
@ -3202,6 +3236,43 @@ void EndpointAppPBX::join_disable_dejitter(struct port_list *portlist, int messa
|
|||
}
|
||||
}
|
||||
|
||||
/* join MESSAGE_DOV_INDICATION */
|
||||
void EndpointAppPBX::join_dov_indication(struct port_list *portlist, int message_type, union parameter *param)
|
||||
{
|
||||
dov_msg_write(param, 0);
|
||||
}
|
||||
|
||||
/* join MESSAGE_DOV_REQUEST */
|
||||
void EndpointAppPBX::join_dov_request(struct port_list *portlist, int message_type, union parameter *param)
|
||||
{
|
||||
struct lcr_msg *message;
|
||||
|
||||
/* don't send DOV from estension to extension */
|
||||
if (e_ext.number[0])
|
||||
return;
|
||||
|
||||
while(portlist) {
|
||||
message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DOV_REQUEST);
|
||||
memcpy(&message->param, param, sizeof(union parameter));
|
||||
message_put(message);
|
||||
logmessage(message_type, param, portlist->port_id, DIRECTION_OUT);
|
||||
portlist = portlist->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* join MESSAGE_DOV_LISTEN */
|
||||
void EndpointAppPBX::join_dov_listen(struct port_list *portlist, int message_type, union parameter *param)
|
||||
{
|
||||
struct lcr_msg *message;
|
||||
|
||||
while(portlist) {
|
||||
message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DOV_LISTEN);
|
||||
memcpy(&message->param, param, sizeof(union parameter));
|
||||
message_put(message);
|
||||
portlist = portlist->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* JOIN sends messages to the endpoint
|
||||
*/
|
||||
void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
|
||||
|
@ -3379,6 +3450,24 @@ void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, uni
|
|||
join_disable_dejitter(portlist, message_type, param);
|
||||
break;
|
||||
|
||||
/* JOIN sends a Data-Over-Voice message indication */
|
||||
case MESSAGE_DOV_INDICATION:
|
||||
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received Data-Over-Voice indication.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
|
||||
join_dov_indication(portlist, message_type, param);
|
||||
break;
|
||||
|
||||
/* JOIN sends a Data-Over-Voice message request */
|
||||
case MESSAGE_DOV_REQUEST:
|
||||
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received Data-Over-Voice request.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
|
||||
join_dov_request(portlist, message_type, param);
|
||||
break;
|
||||
|
||||
/* JOIN sends a Data-Over-Voice listen order */
|
||||
case MESSAGE_DOV_LISTEN:
|
||||
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received Data-Over-Voice listen order.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
|
||||
join_dov_listen(portlist, message_type, param);
|
||||
break;
|
||||
|
||||
default:
|
||||
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received a wrong message: #%d\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, message_type);
|
||||
}
|
||||
|
@ -4795,6 +4884,23 @@ void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsign
|
|||
end_trace();
|
||||
break;
|
||||
|
||||
case MESSAGE_DOV_INDICATION:
|
||||
case MESSAGE_DOV_REQUEST:
|
||||
trace_header("Data-Over-Voice", dir);
|
||||
if (dir == DIRECTION_OUT)
|
||||
add_trace("to", NULL, "CH(%lu)", port_id);
|
||||
if (dir == DIRECTION_IN)
|
||||
add_trace("from", NULL, "CH(%lu)", port_id);
|
||||
{
|
||||
char dov_str[param->dov.length + 1];
|
||||
memcpy(dov_str, param->dov.data, param->dov.length);
|
||||
dov_str[param->dov.length] = '\0';
|
||||
add_trace("string", NULL, "%s", dov_str);
|
||||
}
|
||||
add_trace("type", NULL, "%d", param->dov.type);
|
||||
end_trace();
|
||||
break;
|
||||
|
||||
default:
|
||||
PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
|
||||
}
|
||||
|
@ -4828,3 +4934,38 @@ void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cau
|
|||
logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
|
||||
}
|
||||
|
||||
void EndpointAppPBX::dov_msg_write(union parameter *param, int sent)
|
||||
{
|
||||
FILE *fp;
|
||||
struct tm *tm;
|
||||
time_t ti;
|
||||
int __attribute__((__unused__)) rc;
|
||||
|
||||
/* no write, if no log file given */
|
||||
if (!e_ext.dov_log[0])
|
||||
return;
|
||||
|
||||
fp = fopen(e_ext.dov_log, "a");
|
||||
if (!fp) {
|
||||
PERROR("EPOINT(%d) failed to open Data-Over-Voice log file '%s'\n", ea_endpoint->ep_serial, e_ext.dov_log);
|
||||
return;
|
||||
}
|
||||
|
||||
ti = time(NULL);
|
||||
tm = localtime(&ti);
|
||||
fprintf(fp, "%02d.%02d.%02d %02d:%02d:%02d ", tm->tm_mday, tm->tm_mon+1, tm->tm_year%100, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
|
||||
|
||||
if (sent) {
|
||||
fprintf(fp, "sent [%s] ", numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
|
||||
} else {
|
||||
fprintf(fp, "received [%s] ", e_dialinginfo.id);
|
||||
}
|
||||
|
||||
rc = fwrite(param->dov.data, param->dov.length, 1, fp);
|
||||
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
|
|
7
apppbx.h
7
apppbx.h
|
@ -219,6 +219,7 @@ class EndpointAppPBX : public EndpointApp
|
|||
void port_disable_dejitter(struct port_list *portlist, int message_type, union parameter *param);
|
||||
void port_updatebridge(struct port_list *portlist, int message_type, union parameter *param);
|
||||
void port_vootp(struct port_list *portlist, int message_type, union parameter *param);
|
||||
void port_dov_indication(struct port_list *portlist, int message_type, union parameter *param);
|
||||
void ea_message_join(unsigned int join_id, int message, union parameter *param);
|
||||
void join_crypt(struct port_list *portlist, int message_type, union parameter *param);
|
||||
void join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param);
|
||||
|
@ -234,6 +235,9 @@ class EndpointAppPBX : public EndpointApp
|
|||
void join_facility(struct port_list *portlist, int message_type, union parameter *param);
|
||||
void join_dtmf(struct port_list *portlist, int message_type, union parameter *param);
|
||||
void join_disable_dejitter(struct port_list *portlist, int message_type, union parameter *param);
|
||||
void join_dov_indication(struct port_list *portlist, int message_type, union parameter *param);
|
||||
void join_dov_request(struct port_list *portlist, int message_type, union parameter *param);
|
||||
void join_dov_listen(struct port_list *portlist, int message_type, union parameter *param);
|
||||
|
||||
/* epoint */
|
||||
void new_state(int state);
|
||||
|
@ -372,6 +376,9 @@ class EndpointAppPBX : public EndpointApp
|
|||
void message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display);
|
||||
void logmessage(int message_type, union parameter *param, unsigned int port_id, int dir);
|
||||
void trace_header(const char *name, int direction);
|
||||
|
||||
/* DOV */
|
||||
void dov_msg_write(union parameter *param, int sent);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,612 @@
|
|||
/*****************************************************************************\
|
||||
** **
|
||||
** Linux-Call-Router **
|
||||
** **
|
||||
**---------------------------------------------------------------------------**
|
||||
** Copyright: Andreas Eversberg **
|
||||
** **
|
||||
** data-over-voice **
|
||||
** **
|
||||
\*****************************************************************************/
|
||||
|
||||
/*
|
||||
|
||||
Protocol description:
|
||||
|
||||
PCM: A bit is defined as sample value. A 1 is positive level, a 0 negative.
|
||||
The bit rate is 8000 Hz.
|
||||
|
||||
PWM: A bit is defined by a duration between polarity change of signal. 4
|
||||
samples duration is 0, 12 samples duration is 1.
|
||||
|
||||
GGGGGGGGGGGGG....
|
||||
0LLLLLLLL
|
||||
0DDDDDDDD
|
||||
0DDDDDDDD
|
||||
....
|
||||
0CCCCCCCC
|
||||
0CCCCCCCC
|
||||
0CCCCCCCC
|
||||
0CCCCCCCC
|
||||
GGGGGGGGGGGGG....
|
||||
|
||||
G=guard / sync sequnce (bit=1)
|
||||
L=length information (lsb first)
|
||||
D=data (lsb first)
|
||||
C=CRC (lsb first, network byte order)
|
||||
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
|
||||
//#define DEBUG_DOV
|
||||
|
||||
#define DOV_PWM_LEVEL 819
|
||||
#define DOV_PCM_LEVEL 100
|
||||
#define DOV_PCM_GUARD 400
|
||||
#define DOV_PWM_GUARD 34
|
||||
|
||||
#define DOV_TX_SEND_DELAY 3, 0
|
||||
#define DOV_RX_LISTEN_TIMEOUT 30, 0
|
||||
|
||||
static unsigned int dov_crc32_table[256];
|
||||
|
||||
inline unsigned int dov_crc_reflect(unsigned int ref, unsigned char ch)
|
||||
{
|
||||
unsigned int value = 0;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < ch + 1; i++) {
|
||||
if ((ref & 1))
|
||||
value |= 1 << (ch - i);
|
||||
ref >>= 1;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* initialize CRC table
|
||||
*/
|
||||
void dov_crc_init(void)
|
||||
{
|
||||
unsigned int ulPolynomial = 0x04c11db7;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
dov_crc32_table[i] = dov_crc_reflect(i, 8) << 24;
|
||||
for (j = 0; j < 8; j++)
|
||||
dov_crc32_table[i] = (dov_crc32_table[i] << 1) ^
|
||||
(dov_crc32_table[i] & (1 << 31) ?
|
||||
ulPolynomial : 0);
|
||||
dov_crc32_table[i] =
|
||||
dov_crc_reflect(dov_crc32_table[i], 32);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* calculate CRC 32 of given data
|
||||
*
|
||||
* data: pointer to data
|
||||
* length: length of data
|
||||
* return: CRC 32
|
||||
*/
|
||||
unsigned int dov_crc32(unsigned char *data, int length)
|
||||
{
|
||||
unsigned int crc = 0xffffffff;
|
||||
|
||||
while (length--)
|
||||
crc = (crc >> 8) ^ dov_crc32_table[(crc & 0xff) ^ *data++];
|
||||
|
||||
return crc ^ 0xffffffff;
|
||||
}
|
||||
|
||||
int dov_tx_timer(struct lcr_timer *timer, void *instance, int index);
|
||||
int dov_rx_timer(struct lcr_timer *timer, void *instance, int index);
|
||||
|
||||
void Port::dov_init(void)
|
||||
{
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: init\n");
|
||||
#endif
|
||||
|
||||
dov_crc_init();
|
||||
p_dov_tx = 0;
|
||||
p_dov_rx = 0;
|
||||
p_dov_tx_data = NULL;
|
||||
p_dov_rx_data = NULL;
|
||||
memset(&p_dov_tx_timer, 0, sizeof(p_dov_tx_timer));
|
||||
add_timer(&p_dov_tx_timer, dov_tx_timer, this, 0);
|
||||
memset(&p_dov_rx_timer, 0, sizeof(p_dov_rx_timer));
|
||||
add_timer(&p_dov_rx_timer, dov_rx_timer, this, 0);
|
||||
}
|
||||
|
||||
|
||||
void Port::dov_reset_tx(void)
|
||||
{
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: reset TX\n");
|
||||
#endif
|
||||
|
||||
if (p_dov_tx_data)
|
||||
FREE(p_dov_tx_data, p_dov_tx_data_length);
|
||||
p_dov_tx_data = NULL;
|
||||
p_dov_tx = 0;
|
||||
unsched_timer(&p_dov_tx_timer);
|
||||
}
|
||||
|
||||
void Port::dov_reset_rx(void)
|
||||
{
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: reset RX\n");
|
||||
#endif
|
||||
|
||||
if (p_dov_rx_data)
|
||||
FREE(p_dov_rx_data, 255 + 5);
|
||||
p_dov_rx_data = NULL;
|
||||
p_dov_rx = 0;
|
||||
update_rxoff();
|
||||
unsched_timer(&p_dov_rx_timer);
|
||||
}
|
||||
|
||||
void Port::dov_exit(void)
|
||||
{
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: exit\n");
|
||||
#endif
|
||||
|
||||
dov_reset_tx();
|
||||
del_timer(&p_dov_tx_timer);
|
||||
dov_reset_rx();
|
||||
del_timer(&p_dov_rx_timer);
|
||||
}
|
||||
|
||||
void Port::dov_sendmsg(unsigned char *data, int length, enum dov_type type, int level)
|
||||
{
|
||||
unsigned int crc;
|
||||
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: send message, start timer\n");
|
||||
#endif
|
||||
|
||||
dov_reset_tx();
|
||||
|
||||
if (!length)
|
||||
return;
|
||||
p_dov_tx_data = (unsigned char *)MALLOC(length + 5);
|
||||
p_dov_tx_data[0] = length;
|
||||
memcpy(p_dov_tx_data + 1, data, length);
|
||||
crc = dov_crc32(data, length);
|
||||
p_dov_tx_data[length+1] = crc >> 24;
|
||||
p_dov_tx_data[length+2] = crc >> 16;
|
||||
p_dov_tx_data[length+3] = crc >> 8;
|
||||
p_dov_tx_data[length+4] = crc;
|
||||
p_dov_tx_data_length = length + 5;
|
||||
p_dov_tx_data_pos = 0;
|
||||
p_dov_tx_sync = 1;
|
||||
p_dov_tx_bit_pos = 0;
|
||||
p_dov_tx_pwm_pos = 0;
|
||||
|
||||
p_dov_tx_type = type;
|
||||
if (level) {
|
||||
p_dov_up = audio_s16_to_law[(level) & 0xffff];
|
||||
p_dov_down = audio_s16_to_law[(-level) & 0xffff];
|
||||
} else if (type == DOV_TYPE_PWM) {
|
||||
p_dov_up = audio_s16_to_law[(DOV_PWM_LEVEL) & 0xffff];
|
||||
p_dov_down = audio_s16_to_law[(-DOV_PWM_LEVEL) & 0xffff];
|
||||
} else {
|
||||
p_dov_up = audio_s16_to_law[(DOV_PCM_LEVEL) & 0xffff];
|
||||
p_dov_down = audio_s16_to_law[(-DOV_PCM_LEVEL) & 0xffff];
|
||||
}
|
||||
|
||||
schedule_timer(&p_dov_tx_timer, DOV_TX_SEND_DELAY);
|
||||
}
|
||||
|
||||
int dov_tx_timer(struct lcr_timer *timer, void *instance, int index)
|
||||
{
|
||||
class Port *port = (class Port *)instance;
|
||||
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: timer fires, now sending\n");
|
||||
#endif
|
||||
|
||||
port->p_dov_tx = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Port::dov_tx(unsigned char *data, int length)
|
||||
{
|
||||
int left = 0;
|
||||
|
||||
if (!p_dov_tx)
|
||||
return 0;
|
||||
|
||||
switch (p_dov_tx_type) {
|
||||
case DOV_TYPE_PWM:
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: prepare %d bytes of PWM data\n", length);
|
||||
#endif
|
||||
left = dov_tx_pwm(data, length);
|
||||
break;
|
||||
case DOV_TYPE_PCM:
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: prepare %d bytes of PCM data\n", length);
|
||||
#endif
|
||||
left = dov_tx_pcm(data, length);
|
||||
break;
|
||||
}
|
||||
|
||||
return length - left;
|
||||
}
|
||||
|
||||
int Port::dov_tx_pwm(unsigned char *data, int length)
|
||||
{
|
||||
while (length) {
|
||||
/* send sync / guard sequence */
|
||||
if (p_dov_tx_sync) {
|
||||
if (p_dov_tx_up) {
|
||||
while (p_dov_tx_pwm_pos < 12) {
|
||||
*data++ = p_dov_up;
|
||||
p_dov_tx_pwm_pos++;
|
||||
if (--length == 0)
|
||||
return 0;
|
||||
}
|
||||
p_dov_tx_up = 0;
|
||||
} else {
|
||||
while (p_dov_tx_pwm_pos < 12) {
|
||||
*data++ = p_dov_down;
|
||||
p_dov_tx_pwm_pos++;
|
||||
if (--length == 0)
|
||||
return 0;
|
||||
}
|
||||
p_dov_tx_up = 1;
|
||||
}
|
||||
p_dov_tx_pwm_pos = 0;
|
||||
if (++p_dov_tx_bit_pos == DOV_PWM_GUARD) {
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: TX, done with guard\n");
|
||||
#endif
|
||||
p_dov_tx_bit_pos = -1;
|
||||
if (p_dov_tx_sync == 2) {
|
||||
dov_reset_tx();
|
||||
return length;
|
||||
}
|
||||
p_dov_tx_sync = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* send start of byte */
|
||||
if (p_dov_tx_data_length == -1) {
|
||||
if (p_dov_tx_up) {
|
||||
while (p_dov_tx_pwm_pos < 4) {
|
||||
*data++ = p_dov_up;
|
||||
p_dov_tx_pwm_pos++;
|
||||
if (--length == 0)
|
||||
return 0;
|
||||
}
|
||||
p_dov_tx_up = 0;
|
||||
} else {
|
||||
while (p_dov_tx_pwm_pos < 4) {
|
||||
*data++ = p_dov_down;
|
||||
p_dov_tx_pwm_pos++;
|
||||
if (--length == 0)
|
||||
return 0;
|
||||
}
|
||||
p_dov_tx_up = 1;
|
||||
}
|
||||
p_dov_tx_pwm_pos = 0;
|
||||
p_dov_tx_bit_pos = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* send data */
|
||||
if ((p_dov_tx_data[p_dov_tx_data_pos] >> p_dov_tx_bit_pos) & 1) {
|
||||
if (p_dov_tx_up) {
|
||||
while (p_dov_tx_pwm_pos < 12) {
|
||||
*data++ = p_dov_up;
|
||||
p_dov_tx_pwm_pos++;
|
||||
if (--length == 0)
|
||||
return 0;
|
||||
}
|
||||
p_dov_tx_up = 0;
|
||||
} else {
|
||||
while (p_dov_tx_pwm_pos < 12) {
|
||||
*data++ = p_dov_down;
|
||||
p_dov_tx_pwm_pos++;
|
||||
if (--length == 0)
|
||||
return 0;
|
||||
}
|
||||
p_dov_tx_up = 1;
|
||||
}
|
||||
} else {
|
||||
if (p_dov_tx_up) {
|
||||
while (p_dov_tx_pwm_pos < 4) {
|
||||
*data++ = p_dov_up;
|
||||
p_dov_tx_pwm_pos++;
|
||||
if (--length == 0)
|
||||
return 0;
|
||||
}
|
||||
p_dov_tx_up = 0;
|
||||
} else {
|
||||
while (p_dov_tx_pwm_pos < 4) {
|
||||
*data++ = p_dov_down;
|
||||
p_dov_tx_pwm_pos++;
|
||||
if (--length == 0)
|
||||
return 0;
|
||||
}
|
||||
p_dov_tx_up = 1;
|
||||
}
|
||||
}
|
||||
p_dov_tx_pwm_pos = 0;
|
||||
if (++p_dov_tx_bit_pos == 8) {
|
||||
p_dov_tx_bit_pos = -1;
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: TX, done with byte %d\n", p_dov_tx_data[p_dov_tx_data_pos]);
|
||||
#endif
|
||||
if (p_dov_tx_data_pos++ == p_dov_tx_data_length) {
|
||||
p_dov_tx_sync = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Port::dov_tx_pcm(unsigned char *data, int length)
|
||||
{
|
||||
while (length--) {
|
||||
/* send sync / guard sequence */
|
||||
if (p_dov_tx_sync) {
|
||||
*data++ = p_dov_up;
|
||||
if (++p_dov_tx_bit_pos == DOV_PCM_GUARD) {
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: TX, done with guard\n");
|
||||
#endif
|
||||
p_dov_tx_bit_pos = -1;
|
||||
if (p_dov_tx_sync == 2) {
|
||||
dov_reset_tx();
|
||||
return length;
|
||||
}
|
||||
p_dov_tx_sync = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* send start of byte */
|
||||
if (p_dov_tx_data_length == -1) {
|
||||
*data++ = p_dov_down;
|
||||
p_dov_tx_bit_pos = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* send data */
|
||||
*data++ = (((p_dov_tx_data[p_dov_tx_data_pos] >> p_dov_tx_bit_pos) & 1)) ? p_dov_up : p_dov_down;
|
||||
if (++p_dov_tx_bit_pos == 8) {
|
||||
p_dov_tx_bit_pos = -1;
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: TX, done with byte %d\n", p_dov_tx_data[p_dov_tx_data_pos]);
|
||||
#endif
|
||||
if (p_dov_tx_data_pos++ == p_dov_tx_data_length) {
|
||||
p_dov_tx_sync = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Port::dov_listen(enum dov_type type)
|
||||
{
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: start listening, start timer\n");
|
||||
#endif
|
||||
|
||||
dov_reset_rx();
|
||||
|
||||
p_dov_rx_data = (unsigned char *)MALLOC(255 + 5);
|
||||
p_dov_rx_data_pos = 0;
|
||||
p_dov_rx_sync = 1;
|
||||
p_dov_rx_bit_pos = 0;
|
||||
p_dov_rx_pwm_pos = 0;
|
||||
p_dov_rx_pwm_duration = 0;
|
||||
p_dov_rx_pwm_polarity = 0;
|
||||
p_dov_rx_sync_word = 0;
|
||||
|
||||
p_dov_rx_type = type;
|
||||
|
||||
p_dov_rx = 1;
|
||||
update_rxoff();
|
||||
|
||||
schedule_timer(&p_dov_rx_timer, DOV_RX_LISTEN_TIMEOUT);
|
||||
}
|
||||
|
||||
int dov_rx_timer(struct lcr_timer *timer, void *instance, int index)
|
||||
{
|
||||
class Port *port = (class Port *)instance;
|
||||
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: timer fires, now stop listening\n");
|
||||
#endif
|
||||
|
||||
port->dov_reset_rx();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Port::dov_rx(unsigned char *data, int length)
|
||||
{
|
||||
if (!p_dov_rx)
|
||||
return;
|
||||
|
||||
switch (p_dov_rx_type) {
|
||||
case DOV_TYPE_PWM:
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: received %d bytes of PWM data\n", length);
|
||||
#endif
|
||||
dov_rx_pwm(data, length);
|
||||
break;
|
||||
case DOV_TYPE_PCM:
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: received %d bytes of PCM data\n", length);
|
||||
#endif
|
||||
dov_rx_pcm(data, length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Port::dov_rx_pwm(unsigned char *data, int length)
|
||||
{
|
||||
signed int sample;
|
||||
signed int level;
|
||||
|
||||
while (length--) {
|
||||
sample = audio_law_to_s32[*data++];
|
||||
p_dov_rx_pwm_duration++;
|
||||
if (p_dov_rx_pwm_polarity == 1) {
|
||||
if (sample > 0)
|
||||
continue;
|
||||
p_dov_rx_pwm_polarity = 0;
|
||||
if (p_dov_rx_pwm_duration < 8)
|
||||
level = 0;
|
||||
else
|
||||
level = 1;
|
||||
p_dov_rx_pwm_duration = 0;
|
||||
} else {
|
||||
if (sample <= 0)
|
||||
continue;
|
||||
p_dov_rx_pwm_polarity = 1;
|
||||
if (p_dov_rx_pwm_duration < 8)
|
||||
level = 0;
|
||||
else
|
||||
level = 1;
|
||||
p_dov_rx_pwm_duration = 0;
|
||||
}
|
||||
|
||||
/* catch sync */
|
||||
p_dov_rx_sync_word <<= 1;
|
||||
if (level > 0)
|
||||
p_dov_rx_sync_word |= 1;
|
||||
if ((p_dov_rx_sync_word & 0x1ff) == 0x1ff) {
|
||||
p_dov_rx_bit_pos = -1;
|
||||
p_dov_rx_sync = 1;
|
||||
p_dov_rx_data_pos = 0;
|
||||
continue;
|
||||
}
|
||||
/* wait for sync */
|
||||
if (!p_dov_rx_sync) {
|
||||
continue;
|
||||
}
|
||||
/* read start bit */
|
||||
if (p_dov_rx_bit_pos == -1) {
|
||||
/* check violation of start bit */
|
||||
if (level > 0) {
|
||||
p_dov_rx_sync = 0;
|
||||
continue;
|
||||
}
|
||||
p_dov_rx_bit_pos = 0;
|
||||
continue;
|
||||
}
|
||||
/* read data */
|
||||
p_dov_rx_data[p_dov_rx_data_pos] >>= 1;
|
||||
if (level > 0)
|
||||
p_dov_rx_data[p_dov_rx_data_pos] |= 128;
|
||||
if (++p_dov_rx_bit_pos == 8) {
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: RX byte %d\n", p_dov_rx_data[p_dov_rx_data_pos]);
|
||||
#endif
|
||||
p_dov_rx_bit_pos = -1;
|
||||
/* check for length,data,crc32 */
|
||||
if (++p_dov_rx_data_pos == p_dov_rx_data[0] + 5) {
|
||||
dov_message(p_dov_rx_data + 1, p_dov_rx_data[0]);
|
||||
p_dov_rx_sync = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Port::dov_rx_pcm(unsigned char *data, int length)
|
||||
{
|
||||
signed int level;
|
||||
|
||||
while (length--) {
|
||||
level = audio_law_to_s32[*data++];
|
||||
/* catch sync */
|
||||
p_dov_rx_sync_word <<= 1;
|
||||
if (level > 0)
|
||||
p_dov_rx_sync_word |= 1;
|
||||
if ((p_dov_rx_sync_word & 0x1ff) == 0x1ff) {
|
||||
p_dov_rx_bit_pos = -1;
|
||||
p_dov_rx_sync = 1;
|
||||
p_dov_rx_data_pos = 0;
|
||||
continue;
|
||||
}
|
||||
/* wait for sync */
|
||||
if (!p_dov_rx_sync) {
|
||||
continue;
|
||||
}
|
||||
/* read start bit */
|
||||
if (p_dov_rx_bit_pos == -1) {
|
||||
/* check violation of start bit */
|
||||
if (level > 0) {
|
||||
p_dov_rx_sync = 0;
|
||||
continue;
|
||||
}
|
||||
p_dov_rx_bit_pos = 0;
|
||||
continue;
|
||||
}
|
||||
/* read data */
|
||||
p_dov_rx_data[p_dov_rx_data_pos] >>= 1;
|
||||
if (level > 0)
|
||||
p_dov_rx_data[p_dov_rx_data_pos] |= 128;
|
||||
if (++p_dov_rx_bit_pos == 8) {
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: RX byte %d\n", p_dov_rx_data[p_dov_rx_data_pos]);
|
||||
#endif
|
||||
p_dov_rx_bit_pos = -1;
|
||||
/* check for length,data,crc32 */
|
||||
if (++p_dov_rx_data_pos == p_dov_rx_data[0] + 5) {
|
||||
dov_message(p_dov_rx_data + 1, p_dov_rx_data[0]);
|
||||
p_dov_rx_sync = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Port::dov_message(unsigned char *data, int length)
|
||||
{
|
||||
unsigned int crc;
|
||||
struct lcr_msg *message;
|
||||
|
||||
/* prevent receiving zeroes (due to line noise). this would cause 0 crc, which seems correct. */
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: received message\n");
|
||||
#endif
|
||||
|
||||
crc = dov_crc32(p_dov_rx_data + 1, p_dov_rx_data[0]);
|
||||
if (crc != (unsigned int) ( ((p_dov_rx_data[length+1]) << 24) |
|
||||
((p_dov_rx_data[length+2]) << 16) |
|
||||
((p_dov_rx_data[length+3]) << 8) |
|
||||
(p_dov_rx_data[length+4]) ))
|
||||
return;
|
||||
|
||||
#ifdef DEBUG_DOV
|
||||
printf("DOV: crc OK\n");
|
||||
#endif
|
||||
|
||||
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DOV_INDICATION);
|
||||
message->param.dov.type = p_dov_rx_type;
|
||||
message->param.dov.length = p_dov_rx_data[0];
|
||||
memcpy(message->param.dov.data, p_dov_rx_data + 1, p_dov_rx_data[0]);
|
||||
PDEBUG(DEBUG_PORT, "PmISDN(%s) Data-Over-Voice message received (len=%d)\n", p_name, message->param.dov.length);
|
||||
message_put(message);
|
||||
|
||||
dov_reset_rx();
|
||||
}
|
||||
|
37
extension.c
37
extension.c
|
@ -759,6 +759,31 @@ int read_extension(struct extension *ext, char *num)
|
|||
if (!strcmp(option,"otp-ident")) {
|
||||
SCPY(ext->otp_ident, param);
|
||||
PDEBUG(DEBUG_CONFIG, "otp-ident: %s\n",param);
|
||||
} else
|
||||
if (!strcmp(option,"dov_ident")) {
|
||||
if (param[0]) {
|
||||
SCPY(ext->dov_ident, param);
|
||||
PDEBUG(DEBUG_CONFIG, "dov_ident string: %s\n",param);
|
||||
}
|
||||
} else
|
||||
if (!strcmp(option,"dov_log")) {
|
||||
if (param[0]) {
|
||||
SCPY(ext->dov_log, param);
|
||||
PDEBUG(DEBUG_CONFIG, "dov_log filename: %s\n",param);
|
||||
}
|
||||
} else
|
||||
if (!strcmp(option,"dov_type")) {
|
||||
if (!strcasecmp(param, "pcm"))
|
||||
ext->dov_type = DOV_TYPE_PCM;
|
||||
else
|
||||
ext->dov_type = DOV_TYPE_PWM;
|
||||
PDEBUG(DEBUG_CONFIG, "given dov type: %s\n", param);
|
||||
} else
|
||||
if (!strcmp(option,"dov_level")) {
|
||||
if (atoi(param)) {
|
||||
ext->dov_level = atoi(param);
|
||||
PDEBUG(DEBUG_CONFIG, "dov_level: %s\n",param);
|
||||
}
|
||||
} else {
|
||||
PERROR_RUNTIME("Error in %s (line %d): wrong option keyword %s.\n",filename,line,option);
|
||||
}
|
||||
|
@ -1166,6 +1191,18 @@ int write_extension(struct extension *ext, char *number)
|
|||
}
|
||||
fprintf(fp,"\n");
|
||||
|
||||
fprintf(fp,"# Identify to/from remove via Data-Over-Voice feature.\n");
|
||||
fprintf(fp,"dov_ident %s\n", ext->dov_ident);
|
||||
fprintf(fp,"dov_log %s\n", ext->dov_log);
|
||||
switch(ext->dov_type) {
|
||||
case DOV_TYPE_PWM:
|
||||
fprintf(fp,"dov_type pwm\n");
|
||||
break;
|
||||
case DOV_TYPE_PCM:
|
||||
fprintf(fp,"dov_type pcm\n");
|
||||
break;
|
||||
}
|
||||
fprintf(fp,"dov_level %d\n\n", ext->dov_level);
|
||||
|
||||
if (fp) fclose(fp);
|
||||
return(1);
|
||||
|
|
|
@ -171,6 +171,10 @@ struct extension {
|
|||
int no_seconds; /* don't include seconds in the connect message */
|
||||
|
||||
char otp_ident[9]; /* up to 8 bytes of ident */
|
||||
char dov_ident[256]; /* ident string to be sent to remote via Data-Over-Voice */
|
||||
char dov_log[256]; /* log file to store received and sent Data-Over-Voice messages */
|
||||
int dov_type; /* type of modulation */
|
||||
int dov_level; /* amplitude of signal */
|
||||
};
|
||||
|
||||
int read_extension(struct extension *ext, char *number);
|
||||
|
|
15
mISDN.cpp
15
mISDN.cpp
|
@ -965,7 +965,7 @@ void PmISDN::load_tx(void)
|
|||
p_m_load = 0;
|
||||
|
||||
/* to send data, tone must be on */
|
||||
if ((p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on) /* what tones? */
|
||||
if ((p_tone_name[0] || p_dov_tx || p_m_crypt_msg_loops || p_m_inband_send_on) /* what tones? */
|
||||
&& (p_m_load < p_m_preload) /* not too much load? */
|
||||
&& (p_state==PORT_STATE_CONNECT || p_m_mISDNport->tones || p_m_inband_send_on)) { /* connected or inband-tones? */
|
||||
int tosend = p_m_preload - p_m_load, length;
|
||||
|
@ -1005,6 +1005,11 @@ void PmISDN::load_tx(void)
|
|||
tosend -= length;
|
||||
}
|
||||
|
||||
/* copy dov */
|
||||
if (p_dov_tx) {
|
||||
tosend -= dov_tx(p, tosend);
|
||||
}
|
||||
|
||||
/* copy tones */
|
||||
if (p_tone_name[0] && tosend) {
|
||||
tosend -= read_audio(p, tosend);
|
||||
|
@ -1142,6 +1147,10 @@ void PmISDN::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len
|
|||
return;
|
||||
}
|
||||
|
||||
/* dov is processed */
|
||||
if (p_dov_rx)
|
||||
dov_rx(data, len);
|
||||
|
||||
/* inband is processed */
|
||||
if (p_m_inband_receive_on)
|
||||
inband_receive(data, len);
|
||||
|
@ -1500,7 +1509,7 @@ void PmISDN::update_rxoff(void)
|
|||
int tx_dejitter = 0;
|
||||
|
||||
/* call bridges in user space OR crypto OR recording */
|
||||
if (p_bridge || p_m_crypt_msg_loops || p_m_crypt_listen || p_record || p_tap || p_m_inband_receive_on) {
|
||||
if (p_bridge || p_m_crypt_msg_loops || p_m_crypt_listen || p_record || p_tap || p_m_inband_receive_on || p_dov_rx) {
|
||||
/* rx IS required */
|
||||
if (p_m_rxoff) {
|
||||
/* turn on RX */
|
||||
|
@ -2313,7 +2322,7 @@ int PmISDN::bridge_rx(unsigned char *data, int length)
|
|||
/* check if high priority tones exist
|
||||
* ignore data in this case
|
||||
*/
|
||||
if (p_tone_name[0] || p_m_crypt_msg_loops || p_m_inband_send_on)
|
||||
if (p_tone_name[0] || p_dov_tx || p_m_crypt_msg_loops || p_m_inband_send_on)
|
||||
return -EBUSY;
|
||||
|
||||
/* preload procedure
|
||||
|
|
14
message.h
14
message.h
|
@ -357,6 +357,13 @@ struct param_vootp {
|
|||
char id[32];
|
||||
};
|
||||
|
||||
struct param_dov {
|
||||
int type; /* dov_type coding */
|
||||
int level; /* volume of sending signals */
|
||||
int length;
|
||||
unsigned char data[255];
|
||||
};
|
||||
|
||||
/* structure of message parameter */
|
||||
union parameter {
|
||||
struct param_tone tone; /* MESSAGE_TONE */
|
||||
|
@ -384,6 +391,7 @@ union parameter {
|
|||
unsigned int bridge_id; /* MESSAGE_BRIDGE */
|
||||
struct param_traffic traffic; /* MESSAGE_TRAFFIC */
|
||||
struct param_3pty threepty; /* MESSAGE_TRAFFIC */
|
||||
struct param_dov dov; /* MESSAGE_DOV */
|
||||
unsigned int queue; /* MESSAGE_DISABLE_DEJITTER */
|
||||
struct param_vootp vootp; /* MESSAGE_VOOTP */
|
||||
};
|
||||
|
@ -445,6 +453,9 @@ enum { /* messages between entities */
|
|||
MESSAGE_DISABLE_DEJITTER,/* tell (mISDN) port not to dejitter */
|
||||
MESSAGE_UPDATEBRIDGE, /* tell join to update bridge. (sent by mISDN port) */
|
||||
MESSAGE_VOOTP, /* enable/disable VoOTP */
|
||||
MESSAGE_DOV_INDICATION, /* data over voice message received */
|
||||
MESSAGE_DOV_REQUEST, /* sending data over voice message */
|
||||
MESSAGE_DOV_LISTEN, /* listen order to data over voice message */
|
||||
};
|
||||
|
||||
#define MESSAGES static const char *messages_txt[] = { \
|
||||
|
@ -486,6 +497,9 @@ enum { /* messages between entities */
|
|||
"MESSAGE_DISABLE_DEJITTER", \
|
||||
"MESSAGE_UPDATEBRIDGE", \
|
||||
"MESSAGE_VOOTP", \
|
||||
"MESSAGE_DOV_INDIVATION", \
|
||||
"MESSAGE_DOV_REQUEST", \
|
||||
"MESSAGE_DOV_LISTEN", \
|
||||
};
|
||||
|
||||
|
||||
|
|
14
port.cpp
14
port.cpp
|
@ -192,6 +192,8 @@ Port::Port(int type, const char *portname, struct port_settings *settings, struc
|
|||
#ifdef WITH_VOOTP
|
||||
p_vootp = NULL;
|
||||
#endif
|
||||
/* D-O-V */
|
||||
dov_init();
|
||||
|
||||
/* append port to chain */
|
||||
next = NULL;
|
||||
|
@ -234,6 +236,8 @@ Port::~Port(void)
|
|||
if (p_record)
|
||||
close_record(0, 0);
|
||||
|
||||
dov_exit();
|
||||
|
||||
classuse--;
|
||||
|
||||
/* disconnect port from endpoint */
|
||||
|
@ -660,6 +664,16 @@ int Port::message_epoint(unsigned int epoint_id, int message_id, union parameter
|
|||
set_vootp(¶m->vootp);
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
case MESSAGE_DOV_REQUEST: /* Data-Over-Voice message */
|
||||
PDEBUG(DEBUG_PORT, "PORT(%s) sending data over voice message (len=%d)\n", p_name, param->dov.length);
|
||||
dov_sendmsg(param->dov.data, param->dov.length, (enum dov_type)param->dov.type, param->dov.level);
|
||||
return 1;
|
||||
|
||||
case MESSAGE_DOV_LISTEN: /* Data-Over-Voice listen order */
|
||||
PDEBUG(DEBUG_PORT, "PORT(%s) sending data over voice listen order\n", p_name);
|
||||
dov_listen((enum dov_type)param->dov.type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
35
port.h
35
port.h
|
@ -182,6 +182,11 @@ struct port_bridge {
|
|||
|
||||
extern struct port_bridge *p_bridge_first;
|
||||
|
||||
enum dov_type {
|
||||
DOV_TYPE_PWM,
|
||||
DOV_TYPE_PCM,
|
||||
};
|
||||
|
||||
/* generic port class */
|
||||
class Port
|
||||
{
|
||||
|
@ -276,6 +281,36 @@ class Port
|
|||
void set_vootp(struct param_vootp *vootp);
|
||||
#endif
|
||||
|
||||
/* DOV */
|
||||
int p_dov_tx, p_dov_rx;
|
||||
int p_dov_tx_sync, p_dov_rx_sync;
|
||||
enum dov_type p_dov_tx_type, p_dov_rx_type;
|
||||
unsigned char *p_dov_tx_data, *p_dov_rx_data;
|
||||
int p_dov_tx_data_length;
|
||||
int p_dov_tx_data_pos, p_dov_rx_data_pos;
|
||||
int p_dov_tx_bit_pos, p_dov_rx_bit_pos;
|
||||
int p_dov_tx_pwm_pos, p_dov_rx_pwm_pos;
|
||||
int p_dov_rx_pwm_duration, p_dov_rx_pwm_polarity;
|
||||
int p_dov_tx_up;
|
||||
int p_dov_rx_sync_word;
|
||||
unsigned char p_dov_up;
|
||||
unsigned char p_dov_down;
|
||||
void dov_init(void);
|
||||
void dov_exit(void);
|
||||
void dov_reset_tx(void);
|
||||
void dov_reset_rx(void);
|
||||
struct lcr_timer p_dov_tx_timer;
|
||||
struct lcr_timer p_dov_rx_timer;
|
||||
void dov_sendmsg(unsigned char *data, int length, enum dov_type type, int level);
|
||||
int dov_tx(unsigned char *data, int length);
|
||||
int dov_tx_pcm(unsigned char *data, int length);
|
||||
int dov_tx_pwm(unsigned char *data, int length);
|
||||
void dov_listen(enum dov_type type);
|
||||
void dov_rx(unsigned char *data, int length);
|
||||
void dov_rx_pcm(unsigned char *data, int length);
|
||||
void dov_rx_pwm(unsigned char *data, int length);
|
||||
void dov_message(unsigned char *data, int length);
|
||||
|
||||
void free_epointlist(struct epoint_list *epointlist);
|
||||
void free_epointid(unsigned int epoint_id);
|
||||
struct epoint_list *epointlist_new(unsigned int epoint_id);
|
||||
|
|
|
@ -140,6 +140,8 @@ void Premote::message_remote(int message_type, union parameter *param)
|
|||
|
||||
switch (message_type) {
|
||||
case MESSAGE_TRAFFIC:
|
||||
if (p_dov_rx)
|
||||
dov_rx(param->traffic.data, param->traffic.len);
|
||||
/* record audio */
|
||||
if (p_record)
|
||||
record(param->traffic.data, param->traffic.len, 0); // from down
|
||||
|
@ -154,6 +156,10 @@ void Premote::message_remote(int message_type, union parameter *param)
|
|||
if (p_tap)
|
||||
tap(param->traffic.data, param->traffic.len, 1); // from up
|
||||
admin_message_from_lcr(p_r_remote_id, p_r_ref, MESSAGE_TRAFFIC, param);
|
||||
} else if (p_dov_tx) {
|
||||
/* use receeived traffic to trigger sending DOV */
|
||||
dov_tx(param->traffic.data, param->traffic.len);
|
||||
admin_message_from_lcr(p_r_remote_id, p_r_ref, MESSAGE_TRAFFIC, param);
|
||||
}
|
||||
return;
|
||||
|
||||
|
|
14
sip.cpp
14
sip.cpp
|
@ -280,6 +280,8 @@ we only support alaw and ulaw!
|
|||
}
|
||||
while(n--)
|
||||
*to++ = flip[*from++];
|
||||
if (psip->p_dov_rx)
|
||||
psip->dov_rx(payload, payload_len);
|
||||
psip->bridge_tx(payload, payload_len);
|
||||
|
||||
return 0;
|
||||
|
@ -600,7 +602,10 @@ int Psip::bridge_rx(unsigned char *data, int len)
|
|||
int ret;
|
||||
|
||||
/* don't bridge, if tones are provided */
|
||||
if (p_tone_name[0])
|
||||
if (p_tone_name[0] || p_dov_tx)
|
||||
return -EBUSY;
|
||||
|
||||
if (p_dov_tx)
|
||||
return -EBUSY;
|
||||
|
||||
if ((ret = Port::bridge_rx(data, len)))
|
||||
|
@ -2045,7 +2050,7 @@ void Psip::update_load(void)
|
|||
return;
|
||||
|
||||
/* don't start timer if ... */
|
||||
if (!p_tone_name[0])
|
||||
if (!p_tone_name[0] && !p_dov_tx)
|
||||
return;
|
||||
|
||||
p_s_next_tv_sec = 0;
|
||||
|
@ -2057,7 +2062,7 @@ static int load_timer(struct lcr_timer *timer, void *instance, int index)
|
|||
class Psip *psip = (class Psip *)instance;
|
||||
|
||||
/* stop timer if ... */
|
||||
if (!psip->p_tone_name[0])
|
||||
if (!psip->p_tone_name[0] && !psip->p_dov_tx)
|
||||
return 0;
|
||||
|
||||
psip->load_tx();
|
||||
|
@ -2111,6 +2116,9 @@ void Psip::load_tx(void)
|
|||
/* copy tones */
|
||||
if (p_tone_name[0]) {
|
||||
tosend -= read_audio(p, tosend);
|
||||
} else
|
||||
if (p_dov_tx) {
|
||||
tosend -= dov_tx(p, tosend);
|
||||
}
|
||||
if (tosend) {
|
||||
PERROR("buffer is not completely filled\n");
|
||||
|
|
Loading…
Reference in New Issue