⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 winiphone.c

📁 ppciaxclient softphone
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * 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
 */

/* #define	PRINTCHUCK /* enable this to indicate chucked incomming packets */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <io.h>
#include <conio.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <process.h>
#include <windows.h>
#include <winsock.h>
#include <mmsystem.h>
#include <malloc.h>
#include "gsm.h"
#include "iax-client.h"
#include "frame.h"
#include "miniphone.h"


struct peer {
	int time;
	gsm gsmin;
	gsm gsmout;

	struct iax_session *session;
	struct peer *next;
};

static struct peer *peers;
static int answered_call = 0;

/* stuff for wave audio device */
HWAVEOUT wout;
HWAVEIN win;

typedef struct whout {
	WAVEHDR w;
	short	data[160];
	struct whout *next;
} WHOUT;

WHOUT *outqueue = NULL;

/* parameters for audio in */
#define	NWHIN 8				/* number of input buffer entries */
/* NOTE the OUT_INTERVAL parameter *SHOULD* be more around 18 to 20 or so, since the packets should
be spaced by 20 milliseconds. However, in practice, especially in Windoze-95, setting it that high
caused underruns. 10 is just ever so slightly agressive, and the receiver has to chuck a packet
every now and then. Thats about the way it should be to be happy. */
#define	OUT_INTERVAL 10		/* number of ms to wait before sending more data to peer */
/* parameters for audio out */
#define	OUT_DEPTH 12		/* number of outbut buffer entries */
#define	OUT_PAUSE_THRESHOLD 2 /* number of active entries needed to start output (for smoothing) */

/* audio input buffer headers */
WAVEHDR whin[NWHIN];
/* audio input buffers */
char bufin[NWHIN][320];

/* initialize the sequence variables for the audio in stuff */
unsigned int whinserial = 1,nextwhin = 1;

static struct peer *find_peer(struct iax_session *);
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 **);

static char *help[] = {
"Welcome to the miniphone telephony client, the commands are as follows:\n",
"Help\t\t-\tDisplays this screen.",
"Call <Number>\t-\tDials the number supplied.",
"Answer\t\t-\tAnswers an Inbound call.",
"Reject\t\t-\tRejects an Inbound call.",
"Dump\t\t-\tDumps (disconnects) the current call.",
"Dtmf <Digit>\t-\tSends specified DTMF digit.",
"Status\t\t-\tLists the current sessions and their current status.",
"Quit\t\t-\tShuts down the client.",
"",
0
};

static struct peer *most_recent_answer;
static struct iax_session *newcall = 0;

/* holder of the time, relative to startup in system ticks. See our
gettimeofday() implementation */
time_t	startuptime;

/* routine called at exit to shutdown audio I/O and close nicely.
NOTE: If all this isnt done, the system doesnt not handle this
cleanly and has to be rebooted. What a pile of doo doo!! */
void killem(void)
{
	waveInStop(win);
	waveInReset(win);
	waveInClose(win); 
	waveOutReset(wout);
	waveOutClose(wout);
	WSACleanup(); /* dont forget socket stuff too */
	return;
}

/* Win-doze doenst have gettimeofday(). This sux. So, what we did is
provide some gettimeofday-like functionality that works for our purposes.
In the main(), we take a sample of the system tick counter (into startuptime).
This function returns the relative time since program startup, more or less,
which is certainly good enough for our purposes. */
void gettimeofday(struct timeval *tv, struct timezone *tz)
{
	long l = startuptime + GetTickCount();

	tv->tv_sec = l / 1000;
	tv->tv_usec = (l % 1000) * 1000;
	return;
}


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;
}

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;

	memset(argv, 0, 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);
}

/* handle all network requests, and a pending scheduled event, if any */
void service_network(int netfd, FILE *f)
{
	fd_set readfd;
	struct timeval dumbtimer;

	/* set up a timer that falls-through */
	dumbtimer.tv_sec = 0;
	dumbtimer.tv_usec = 0;


		for(;;) /* suck everything outa network stuff */
		{
			FD_ZERO(&readfd);
			FD_SET(netfd, &readfd);
			if (select(netfd + 1, &readfd, 0, 0, &dumbtimer) > 0)
			{
				if (FD_ISSET(netfd,&readfd))
				{
					do_iax_event(f);
					(void) iax_time_to_next_event();
				} else break;
			} else break;
		}
		do_iax_event(f); /* do pending event if any */
}


