📄 miniphone.c
字号:
/*
* Miniphone: A simple, command line telephone
*
* IAX Support for talking to Asterisk and other Gnophone clients
*
* Copyright (C) 1999, Linux Support Services, Inc.
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <iax-client.h>
#include <linux/soundcard.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <gsm.h>
#include <miniphone.h>
#include <time.h>
#include "busy.h"
#include "dialtone.h"
#include "answer.h"
#include "ringtone.h"
#include "ring10.h"
#include "options.h"
#define FRAME_SIZE 160
static char callerid[80];
struct peer {
int time;
gsm gsmin;
gsm gsmout;
struct iax_session *session;
struct peer *next;
};
static char *audiodev = "/dev/dsp";
static int audiofd = -1;
static struct peer *peers;
static int answered_call = 0;
static struct peer *find_peer(struct iax_session *);
static int audio_setup(char *);
static void sighandler(int);
static void parse_args(FILE *, unsigned char *);
void do_iax_event(FILE *);
void call(FILE *, char *);
void answer_call(void);
void reject_call(void);
static void handle_event(FILE *, struct iax_event *e, struct peer *p);
void parse_cmd(FILE *, int, char **);
void issue_prompt(FILE *);
void dump_array(FILE *, char **);
struct sound {
short *data;
int datalen;
int samplen;
int silencelen;
int repeat;
};
static int cursound = -1;
static int sampsent = 0;
static int offset = 0;
static int silencelen = 0;
static int nosound = 0;
static int offhook = 0;
static int ringing = 0;
static int writeonly = 0;
static struct iax_session *registry = NULL;
static struct timeval regtime;
#define TONE_NONE -1
#define TONE_RINGTONE 0
#define TONE_BUSY 1
#define TONE_CONGEST 2
#define TONE_RINGER 3
#define TONE_ANSWER 4
#define TONE_DIALTONE 5
#define OUTPUT_NONE 0
#define OUTPUT_SPEAKER 1
#define OUTPUT_HANDSET 2
#define OUTPUT_BOTH 3
static struct sound sounds[] = {
{ ringtone, sizeof(ringtone)/2, 16000, 32000, 1 },
{ busy, sizeof(busy)/2, 4000, 4000, 1 },
{ busy, sizeof(busy)/2, 2000, 2000, 1 },
{ ring10, sizeof(ring10)/2, 16000, 32000, 1 },
{ answer, sizeof(answer)/2, 2200, 0, 0 },
{ dialtone, sizeof(dialtone)/2, 8000, 0, 1 },
};
static char *help[] = {
"Welcome to the miniphone telephony client, the commands are as follows:\n",
"Help\t\t-\tDisplays this screen.",
"Help <Command>\t-\tInqueries specific information on a command.",
"Dial <Number>\t-\tDials the number supplied in the first arguement",
"Status\t\t-\tLists the current sessions and their current status.",
"Quit\t\t-\tShuts down the client.",
"",
0
};
static short silence[FRAME_SIZE];
static struct peer *most_recent_answer;
static struct iax_session *newcall = 0;
static struct peer *find_peer(struct iax_session *session)
{
struct peer *cur = peers;
while(cur) {
if (cur->session == session)
return cur;
cur = cur->next;
}
return NULL;
}
static int audio_setup(char *dev)
{
int fd;
int fmt = AFMT_S16_LE;
int channels = 1;
int speed = 8000;
int fragsize = (40 << 16) | 6;
if ( (fd = open(dev, O_RDWR | O_NONBLOCK)) < 0) {
fprintf(stderr, "Unable to open audio device %s: %s\n", dev, strerror(errno));
return -1;
}
if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) || (fmt != AFMT_S16_LE)) {
fprintf(stderr, "Unable to set in signed linear format.\n");
return -1;
}
if (ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0)) {
fprintf(stderr, "Unable to set full duplex operation.\n");
writeonly = 1;
/* return -1; */
}
if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) || (channels != 1)) {
fprintf(stderr, "Unable to set to mono\n");
return -1;
}
if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) || (speed != 8000)) {
fprintf(stderr, "Unable to set speed to 8000 hz\n");
return -1;
}
if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fragsize)) {
fprintf(stderr, "Unable to set fragment size...\n");
return -1;
}
return fd;
}
static int send_sound(int soundfd)
{
/* Send FRAME_SIZE samples of whatever */
short myframe[FRAME_SIZE];
short *frame = NULL;
int total = FRAME_SIZE;
int amt=0;
int res;
int myoff;
audio_buf_info abi;
if (cursound > -1) {
res = ioctl(soundfd, SNDCTL_DSP_GETOSPACE ,&abi);
if (res) {
fprintf(stderr,"Unable to read output space\n");
return -1;
}
/* Calculate how many samples we can send, max */
if (total > (abi.fragments * abi.fragsize / 2))
total = abi.fragments * abi.fragsize / 2;
res = total;
if (sampsent < sounds[cursound].samplen) {
myoff=0;
while(total) {
amt = total;
if (amt > (sounds[cursound].datalen - offset))
amt = sounds[cursound].datalen - offset;
memcpy(myframe + myoff, sounds[cursound].data + offset, amt * 2);
total -= amt;
offset += amt;
sampsent += amt;
myoff += amt;
if (offset >= sounds[cursound].datalen)
offset = 0;
}
/* Set it up for silence */
if (sampsent >= sounds[cursound].samplen)
silencelen = sounds[cursound].silencelen;
frame = myframe;
} else {
if (silencelen > 0) {
frame = silence;
silencelen -= res;
} else {
if (sounds[cursound].repeat) {
/* Start over */
sampsent = 0;
offset = 0;
} else {
cursound = -1;
nosound = 0;
}
}
}
#if 0
if (frame)
printf("res is %d, frame[0] is %d\n", res, frame[0]);
#endif
res = write(soundfd, frame, res * 2);
if (res > 0)
return 0;
return res;
}
return 0;
}
static int iax_regtimeout(int timeout)
{
if (timeout) {
gettimeofday(®time, NULL);
regtime.tv_sec += timeout;
} else {
regtime.tv_usec = 0;
regtime.tv_sec = 0;
}
return 0;
}
static int check_iax_register(void)
{
int res;
if (strlen(regpeer) && strlen(server)) {
registry = iax_session_new();
res = iax_register(registry, server,regpeer,regsecret, refresh);
if (res) {
fprintf(stderr, "Failed registration: %s\n", iax_errstr);
return -1;
}
iax_regtimeout(5 * refresh / 6);
} else {
iax_regtimeout(0);
refresh = 60;
}
return 0;
}
static int check_iax_timeout(void)
{
struct timeval tv;
int ms;
if (!regtime.tv_usec || !regtime.tv_sec)
return -1;
gettimeofday(&tv, NULL);
if ((tv.tv_usec >= regtime.tv_usec) && (tv.tv_sec >= regtime.tv_sec)) {
check_iax_register();
/* Have it check again soon */
return 100;
}
ms = (regtime.tv_sec - tv.tv_sec) * 1000 + (regtime.tv_usec - tv.tv_usec) / 1000;
return ms;
}
static int gentone(int sound, int uninterruptible)
{
cursound = sound;
sampsent = 0;
offset = 0;
silencelen = 0;
nosound = uninterruptible;
// printf("Sending tone %d\n", sound);
return 0;
}
void
sighandler(int sig)
{
if(sig == SIGHUP) {
puts("rehashing!");
} else if(sig == SIGINT) {
static int prev = 0;
int cur;
if ( (cur = time(0))-prev <= 5) {
// printf("Terminating!\n");
exit(0);
} else {
prev = cur;
printf("Press interrupt key again in the next %d seconds to really terminate\n", 5-(cur-prev));
}
}
}
void
parse_args(FILE *f, unsigned char *cmd)
{
static char *argv[MAXARGS];
unsigned char *parse = cmd;
int argc = 0, t = 0;
// Don't mess with anything that doesn't exist...
if(!*parse)
return;
bzero(argv, sizeof(argv));
while(*parse) {
if(*parse < 33 || *parse > 128) {
*parse = 0, t++;
if(t > MAXARG) {
fprintf(f, "Warning: Argument exceeds maximum argument size, command ignored!\n");
return;
}
} else if(t || !argc) {
if(argc == MAXARGS) {
fprintf(f, "Warning: Command ignored, too many arguments\n");
return;
}
argv[argc++] = parse;
t = 0;
}
parse++;
}
if(argc)
parse_cmd(f, argc, argv);
}
int
main(int argc, char *argv[])
{
int port;
int netfd;
int c, h=0, m, regm;
FILE *f;
int fd = STDIN_FILENO;
char rcmd[RBUFSIZE];
fd_set readfd;
fd_set writefd;
struct timeval timer;
struct timeval *timerptr = NULL;
gsm_frame fo;
load_options();
if (!strlen(callerid))
gethostname(callerid, sizeof(callerid));
signal(SIGHUP, sighandler);
signal(SIGINT, sighandler);
if ( !(f = fdopen(fd, "w+"))) {
fprintf(stderr, "Unable to create file on fd %d\n", fd);
return -1;
}
if ( (audiofd = audio_setup(audiodev)) == -1) {
fprintf(stderr, "Fatal error: failed to open sound device");
return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -