summaryrefslogtreecommitdiffstats
path: root/vbox.cpp
diff options
context:
space:
mode:
authorSuper User2007-05-06 15:54:52 +0200
committerSuper User2007-05-06 15:54:52 +0200
commit2ed0fee489c37a6e2d4473f6185ebbe3e746ac11 (patch)
treefcf232bc282c083404cfde0ce5b04236fe202c3e /vbox.cpp
parentfirst commit (diff)
downloadlcr-2ed0fee489c37a6e2d4473f6185ebbe3e746ac11.tar.gz
lcr-2ed0fee489c37a6e2d4473f6185ebbe3e746ac11.tar.xz
lcr-2ed0fee489c37a6e2d4473f6185ebbe3e746ac11.zip
only for backup, still in coding state - no compile!!!
Diffstat (limited to 'vbox.cpp')
-rw-r--r--vbox.cpp350
1 files changed, 350 insertions, 0 deletions
diff --git a/vbox.cpp b/vbox.cpp
new file mode 100644
index 0000000..2a96962
--- /dev/null
+++ b/vbox.cpp
@@ -0,0 +1,350 @@
+/*****************************************************************************\
+** **
+** PBX4Linux **
+** **
+**---------------------------------------------------------------------------**
+** Copyright: Andreas Eversberg **
+** **
+** answering machine port **
+** **
+** this is a child of the port class, which emulates the recorder function **
+** of an answering machine **
+** it will directly answer to the setup message with a connect **
+** **
+\*****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <poll.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "main.h"
+
+/* note: recording log is written at endpoint */
+
+/*
+ * initialize vbox port
+ */
+VBoxPort::VBoxPort(int type, struct port_settings *settings) : Port(type, "vbox", settings)
+{
+ p_vbox_timeout = 0;
+ p_vbox_announce_fh = -1;
+ p_vbox_audio_start = 0;
+ p_vbox_audio_transferred = 0;
+ p_vbox_record_start = 0;
+ p_vbox_record_limit = 0;
+}
+
+
+/*
+ * destructor
+ */
+VBoxPort::~VBoxPort()
+{
+ if (p_vbox_announce_fh >= 0)
+ {
+ close(p_vbox_announce_fh);
+ p_vbox_announce_fh = -1;
+ fhuse--;
+ }
+}
+
+
+/*
+ * handler of vbox
+ */
+int VBoxPort::handler(void)
+{
+ struct message *message;
+ unsigned long tosend;
+ signed short buffer[128<<1];
+ time_t currenttime;
+ class Endpoint *epoint;
+
+ if (p_vbox_record_start && p_vbox_record_limit)
+ {
+ time(&currenttime);
+ if (currenttime > (p_vbox_record_limit+p_vbox_record_start))
+ {
+ while(p_epointlist)
+ {
+ /* send release */
+ message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
+ message->param.disconnectinfo.cause = 16;
+ message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+ message_put(message);
+ /* remove epoint */
+ free_epointlist(p_epointlist);
+ }
+ /* recording is close during destruction */
+ delete this;
+ return(-1); /* must return because port is gone */
+ }
+ }
+
+ if (p_vbox_audio_start < 1)
+ {
+ /* set time the first time */
+ p_vbox_audio_start = now_d;
+ } else
+ {
+ /* calculate the number of bytes */
+ tosend = (unsigned long)((now_d-p_vbox_audio_start)*8000) - p_vbox_audio_transferred;
+
+ /* wait for more */
+ if (tosend < 32)
+ return(0);
+
+ /* too many samples, so we just process 128 bytes until the next call of handler() */
+ if (tosend > 128)
+ tosend = 128;
+
+ /* dummy read, to clock record buffer */
+ read_audio((unsigned char *)buffer, tosend, 0);
+
+ /* add the number of samples elapsed */
+ p_vbox_audio_transferred += tosend;
+
+ /* if announcement is currently played, send audio data */
+ if (p_vbox_announce_fh >=0)
+ {
+ /* read from announcement file */
+ switch(p_vbox_announce_codec)
+ {
+ case CODEC_LAW:
+ tosend = read_tone(p_vbox_announce_fh, buffer, p_vbox_announce_codec, tosend, p_vbox_announce_size, &p_vbox_announce_left, 1);
+ break;
+
+ case CODEC_MONO:
+ case CODEC_STEREO:
+ case CODEC_8BIT:
+ tosend = read_tone(p_vbox_announce_fh, buffer, p_vbox_announce_codec, tosend, p_vbox_announce_size, &p_vbox_announce_left, 1);
+ break;
+
+ default:
+ PERROR("correct codec not given.\n");
+ exit(-1);
+ }
+ if (tosend <= 0)
+ {
+ /* end of file */
+ close(p_vbox_announce_fh);
+ p_vbox_announce_fh = -1;
+ fhuse--;
+
+ time(&currenttime);
+ p_vbox_record_start = currenttime;
+
+ /* connect if not already */
+ epoint = find_epoint_id(ACTIVE_EPOINT(p_epointlist));
+ if (epoint)
+ {
+ /* if we sent our announcement during ringing, we must now connect */
+ if (p_vbox_apppbx->e_ext.vbox_free)
+ {
+ /* send connect message */
+ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
+ memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
+ message_put(message);
+ new_state(PORT_STATE_CONNECT);
+ }
+ }
+
+ /* start recording, if not already */
+ if (p_vbox_mode == VBOX_MODE_NORMAL)
+ {
+ /* send recording start message */
+ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_VBOX_RECORD);
+ message_put(message);
+ } else // else!!
+ if (p_vbox_mode == VBOX_MODE_ANNOUNCEMENT)
+ {
+ /* send release */
+ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
+ message->param.disconnectinfo.cause = 16;
+ message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+ message_put(message);
+ /* recording is close during destruction */
+ delete this;
+ return(-1); /* must return because port is gone */
+ }
+ } else
+ {
+ switch(p_vbox_announce_codec)
+ {
+ case CODEC_LAW:
+ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DATA);
+ message->param.data.compressed = 1;
+ message->param.data.port_type = p_type;
+ message->param.data.port_id = p_serial;
+ message->param.data.len = tosend;
+ memcpy(message->param.data.data, buffer, tosend);
+ message_put(message);
+ break;
+
+ case CODEC_MONO:
+ case CODEC_STEREO:
+ case CODEC_8BIT:
+ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DATA);
+ message->param.data.compressed = 0;
+ message->param.data.port_type = p_type;
+ message->param.data.port_id = p_serial;
+ message->param.data.len = tosend<<1;
+ memcpy(message->param.data.data, buffer, tosend<<1);
+ message_put(message);
+ break;
+
+ default:
+ PERROR("correct announce_codec not given.\n");
+ exit(-1);
+ }
+ }
+ }
+
+ }
+ return(1);
+}
+
+
+/*
+ * endpoint sends messages to the vbox port
+ */
+int VBoxPort::message_epoint(unsigned long epoint_id, int message_id, union parameter *param)
+{
+ struct message *message;
+ class Endpoint *epoint;
+ char filename[256], *c;
+ class EndpointAppPBX *eapp;
+
+ epoint = find_epoint_id(epoint_id);
+ if (!epoint)
+ {
+ PDEBUG(DEBUG_EPOINT|DEBUG_VBOX, "PORT(%s) no endpoint object found where the message is from.\n", p_name);
+ return(0);
+ }
+
+ if (Port::message_epoint(epoint_id, message_id, param))
+ return(1);
+
+ switch(message_id)
+ {
+ case MESSAGE_DISCONNECT: /* call has been disconnected */
+ PDEBUG(DEBUG_VBOX, "PORT(%s) vbox port with (caller id %s) received disconnect cause=%d\n", p_name, p_callerinfo.id, param->disconnectinfo.cause);
+
+ new_state(PORT_STATE_OUT_DISCONNECT);
+
+ while(p_epointlist)
+ {
+ message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
+ message->param.disconnectinfo.cause = CAUSE_NORMAL;
+ message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+ message_put(message);
+ /* remove epoint */
+ free_epointlist(p_epointlist);
+ }
+ /* recording is close during destruction */
+ delete this;
+ return(-1); /* must return because port is gone */
+ break;
+
+ case MESSAGE_RELEASE: /* release vbox port */
+ PDEBUG(DEBUG_VBOX, "PORT(%s) vbox port with (caller id %s) received release\n", p_name, p_callerinfo.id);
+
+ /* we are done */
+ /* recording is close during destruction */
+ delete this;
+ return(-1); /* must return because port is gone */
+ break;
+
+ case MESSAGE_SETUP: /* dial-out command received from epoint, answer with connect */
+ /* get apppbx */
+ eapp = (class EndpointAppPBX *)(epoint->ep_app);
+ p_vbox_apppbx = eapp;
+ /* extract optional announcement file */
+ if ((c = strchr(param->setup.dialinginfo.number, ',')))
+ {
+ if (c[1] == '/')
+ SPRINT(filename, c+1);
+ else
+ SPRINT(filename, "%s/%s/%s/vbox/%s", INSTALL_DATA, options.extensions_dir, p_vbox_apppbx->e_terminal);
+ *c = '\0';
+ } else
+ {
+ SPRINT(filename, "%s/%s/%s/vbox/announcement", INSTALL_DATA, options.extensions_dir, p_vbox_apppbx->e_terminal);
+ }
+ PDEBUG(DEBUG_VBOX, "PORT(%s) vbox port received setup from '%s' to '%s'\n", p_name, param->setup.callerinfo.id, param->setup.dialinginfo.number);
+ memcpy(&p_callerinfo, &param->setup.callerinfo, sizeof(p_callerinfo));
+ memcpy(&p_redirinfo, &param->setup.redirinfo, sizeof(p_redirinfo));
+ /* link relation */
+ if (p_epointlist)
+ {
+ PERROR("PORT(%s) software error: epoint pointer is set in idle state, how bad!! exitting.\n", p_name);
+ exit(-1);
+ }
+ if (!(epointlist_new(epoint_id)))
+ {
+ PERROR("no memory for epointlist\n");
+ exit(-1);
+ }
+
+ /* copy setup infos to port */
+ SCPY(p_vbox_extension, param->setup.dialinginfo.number);
+
+ /* create connect info */
+ SCPY(p_connectinfo.id, p_vbox_extension);
+ p_connectinfo.itype = INFO_ITYPE_VBOX;
+ p_connectinfo.present = INFO_PRESENT_ALLOWED;
+ p_connectinfo.screen = INFO_SCREEN_NETWORK;
+
+ /* connect unless we can send announcement while ringing */
+ if (!p_vbox_apppbx->e_ext.vbox_free)
+ {
+ /* send connect message */
+ message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_CONNECT);
+ memcpy(&message->param.connectinfo, &p_connectinfo, sizeof(struct connect_info));
+ message_put(message);
+ new_state(PORT_STATE_CONNECT);
+ } else
+ {
+ /* send alerting message */
+ message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_ALERTING);
+ message_put(message);
+ new_state(PORT_STATE_IN_ALERTING);
+ }
+
+ /* start recording during announcement */
+ /* start parallel recording if desired */
+ p_vbox_mode = p_vbox_apppbx->e_ext.vbox_mode;
+ p_vbox_record_limit = p_vbox_apppbx->e_ext.vbox_time;
+ if (p_vbox_mode == VBOX_MODE_PARALLEL)
+ {
+ /* send recording start message */
+ message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_VBOX_RECORD);
+ message_put(message);
+ }
+ /* play the announcement */
+ if ((p_vbox_announce_fh = open_tone(filename, &p_vbox_announce_codec, &p_vbox_announce_size, &p_vbox_announce_left)) >= 0)
+ {
+ fhuse++;
+ } else
+ {
+ PDEBUG(DEBUG_VBOX, "PORT(%s) no announcement found at: '%s' so we start recording now.\n", p_name, filename);
+ /* send recording start message */
+ message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_VBOX_RECORD);
+ message_put(message);
+ }
+ break;
+
+ default:
+ PDEBUG(DEBUG_VBOX, "PORT(%s) vbox port with (caller id %s) received an unsupported message: %d\n", p_name, p_callerinfo.id, message_id);
+ }
+
+ return(0);
+}
+
+