int
main(int argc, char *argv[])
{
	int port;
	int netfd;
 	int c, i;
	FILE *f;
	char rcmd[RBUFSIZE];
	gsm_frame fo;
	WSADATA foop;
	time_t	t;
	WAVEFORMATEX wf;
	WHOUT *wh,*wh1,*wh2;
	unsigned long lastouttick = 0;



	/* get time of day in milliseconds, offset by tick count (see our
	   gettimeofday() implementation) */
	time(&t);
	startuptime = ((t % 86400) * 1000) - GetTickCount();

	f = stdout;
	_dup2(fileno(stdout),fileno(stderr));

	/* start up the windoze-socket layer stuff */
	if (WSAStartup(0x0101,&foop)) {
		fprintf(stderr,"Fatal error: Falied to startup windows sockets\n");
		return -1;
	}


	/* setup the format for opening audio channels */
	wf.wFormatTag = WAVE_FORMAT_PCM;
	wf.nChannels = 1;
	wf.nSamplesPerSec = 8000;
	wf.nAvgBytesPerSec = 16000;
	wf.nBlockAlign = 2;
	wf.wBitsPerSample = 16;
	wf.cbSize = 0;
	/* open the audio out channel */
	if (waveOutOpen(&wout,0,&wf,0,0,CALLBACK_NULL) != MMSYSERR_NOERROR)
		{
			fprintf(stderr,"Fatal Error: Failed to open wave output device\n");
			return -1;
		}
	/* open the audio in channel */
	if (waveInOpen(&win,0,&wf,0,0,CALLBACK_NULL) != MMSYSERR_NOERROR)
		{
			fprintf(stderr,"Fatal Error: Failed to open wave input device\n");
			waveOutReset(wout);
			waveOutClose(wout);
			return -1;
		}
	/* activate the exit handler */
	atexit(killem);
	/* initialize the audio in buffer structures */
	memset(&whin,0,sizeof(whin));

	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();

	fprintf(f, "Text Based Telephony Client.\n\n");
	issue_prompt(f);

	/* main tight loop */
	while(1) {
		/* service the network stuff */
		service_network(netfd,f);
		if (outqueue) /* if stuff in audio output queue, free it up if its available */
		{
			/* go through audio output queue */
			for(wh = outqueue,wh1 = wh2 = NULL,i = 0; wh != NULL; wh = wh->next)
			{
				service_network(netfd,f); /* service network here for better performance */
				/* if last one was removed from queue, zot it here */
				if (i && wh1)
				{ 
					free(wh1);
					wh1 = wh2;
				}
				i = 0; /* reset "last one removed" flag */
				if (wh->w.dwFlags & WHDR_DONE) /* if this one is done */
				{
					/* prepare audio header */
					if ((c = waveOutUnprepareHeader(wout,&wh->w,sizeof(WAVEHDR))) != MMSYSERR_NOERROR)
					{ 
						fprintf(stderr,"Cannot unprepare audio out header, error %d\n",c);
						exit(255);
					}
					if (wh1 != NULL) /* if there was a last one */
					{
						wh1->next = wh->next;
					} 
					if (outqueue == wh) /* is first one, so set outqueue to next one */
					{
						outqueue = wh->next;
					}
					i = 1; /* set 'to free' flag */
				}
				wh2 = wh1;	/* save old,old wh pointer */
				wh1 = wh; /* save the old wh pointer */
			}
		}
		/* go through all audio in buffers, and prepare and queue ones that are currently idle */
		for(i = 0; i < NWHIN; i++)
		{
			service_network(netfd,f); /* service network stuff here for better performance */
			if (!(whin[i].dwFlags & WHDR_PREPARED)) /* if not prepared, do so */
			{
				/* setup this input buffer header */
				memset(&whin[i],0,sizeof(WAVEHDR));
				whin[i].lpData = bufin[i];
				whin[i].dwBufferLength = 320;
				whin[i].dwUser = whinserial++; /* set 'user data' to current serial number */
				/* prepare the buffer */
				if (waveInPrepareHeader(win,&whin[i],sizeof(WAVEHDR)))
				{
					fprintf(stderr,"Unable to prepare header for input\n");
					return -1;
				}
				/* add it to device (queue) */
				if (waveInAddBuffer(win,&whin[i],sizeof(WAVEHDR)))
				{
					fprintf(stderr,"Unable to prepare header for input\n");
					return -1;
				}
			}
			waveInStart(win); /* start it (if not already started) */
		}
		
		/* if key pressed, do command stuff */
		if(_kbhit())
		{
				if ( ( fgets(&*rcmd, 256, stdin))) {
					rcmd[strlen(rcmd)-1] = 0;
					parse_args(f, &*rcmd);
				} else fprintf(f, "Fatal error: failed to read data!\n");

				issue_prompt(f);
		}
		/* do audio input stuff for buffers that have received data from audio in device already. Must
			do them in serial number order (the order in which they were originally queued). */
		if(answered_call) /* send audio only if call answered */
		{
			for(;;) /* loop until all are found */
			{
				for(i = 0; i < NWHIN; i++) /* find an available one that's the one we are looking for */
				{
					service_network(netfd,f); /* service network here for better performance */
					/* if not time to send any more, dont */
					if (GetTickCount() < (lastouttick + OUT_INTERVAL))
					{
						i = NWHIN; /* set to value that WILL exit loop */
						break;
					}
					if ((whin[i].dwUser == nextwhin) && (whin[i].dwFlags & WHDR_DONE)) { /* if audio is ready */

						/* must have read exactly 320 bytes */
						if (whin[i].dwBytesRecorded != whin[i].dwBufferLength)
						{
							fprintf(stderr,"Short audio read, got %d bytes, expected %d bytes\n", whin[i].dwBytesRecorded,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -