isdn4k-utils/vbox3/vboxgetty/voice.c

377 lines
9.2 KiB
C
Raw Blame History

/*
** $Id: voice.c,v 1.3 1998/07/06 09:05:38 michael Exp $
**
** Copyright 1996-1998 Michael 'Ghandi' Herold <michael@abadonna.mayn.de>
**
** $Log: voice.c,v $
** Revision 1.3 1998/07/06 09:05:38 michael
** - New control file code added. The controls are not longer only empty
** files - they can contain additional informations.
** - Control "vboxctrl-answer" added.
** - Control "vboxctrl-suspend" added.
** - Locking mechanism added.
** - Configuration parsing added.
** - Some code cleanups.
**
** Revision 1.2 1998/06/17 17:01:26 michael
** - First part of the automake/autoconf implementation. Currently vbox will
** *not* compile!
**
*/
#ifdef HAVE_CONFIG_H
# include "../config.h"
#endif
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include "voice.h"
#include "log.h"
#include "modem.h"
#include "stringutils.h"
#include "userrc.h"
#include "vboxrc.h"
#include "vboxgetty.h"
#include "tclscript.h"
#include "control.h"
/** Variables ************************************************************/
static struct vboxuser *voicevboxuser;
static struct vboxcall *voicevboxcall;
static int voicesave = -1;
static int voicevbox = 0;
static int voicehear = -1;
static int voicestat = VBOXVOICE_STAT_OK;
static char voicename_ulaw[PATH_MAX + 1];
static char voicename_vbox[PATH_MAX + 1];
/*************************************************************************/
/** **/
/*************************************************************************/
int voice_init(struct vboxuser *vboxuser, struct vboxcall *vboxcall)
{
char msgsavetime[32];
char voicestoppl[2];
char voicestoprc[2];
time_t currenttime;
char *stop;
int rc;
struct vbox_tcl_variable vars[] =
{
{ "vbxv_savetime" , msgsavetime },
{ "vbxv_callerid" , vboxuser->incomingid },
{ "vbxv_callername" , vboxcall->name },
{ "vbxv_localphone" , vboxuser->localphone },
{ "vbxv_username" , vboxuser->name },
{ "vbxv_userhome" , vboxuser->home },
{ "vbxv_usedscript" , vboxcall->script },
{ "vbxv_saveulaw" , voicename_ulaw },
{ "vbxv_savevbox" , voicename_vbox },
{ NULL , NULL }
};
printstring(msgsavetime, "%d", vboxcall->savetime);
/* Die beiden <20>bergebenen Strukturen global machen, damit alle */
/* Voice Funktionen sie benutzen k<>nnen. */
voicevboxuser = vboxuser;
voicevboxcall = vboxcall;
/* Die Namen der beiden Dateien (*.ulaw und *.vbox) erzeugen. */
/* Eine Datei enth<74>lt die Audiodaten, die andere die Inform- */
/* ationen <20>ber den Benutzer. */
currenttime = time(NULL);
printstring(voicename_ulaw, "%s/incoming/%11.11lu-%8.8lu.ulaw", vboxuser->home, (unsigned long)currenttime, (unsigned long)getpid());
printstring(voicename_vbox, "%s/incoming/%11.11lu-%8.8lu.vbox", vboxuser->home, (unsigned long)currenttime, (unsigned long)getpid());
/* Variablen f<>r Tcl erzeugen, Kompression setzen, Full Duplex */
/* Audio Modus starten und das Skript aufrufen. */
if (scr_init_variables(vars) == 0)
{
log_line(LOG_D, "Setting voice compression to \"ulaw\"...\n");
if (modem_command(&vboxmodem, "AT+VSM=6+VLS=2", "OK") > 0)
{
log_line(LOG_D, "Starting full duplex audio mode...\n");
if (modem_command(&vboxmodem, "AT+VTX+VRX", "CONNECT") > 0)
{
rc = scr_execute(vboxcall->script, vboxuser);
voice_hear(0);
voice_save(0);
printstring(voicestoppl, "%c%c", DLE, ETX);
printstring(voicestoprc, "%c%c", DLE, DC4);
log_line(LOG_D, "Sending \"<DLE><ETX>\" to stop playback mode...\n");
vboxmodem_raw_write(&vboxmodem, voicestoppl, 2);
log_line(LOG_D, "Sending \"<DLE><DC4>\" to stop record mode...\n");
vboxmodem_raw_write(&vboxmodem, voicestoprc, 2);
modem_flush(&vboxmodem, 0);
if ((stop = ctrl_exists(vboxuser->home, "suspend")))
{
ctrl_remove(vboxuser->home, "suspend");
log_line(LOG_A, "Suspending call to number %s...\n", stop);
if (modem_command(&vboxmodem, "AT+S1", "OK") > 0) {
log_line(LOG_D, "Call suspended to number %s.\n", stop);
} else {
log_line(LOG_E, "Can't suspend call to number %s.\n", stop);
}
}
return(rc);
}
}
}
return(-1);
}
/*************************************************************************/
/** voice_wait(): Liest eine angegebene Zeit lang Audiodaten vom Modem. **/
/*************************************************************************/
/** => timeout Timeout in Sekunden **/
/*************************************************************************/
/** <= 0 wenn der Timeout eingetreten ist. **/
/** 1 wenn eine g<>ltige Touchtonesequenz gefunden wurde. **/
/** 2 wenn der Anruf suspended werden soll. **/
/** -1 bei einem Fehler. **/
/*************************************************************************/
int voice_wait(int timeout)
{
char line_i[1];
char line_o[VBOXVOICE_BUFFER_SIZE + 1];
int byte_i;
int byte_o;
int result;
int gotdle;
voicestat = VBOXVOICE_STAT_OK;
gotdle = 0;
if (voicesave == -1)
log_line(LOG_D, "Reading audio datas (%ds timeout)...\n", timeout);
else
log_line(LOG_D, "Recording \"%s\" (%ds timeout)...\n", voicename_ulaw, timeout);
modem_set_timeout(timeout);
while (voicestat == VBOXVOICE_STAT_OK)
{
byte_i = 0;
byte_o = 0;
result = 0;
while ((byte_o < VBOXVOICE_BUFFER_SIZE) && (voicestat == VBOXVOICE_STAT_OK))
{
if ((result = vboxmodem_raw_read(&vboxmodem, line_i, 1)) == 1)
{
byte_i++;
if (gotdle)
{
switch (*line_i)
{
case ETX:
voicestat |= VBOXVOICE_STAT_HANGUP;
break;
default:
/*if (voice_check_touchtone(*line_i) == 0) voicestat |= VBOXVOICE_STAT_TOUCHTONE;*/
break;
}
gotdle = 0;
}
else
{
if (*line_i != DLE)
{
line_o[byte_o++] = *line_i;
}
else gotdle = 1;
}
}
else break;
}
if (byte_o > 0)
{
if (voicesave != -1) write(voicesave, line_o, byte_o);
if (voicehear != -1) write(voicehear, line_o, byte_o);
}
if (ctrl_exists(voicevboxuser->home, "suspend")) voicestat |= VBOXVOICE_STAT_SUSPEND;
if ((result != 1) || (modem_get_timeout()))
{
if (!modem_get_timeout())
{
log_line(LOG_W, "Can't read voice data: %s!\n", strerror(errno));
voicestat |= VBOXVOICE_STAT_TIMEOUT;
}
else voicestat |= VBOXVOICE_STAT_TIMEOUT;
}
}
modem_set_timeout(0);
result = 0;
if (voicestat & VBOXVOICE_STAT_TOUCHTONE)
{
log_line(LOG_D, "Full touchtone sequence found!\n");
result = 1;
}
if (voicestat & VBOXVOICE_STAT_SUSPEND) result = 2;
if ((voicestat & VBOXVOICE_STAT_HANGUP) || (vboxmodem.nocarrier))
{
log_line(LOG_D, "Remote hangup - audio output & saving stopped.\n");
voice_save(0);
voice_hear(0);
modem_command(&vboxmodem, "", "NO CARRIER");
result = -1;
}
return(result);
}
/*************************************************************************/
/** voice_save(): Schaltet das mitspeichern der eingehenden Audiodaten **/
/** ein oder aus. **/
/*************************************************************************/
/** => save 1 wenn die Daten gespeichert werden sollen oder 0 **/
/** wenn nicht. **/
/** **/
/** <= 0 wenn die Aktion ausgef<65>hrt werden konnte oder -1 **/
/** einem Fehler. **/
/*************************************************************************/
int voice_save(int save)
{
struct vboxsave vboxsave;
int desc;
if (save)
{
log_line(LOG_D, "Starting audio recording...\n");
if (!voicevbox)
{
/* Wenn die *.vbox Datei noch nicht existiert wird sie */
/* jetzt erzeugt. Die Datei enth<74>lt die Informationen */
/* wer wann wie die Nachricht gesprochen hat. */
log_line(LOG_D, "Opening \"%s\"...\n", voicename_vbox);
if ((desc = open(voicename_vbox, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != -1)
{
vboxsave.time = time(NULL);
xstrncpy(vboxsave.name , voicevboxcall->name , VBOXSAVE_NAME);
xstrncpy(vboxsave.id , voicevboxuser->incomingid, VBOXSAVE_ID );
if (write(desc, &vboxsave, sizeof(vboxsave)) == sizeof(vboxsave))
{
voicevbox = 1;
}
close(desc);
}
else log_line(LOG_E, "Can't create \"%s\".\n", voicename_vbox);
}
if (voicesave == -1)
{
log_line(LOG_D, "Opening \"%s\"...\n", voicename_ulaw);
voicesave = open(voicename_ulaw, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
}
if (voicesave != -1) return(0);
log_line(LOG_E, "Can't open/append \"%s\".\n", voicename_ulaw);
}
else
{
log_line(LOG_D, "Stopping audio recording...\n");
if (voicesave != -1)
{
log_line(LOG_D, "Closing \"%s\"...\n", voicename_ulaw);
close(voicesave);
}
voicesave = -1;
return(0);
}
return(-1);
}
int voice_hear(int hear)
{
if (hear)
{
if (voicehear == -1)
{
voicehear = open("/dev/audio", O_WRONLY);
}
if (voicehear != -1) return(0);
}
else
{
if (voicehear != -1) close(voicehear);
voicehear = -1;
return(0);
}
return(-1);
}