mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-02-20 09:26:37 +00:00
Write simple vomp console client
This commit is contained in:
parent
66e0711d6b
commit
fa7719fbe8
@ -48,6 +48,7 @@ SERVALD_SRC_FILES = \
|
||||
serval-dna/str.c \
|
||||
serval-dna/keyring.c \
|
||||
serval-dna/vomp.c \
|
||||
serval-dna/vomp_console.c \
|
||||
serval-dna/lsif.c \
|
||||
serval-dna/dna_helper.c \
|
||||
serval-dna/sighandlers.c \
|
||||
|
@ -62,6 +62,7 @@ SRCS= \
|
||||
strbuf_helpers.c \
|
||||
strlcpy.c \
|
||||
vomp.c \
|
||||
vomp_console.c \
|
||||
xprintf.c
|
||||
|
||||
MONITORCLIENTSRCS=conf.c \
|
||||
|
@ -1652,6 +1652,8 @@ struct command_line_option command_line_options[]={
|
||||
"Set specified configuration variable."},
|
||||
{app_config_get,{"config","get","[<variable>]",NULL},CLIFLAG_STANDALONE,
|
||||
"Get specified configuration variable."},
|
||||
{app_vomp_console,{"console",NULL},0,
|
||||
"Test phone call life-cycle from the console"},
|
||||
{app_rhizome_hash_file,{"rhizome","hash","file","<filepath>",NULL},CLIFLAG_STANDALONE,
|
||||
"Compute the Rhizome hash of a file"},
|
||||
{app_rhizome_add_file,{"rhizome","add","file","<author_sid>","<pin>","<filepath>","[<manifestpath>]","[<bsk>]",NULL},CLIFLAG_STANDALONE,
|
||||
|
@ -297,9 +297,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#define VOMP_CODEC_DTMF 0x80
|
||||
#define VOMP_CODEC_ENGAGED 0x81
|
||||
#define VOMP_CODEC_ONHOLD 0x82
|
||||
#define VOMP_CODEC_CALLERID 0x83
|
||||
#define VOMP_CODEC_CODECSISUPPORT 0xfe
|
||||
#define VOMP_CODEC_CHANGEYOURCODECTO 0xff
|
||||
|
||||
#define CODEC_FLAGS_LENGTH 32
|
||||
|
||||
/* in milliseconds of inactivity */
|
||||
// 20 seconds to start ringing
|
||||
|
@ -123,7 +123,12 @@ static void resolve_request(){
|
||||
static char line_buff[1024];
|
||||
static int line_pos=0;
|
||||
|
||||
set_nonblock(STDIN_FILENO);
|
||||
|
||||
int bytes = read(STDIN_FILENO, line_buff + line_pos, sizeof(line_buff) - line_pos);
|
||||
|
||||
set_block(STDIN_FILENO);
|
||||
|
||||
int i = line_pos;
|
||||
int processed=0;
|
||||
line_pos+=bytes;
|
||||
@ -156,8 +161,6 @@ int main(int argc, char **argv){
|
||||
if (overlay_mdp_bind(srcsid,MDP_PORT_DIRECTORY))
|
||||
return WHY("Could not bind to MDP socket");
|
||||
|
||||
set_nonblock(STDIN_FILENO);
|
||||
|
||||
fds[0].fd = STDIN_FILENO;
|
||||
fds[0].events = POLLIN;
|
||||
fds[1].fd = mdp_client_socket;
|
||||
|
@ -163,6 +163,9 @@ int monitor_client_read(int fd, struct monitor_state *res, struct monitor_comman
|
||||
/* Read any available bytes */
|
||||
int oldOffset = res->bufferBytes;
|
||||
|
||||
if (oldOffset+1>=MONITOR_CLIENT_BUFFER_SIZE)
|
||||
return WHY("Buffer full without finding command");
|
||||
|
||||
if (res->bufferBytes==0)
|
||||
res->cmd = (char *)res->buffer;
|
||||
|
||||
@ -182,14 +185,12 @@ int monitor_client_read(int fd, struct monitor_state *res, struct monitor_comman
|
||||
WHY_perror("read");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res->bufferBytes+=bytesRead;
|
||||
|
||||
again:
|
||||
// wait until we have the whole command line
|
||||
if (res->state == STATE_INIT){
|
||||
int i;
|
||||
|
||||
for(i=oldOffset;i<res->bufferBytes;i++){
|
||||
if (res->buffer[i]=='\n'){
|
||||
// skip any leading \n's
|
||||
@ -205,6 +206,8 @@ again:
|
||||
res->cmd++;
|
||||
for (; isdigit(*res->cmd); ++res->cmd)
|
||||
res->dataBytes = res->dataBytes * 10 + *res->cmd - '0';
|
||||
if (res->dataBytes<0 || res->dataBytes > MONITOR_CLIENT_BUFFER_SIZE)
|
||||
return WHYF("Invalid data length %d", res->dataBytes);
|
||||
if (*res->cmd==':')
|
||||
res->cmd++;
|
||||
}
|
||||
@ -213,7 +216,7 @@ again:
|
||||
{
|
||||
char *p=res->cmd;
|
||||
res->argc=0;
|
||||
while (*p){
|
||||
while (*p && res->argc<MAX_ARGS){
|
||||
if (*p==':'){
|
||||
*p=0;
|
||||
res->argv[res->argc]=p+1;
|
||||
|
52
monitor.c
52
monitor.c
@ -39,7 +39,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#define MONITOR_DATA_SIZE MAX_AUDIO_BYTES
|
||||
struct monitor_context {
|
||||
struct sched_ent alarm;
|
||||
// monitor interest bitmask
|
||||
int flags;
|
||||
// what types of audio can we write to this client?
|
||||
// (packed bits)
|
||||
unsigned char supported_codecs[CODEC_FLAGS_LENGTH];
|
||||
|
||||
char line[MONITOR_LINE_LENGTH];
|
||||
int line_length;
|
||||
#define MONITOR_STATE_COMMAND 1
|
||||
@ -335,7 +340,7 @@ static void monitor_new_client(int s) {
|
||||
c->alarm.poll.events=POLLIN;
|
||||
c->line_length = 0;
|
||||
c->state = MONITOR_STATE_COMMAND;
|
||||
write_str(s,"\nMONITOR:You are talking to servald\n");
|
||||
write_str(s,"\nINFO:You are talking to servald\n");
|
||||
INFOF("Got %d clients", monitor_socket_count);
|
||||
watch(&c->alarm);
|
||||
|
||||
@ -346,11 +351,30 @@ static void monitor_new_client(int s) {
|
||||
return;
|
||||
}
|
||||
|
||||
void monitor_get_all_supported_codecs(unsigned char *codecs){
|
||||
int i, j;
|
||||
bzero(codecs,CODEC_FLAGS_LENGTH);
|
||||
for(i=monitor_socket_count -1;i>=0;i--) {
|
||||
if (monitor_sockets[i].flags & MONITOR_VOMP){
|
||||
for (j=0;j<CODEC_FLAGS_LENGTH;j++)
|
||||
codecs[j]|=monitor_sockets[i].supported_codecs[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int monitor_set(int argc, const char *const *argv, struct command_line_option *o, void *context){
|
||||
struct monitor_context *c=context;
|
||||
if (strcase_startswith((char *)argv[1],"vomp",NULL))
|
||||
if (strcase_startswith((char *)argv[1],"vomp",NULL)){
|
||||
c->flags|=MONITOR_VOMP;
|
||||
else if (strcase_startswith((char *)argv[1],"rhizome", NULL))
|
||||
// store the list of supported codecs against the monitor connection,
|
||||
// since we need to forget about them when the client disappears.
|
||||
int i;
|
||||
for (i=2;i<argc;i++){
|
||||
int codec = atoi(argv[i]);
|
||||
if (codec>=0 && codec <=255)
|
||||
set_codec_flag(codec, c->supported_codecs);
|
||||
}
|
||||
}else if (strcase_startswith((char *)argv[1],"rhizome", NULL))
|
||||
c->flags|=MONITOR_RHIZOME;
|
||||
else if (strcase_startswith((char *)argv[1],"peers", NULL))
|
||||
c->flags|=MONITOR_PEERS;
|
||||
@ -482,6 +506,7 @@ static int monitor_call_dtmf(int argc, const char *const *argv, struct command_l
|
||||
}
|
||||
|
||||
struct command_line_option monitor_options[]={
|
||||
{monitor_set,{"monitor","vomp","<codec>","...",NULL},0,""},
|
||||
{monitor_set,{"monitor","<type>",NULL},0,""},
|
||||
{monitor_clear,{"ignore","<type>",NULL},0,""},
|
||||
{monitor_lookup_match,{"lookup","match","<sid>","<port>","<ext>","<name>",NULL},0,""},
|
||||
@ -491,28 +516,9 @@ struct command_line_option monitor_options[]={
|
||||
{monitor_call_audio,{"audio","<token>","<type>","[<offset>]",NULL},0,""},
|
||||
{monitor_call_hangup, {"hangup","<token>",NULL},0,""},
|
||||
{monitor_call_dtmf, {"dtmf","<token>","<digits>",NULL},0,""},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
static int parse_argv(char *cmdline, char delim, char **argv, int max_argv){
|
||||
int argc=0;
|
||||
|
||||
if (*cmdline && argc<max_argv){
|
||||
argv[argc++]=cmdline;
|
||||
}
|
||||
|
||||
// TODO quoted argument handling?
|
||||
|
||||
while(*cmdline){
|
||||
if (*cmdline==delim){
|
||||
*cmdline=0;
|
||||
if (cmdline[1] && argc<max_argv)
|
||||
argv[argc++]=cmdline+1;
|
||||
}
|
||||
cmdline++;
|
||||
}
|
||||
return argc;
|
||||
}
|
||||
|
||||
int monitor_process_command(struct monitor_context *c)
|
||||
{
|
||||
char *argv[16]={NULL,};
|
||||
|
@ -212,14 +212,12 @@ int overlay_mdp_process_bind_request(int sock, struct subscriber *subscriber, in
|
||||
}
|
||||
|
||||
/* See if binding already exists */
|
||||
int found=-1; // XXX: this is never set, why is it here?
|
||||
int free=-1;
|
||||
for(i=0;i<MDP_MAX_BINDINGS;i++) {
|
||||
/* Look for duplicate bindings */
|
||||
if (mdp_bindings[i].port == port && mdp_bindings[i].subscriber == subscriber) {
|
||||
if (found != -1 &&
|
||||
mdp_bindings[found].name_len==recvaddrlen &&
|
||||
!memcmp(mdp_bindings[found].socket_name,recvaddr->sun_path,recvaddrlen)) {
|
||||
if (mdp_bindings[i].name_len==recvaddrlen &&
|
||||
!memcmp(mdp_bindings[i].socket_name,recvaddr->sun_path,recvaddrlen)) {
|
||||
// this client already owns this port binding?
|
||||
INFO("Identical binding exists");
|
||||
return 0;
|
||||
@ -657,6 +655,8 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
|
||||
|
||||
/* Prepare the overlay frame for dispatch */
|
||||
struct overlay_frame *frame = calloc(1,sizeof(struct overlay_frame));
|
||||
if (!frame)
|
||||
FATAL("Couldn't allocate frame buffer");
|
||||
|
||||
if (is_sid_any(mdp->out.src.sid)){
|
||||
/* set source to ourselves */
|
||||
|
6
serval.h
6
serval.h
@ -788,6 +788,10 @@ void _serval_debug_free(void *p, struct __sourceloc where);
|
||||
|
||||
|
||||
struct vomp_call_state;
|
||||
|
||||
void set_codec_flag(int codec, unsigned char *flags);
|
||||
int is_codec_set(int codec, unsigned char *flags);
|
||||
|
||||
struct vomp_call_state *vomp_find_call_by_session(int session_token);
|
||||
int vomp_mdp_received(overlay_mdp_frame *mdp);
|
||||
int vomp_tick_interval();
|
||||
@ -799,6 +803,7 @@ int vomp_pickup(struct vomp_call_state *call);
|
||||
int vomp_hangup(struct vomp_call_state *call);
|
||||
int vomp_ringing(struct vomp_call_state *call);
|
||||
int vomp_received_audio(struct vomp_call_state *call, int audio_codec, const unsigned char *audio, int audio_length);
|
||||
void monitor_get_all_supported_codecs(unsigned char *codecs);
|
||||
|
||||
int cli_putchar(char c);
|
||||
int cli_puts(const char *str);
|
||||
@ -825,6 +830,7 @@ struct command_line_option;
|
||||
int app_pa_phone(int argc, const char *const *argv, struct command_line_option *o, void *context);
|
||||
#endif
|
||||
int app_monitor_cli(int argc, const char *const *argv, struct command_line_option *o, void *context);
|
||||
int app_vomp_console(int argc, const char *const *argv, struct command_line_option *o, void *context);
|
||||
|
||||
int monitor_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
|
||||
|
||||
|
20
str.c
20
str.c
@ -42,3 +42,23 @@ int strcase_startswith(char *str, const char *substring, char **afterp)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse_argv(char *cmdline, char delim, char **argv, int max_argv){
|
||||
int argc=0;
|
||||
|
||||
if (*cmdline && argc<max_argv){
|
||||
argv[argc++]=cmdline;
|
||||
}
|
||||
|
||||
// TODO quoted argument handling?
|
||||
|
||||
while(*cmdline){
|
||||
if (*cmdline==delim){
|
||||
*cmdline=0;
|
||||
if (cmdline[1] && argc<max_argv)
|
||||
argv[argc++]=cmdline+1;
|
||||
}
|
||||
cmdline++;
|
||||
}
|
||||
return argc;
|
||||
}
|
||||
|
||||
|
1
str.h
1
str.h
@ -37,5 +37,6 @@ int str_startswith(char *str, const char *substring, char **afterp);
|
||||
*/
|
||||
int strcase_startswith(char *str, const char *substring, char **afterp);
|
||||
|
||||
int parse_argv(char *cmdline, char delim, char **argv, int max_argv);
|
||||
|
||||
#endif
|
108
vomp.c
108
vomp.c
@ -49,7 +49,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
// this might be a replay attack
|
||||
< NOCALL + codecs
|
||||
// Ok, we have a network path, lets try to establish the call
|
||||
$ CODECS [token] [their supported codec list]
|
||||
> RINGOUT
|
||||
$ CODECS [token] [their supported codec list]
|
||||
// (Note that if both parties are trying to dial each other,
|
||||
// the call should jump straight to INCALL)
|
||||
// inform client about the call request
|
||||
@ -145,7 +147,7 @@ struct vomp_call_state {
|
||||
time_ms_t audio_clock;
|
||||
// last local & remote status we sent to all interested parties
|
||||
int last_sent_status;
|
||||
unsigned char remote_codec_list[256];
|
||||
unsigned char remote_codec_flags[CODEC_FLAGS_LENGTH];
|
||||
|
||||
// track when we first heard audio, so we can calculate timing from the current sequence number
|
||||
int first_remote_audio_sequence;
|
||||
@ -168,8 +170,18 @@ static void vomp_process_tick(struct sched_ent *alarm);
|
||||
static const char *vomp_describe_codec(int c);
|
||||
strbuf strbuf_append_vomp_supported_codecs(strbuf sb, const unsigned char supported_codecs[256]);
|
||||
|
||||
/* which codecs we support (set by registered listener) */
|
||||
unsigned char vomp_local_codec_list[256];
|
||||
|
||||
void set_codec_flag(int codec, unsigned char *flags){
|
||||
if (codec<0 || codec>255)
|
||||
return;
|
||||
flags[codec >> 3] |= 1<<(codec & 7);
|
||||
}
|
||||
|
||||
int is_codec_set(int codec, unsigned char *flags){
|
||||
if (codec<0 || codec>255)
|
||||
return 0;
|
||||
return flags[codec >> 3] & (1<<(codec & 7));
|
||||
}
|
||||
|
||||
struct vomp_call_state *vomp_find_call_by_session(int session_token)
|
||||
{
|
||||
@ -338,19 +350,22 @@ int vomp_send_status_remote(struct vomp_call_state *call)
|
||||
prepare_vomp_header(call, &mdp);
|
||||
|
||||
if (call->local.state < VOMP_STATE_RINGINGOUT && call->remote.state < VOMP_STATE_RINGINGOUT) {
|
||||
/* Include src and dst phone numbers */
|
||||
int didLen;
|
||||
unsigned char codecs[CODEC_FLAGS_LENGTH];
|
||||
|
||||
/* Include the list of supported codecs */
|
||||
monitor_get_all_supported_codecs(codecs);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 256; ++i)
|
||||
if (vomp_local_codec_list[i]) {
|
||||
if (is_codec_set(i,codecs)) {
|
||||
mdp.out.payload[(*len)++]=i;
|
||||
if (debug & DEBUG_VOMP)
|
||||
DEBUGF("I support the %s codec", vomp_describe_codec(i));
|
||||
}
|
||||
mdp.out.payload[(*len)++]=0;
|
||||
|
||||
/* Include src and dst phone numbers */
|
||||
if (call->initiated_call){
|
||||
DEBUGF("Sending phone numbers %s, %s",call->local.did,call->remote.did);
|
||||
didLen = snprintf((char *)(mdp.out.payload + *len), sizeof(mdp.out.payload) - *len, "%s", call->local.did);
|
||||
@ -363,9 +378,10 @@ int vomp_send_status_remote(struct vomp_call_state *call)
|
||||
DEBUGF("mdp frame with codec list is %d bytes", mdp.out.payload_length);
|
||||
}
|
||||
|
||||
call->local.sequence++;
|
||||
|
||||
overlay_mdp_dispatch(&mdp,0,NULL,0);
|
||||
|
||||
call->local.sequence++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -406,13 +422,13 @@ int vomp_received_audio(struct vomp_call_state *call, int audio_codec, const uns
|
||||
offset+=codec_block_size;
|
||||
|
||||
call->audio_clock += codec_duration;
|
||||
call->local.sequence++;
|
||||
|
||||
// send the payload more than once to add resilience to dropped packets
|
||||
// TODO remove once network links have built in retries
|
||||
mdp.out.send_copies=VOMP_MAX_RECENT_SAMPLES;
|
||||
overlay_mdp_dispatch(&mdp,0,NULL,0);
|
||||
|
||||
call->local.sequence++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -462,6 +478,24 @@ int vomp_update_local_state(struct vomp_call_state *call, int new_state){
|
||||
if (call->local.state>=new_state)
|
||||
return 0;
|
||||
|
||||
if (new_state > VOMP_STATE_CALLPREP && new_state <= VOMP_STATE_INCALL && call->local.state<=VOMP_STATE_CALLPREP){
|
||||
// tell clients about the remote codec list
|
||||
int i;
|
||||
unsigned char our_codecs[CODEC_FLAGS_LENGTH];
|
||||
char msg[256];
|
||||
monitor_get_all_supported_codecs(our_codecs);
|
||||
strbuf b = strbuf_local(msg, sizeof msg);
|
||||
strbuf_sprintf(b, "\nCODECS:%06x", call->local.session);
|
||||
|
||||
for (i = 0; i < 256; ++i){
|
||||
if (is_codec_set(i,call->remote_codec_flags) && is_codec_set(i,our_codecs)) {
|
||||
strbuf_sprintf(b, ":%d", i);
|
||||
}
|
||||
}
|
||||
strbuf_putc(b, '\n');
|
||||
monitor_tell_clients(strbuf_str(b), strbuf_len(b), MONITOR_VOMP);
|
||||
}
|
||||
|
||||
switch(new_state){
|
||||
case VOMP_STATE_CALLPREP:
|
||||
// tell client our session id.
|
||||
@ -601,15 +635,13 @@ int vomp_ringing(struct vomp_call_state *call){
|
||||
int vomp_call_destroy(struct vomp_call_state *call)
|
||||
{
|
||||
if (debug & DEBUG_VOMP)
|
||||
DEBUGF("Destroying call %s <--> %s", call->local.did,call->remote.did);
|
||||
|
||||
/* tell everyone the call has died */
|
||||
vomp_update_local_state(call, VOMP_STATE_CALLENDED);
|
||||
vomp_update(call);
|
||||
|
||||
DEBUGF("Destroying call %06x:%06x [%s,%s]", call->local.session, call->remote.session, call->local.did,call->remote.did);
|
||||
|
||||
/* now release the call structure */
|
||||
int i = (call - vomp_call_states);
|
||||
unschedule(&call->alarm);
|
||||
call->local.session=0;
|
||||
call->remote.session=0;
|
||||
|
||||
vomp_call_count--;
|
||||
if (i!=vomp_call_count){
|
||||
@ -693,7 +725,8 @@ int vomp_extract_remote_codec_list(struct vomp_call_state *call,overlay_mdp_fram
|
||||
dump("codec list mdp frame", (unsigned char *)&mdp->in.payload[0],mdp->in.payload_length);
|
||||
|
||||
for (;ofs<mdp->in.payload_length && mdp->in.payload[ofs];ofs++){
|
||||
call->remote_codec_list[mdp->in.payload[ofs]]=1;
|
||||
int codec = mdp->in.payload[ofs];
|
||||
set_codec_flag(codec, call->remote_codec_flags);
|
||||
}
|
||||
if (!call->initiated_call){
|
||||
ofs++;
|
||||
@ -764,16 +797,34 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
|
||||
{
|
||||
/* No registered listener, so we cannot answer the call, so just reject
|
||||
it. */
|
||||
if (debug & DEBUG_VOMP)
|
||||
DEBUGF("Rejecting call due to lack of a listener: states=%d,%d", recvr_state, sender_state);
|
||||
|
||||
WHY("Rejecting call, no listening clients");
|
||||
recvr_state=VOMP_STATE_CALLENDED;
|
||||
/* now let the state machine progress to destroy the call */
|
||||
}
|
||||
|
||||
if (recvr_state < VOMP_STATE_RINGINGOUT && sender_state < VOMP_STATE_RINGINGOUT){
|
||||
unsigned char supported_codecs[CODEC_FLAGS_LENGTH];
|
||||
int i, found=0;
|
||||
|
||||
// the other party should have given us their list of supported codecs
|
||||
vomp_extract_remote_codec_list(call,mdp);
|
||||
|
||||
// make sure we have at least one codec in common
|
||||
monitor_get_all_supported_codecs(supported_codecs);
|
||||
|
||||
// look for a matching bit
|
||||
for (i=0;i<CODEC_FLAGS_LENGTH;i++){
|
||||
if (supported_codecs[i] & call->remote_codec_flags[i]){
|
||||
found=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// nope, we can't speak the same language.
|
||||
if (!found){
|
||||
WHY("Rejecting call, no matching codecs found");
|
||||
recvr_state=VOMP_STATE_CALLENDED;
|
||||
}
|
||||
}
|
||||
|
||||
if (sender_state==VOMP_STATE_CALLENDED){
|
||||
@ -889,10 +940,6 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
|
||||
|
||||
/* send an update to the call status if required */
|
||||
vomp_update(call);
|
||||
|
||||
if (sender_state==VOMP_STATE_CALLENDED
|
||||
&&recvr_state==VOMP_STATE_CALLENDED)
|
||||
return vomp_call_destroy(call);
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
@ -920,7 +967,6 @@ static const char *vomp_describe_codec(int c)
|
||||
case VOMP_CODEC_DTMF: return "DTMF";
|
||||
case VOMP_CODEC_ENGAGED: return "Engaged-tone";
|
||||
case VOMP_CODEC_ONHOLD: return "On-Hold";
|
||||
case VOMP_CODEC_CALLERID: return "CallerID";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
@ -941,7 +987,6 @@ int vomp_sample_size(int c)
|
||||
case VOMP_CODEC_DTMF: return 1;
|
||||
case VOMP_CODEC_ENGAGED: return 0;
|
||||
case VOMP_CODEC_ONHOLD: return 0;
|
||||
case VOMP_CODEC_CALLERID: return 32;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -961,7 +1006,6 @@ int vomp_codec_timespan(int c)
|
||||
case VOMP_CODEC_DTMF: return 80;
|
||||
case VOMP_CODEC_ENGAGED: return 20;
|
||||
case VOMP_CODEC_ONHOLD: return 20;
|
||||
case VOMP_CODEC_CALLERID: return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -997,7 +1041,7 @@ static void vomp_process_tick(struct sched_ent *alarm)
|
||||
time_ms_t now = gettime_ms();
|
||||
|
||||
struct vomp_call_state *call = (struct vomp_call_state *)alarm;
|
||||
|
||||
|
||||
/* See if any calls need to be expired.
|
||||
Allow VOMP_CALL_DIAL_TIMEOUT ms for the other party to ring / request ringing
|
||||
Allow VOMP_CALL_RING_TIMEOUT ms for the ringing party to answer
|
||||
@ -1007,6 +1051,20 @@ static void vomp_process_tick(struct sched_ent *alarm)
|
||||
if ((call->remote.state < VOMP_STATE_RINGINGOUT && call->create_time + VOMP_CALL_DIAL_TIMEOUT < now) ||
|
||||
(call->local.state < VOMP_STATE_INCALL && call->create_time + VOMP_CALL_RING_TIMEOUT < now) ||
|
||||
(call->last_activity+VOMP_CALL_NETWORK_TIMEOUT<now) ){
|
||||
|
||||
/* tell any local clients that call has died */
|
||||
vomp_update_local_state(call, VOMP_STATE_CALLENDED);
|
||||
vomp_update_remote_state(call, VOMP_STATE_CALLENDED);
|
||||
vomp_update(call);
|
||||
}
|
||||
|
||||
/*
|
||||
If we are calling ourselves, mdp packets are processed as soon as they are sent.
|
||||
So we can't risk moving call entries around at that time as that will change pointers that are still on the stack.
|
||||
So instead we wait for the next vomp tick to destroy the structure
|
||||
*/
|
||||
if (call->local.state==VOMP_STATE_CALLENDED
|
||||
&&call->remote.state==VOMP_STATE_CALLENDED){
|
||||
vomp_call_destroy(call);
|
||||
return;
|
||||
}
|
||||
|
291
vomp_console.c
Normal file
291
vomp_console.c
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
Copyright (C) 2012 Serval Project
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "serval.h"
|
||||
#include "cli.h"
|
||||
#include "monitor-client.h"
|
||||
#include "str.h"
|
||||
#include "constants.h"
|
||||
|
||||
int call_token=-1;
|
||||
int monitor_client_fd=-1;
|
||||
|
||||
static void send_hangup(int session_id){
|
||||
monitor_client_writeline(monitor_client_fd, "hangup %06x\n",session_id);
|
||||
}
|
||||
static void send_ringing(int session_id){
|
||||
monitor_client_writeline(monitor_client_fd, "ringing %06x\n",session_id);
|
||||
}
|
||||
static void send_pickup(int session_id){
|
||||
monitor_client_writeline(monitor_client_fd, "pickup %06x\n",session_id);
|
||||
}
|
||||
static void send_call(const char *sid, const char *caller_id, const char *remote_ext){
|
||||
monitor_client_writeline(monitor_client_fd, "call %s %s %s\n", sid, caller_id, remote_ext);
|
||||
}
|
||||
static void send_audio(int session_id, unsigned char *buffer, int len, int codec){
|
||||
monitor_client_writeline_and_data(monitor_client_fd, buffer, len, "audio %06x %d\n", session_id, codec);
|
||||
}
|
||||
|
||||
static int remote_call(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
||||
int token = strtol(argv[0], NULL, 16);
|
||||
|
||||
if (call_token != -1){
|
||||
send_hangup(token);
|
||||
printf("Rejected incoming call, already busy\n");
|
||||
fflush(stdout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
call_token = token;
|
||||
printf("Incoming call\n");
|
||||
fflush(stdout);
|
||||
send_ringing(token);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int remote_ringing(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
||||
int token = strtol(argv[0], NULL, 16);
|
||||
if (call_token == token){
|
||||
printf("They're ringing\n");
|
||||
fflush(stdout);
|
||||
}else
|
||||
send_hangup(token);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int remote_pickup(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
||||
int token = strtol(argv[0], NULL, 16);
|
||||
if (call_token == token){
|
||||
printf("They've picked up\n");
|
||||
fflush(stdout);
|
||||
}else
|
||||
send_hangup(token);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int remote_dialing(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
||||
int token = strtol(argv[0], NULL, 16);
|
||||
if (call_token == -1){
|
||||
call_token=token;
|
||||
printf("Dialling\n");
|
||||
fflush(stdout);
|
||||
}else
|
||||
send_hangup(token);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int remote_hangup(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
||||
int token = strtol(argv[0], NULL, 16);
|
||||
if (call_token == token){
|
||||
printf("Hangup\n");
|
||||
fflush(stdout);
|
||||
call_token=-1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int remote_audio(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
||||
int token = strtol(argv[0], NULL, 16);
|
||||
if (call_token == token){
|
||||
printf("Incoming audio\n");
|
||||
fflush(stdout);
|
||||
}else
|
||||
send_hangup(token);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int remote_codecs(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
||||
int token = strtol(argv[0], NULL, 16);
|
||||
if (call_token == token){
|
||||
printf("Codec list ...\n");
|
||||
fflush(stdout);
|
||||
}else
|
||||
send_hangup(token);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int remote_print(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
||||
int i;
|
||||
printf("%s",cmd);
|
||||
for (i=0;i<argc;i++){
|
||||
printf(" %s",argv[i]);
|
||||
}
|
||||
printf("\n");
|
||||
if (dataLen){
|
||||
dump(NULL,data,dataLen);
|
||||
}
|
||||
fflush(stdout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int remote_noop(char *cmd, int argc, char **argv, unsigned char *data, int dataLen, void *context){
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct monitor_command_handler console_handlers[]={
|
||||
{.command="CALLFROM", .handler=remote_call},
|
||||
{.command="RINGING", .handler=remote_ringing},
|
||||
{.command="ANSWERED", .handler=remote_pickup},
|
||||
{.command="CALLTO", .handler=remote_dialing},
|
||||
{.command="HANGUP", .handler=remote_hangup},
|
||||
{.command="AUDIOPACKET", .handler=remote_audio},
|
||||
{.command="CODECS", .handler=remote_codecs},
|
||||
{.command="INFO", .handler=remote_print},
|
||||
{.command="CALLSTATUS", .handler=remote_noop},
|
||||
{.command="KEEPALIVE", .handler=remote_noop},
|
||||
{.command="MONITORSTATUS", .handler=remote_noop},
|
||||
};
|
||||
|
||||
static int console_dial(int argc, const char *const *argv, struct command_line_option *o, void *context){
|
||||
if (call_token!=-1){
|
||||
printf("Already in a call\n");
|
||||
return 0;
|
||||
}
|
||||
const char *sid=argv[1];
|
||||
const char *local=argc>=3?argv[2]:"55500000";
|
||||
const char *remote=argc>=4?argv[3]:"55500000";
|
||||
send_call(sid, local, remote);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int console_answer(int argc, const char *const *argv, struct command_line_option *o, void *context){
|
||||
if (call_token==-1){
|
||||
printf("No call to answer\n");
|
||||
fflush(stdout);
|
||||
}else
|
||||
send_pickup(call_token);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int console_hangup(int argc, const char *const *argv, struct command_line_option *o, void *context){
|
||||
if (call_token==-1){
|
||||
printf("No call to hangup\n");
|
||||
fflush(stdout);
|
||||
}else
|
||||
send_hangup(call_token);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int console_usage(int argc, const char *const *argv, struct command_line_option *o, void *context);
|
||||
|
||||
struct command_line_option console_commands[]={
|
||||
{console_dial,{"call","<sid>","[<local_number>]","[<remote_extension>]",NULL},0,"Start dialling a given person"},
|
||||
{console_answer,{"answer",NULL},0,"Answer an incoming phone call"},
|
||||
{console_hangup,{"hangup",NULL},0,"Hangup the line"},
|
||||
{console_usage,{"help",NULL},0,"This usage message"},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
static int console_usage(int argc, const char *const *argv, struct command_line_option *o, void *context){
|
||||
cli_usage(console_commands);
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void console_command(char *line){
|
||||
char *argv[16];
|
||||
int argc = parse_argv(line, ' ', argv, 16);
|
||||
|
||||
if (cli_execute(NULL, argc, (const char *const*)argv, console_commands, NULL)){
|
||||
printf("Unknown command, try help\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
struct line_state{
|
||||
int fd;
|
||||
char line_buff[1024];
|
||||
int line_pos;
|
||||
};
|
||||
|
||||
static void read_lines(struct line_state *state, void (*process_line)(char *line)){
|
||||
set_nonblock(STDIN_FILENO);
|
||||
int bytes = read(state->fd, state->line_buff + state->line_pos, sizeof(state->line_buff) - state->line_pos);
|
||||
set_block(STDIN_FILENO);
|
||||
int i = state->line_pos;
|
||||
int processed=0;
|
||||
state->line_pos+=bytes;
|
||||
char *line_start=state->line_buff;
|
||||
|
||||
for (;i<state->line_pos;i++){
|
||||
if (state->line_buff[i]=='\n'){
|
||||
state->line_buff[i]=0;
|
||||
if (*line_start)
|
||||
process_line(line_start);
|
||||
processed=i+1;
|
||||
line_start = state->line_buff + processed;
|
||||
}
|
||||
}
|
||||
|
||||
if (processed){
|
||||
// squash unprocessed data back to the start of the buffer
|
||||
state->line_pos -= processed;
|
||||
bcopy(state->line_buff, line_start, state->line_pos);
|
||||
}
|
||||
}
|
||||
|
||||
int app_vomp_console(int argc, const char *const *argv, struct command_line_option *o, void *context){
|
||||
struct pollfd fds[2];
|
||||
struct line_state stdin_state;
|
||||
struct monitor_state *state;
|
||||
monitor_client_fd = monitor_client_open(&state);
|
||||
|
||||
monitor_client_writeline(monitor_client_fd, "monitor vomp %d %d %d\n",
|
||||
VOMP_CODEC_8ULAW,VOMP_CODEC_8ALAW,VOMP_CODEC_PCM);
|
||||
|
||||
bzero(&stdin_state, sizeof(struct line_state));
|
||||
stdin_state.fd = STDIN_FILENO;
|
||||
set_nonblock(monitor_client_fd);
|
||||
|
||||
fds[0].fd = STDIN_FILENO;
|
||||
fds[0].events = POLLIN;
|
||||
fds[1].fd = monitor_client_fd;
|
||||
fds[1].events = POLLIN;
|
||||
|
||||
while(1){
|
||||
int r = poll(fds, 2, 10000);
|
||||
if (r>0){
|
||||
|
||||
if (fds[0].revents & POLLIN)
|
||||
read_lines(&stdin_state, console_command);
|
||||
|
||||
if (fds[1].revents & POLLIN){
|
||||
if (monitor_client_read(monitor_client_fd, state, console_handlers,
|
||||
sizeof(console_handlers)/sizeof(struct monitor_command_handler))<0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fds[0].revents & (POLLHUP | POLLERR))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
monitor_client_close(monitor_client_fd, state);
|
||||
monitor_client_fd=-1;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user