Improve mp3 player quality (bug #1527)
[asterisk/asterisk.git] / callerid.c
index f78714f..3f3e2f7 100755 (executable)
 #include <unistd.h>
 #include <math.h>
 #include <asterisk/ulaw.h>
 #include <unistd.h>
 #include <math.h>
 #include <asterisk/ulaw.h>
+#include <asterisk/alaw.h>
+#include <asterisk/frame.h>
 #include <asterisk/callerid.h>
 #include <asterisk/logger.h>
 #include <asterisk/fskmodem.h>
 #include <asterisk/callerid.h>
 #include <asterisk/logger.h>
 #include <asterisk/fskmodem.h>
-#include "sas.h"
-#include "cas.h"
-
 
 struct callerid_state {
        fsk_data fskd;
 
 struct callerid_state {
        fsk_data fskd;
@@ -43,27 +42,76 @@ struct callerid_state {
        int len;
 };
 
        int len;
 };
 
-static float dr[4], di[4];
-static float clidsb = 8000.0 / 1200.0;
+
+float cid_dr[4], cid_di[4];
+float clidsb = 8000.0 / 1200.0;
+float sasdr, sasdi;
+float casdr1, casdi1, casdr2, casdi2;
 
 #define CALLERID_SPACE 2200.0          /* 2200 hz for "0" */
 #define CALLERID_MARK  1200.0          /* 1200 hz for "1" */
 
 #define CALLERID_SPACE 2200.0          /* 2200 hz for "0" */
 #define CALLERID_MARK  1200.0          /* 1200 hz for "1" */
+#define SAS_FREQ                440.0
+#define CAS_FREQ1              2130.0
+#define CAS_FREQ2              2750.0
+
+static inline void gen_tones(unsigned char *buf, int len, int codec, float ddr1, float ddi1, float ddr2, float ddi2, float *cr1, float *ci1, float *cr2, float *ci2)
+{
+       int x;
+       float t;
+       for (x=0;x<len;x++) {
+               t = *cr1 * ddr1 - *ci1 * ddi1;
+               *ci1 = *cr1 * ddi1 + *ci1 * ddr1;
+               *cr1 = t;
+               t = 2.0 - (*cr1 * *cr1 + *ci1 * *ci1);
+               *cr1 *= t;
+               *ci1 *= t;      
+
+               t = *cr2 * ddr2 - *ci2 * ddi2;
+               *ci2 = *cr2 * ddi2 + *ci2 * ddr2;
+               *cr2 = t;
+               t = 2.0 - (*cr2 * *cr2 + *ci2 * *ci2);
+               *cr2 *= t;
+               *ci2 *= t;      
+               buf[x] = AST_LIN2X((*cr1 + *cr2) * 8192.0);
+       }
+}
+
+static inline void gen_tone(unsigned char *buf, int len, int codec, float ddr1, float ddi1, float *cr1, float *ci1)
+{
+       int x;
+       float t;
+       for (x=0;x<len;x++) {
+               t = *cr1 * ddr1 - *ci1 * ddi1;
+               *ci1 = *cr1 * ddi1 + *ci1 * ddr1;
+               *cr1 = t;
+               t = 2.0 - (*cr1 * *cr1 + *ci1 * *ci1);
+               *cr1 *= t;
+               *ci1 *= t;      
+               buf[x] = AST_LIN2X(*cr1 * 8192.0);
+       }
+}
 
 void callerid_init(void)
 {
        /* Initialize stuff for inverse FFT */
 
 void callerid_init(void)
 {
        /* Initialize stuff for inverse FFT */
-       dr[0] = cos(CALLERID_SPACE * 2.0 * M_PI / 8000.0);
-       di[0] = sin(CALLERID_SPACE * 2.0 * M_PI / 8000.0);
-       dr[1] = cos(CALLERID_MARK * 2.0 * M_PI / 8000.0);
-       di[1] = sin(CALLERID_MARK * 2.0 * M_PI / 8000.0);
+       cid_dr[0] = cos(CALLERID_SPACE * 2.0 * M_PI / 8000.0);
+       cid_di[0] = sin(CALLERID_SPACE * 2.0 * M_PI / 8000.0);
+       cid_dr[1] = cos(CALLERID_MARK * 2.0 * M_PI / 8000.0);
+       cid_di[1] = sin(CALLERID_MARK * 2.0 * M_PI / 8000.0);
+       sasdr = cos(SAS_FREQ * 2.0 * M_PI / 8000.0);
+       sasdi = sin(SAS_FREQ * 2.0 * M_PI / 8000.0);
+       casdr1 = cos(CAS_FREQ1 * 2.0 * M_PI / 8000.0);
+       casdi1 = sin(CAS_FREQ1 * 2.0 * M_PI / 8000.0);
+       casdr2 = cos(CAS_FREQ2 * 2.0 * M_PI / 8000.0);
+       casdi2 = sin(CAS_FREQ2 * 2.0 * M_PI / 8000.0);
 }
 
 struct callerid_state *callerid_new(void)
 {
        struct callerid_state *cid;
        cid = malloc(sizeof(struct callerid_state));
 }
 
 struct callerid_state *callerid_new(void)
 {
        struct callerid_state *cid;
        cid = malloc(sizeof(struct callerid_state));
-       memset(cid, 0, sizeof(*cid));
        if (cid) {
        if (cid) {
+               memset(cid, 0, sizeof(struct callerid_state));
                cid->fskd.spb = 7;              /* 1200 baud */
                cid->fskd.hdlc = 0;             /* Async */
                cid->fskd.nbit = 8;             /* 8 bits */
                cid->fskd.spb = 7;              /* 1200 baud */
                cid->fskd.hdlc = 0;             /* Async */
                cid->fskd.nbit = 8;             /* 8 bits */
@@ -98,34 +146,28 @@ void callerid_get(struct callerid_state *cid, char **name, char **number, int *f
                *number = cid->number;
 }
 
                *number = cid->number;
 }
 
-int ast_callerid_gen_cas(unsigned char *outbuf, int len)
+int ast_gen_cas(unsigned char *outbuf, int sendsas, int len, int codec)
 {
        int pos = 0;
 {
        int pos = 0;
-       int cnt;
        int saslen=2400;
        int saslen=2400;
-       if (len < saslen)
-               return -1;
-       while(saslen) {
-               cnt = saslen;
-               if (cnt > sizeof(sas))
-                       cnt = sizeof(sas);
-               memcpy(outbuf + pos, sas, cnt);
-               pos += cnt;
-               len -= cnt;
-               saslen -= cnt;
-       }
-       while(len) {
-               cnt = len;
-               if (cnt > sizeof(cas))
-                       cnt = sizeof(cas);
-               memcpy(outbuf + pos, cas, cnt);
-               pos += cnt;
-               len -= cnt;
+       float cr1 = 1.0;
+       float ci1 = 0.0;
+       float cr2 = 1.0;
+       float ci2 = 0.0;
+       if (sendsas) {
+               if (len < saslen)
+                       return -1;
+               gen_tone(outbuf, saslen, codec, sasdr, sasdi, &cr1, &ci1);
+               len -= saslen;
+               pos += saslen;
+               cr2 = cr1;
+               ci2 = ci1;
        }
        }
+       gen_tones(outbuf + pos, len, codec, casdr1, casdi1, casdr2, casdi2, &cr1, &ci1, &cr2, &ci2);
        return 0;
 }
 
        return 0;
 }
 
-int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len)
+int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, int codec)
 {
        int mylen = len;
        int olen;
 {
        int mylen = len;
        int olen;
@@ -142,10 +184,14 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len)
        memcpy(buf, cid->oldstuff, cid->oldlen);
        mylen += cid->oldlen/2;
        for (x=0;x<len;x++) 
        memcpy(buf, cid->oldstuff, cid->oldlen);
        mylen += cid->oldlen/2;
        for (x=0;x<len;x++) 
-               buf[x+cid->oldlen/2] = ast_mulaw[ubuf[x]];
+               buf[x+cid->oldlen/2] = AST_XLAW(ubuf[x]);
        while(mylen >= 80) {
                olen = mylen;
                res = fsk_serie(&cid->fskd, buf, &mylen, &b);
        while(mylen >= 80) {
                olen = mylen;
                res = fsk_serie(&cid->fskd, buf, &mylen, &b);
+               if (mylen < 0) {
+                       ast_log(LOG_ERROR, "fsk_serie made mylen < 0 (%d)\n", mylen);
+                       return -1;
+               }
                buf += (olen - mylen);
                if (res < 0) {
                        ast_log(LOG_NOTICE, "fsk_serie failed\n");
                buf += (olen - mylen);
                if (res < 0) {
                        ast_log(LOG_NOTICE, "fsk_serie failed\n");
@@ -207,6 +253,7 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len)
                                                        /* Date */
                                                        break;
                                                case 2: /* Number */
                                                        /* Date */
                                                        break;
                                                case 2: /* Number */
+                                               case 3: /* Number (for Zebble) */
                                                case 4: /* Number */
                                                        res = cid->rawdata[x];
                                                        if (res > 32) {
                                                case 4: /* Number */
                                                        res = cid->rawdata[x];
                                                        if (res > 32) {
@@ -227,6 +274,8 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len)
                                                        memcpy(cid->name, cid->rawdata + x + 1, res);
                                                        cid->name[res] = '\0';
                                                        break;
                                                        memcpy(cid->name, cid->rawdata + x + 1, res);
                                                        cid->name[res] = '\0';
                                                        break;
+                                               case 22: /* Something French */
+                                                       break;
                                                default:
                                                        ast_log(LOG_NOTICE, "Unknown IE %d\n", cid->rawdata[x-1]);
                                                }
                                                default:
                                                        ast_log(LOG_NOTICE, "Unknown IE %d\n", cid->rawdata[x-1]);
                                                }
@@ -235,7 +284,7 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len)
                                        }
                                } else {
                                        /* SDMF */
                                        }
                                } else {
                                        /* SDMF */
-                                       strncpy(cid->number, cid->rawdata + 8, sizeof(cid->number));
+                                       strncpy(cid->number, cid->rawdata + 8, sizeof(cid->number)-1);
                                }
                                /* Update flags */
                                cid->flags = 0;
                                }
                                /* Update flags */
                                cid->flags = 0;
@@ -263,7 +312,8 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len)
        if (mylen) {
                memcpy(cid->oldstuff, buf, mylen * 2);
                cid->oldlen = mylen * 2;
        if (mylen) {
                memcpy(cid->oldstuff, buf, mylen * 2);
                cid->oldlen = mylen * 2;
-       }
+       } else
+               cid->oldlen = 0;
        free(obuf);
        return 0;
 }
        free(obuf);
        return 0;
 }
