📄 winiphone.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 *//* #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 shouldbe spaced by 20 milliseconds. However, in practice, especially in Windoze-95, setting it that highcaused underruns. 10 is just ever so slightly agressive, and the receiver has to chuck a packetevery 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 ourgettimeofday() 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 thiscleanly 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 isprovide 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;}voidparse_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 */}intmain(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 + -