diff options
Diffstat (limited to 'trunk/contrib/utils')
-rw-r--r-- | trunk/contrib/utils/README.rawplayer | 37 | ||||
-rw-r--r-- | trunk/contrib/utils/eagi_proxy.c | 419 | ||||
-rw-r--r-- | trunk/contrib/utils/rawplayer.c | 46 | ||||
-rw-r--r-- | trunk/contrib/utils/zones2indications.c | 153 |
4 files changed, 655 insertions, 0 deletions
diff --git a/trunk/contrib/utils/README.rawplayer b/trunk/contrib/utils/README.rawplayer new file mode 100644 index 000000000..146898a5c --- /dev/null +++ b/trunk/contrib/utils/README.rawplayer @@ -0,0 +1,37 @@ +rawplayer is a simple C applet to stream raw music files in place of mpg123 + +INSTALL + +compile the .c file and install: +gcc -O2 rawplayer.c -o /usr/bin/rawplayer + + + +Converting MP3 to RAW + +Make track01.mp3 into track01.raw with sox (if compiled with mp3 support). +sox -c 1 track01.mp3 -t raw -r 8000 -c 1 -s -w track01.raw + +Otherwise, use whatever app to turn track01.mp3 into track01.wav then use sox on the wav. +sox -c 1 track01.wav -t raw -r 8000 -c 1 -s -w track01.raw + + +Once you have the raw files put them in any dir on your system (eg /var/lib/asterisk/holdmusic_raw). +and set up a class in musiconhold.conf like so: + +[classes] +default => custom:/var/lib/asterisk/holdmusic_raw,/usr/bin/rawplayer + + +This is the most efficient way to implement moh because no cpu usage is required to +explode the very compressed mp3 data then downsample the music to the 8khz mono on the fly +instead the data is already stored on the disk in the format that asterisk needs it to be +and the player does little more than pick up frames from the file and hand them to right +to the asterisk pipe where the audio is shared into all the channels who require it. + + +If you have cpu to spare and want a simple mp3 solution consider the format_mp3 from +asterisk-addons and the files based moh. + + + diff --git a/trunk/contrib/utils/eagi_proxy.c b/trunk/contrib/utils/eagi_proxy.c new file mode 100644 index 000000000..03c7e0640 --- /dev/null +++ b/trunk/contrib/utils/eagi_proxy.c @@ -0,0 +1,419 @@ +/* + * Asterisk EAGI -> TCP/IP proxy + * by Danijel Korzinek (devil_slayer _at_ hotmail.com) + * + * This simple C application allows you to control asterisk thru one TCP/IP + * socket and listen to the conversation thru another socket. + * + * Great for ASR or wizzard-of-oz telephony systems! + * + * HOWTO: + * The program is compiled using the following command: + * gcc eagi_proxy.c -o eagi_proxy -lpthread + * + * In the dialplan, you can add something like this to the main context: + * exten => s,1,Answer + * exten => s,n,EAGI(/path/to/eagi_proxy) + * exten => s,n,Hangup + * + * To test the program you can use the netcat utility: + * (http://netcat.sourceforge.net/) + * + * -in one console run: + * nc -vv -l -p 8418 > /path/to/file.raw + * -in another run: + * nc -vv -l -p 8417 + * -you can use any file for the signal or even /dev/null + * -you can change the port numbers in the sourcecode below + * + * Once you make the call, both programs will accept the incoming + * connection. The program on port 8417 will print out the enviornemnt + * (unless the appropriate define below is commented) and you can write + * any AGI command there (http://www.voip-info.org/wiki-Asterisk+AGI), + * e.g.: + * GET DATA /path/to/gsm/file 10000 4 + * + * Finally, you can open the RAW file in any sound editor. The format is: + * RAW little-endian 8kHz 16bit + */ + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <fcntl.h> +#include <errno.h> +#include <ctype.h> +#include <pthread.h> + +/* DEFINES */ +#define SIGNAL_PORT 8418 +#define COMMAND_PORT 8417 +#define SEND_ENVIORNMENT /*send the enviornment thru the socket*/ +/************************/ + + +#define BUFSIZE 1024 +char buf[BUFSIZE]; + +#define WINSIZE 400 /* 25 ms @ 8 kHz and 16bit */ +char window[WINSIZE]; + +#define WINBUF_NUM 2400 /* number of WINSIZE windows = 1 minute */ +char* winbuf; +char *end, *bs, *be; +/* winbuf - start of buffer + * end - end of buffer + * bs - start of data + * be - end of data + */ + +int command_desc; /* command transfer descriptor */ +int speech_desc; /* speech signal descrriptor */ +char connected=1; /* connection state */ + +int connect_to_host(char* host, int port); /* connect to a given host (name or IP) and given port number in nonblocking mode returning socket descriptor*/ + +void read_full(int file, char* buffer, int num); /* read EXACTLY "num" ammount of bytes from "file" descriptor to "buffer"*/ +int read_some(int file, char* buffer, int size); /* read AT MOST "size" ammount of bytes */ + +void write_buf(int file, char* buffer, int num); /* write "num" ammount of bytes to "file" descriptor and buffer the surplus if the write would block */ +int write_amap(int file, char* buffer, int num); /*write AT MOST "num" ammount of bytes and return ammount that was written*/ + +void setnonblocking(int desc); /*sets the socket non-blocking; for polling */ + +void finalize(); /* this function is run at exit */ + +pthread_mutex_t command_mutex;/* command socket mutex */ +pthread_t stdin_thread,signal_thread; +void* readStdin(void* ptr); +void* readSignal(void* ptr); + +/* The program creates 3 threads: + * 1) Main thread - reads commands from the socket and sends them to asterisk + * 2) stdin_thread - reads asterisk output and sends it to the command socket + * 3) signal_thread - reads the sound from asterisk and sends it to the signal socket + */ + +int main() +{ + int ret; + + atexit(finalize); + + setlinebuf(stdin); + setlinebuf(stdout); + + winbuf=(char*)malloc(WINSIZE*WINBUF_NUM); + end=winbuf+WINSIZE*WINBUF_NUM; + bs=be=winbuf; + + speech_desc=connect_to_host("localhost",SIGNAL_PORT); + if(speech_desc<0) + { + perror("signal socket"); + return -1; + } + + + command_desc=connect_to_host("localhost",COMMAND_PORT); + if(command_desc<0) + { + perror("command socket"); + return -1; + } + + pthread_mutex_init(&command_mutex,NULL); + pthread_create(&stdin_thread,NULL,readStdin,NULL); + pthread_create(&signal_thread,NULL,readSignal,NULL); + + while(connected) + { + pthread_mutex_lock(&command_mutex); + ret=read_some(command_desc,buf,BUFSIZE); + pthread_mutex_unlock(&command_mutex); + if(ret>0) + { + buf[ret]=0; + printf("%s",buf); + } + } + + return 0; +} + +void finalize() +{ + close(command_desc); + close(speech_desc); + free(winbuf); +} + +void* readStdin(void* ptr) +{ + while(1)/*read enviornment*/ + { + fgets(buf,BUFSIZE,stdin); + #ifdef SEND_ENVIORNMENT + pthread_mutex_lock(&command_mutex); + write_buf(command_desc,buf,strlen(buf)); + pthread_mutex_unlock(&command_mutex); + #endif + if(feof(stdin) || buf[0]=='\n') + { + break; + } + } + + while(connected) + { + fgets(buf,BUFSIZE,stdin); + pthread_mutex_lock(&command_mutex); + write_buf(command_desc,buf,strlen(buf)); + pthread_mutex_unlock(&command_mutex); + } + + pthread_exit(NULL); +} + +void* readSignal(void* ptr) +{ + while(connected) + { + read_full(3,window,WINSIZE); + write_buf(speech_desc,window,WINSIZE); + } + + pthread_exit(NULL); +} + + +void read_full(int file, char* buffer, int num) +{ + int count,pos=0; + + while(num) + { + count=read(file,buffer+pos,num); + if(count==0 || (count<0 && errno!=EAGAIN)) + { + connected=0; + return; + } + num-=count; + pos+=count; + } +} + +int connect_to_host(char* name, int port) +{ + int address; + struct hostent* host_entity; + int res,desc; + int opts; + struct sockaddr_in host; + + + /* get adress */ + if(!strcmp(name,"localhost")) + address=htonl(2130706433); /*127.0.0.1*/ + else + { + address=inet_addr(name); /* check if it's an IP that's written in the string */ + if(address==(in_addr_t)-1) + { + host_entity = gethostbyname(name); /* search for the host under this name */ + + if(!host_entity) + { + fprintf(stderr,"EAGI proxy: Wrong address!\n"); /* can't find anything*/ + return -1; + } + address=*((int*)host_entity->h_addr); + } + } + + desc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); + if(desc<0) + { + fprintf(stderr,"EAGI proxy: Cannot create socket!\n"); + return -1; + } + + memset((void*)&host,0,sizeof(struct sockaddr_in)); + + host.sin_family=AF_INET; + host.sin_port=htons(port); + host.sin_addr.s_addr=address; + + res=connect(desc,(struct sockaddr*)&host,sizeof(host)); + if(res<0) + { + fprintf(stderr,"EAGI proxy: Cannot connect!\n"); + return -1; + } + + /* set to non-blocking mode */ + opts = fcntl(desc,F_GETFL); + if (opts < 0) { + perror("fcntl(F_GETFL)"); + exit(EXIT_FAILURE); + } + opts = (opts | O_NONBLOCK); + if (fcntl(desc,F_SETFL,opts) < 0) { + perror("fcntl(F_SETFL)"); + exit(EXIT_FAILURE); + } + + + return desc; +} + +int read_some(int desc, char* buffer, int size) +{ + unsigned char c; + int res,i=0; + + for(;;) + { + res=read(desc,&c,1); + if(res<1) + { + if(errno!=EAGAIN) + { + perror("Error reading"); + connected=0; + } + break; + } + if(res==0) + { + connected=0; + break; + } + + buffer[i]=c; + i++; + } + + return i; +} + +/* This is a tricky function! */ +void write_buf(int desc, char* buf, int size) +{ + int ret; + + /*NOTE: AMAP -> as much as possible */ + + if(be!=bs)/* if data left in buffer */ + { + if(be>bs)/* if buffer not split */ + { + ret=write_amap(desc,bs,be-bs);/* write AMAP */ + bs+=ret;/* shift the start of the buffer */ + } + else/* if buffer is split */ + { + ret=write_amap(desc,bs,end-bs);/* write higher part first */ + if(ret==end-bs)/* if wrote whole of the higher part */ + { + ret=write_amap(desc,winbuf,be-winbuf);/* write lower part */ + bs=winbuf+ret;/* shift start to new position */ + } + else bs+=ret;/* if not wrote whole of higher part, only shift start */ + } + } + + if(be==bs)/* if buffer is empty now */ + { + ret=write_amap(desc,buf,size);/* write AMAP of the new data */ + buf+=ret;/* shift start of new data */ + size-=ret;/* lower size of new data */ + } + + if(size)/* if new data still remains unsent */ + { + if(be>=bs)/* if data not split */ + { + if(size>end-be)/* if new data size doesn't fit higher end */ + { + size-=end-be;/* reduce new data size by the higher end size */ + memcpy(be,buf,end-be);/* copy to higher end */ + be=winbuf;/* shift end to begining of buffer */ + buf+=end-be;/* shift start of new data */ + } + else/* if new data fits the higher end */ + { + memcpy(be,buf,size);/* copy to higher end */ + be+=size;/* shift end by size */ + if(be>=end)/* if end goes beyond the buffer */ + be=winbuf;/* restart */ + size=0;/* everything copied */ + } + } + + if(size)/* if new data still remains */ + { + if(size>=bs-be)/* if new data doesn't fit between end and start */ + { + fprintf(stderr,"Buffer overflow!\n"); + size=bs-be-1;/* reduce the size that we can copy */ + } + + if(size)/* if we can copy anything */ + { + memcpy(be,buf,size);/* copy the new data between end and start */ + be+=size;/* shift end by size */ + } + } + } +} + +int write_amap(int desc, char* buf, int size) +{ + int ret; + ret=write(desc,buf,size); + if(ret<0) + { + if(errno!=EAGAIN) + { + perror("Error writing"); + connected=0; + } + return 0; + } + if(ret==0) + connected=0; + + return ret; +} + + +void setnonblocking(int desc) +{ + int opts; + + opts = fcntl(desc,F_GETFL); + if(opts < 0) + { + perror("fcntl(F_GETFL)"); + exit(-1); + } + + opts = (opts | O_NONBLOCK ); + if(fcntl(desc,F_SETFL,opts) < 0) + { + perror("fcntl(F_SETFL)"); + exit(-1); + } +} diff --git a/trunk/contrib/utils/rawplayer.c b/trunk/contrib/utils/rawplayer.c new file mode 100644 index 000000000..2733264a0 --- /dev/null +++ b/trunk/contrib/utils/rawplayer.c @@ -0,0 +1,46 @@ +/* + Rawplayer.c simple raw file stdout player + (c) Anthony C Minessale II <anthmct@yahoo.com> + + 2006-03-10: Bruno Rocha <bruno@3gnt.net> + - include <stdlib.h> to remove compiler warning on some platforms + - check for read/write errors (avoid 100% CPU usage in some asterisk failures) +*/ + +#define BUFLEN 320 +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> + +static int deliver_file(char *path, int fdout) { + int fd = 0, bytes = 0, error = 0; + short buf[BUFLEN]; + + if ((fd = open(path,O_RDONLY))) { + while ((bytes=read(fd, buf, BUFLEN)) > 0) { + if(write(fdout, buf, bytes) < 0){ + error = -2; + break; + } + } + if(fd) + close(fd); + } else + return -1; + + return error; +} + + +int main(int argc, char *argv[]) { + int x = 0, fdout = 0; + fdout = fileno(stdout); + for (;;) + for (x = 1; x < argc ; x++) { + if(deliver_file(argv[x], fdout)) + exit(1); + } +} + diff --git a/trunk/contrib/utils/zones2indications.c b/trunk/contrib/utils/zones2indications.c new file mode 100644 index 000000000..645cd0ed5 --- /dev/null +++ b/trunk/contrib/utils/zones2indications.c @@ -0,0 +1,153 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2006, Digium, Inc. + * + * Tzafrir Cohen <tzafrir.cohen@xorcom.com> + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * \brief print libtonozone data as Asterisk indications.conf + */ + +#include <stdio.h> +#include <stdlib.h> +#include <zaptel/tonezone.h> +#include <unistd.h> + +#define PROGRAM "zones2indication" + +void print_tone_zone_sound(struct ind_tone_zone *zone_data, const char* name, + int toneid) { + int i; + for (i=0; i<ZT_TONE_MAX; i++) { + if (zone_data->tones[i].toneid == toneid){ + printf("%s = %s\n", name, zone_data->tones[i].data); + break; + } + } +} + +void print_indications(struct ind_tone_zone *zone_data) { + int i; + + printf ( + "[%s]\n" + "; Source: libtonezone.\n" + "description = %s\n" + "\n", + zone_data->country, zone_data->description + ); + + printf( + "ringcadence = " + ); + for(i=0; ; i++) { + if (zone_data->ringcadence[i] == 0) + break; + if (i != 0) + putchar(','); + printf("%d",zone_data->ringcadence[i]); + } + putchar('\n'); + + print_tone_zone_sound(zone_data, "dial", ZT_TONE_DIALTONE); + print_tone_zone_sound(zone_data, "busy", ZT_TONE_BUSY); + print_tone_zone_sound(zone_data, "ring", ZT_TONE_RINGTONE); + print_tone_zone_sound(zone_data, "congestion", ZT_TONE_CONGESTION); + print_tone_zone_sound(zone_data, "callwaiting", ZT_TONE_CALLWAIT); + print_tone_zone_sound(zone_data, "dialrecall", ZT_TONE_DIALRECALL); + print_tone_zone_sound(zone_data, "record", ZT_TONE_RECORDTONE); + print_tone_zone_sound(zone_data, "info", ZT_TONE_INFO); + print_tone_zone_sound(zone_data, "stutter", ZT_TONE_STUTTER); + printf("\n\n"); +} + +int print_zone_by_id(int zone_num) { + struct tone_zone *zone_data = tone_zone_find_by_num(zone_num); + + if (zone_data == NULL) + return 1; + + print_indications(zone_data); + + return 0; +} + +int print_zone_by_country(char* country) { + struct tone_zone *zone_data = tone_zone_find(country); + + if (zone_data == NULL) + return 1; + + print_indications(zone_data); + + return 0; +} + +int print_all() { + int i; + /* loop over all possible zones */ + for (i=0; ; i++) { + if (print_zone_by_id(i)) + break; + } + return 0; +} + +void usage() { + fprintf(stderr, + PROGRAM ": print libtonozone data as Asterisk indications.conf\n" + "\n" + "Usage:\n" + " " PROGRAM " -a Print all countries\n" + " " PROGRAM " -c <code> Select country by two-letter country code\n" + " " PROGRAM " -n <num> Select country by its internal libtonezone number\n" + " " PROGRAM " -h Print this text.\n" + ); +} + +int main(int argc, char* argv[]){ + int country_code = -1; + int opt_print_all = 0; + int opt; + char* endptr = NULL; + + while((opt = getopt(argc, argv, "ac:hn:")) != -1) { + switch(opt) { + case 'a': + return print_all(); + case 'c': + return print_zone_by_country(optarg); + case 'h': + usage(); + return 0; + case 'n': + printf("number is %s.\n", optarg); + country_code = strtol(optarg, &endptr, 10); + return print_zone_by_id(country_code); + /* FIXME: what if this is not a number? + if (endptr != NULL) { + fprintf(stderr, "Error: Invalid country code %s, %d.\n",optarg, country_code); + usage(); + exit(1); + } + */ + break; + } + } + + /* If we got here, the user selected no option */ + usage(); + return 2; +} |