@@ -273,22 +323,22 @@ void callerid_free(struct callerid_state *cid)
        free(cid);
 }
 
        free(cid);
 }
 
-static void callerid_genmsg(char *msg, int size, char *number, char *name, int flags)
+static int callerid_genmsg(char *msg, int size, char *number, char *name, int flags)
 {
        time_t t;
 {
        time_t t;
-       struct tm *tm;
+       struct tm tm;
        char *ptr;
        int res;
        int i,x;
        /* Get the time */
        time(&t);
        char *ptr;
        int res;
        int i,x;
        /* Get the time */
        time(&t);
-       tm = localtime(&t);
+       localtime_r(&t,&tm);
        
        ptr = msg;
        
        /* Format time and message header */
        
        ptr = msg;
        
        /* Format time and message header */
-       res = snprintf(ptr, size, "\001\010%02d%02d%02d%02d", tm->tm_mon + 1,
-                               tm->tm_mday, tm->tm_hour, tm->tm_min);
+       res = snprintf(ptr, size, "\001\010%02d%02d%02d%02d", tm.tm_mon + 1,
+                               tm.tm_mday, tm.tm_hour, tm.tm_min);
        size -= res;
        ptr += res;
        if (!number || !strlen(number) || (flags & CID_UNKNOWN_NUMBER)) {
        size -= res;
        ptr += res;
        if (!number || !strlen(number) || (flags & CID_UNKNOWN_NUMBER)) {
@@ -302,9 +352,9 @@ static void callerid_genmsg(char *msg, int size, char *number, char *name, int f
                size -= res;
                ptr += res;
        } else {
                size -= res;
                ptr += res;
        } else {
-               /* Send up to 10 digits of number MAX */
+               /* Send up to 16 digits of number MAX */
                i = strlen(number);
                i = strlen(number);
-               if (i > 10) i = 10;
+               if (i > 16) i = 16;
                res = snprintf(ptr, size, "\002%c", i);
                size -= res;
                ptr += res;
                res = snprintf(ptr, size, "\002%c", i);
                size -= res;
                ptr += res;
@@ -326,7 +376,7 @@ static void callerid_genmsg(char *msg, int size, char *number, char *name, int f
                size -= res;
                ptr += res;
        } else {
                size -= res;
                ptr += res;
        } else {
-               /* Send up to 10 digits of number MAX */
+               /* Send up to 16 digits of name MAX */
                i = strlen(name);
                if (i > 16) i = 16;
                res = snprintf(ptr, size, "\007%c", i);
                i = strlen(name);
                if (i > 16) i = 16;
                res = snprintf(ptr, size, "\007%c", i);
@@ -338,70 +388,83 @@ static void callerid_genmsg(char *msg, int size, char *number, char *name, int f
                ptr += i;
                size -= i;
        }
                ptr += i;
                size -= i;
        }
+       return (ptr - msg);
        
 }
 
        
 }
 
-static inline float callerid_getcarrier(float *cr, float *ci, int bit)
+int vmwi_generate(unsigned char *buf, int active, int mdmf, int codec)
 {
 {
-       /* Move along.  There's nothing to see here... */
-       float t;
-       t = *cr * dr[bit] - *ci * di[bit];
-       *ci = *cr * di[bit] + *ci * dr[bit];
-       *cr = t;
-       
-       t = 2.0 - (*cr * *cr + *ci * *ci);
-       *cr *= t;
-       *ci *= t;
-       return *cr;
-}      
-
-#define PUT_BYTE(a) do { \
-       *(buf++) = (a); \
-       bytes++; \
-} while(0)
-
-#define PUT_AUDIO_SAMPLE(y) do { \
-       int index = (short)(rint(8192.0 * (y))); \
-       *(buf++) = ast_lin2mu[index + 32768]; \
-       bytes++; \
-} while(0)
-       
-#define PUT_CLID_MARKMS do { \
-       int x; \
-       for (x=0;x<8;x++) \
-               PUT_AUDIO_SAMPLE(callerid_getcarrier(&cr, &ci, 1)); \
-} while(0)
-
-#define PUT_CLID_BAUD(bit) do { \
-       while(scont < clidsb) { \
-               PUT_AUDIO_SAMPLE(callerid_getcarrier(&cr, &ci, bit)); \
-               scont += 1.0; \
-       } \
-       scont -= clidsb; \
-} while(0)
-
-
-#define PUT_CLID(byte) do { \
-       int z; \
-       unsigned char b = (byte); \
-       PUT_CLID_BAUD(0);       /* Start bit */ \
-       for (z=0;z<8;z++) { \
-               PUT_CLID_BAUD(b & 1); \
-               b >>= 1; \
-       } \
-       PUT_CLID_BAUD(1);       /* Stop bit */ \
-} while(0);    
+       unsigned char msg[256];
+       int len=0;
+       int sum;
+       int x;
+       int bytes = 0;
+       float cr = 1.0;
+       float ci = 0.0;
+       float scont = 0.0;
+       if (mdmf) {
+               /* MDMF Message waiting */
+               msg[len++] = 0x82;
+               /* Length is 3 */
+               msg[len++] = 3;
+               /* IE is "Message Waiting Parameter" */
+               msg[len++] = 0xb;
+               /* Length of IE is one */
+               msg[len++] = 1;
+               /* Active or not */
+               if (active)
+                       msg[len++] = 0xff;
+               else
+                       msg[len++] = 0x00;
+       } else {
+               /* SDMF Message waiting */
+               msg[len++] = 0x6;
+               /* Length is 3 */
+               msg[len++] = 3;
+               if (active) {
+                       msg[len++] = 0x42;
+                       msg[len++] = 0x42;
+                       msg[len++] = 0x42;
+               } else {
+                       msg[len++] = 0x6f;
+                       msg[len++] = 0x6f;
+                       msg[len++] = 0x6f;
+               }
+       }
+       sum = 0;
+       for (x=0;x<len;x++)
+               sum += msg[x];
+       sum = (256 - (sum & 255));
+       msg[len++] = sum;
+       /* Wait a half a second */
+       for (x=0;x<4000;x++)
+               PUT_BYTE(0x7f);
+       /* Transmit 30 0x55's (looks like a square wave) for channel seizure */
+       for (x=0;x<30;x++)
+               PUT_CLID(0x55);
+       /* Send 170ms of callerid marks */
+       for (x=0;x<170;x++)
+               PUT_CLID_MARKMS;
+       for (x=0;x<len;x++) {
+               PUT_CLID(msg[x]);
+       }
+       /* Send 50 more ms of marks */
+       for (x=0;x<50;x++)
+               PUT_CLID_MARKMS;
+       return bytes;
+}
 
 
-int callerid_generate(unsigned char *buf, char *number, char *name, int flags, int callwaiting)
+int callerid_generate(unsigned char *buf, char *number, char *name, int flags, int callwaiting, int codec)
 {
        int bytes=0;
        int x, sum;
 {
        int bytes=0;
        int x, sum;
+       int len;
        /* Initial carriers (real/imaginary) */
        float cr = 1.0;
        float ci = 0.0;
        float scont = 0.0;
        /* Initial carriers (real/imaginary) */
        float cr = 1.0;
        float ci = 0.0;
        float scont = 0.0;
-       char msg[256];
-       callerid_genmsg(msg, sizeof(msg), number, name, flags);
+       unsigned char msg[256];
+       len = callerid_genmsg(msg, sizeof(msg), number, name, flags);
        if (!callwaiting) {
                /* Wait a half a second */
                for (x=0;x<4000;x++)
        if (!callwaiting) {
                /* Wait a half a second */
                for (x=0;x<4000;x++)
@@ -416,15 +479,16 @@ int callerid_generate(unsigned char *buf, char *number, char *name, int flags, i
        /* Send 0x80 indicating MDMF format */
        PUT_CLID(0x80);
        /* Put length of whole message */
        /* Send 0x80 indicating MDMF format */
        PUT_CLID(0x80);
        /* Put length of whole message */
-       PUT_CLID(strlen(msg));
+       PUT_CLID(len);
        sum = 0x80 + strlen(msg);
        /* Put each character of message and update checksum */
        sum = 0x80 + strlen(msg);
        /* Put each character of message and update checksum */
-       for (x=0;x<strlen(msg); x++) {
+       for (x=0;x<len; x++) {
                PUT_CLID(msg[x]);
                sum += msg[x];
        }
        /* Send 2's compliment of sum */
        PUT_CLID(256 - (sum & 255));
                PUT_CLID(msg[x]);
                sum += msg[x];
        }
        /* Send 2's compliment of sum */
        PUT_CLID(256 - (sum & 255));
+
        /* Send 50 more ms of marks */
        for (x=0;x<50;x++)
                PUT_CLID_MARKMS;
        /* Send 50 more ms of marks */
        for (x=0;x<50;x++)
                PUT_CLID_MARKMS;
@@ -444,10 +508,10 @@ void ast_shrink_phone_number(char *n)
 int ast_isphonenumber(char *n)
 {
        int x;
 int ast_isphonenumber(char *n)
 {
        int x;
-       if (!n)
+       if (!n || !strlen(n))
                return 0;
        for (x=0;n[x];x++)
                return 0;
        for (x=0;n[x];x++)
-               if (!strchr("0123456789", n[x]))
+               if (!strchr("0123456789*#+", n[x]))
                        return 0;
        return 1;
 }
                        return 0;
        return 1;
 }
@@ -477,19 +541,22 @@ int ast_callerid_parse(char *instr, char **name, char **location)
                                instr[strlen(instr) - 1] = '\0';
                        /* And leading spaces */
                        while(**name && (**name < 33))
                                instr[strlen(instr) - 1] = '\0';
                        /* And leading spaces */
                        while(**name && (**name < 33))
-                               name++;
+                               (*name)++;
                        return 0;
                }
        } else {
                        return 0;
                }
        } else {
-               strncpy(tmp, instr, sizeof(tmp));
+               strncpy(tmp, instr, sizeof(tmp)-1);
                ast_shrink_phone_number(tmp);
                ast_shrink_phone_number(tmp);
-               if (!ast_isphonenumber(tmp)) {
+               if (ast_isphonenumber(tmp)) {
                        /* Assume it's just a location */
                        *name = NULL;
                        *location = instr;
                } else {
                        /* Assume it's just a location */
                        *name = NULL;
                        *location = instr;
                } else {
-                       /* Assume it's just a name */
+                       /* Assume it's just a name.  Make sure it's not quoted though */
                        *name = instr;
                        *name = instr;
+                       while(*(*name) && ((*(*name) < 33) || (*(*name) == '\"'))) (*name)++;
+                       ne = *name + strlen(*name) - 1;
+                       while((ne > *name) && ((*ne < 33) || (*ne == '\"'))) { *ne = '\0'; ne--; }
                        *location = NULL;
                }
                return 0;
                        *location = NULL;
                }
                return 0;
@@ -497,30 +564,30 @@ int ast_callerid_parse(char *instr, char **name, char **location)
        return -1;
 }
 
        return -1;
 }
 
-static int __ast_callerid_generate(unsigned char *buf, char *callerid, int callwaiting)
+static int __ast_callerid_generate(unsigned char *buf, char *callerid, int callwaiting, int codec)
 {
        char tmp[256];
        char *n, *l;
        if (!callerid)
 {
        char tmp[256];
        char *n, *l;
        if (!callerid)
-               return callerid_generate(buf, NULL, NULL, 0, callwaiting);
-       strncpy(tmp, callerid, sizeof(tmp));
+               return callerid_generate(buf, NULL, NULL, 0, callwaiting, codec);
+       strncpy(tmp, callerid, sizeof(tmp)-1);
        if (ast_callerid_parse(tmp, &n, &l)) {
                ast_log(LOG_WARNING, "Unable to parse '%s' into CallerID name & number\n", callerid);
        if (ast_callerid_parse(tmp, &n, &l)) {
                ast_log(LOG_WARNING, "Unable to parse '%s' into CallerID name & number\n", callerid);
-               return callerid_generate(buf, NULL, NULL, 0, callwaiting);
+               return callerid_generate(buf, NULL, NULL, 0, callwaiting, codec);
        }
        if (l)
                ast_shrink_phone_number(l);
        if (!ast_isphonenumber(l))
        }
        if (l)
                ast_shrink_phone_number(l);
        if (!ast_isphonenumber(l))
-               return callerid_generate(buf, NULL, n, 0, callwaiting);
-       return callerid_generate(buf, l, n, 0, callwaiting);
+               return callerid_generate(buf, NULL, n, 0, callwaiting, codec);
+       return callerid_generate(buf, l, n, 0, callwaiting, codec);
 }
 
 }
 
-int ast_callerid_generate(unsigned char *buf, char *callerid)
+int ast_callerid_generate(unsigned char *buf, char *callerid, int codec)
 {
 {
-       return __ast_callerid_generate(buf, callerid, 0);
+       return __ast_callerid_generate(buf, callerid, 0, codec);
 }
 
 }
 
-int ast_callerid_callwaiting_generate(unsigned char *buf, char *callerid)
+int ast_callerid_callwaiting_generate(unsigned char *buf, char *callerid, int codec)
 {
 {
-       return __ast_callerid_generate(buf, callerid, 1);
+       return __ast_callerid_generate(buf, callerid, 1, codec);
 }
 }