/* 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 #include #include #include #include #include #include #include "serval.h" #include "cli.h" #include "monitor-client.h" #include "str.h" #include "constants.h" int call_token=-1; int seen_audio=0; int monitor_client_fd=-1; struct monitor_state *monitor_state; struct line_state{ struct sched_ent alarm; int fd; char line_buff[1024]; int line_pos; void (*process_line)(char *line); }; 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; seen_audio = 0; printf("Incoming call from %s (%s)\n",argv[3],argv[4]); 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; seen_audio=0; 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("Call ended\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){ if (!seen_audio){ printf("Incoming audio\n"); fflush(stdout); seen_audio=1; } }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){ int i; printf("Codec list"); for (i=1;i=3?argv[2]:""; const char *remote=argc>=4?argv[3]:""; 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 active 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_answer,{"answer",NULL},0,"Answer an incoming phone call"}, {console_dial,{"call","","[]","[]",NULL},0,"Start dialling a given person"}, {console_hangup,{"hangup",NULL},0,"Hangup the phone 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); } } static void read_lines(struct sched_ent *alarm){ struct line_state *state=(struct line_state *)alarm; set_nonblock(STDIN_FILENO); int bytes = read(state->alarm.poll.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 (;iline_pos;i++){ if (state->line_buff[i]=='\n'){ state->line_buff[i]=0; if (*line_start) state->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); } } static void monitor_read(struct sched_ent *alarm){ if (monitor_client_read(alarm->poll.fd, monitor_state, console_handlers, sizeof(console_handlers)/sizeof(struct monitor_command_handler))<0){ unwatch(alarm); monitor_client_close(alarm->poll.fd, monitor_state); alarm->poll.fd=-1; monitor_client_fd=-1; } } int app_vomp_console(int argc, const char *const *argv, struct command_line_option *o, void *context){ static struct profile_total stdin_profile={ .name="read_lines", }; struct line_state stdin_state={ .alarm.poll.fd = STDIN_FILENO, .alarm.poll.events = POLLIN, .alarm.function = read_lines, .alarm.stats=&stdin_profile, .process_line=console_command, }; static struct profile_total monitor_profile={ .name="monitor_read", }; struct sched_ent monitor_alarm={ .poll.events = POLLIN, .function = monitor_read, .stats=&monitor_profile, }; monitor_client_fd = monitor_client_open(&monitor_state); monitor_client_writeline(monitor_client_fd, "monitor vomp %d %d %d\n", VOMP_CODEC_8ULAW,VOMP_CODEC_8ALAW,VOMP_CODEC_PCM); set_nonblock(monitor_client_fd); monitor_alarm.poll.fd = monitor_client_fd; watch(&monitor_alarm); watch(&stdin_state.alarm); while(monitor_client_fd!=-1){ fd_poll(); } unwatch(&stdin_state.alarm); return 0; }