📄 miniphone.c
字号:
}
if ( (port = iax_init(0) < 0)) {
fprintf(stderr, "Fatal error: failed to initialize iax with port %d\n", port);
return -1;
}
iax_set_formats(AST_FORMAT_GSM);
netfd = iax_get_fd();
check_iax_register();
fprintf(f, "Text Based Telephony Client.\n\n");
issue_prompt(f);
timer.tv_sec = 0;
timer.tv_usec = 0;
while(1) {
FD_ZERO(&readfd);
FD_ZERO(&writefd);
FD_SET(fd, &readfd);
if(fd > h)
h = fd;
if(answered_call && !writeonly) {
FD_SET(audiofd, &readfd);
if(audiofd > h)
h = audiofd;
}
if (cursound > -1) {
FD_SET(audiofd, &writefd);
if (audiofd > h)
h = audiofd;
}
FD_SET(netfd, &readfd);
if(netfd > h)
h = netfd;
if ( (c = select(h+1, &readfd, &writefd, 0, timerptr)) >= 0) {
if(FD_ISSET(fd, &readfd)) {
if ( ( fgets(&*rcmd, 256, f))) {
rcmd[strlen(rcmd)-1] = 0;
parse_args(f, &*rcmd);
} else fprintf(f, "Fatal error: failed to read data!\n");
issue_prompt(f);
}
if(answered_call) {
if(FD_ISSET(audiofd, &readfd)) {
static int ret, rlen = 0;
static short rbuf[FRAME_SIZE];
if ( (ret = read(audiofd, rbuf + rlen, 2 * (FRAME_SIZE-rlen))) == -1) {
puts("Failed to read audio.");
return -1;
}
rlen += ret/2;
if(rlen == FRAME_SIZE) {
rlen = 0;
if(!most_recent_answer->gsmout)
most_recent_answer->gsmout = gsm_create();
gsm_encode(most_recent_answer->gsmout, rbuf, fo);
if(iax_send_voice(most_recent_answer->session,
AST_FORMAT_GSM, (char *)fo, sizeof(fo)) == -1)
puts("Failed to send voice!");
}
}
}
do_iax_event(f);
m = iax_time_to_next_event();
if(m > -1) {
timerptr = &timer;
timer.tv_sec = m /1000;
timer.tv_usec = (m % 1000) * 1000;
} else
timerptr = 0;
regm = check_iax_timeout();
if (!timerptr || (m > regm)) {
timerptr = &timer;
timer.tv_sec = regm /1000;
timer.tv_usec = (regm % 1000) * 1000;
}
if (FD_ISSET(audiofd, &writefd)) {
send_sound(audiofd);
}
} else {
if(errno == EINTR)
continue;
fprintf(stderr, "Fatal error in select(): %s\n", strerror(errno));
return -1;
}
}
return 0;
}
void
do_iax_event(FILE *f) {
int sessions = 0;
struct iax_event *e = 0;
struct peer *peer;
while ( (e = iax_get_event(0))) {
peer = find_peer(e->session);
if(peer) {
handle_event(f, e, peer);
} else if (e->session == registry) {
fprintf(stderr, "Registration complete: %s (%d)\n",
(e->event.regreply.status == IAX_REG_SUCCESS) ? "Success" : "Failed",
e->event.regreply.status);
registry = NULL;
} else {
if(e->etype != IAX_EVENT_CONNECT) {
fprintf(stderr, "Huh? This is an event for a non-existant session?\n");
continue;
}
sessions++;
if(sessions >= MAX_SESSIONS) {
fprintf(f, "Missed a call... too many sessions open.\n");
}
if(e->event.connect.callerid && e->event.connect.dnid)
fprintf(f, "Call from '%s' for '%s'", e->event.connect.callerid,
e->event.connect.dnid);
else if(e->event.connect.dnid) {
fprintf(f, "Call from '%s'", e->event.connect.dnid);
} else if(e->event.connect.callerid) {
fprintf(f, "Call from '%s'", e->event.connect.callerid);
} else printf("Call from");
fprintf(f, " (%s)\n", inet_ntoa(iax_get_peer_addr(e->session).sin_addr));
if(most_recent_answer) {
fprintf(f, "Incoming call ignored, there's already a call waiting for answer... \
please accept or reject first\n");
iax_reject(e->session, "Too many calls, we're busy!");
} else {
if ( !(peer = malloc(sizeof(struct peer)))) {
fprintf(f, "Warning: Unable to allocate memory!\n");
return;
}
peer->time = time(0);
peer->session = e->session;
if (peer->gsmin)
free(peer->gsmin);
peer->gsmin = 0;
if (peer->gsmout)
free(peer->gsmout);
peer->gsmout = 0;
peer->next = peers;
peers = peer;
iax_accept(peer->session);
iax_ring_announce(peer->session);
most_recent_answer = peer;
ringing = 1;
gentone(TONE_RINGER, 0);
fprintf(f, "Incoming call!\n");
}
issue_prompt(f);
}
iax_event_free(e);
}
}
void
call(FILE *f, char *num)
{
struct peer *peer;
if(!newcall)
newcall = iax_session_new();
else {
fprintf(f, "Already attempting to call somewhere, please cancel first!\n");
return;
}
if ( !(peer = malloc(sizeof(struct peer)))) {
fprintf(f, "Warning: Unable to allocate memory!\n");
return;
}
peer->time = time(0);
peer->session = newcall;
peer->gsmin = 0;
peer->gsmout = 0;
peer->next = peers;
peers = peer;
most_recent_answer = peer;
offhook = 1;
iax_call(peer->session, callerid, num, NULL, 10);
}
void
answer_call(void)
{
if(most_recent_answer)
iax_answer(most_recent_answer->session);
printf("Answering call!\n");
answered_call = 1;
offhook = 1;
ringing = 0;
gentone(TONE_ANSWER, 1);
}
void
reject_call(void)
{
iax_reject(most_recent_answer->session, "Call rejected manually.");
most_recent_answer = 0;
ringing = 0;
gentone(TONE_NONE, 1);
}
void
handle_event(FILE *f, struct iax_event *e, struct peer *p)
{
short fr[FRAME_SIZE];
int len;
switch(e->etype) {
case IAX_EVENT_HANGUP:
iax_hangup(most_recent_answer->session, "Byeee!");
fprintf(f, "Call disconnected by peer\n");
free(most_recent_answer);
most_recent_answer = 0;
answered_call = 0;
peers = 0;
newcall = 0;
if (offhook)
gentone(TONE_CONGEST, 0);
break;
case IAX_EVENT_REJECT:
fprintf(f, "Authentication was rejected\n");
break;
case IAX_EVENT_ACCEPT:
fprintf(f, "Accepted...\n");
issue_prompt(f);
break;
case IAX_EVENT_RINGA:
fprintf(f, "Ringing...\n");
issue_prompt(f);
gentone(TONE_RINGTONE, 0);
break;
case IAX_EVENT_ANSWER:
answer_call();
gentone(TONE_ANSWER, 1);
break;
case IAX_EVENT_VOICE:
switch(e->event.voice.format) {
case AST_FORMAT_GSM:
if(e->event.voice.datalen % 33) {
fprintf(stderr, "Weird gsm frame, not a multiple of 33.\n");
break;
}
if (!p->gsmin)
p->gsmin = gsm_create();
len = 0;
while(len < e->event.voice.datalen) {
if(gsm_decode(p->gsmin, e->event.voice.data + len, fr)) {
fprintf(stderr, "Bad GSM data\n");
break;
} else {
int res;
res = write(audiofd, fr, sizeof(fr));
if (res < 0)
fprintf(f, "Write failed: %s\n", strerror(errno));
}
len += 33;
}
break;
default :
fprintf(f, "Don't know how to handle that format %d\n", e->event.voice.format);
}
break;
default:
fprintf(f, "Unknown event: %d\n", e->etype);
}
}
void
dump_call(void)
{
if(most_recent_answer)
{
printf("Dumping call!\n");
iax_hangup(most_recent_answer->session,"");
free(most_recent_answer);
}
answered_call = 0;
most_recent_answer = 0;
answered_call = 0;
peers = 0;
newcall = 0;
offhook = 0;
ringing = 0;
gentone(TONE_NONE, 0);
}
void
parse_cmd(FILE *f, int argc, char **argv)
{
if(!strcasecmp(argv[0], "HELP")) {
if(argc == 1)
dump_array(f, help);
else if(argc == 2) {
if(!strcasecmp(argv[1], "HELP"))
fprintf(f, "Help <Command>\t-\tDisplays general help or specific help on command if supplied an arguement\n");
else if(!strcasecmp(argv[1], "QUIT"))
fprintf(f, "Quit\t\t-\tShuts down the miniphone\n");
else fprintf(f, "No help available on %s\n", argv[1]);
} else {
fprintf(f, "Too many arguements for command help.\n");
}
} else if(!strcasecmp(argv[0], "STATUS")) {
if(argc == 1) {
int c = 0;
struct peer *peerptr = peers;
if(!peerptr)
fprintf(f, "No session matches found.\n");
else while(peerptr) {
fprintf(f, "Listing sessions:\n\n");
fprintf(f, "Session %d\n", ++c);
fprintf(f, "Session existed for %d seconds\n", (int)time(0)-peerptr->time);
if(answered_call)
fprintf(f, "Call answered.\n");
else fprintf(f, "Call ringing.\n");
peerptr = peerptr->next;
}
} else fprintf(f, "Too many arguments for command status.\n");
} else if(!strcasecmp(argv[0], "ANSWER")) {
if(argc > 1)
fprintf(f, "Too many arguements for command answer\n");
else answer_call();
} else if(!strcasecmp(argv[0], "REJECT")) {
if(argc > 1)
fprintf(f, "Too many arguements for command reject\n");
else {
fprintf(f, "Rejecting current phone call.\n");
reject_call();
}
} else if (!strcasecmp(argv[0], "DUMP")) {
dump_call();
} else if (!strcasecmp(argv[0], "HANGUP")) {
dump_call();
} else if(!strcasecmp(argv[0], "CALL")) {
if(argc > 2)
fprintf(f, "Too many arguements for command call\n");
else {
call(f, argv[1]);
}
} else if(!strcasecmp(argv[0], "QUIT")) {
if(argc > 1)
fprintf(f, "Too many arguements for command quit\n");
else {
fprintf(f, "Good bye!\n");
exit(1);
}
} else fprintf(f, "Unknown command of %s\n", argv[0]);
}
void
issue_prompt(FILE *f)
{
fprintf(f, "TeleClient> ");
fflush(f);
}
void
dump_array(FILE *f, char **array) {
while(*array)
fprintf(f, "%s\n", *array++);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -