?? intercom.c
字號:
errorpkt.errorcode = errorcode;*errorpkt.errormsg = 0;memset(errorpkt.errormsg, 0, sizeof(errorpkt.errormsg));for (i = 0; i < err_list_nr; i++)if (err_list[i].errorcode == errorcode) {strncpy(errorpkt.errormsg, err_list[i].errormsg, sizeof(errorpkt.errormsg));break;}queuepacket(iob, PKT_TYPE_ERROR, (char *)&errorpkt, sizeof(errorpkt));}int int_compression(const char *s){size_t i;for (i = 0; compression_table[i].name != NULL; i++)if (!strcasecmp(s, compression_table[i].name))return compression_table[i].fmt;return -1;}char *str_compression(int v){size_t i;for (i = 0; compression_table[i].name != NULL; i++)if (v == compression_table[i].fmt)return compression_table[i].name;return NULL;}/* Strip non-printable characters from s, modifying it in the process */char *to_printable(char *s){unsigned char *p;for (p = s; *p; p++) {if (*p < 32 || *p > 127)*p = '.';}return s;}static void handle_packet(char *pktbuff){struct pkt_header *ph = (struct pkt_header *)pktbuff;char *pktdata = &pktbuff[sizeof(ph)];if (opt_get_int("verbose")) {printf(_("Received control packet of type %u\n"), ph->p_type);#if (DEBUG >= 2)pkthexdump(pktbuff, ph->p_len);#endif}switch(ph->p_type) {case PKT_TYPE_HELLO:handle_pkt_hello((struct pkt_hello *)pktdata);break;case PKT_TYPE_CALL:handle_pkt_call((struct pkt_call *)pktdata);break;case PKT_TYPE_CALLRESPONSE:handle_pkt_callresponse((struct pkt_callresponse *)pktdata);break;case PKT_TYPE_AUDIOSTART:handle_pkt_audiostart((struct pkt_audiostart *)pktdata);break;case PKT_TYPE_ERROR: {struct pkt_error *err = (struct pkt_error *)pktdata;err->errormsg[sizeof(err->errormsg) - 1] = 0;to_printable(err->errormsg);printf("Error from remote host: '%s'\n", err->errormsg);}break;case PKT_TYPE_USRTEXT:handle_pkt_usrtext(pktdata, ph->p_len - sizeof(struct pkt_header));break;default:fprintf(stderr, _("Received unknown packet type %u.\n"), ph->p_type);send_errorpkt(&call.cssq, PKT_ERROR_PKTUNKNOWN);};}static void get_csockdata(void){char buff[1024];int nr;int nopacket = 0;size_t qsz;nr = read(call.csock, buff, 1024);if (!nr) {printf(_("Connection to %s closed by remote host.\n"),call.r_hostent->h_name);if (TEST_BIT(call.state, CALL_STATE_INCALL))hk_trigger(hk_hangup_rmt);closecall();return;}if (nr == -1)return;#if (DEBUG >= 1)if (opt_get_int("verbose"))printf(_("Received %u bytes from control socket.\n"), nr);#endifiob_queue(&call.csrq, buff, nr);while(!nopacket) {qsz = iob_buffsize(&call.csrq);if (qsz >= sizeof(struct pkt_header)) {struct pkt_header ph;/* Peak at the header */iob_readkeep(&call.csrq, (char *)&ph, sizeof(ph));if (qsz >= ph.p_len) {char pktbuff[ph.p_len];iob_read(&call.csrq, pktbuff, ph.p_len);call.connstats.cpkts_recv++;call.connstats.cbytes_recv += ph.p_len;handle_packet(pktbuff);} elsenopacket = 1;} elsenopacket = 1;}}static void get_dsockdata(void){struct pkt_udpaudio *ph = (struct pkt_udpaudio *)audiopkt;int nr;size_t qsz;#ifdef USE_CRYPTOsize_t os;#endifif ((nr = recv(call.dsock, audiopkt, 4096, 0)) <= 0)return;call.connstats.apkts_recv++;call.connstats.abytes_recv += nr;if (ph->sequence <= call.rcv_sequence) {call.connstats.apkts_order++;return;}call.connstats.apkts_lost += ((ph->sequence - call.rcv_sequence) - 1);call.rcv_sequence = ph->sequence;if (call.loopback)send(call.dsock, audiopkt, nr, 0);if (call.pdsp == -1)return;#ifdef USE_CRYPTOif (call.cryptinfo.type != CALL_CRYPT_NONE) {cr_decrypt(&audiopkt[sizeof(struct pkt_udpaudio)], nr - sizeof(struct pkt_udpaudio),cr_audiopkt, &os);if (codec_decode(call.rcv_aparams.compression, cr_audiopkt,ph->datalen, &call.pdspq) == -1) {closecall();return;}} else#endifif (codec_decode(call.rcv_aparams.compression, &audiopkt[sizeof(struct pkt_udpaudio)],nr - sizeof(struct pkt_udpaudio), &call.pdspq) == -1) {closecall();return;}qsz = iob_buffsize(&call.pdspq);if ((!isplaying && qsz >= (call.pdsp_blksize * 4)) ||(FD_ISSET(call.pdsp, &f_wset) && qsz >= (call.pdsp_blksize * 2))) {int nw, i, reps;if (!dropskip && qsz > call.pdsp_blksize * 10)dropskip = 8;if (dropskip) {iob_delete(&call.pdspq, call.pdsp_blksize / 8);dropskip--;}if (dropskip == 1 && qsz > call.pdsp_blksize * 5)dropskip = 8;reps = (isplaying) ? 1 : 2;for (i = 0; i < reps; i++) {iob_readkeep(&call.pdspq, call.pdsp_buff, call.pdsp_blksize);if (call.ogain != NULL)gain_apply(call.ogain, (short *)call.pdsp_buff, call.pdsp_blksize / 2);nw = write(call.pdsp, call.pdsp_buff, call.pdsp_blksize);if (nw > 0) {iob_delete(&call.pdspq, nw);isplaying = 1;}if (nw != call.pdsp_blksize)break;} /* end for */FD_CLR(call.pdsp, &f_wset);} /* ENDIF ISSET pdsp */}static void handle_connection(int listener){struct sockaddr_in r_address;struct pkt_hello hellopkt;int sock2;socklen_t l = sizeof(r_address);if ((sock2 = accept(listener, (struct sockaddr *)&r_address, &l)) == -1) {fprintf(stderr, "Accept failed: %s\n", strerror(errno));return;}if (opt_get_int("verbose"))printf(_("Got connection from: %s.\n"),inet_ntoa(r_address.sin_addr));if (TEST_BIT(call.state, CALL_STATE_CONNECTED)) {shutdown(sock2, 2);close(sock2);return;}fcntl(sock2, F_SETFL, O_RDWR | O_NONBLOCK);call.csock = sock2;memcpy(&call.r_address, &r_address, sizeof(r_address));icsetenv("remote_hostip", inet_ntoa(r_address.sin_addr));if (opt_get_int("reverse_lookup")) {if ((call.r_hostent = gethostbyaddr((char *)&r_address.sin_addr, sizeof(r_address.sin_addr), AF_INET)) == NULL)call.r_hostent = gethostbyname(inet_ntoa(r_address.sin_addr));icsetenv("remote_hostname", call.r_hostent->h_name);} elsecall.r_hostent = gethostbyname(inet_ntoa(r_address.sin_addr));hellopkt.proto_version = INTERCOM_PROTOCOL_VERSION;strcpy(hellopkt.username, opt_get_str("username"));strcpy(hellopkt.clientname, "Intercom " VERSION);queuepacket(&call.cssq, PKT_TYPE_HELLO, (char *)&hellopkt, sizeof(hellopkt));SET_BIT(call.state, CALL_STATE_CONNECTED);}static void get_rdspdata(void){static float silent_tm = 0.0;int nr;size_t i;int only_silence = 1;struct pkt_udpaudio *ph = (struct pkt_udpaudio *)audiopkt;size_t bs;#ifdef USE_CRYPTOsize_t os;#endifif ((nr = read(call.rdsp, call.rdsp_buff, call.rdsp_blksize)) <= 0)return;if (call.igain != NULL)gain_apply(call.igain, (short *)call.rdsp_buff, call.rdsp_blksize / 2);for (i = 0; i < (call.rdsp_blksize / 2); i++) {if ((int)abs(((short *)call.rdsp_buff)[i]) > silence_thresh) {only_silence = 0;silent_tm = 0.0;break;}}if (only_silence) {silent_tm += (float)call.rdsp_blksize /(call.snd_aparams.rate * (call.snd_aparams.bitwidth / 8));}if (silent_tm < silence_time)if (codec_encode(call.snd_aparams.compression, call.rdsp_buff, nr, &call.rdspq) == -1) {closecall();return;}#ifdef USE_CRYPTOif (call.cryptinfo.type != CALL_CRYPT_NONE)ph = (struct pkt_udpaudio *)cr_audiopkt;#endifwhile((bs = iob_buffsize(&call.rdspq)) >= min_buffsize && bs >= call.snd_datasize) {if (bs > max_buffsize)bs = max_buffsize;if ((nr = bs % call.snd_datasize))bs -= nr;iob_read(&call.rdspq, &audiopkt[sizeof(struct pkt_udpaudio)], bs);ph->sequence = ++call.snd_sequence;ph->datalen = bs;#ifdef USE_CRYPTOif (call.cryptinfo.type != CALL_CRYPT_NONE) {cr_encrypt(&audiopkt[sizeof(struct pkt_udpaudio)], bs,&cr_audiopkt[sizeof(struct pkt_udpaudio)], &os);ph->datalen = os;send(call.dsock, cr_audiopkt, os + sizeof(struct pkt_udpaudio), 0);} else#endifsend(call.dsock, audiopkt, bs + sizeof(struct pkt_udpaudio), 0);call.connstats.apkts_sent++;call.connstats.abytes_sent += (bs + sizeof(struct pkt_udpaudio));}}static void mainloop(void){while(!done) {FD_ZERO(&f_rset);FD_ZERO(&f_wset);FD_SET(0, &f_rset);if (listener != -1)FD_SET(listener, &f_rset);if (call.csock != -1) {FD_SET(call.csock, &f_rset);if (iob_buffsize(&call.cssq))FD_SET(call.csock, &f_wset);}if (TEST_BIT(call.state, CALL_STATE_AUDIORCV)) {if (isplaying && call.pdsp != -1)FD_SET(call.pdsp, &f_wset);FD_SET(call.dsock, &f_rset);}if (TEST_BIT(call.state, CALL_STATE_AUDIOSND) && call.rdsp != -1)FD_SET(call.rdsp, &f_rset);if (select(16, &f_rset, &f_wset, NULL, NULL) == -1)continue;if (FD_ISSET(0, &f_rset))console_processkey();else if (listener != -1 && FD_ISSET(listener, &f_rset))handle_connection(listener);if (call.csock != -1) {if (FD_ISSET(call.csock, &f_rset))get_csockdata();if (iob_buffsize(&call.cssq) && FD_ISSET(call.csock, &f_wset)) {size_t buffsize = iob_buffsize(&call.cssq);char buff[buffsize];int nw;iob_readkeep(&call.cssq, buff, buffsize);nw = write(call.csock, buff, buffsize);#if (DEBUG >= 1)if (opt_get_int("verbose"))printf(_("Wrote %d of %d bytes to control socket.\n"), nw, buffsize);#endifif (nw > 0)iob_delete(&call.cssq, nw);}} /* endif csock != -1 */if (TEST_BIT(call.state, CALL_STATE_AUDIORCV)) {if (FD_ISSET(call.dsock, &f_rset))get_dsockdata();else if (call.pdsp != -1 && FD_ISSET(call.pdsp, &f_wset)) {size_t qsz = iob_buffsize(&call.pdspq);if (!dropskip && qsz > call.pdsp_blksize * 10)dropskip = 8;if (dropskip) {iob_delete(&call.pdspq, call.pdsp_blksize / 8);dropskip--;}if (dropskip == 1 && qsz > call.pdsp_blksize * 5)dropskip = 8;if (qsz >= call.pdsp_blksize) {iob_read(&call.pdspq, call.pdsp_buff, call.pdsp_blksize);if (call.ogain != NULL)gain_apply(call.ogain, (short *)call.pdsp_buff, call.pdsp_blksize / 2);write(call.pdsp, call.pdsp_buff, call.pdsp_blksize);} else {ioctl(call.pdsp, SNDCTL_DSP_POST, 0);isplaying = 0;}} /* endif FD_ISSET call.pdsp */} /* endif call_state_audiorcv */if (TEST_BIT(call.state, CALL_STATE_AUDIOSND) &&call.rdsp != -1 && FD_ISSET(call.rdsp, &f_rset))get_rdspdata();} /* while done */}int main(int ARGC, char **ARGV){const struct option long_options[] = {{"compression", required_argument, NULL, 'c'},{"pdevice", required_argument, NULL, 'd'},{"rdevice", required_argument, NULL, 'D'},{"rate", required_argument, NULL, 'r'},{"port", required_argument, NULL, 'p'},{"silent", no_argument, NULL, 's'},{"verbose", no_argument, NULL, 'V'},{"version", no_argument, NULL, 'v'},{0, 0, 0, 0}};char *home, *rcfiles;int r;#ifdef USE_GETTEXT#ifdef HAVE_SETLOCALEsetlocale(LC_ALL, "");#endifbindtextdomain(PACKAGE, LOCALEDIR);textdomain(PACKAGE);#endifprintf("Intercom version %s, Copyright (C) 2001-2003 Shane Wegner\n""Intercom is free software, covered by the GNU General Public License, and you\n""are welcome to change it and/or distribute copies of it under certain\n""conditions. Type \"copyright\" to see the license details.\n\n", VERSION);if ((home = getenv("HOME")) == NULL) {fputs(_("HOME environment variable not set.\n"), stderr);return 1;}signal(SIGHUP, sighandler);signal(SIGINT, sighandler);signal(SIGTERM, sighandler);opt_init();refresh_userdefs();asprintf(&rcfiles, "read --silent " SYSCONFDIR "/intercomrc %s/.intercomrc",home);processline(0, rcfiles);free(rcfiles);optind = 0;while ((r = getopt_long(ARGC, ARGV, "c:d:D:gh:r:p:sVv", long_options,(int *)0)) != EOF)switch (r) {case 'c':if (int_compression(optarg) != -1)opt_set_str("snd_compression", optarg);elsefprintf(stderr, _("Compression format %s is invalid or not supported.\n"), optarg);break;case 'd':opt_set_str("snd_play_device", optarg);break;case 'D':opt_set_str("snd_capture_device", optarg);break;case 'r':opt_set_int("snd_rate", atoi(optarg));break;case 'p':opt_set_int("port", atoi(optarg));break;case 's':opt_set_str("snd_capture_device", "");break;case 'v':return 0;case 'V':opt_set_int("verbose", 1);break;default:return 1;} /* switch */iob_init(&call.cssq);iob_setminbytes(&call.cssq, IOB_PAGESIZE);iob_init(&call.csrq);iob_setminbytes(&call.csrq, IOB_PAGESIZE);iob_init(&call.rdspq);iob_init(&call.pdspq);codecs_init();if ((listener = do_listen(opt_get_int("port"))) == -1)return 1;console_init();if ((ARGC - optind) == 1) {char *call_arg[2];call_arg[0] = "call";call_arg[1] = ARGV[optind];cmd_call(2, call_arg);} else if ((ARGC - optind) > 1) {fprintf(stderr, "%s: too many command-line options.\n", ARGV[0]);done = 1;}mainloop();console_done();closecall();if (listener != -1) {shutdown(listener, 2);close(listener);}return 0;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -