Ignore:
Timestamp:
Jan 14, 2008 4:18:37 PM (16 years ago)
Author:
bennylp
Message:

Ticket #449: New conference mixing algorithm to replace multiplication with simple addition

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/conference.c

    r1637 r1691  
    7272 * in the port does not cause misaligned signal (which causes noise). 
    7373 */ 
    74 #if 1 
    75 #   define ATTACK_A         10 
    76 #   define ATTACK_B         2 
    77 #   define DECAY_A          10 
    78 #   define DECAY_B          2 
    79 #else 
    80     /* To simulate old behavior */ 
    81 #   define ATTACK_A         0 
    82 #   define ATTACK_B         1 
    83 #   define DECAY_A          0 
    84 #   define DECAY_B          1 
    85 #endif 
    86  
     74#define ATTACK_A    (conf->clock_rate / conf->samples_per_frame) 
     75#define ATTACK_B    1 
     76#define DECAY_A     0 
     77#define DECAY_B     1 
     78 
     79#define SIMPLE_AGC(last, target) \ 
     80    if (target >= last) \ 
     81        target = (ATTACK_A*(last+1)+ATTACK_B*target)/(ATTACK_A+ATTACK_B); \ 
     82    else \ 
     83        target = (DECAY_A*last+DECAY_B*target)/(DECAY_A+DECAY_B) 
     84 
     85#define MAX_LEVEL   (32767) 
     86#define MIN_LEVEL   (-32768) 
     87 
     88#define IS_OVERFLOW(s) ((s > MAX_LEVEL) || (s < MIN_LEVEL)) 
    8789 
    8890 
     
    114116    unsigned             clock_rate;    /**< Port's clock rate.             */ 
    115117    unsigned             samples_per_frame; /**< Port's samples per frame.  */ 
    116  
    117     /* Last level calculated from this port */ 
    118     pj_int32_t           last_level; 
    119118 
    120119    /* Calculated signal levels: */ 
     
    149148    unsigned             rx_buf_count;  /**< # of samples in the buf.       */ 
    150149 
    151     /* Mix buf is a temporary buffer used to calculate the average signal 
    152      * received by this port from all other ports. Samples from all ports 
    153      * that are transmitting to this port will be accumulated here, then 
    154      * they will be divided by the source level before the samples are put 
    155      * to the TX buffer of this port. 
     150    /* Mix buf is a temporary buffer used to mix all signal received 
     151     * by this port from all other ports. The mixed signal will be  
     152     * automatically adjusted to the appropriate level whenever 
     153     * there is possibility of clipping. 
    156154     * 
    157155     * This buffer contains samples at bridge's clock rate. 
    158156     * The size of this buffer is equal to samples per frame of the bridge. 
    159      * 
    160      * Note that the samples here are unsigned 32bit. 
    161      */ 
    162     unsigned             src_level;     /**< Sum of input levels            */ 
    163     unsigned             src_cnt;       /**< Number of sources.             */ 
    164     pj_uint32_t         *mix_buf;       /**< Total sum of signal.           */ 
     157     */ 
     158 
     159    int                  mix_adj;       /**< Adjustment level for mix_buf.  */ 
     160    int                  last_mix_adj;  /**< Last adjustment level.         */ 
     161    pj_int32_t          *mix_buf;       /**< Total sum of signal.           */ 
    165162 
    166163    /* Tx buffer is a temporary buffer to be used when there's mismatch  
     
    209206    pj_mutex_t           *mutex;        /**< Conference mutex.              */ 
    210207    struct conf_port    **ports;        /**< Array of ports.                */ 
    211     pj_uint16_t          *uns_buf;      /**< Buf for unsigned conversion    */ 
    212208    unsigned              clock_rate;   /**< Sampling rate.                 */ 
    213209    unsigned              channel_count;/**< Number of channels (1=mono).   */ 
     
    353349 
    354350    /* Create mix buffer. */ 
    355     conf_port->mix_buf = (pj_uint32_t*) 
     351    conf_port->mix_buf = (pj_int32_t*) 
    356352                         pj_pool_zalloc(pool, conf->samples_per_frame * 
    357353                                              sizeof(conf_port->mix_buf[0])); 
    358354    PJ_ASSERT_RETURN(conf_port->mix_buf, PJ_ENOMEM); 
     355    conf_port->last_mix_adj = NORMAL_LEVEL; 
    359356 
    360357 
     
    527524    if (status != PJ_SUCCESS) 
    528525        return status; 
    529  
    530     /* Create temporary buffer. */ 
    531     conf->uns_buf = (pj_uint16_t*) 
    532                     pj_pool_zalloc(pool, samples_per_frame * 
    533                                          sizeof(conf->uns_buf[0])); 
    534526 
    535527    /* Create mutex. */ 
     
    12321224 
    12331225 
    1234 /* Convert signed 16bit pcm sample to unsigned 16bit sample */ 
    1235 static pj_uint16_t pcm2unsigned(pj_int32_t pcm) 
    1236 { 
    1237     return (pj_uint16_t)(pcm + 32768); 
    1238 } 
    1239  
    1240 /* Convert unsigned 16bit sample to signed 16bit pcm sample */ 
    1241 static pj_int16_t unsigned2pcm(pj_uint32_t uns) 
    1242 { 
    1243     return (pj_int16_t)(uns - 32768); 
    1244 } 
    1245  
    1246  
    12471226/* 
    12481227 * Read from port. 
     
    13781357    unsigned j, ts; 
    13791358    pj_status_t status; 
     1359    pj_int32_t adj_level; 
     1360    pj_int32_t tx_level; 
    13801361 
    13811362    *frm_type = PJMEDIA_FRAME_TYPE_AUDIO; 
     
    14031384        return PJ_SUCCESS; 
    14041385 
    1405     } else if (cport->src_level==0) { 
    1406  
    1407         pjmedia_frame frame; 
    1408  
    1409         /* If silence is transmitted to this port, transmit silence 
    1410          * PCM frame (otherwise if we transmit NULL frame, nothing will 
    1411          * be written to WAV port). This would work with stream too 
    1412          * since stream has it's own silence detector. 
    1413          */ 
    1414         pjmedia_zero_samples((pj_int16_t*)cport->mix_buf,  
    1415                              cport->samples_per_frame); 
    1416  
    1417         /* Adjust the timestamp */ 
    1418         frame.timestamp.u64 = timestamp->u64 * cport->clock_rate / 
    1419                                 conf->clock_rate; 
    1420         frame.type = PJMEDIA_FRAME_TYPE_NONE; 
    1421         frame.buf = (void*)cport->mix_buf; 
    1422         frame.size = (cport->samples_per_frame << 1); 
    1423  
    1424         if (cport->port && cport->port->put_frame) { 
    1425             pjmedia_port_put_frame(cport->port, &frame); 
    1426         } 
    1427  
    1428         cport->tx_level = 0; 
    1429         *frm_type = PJMEDIA_FRAME_TYPE_NONE; 
    1430         return PJ_SUCCESS; 
    1431  
    1432  
    14331386    } else if (cport->tx_setting != PJMEDIA_PORT_ENABLE) { 
    14341387        cport->tx_level = 0; 
     
    14371390    } 
    14381391 
    1439     buf = (pj_int16_t*)cport->mix_buf; 
    1440  
    1441     /* This is the convention set in get_frame(). For optimization purpose, 
    1442      * if we only have one transmitter transmitting to this port, then 
    1443      * the transmitter will directly copy the original 16bit frame to 
    1444      * mix_buf. 
    1445      */ 
    1446     if (cport->transmitter_cnt==1 && cport->src_cnt == 1) { 
    1447  
    1448         /* But still see if we need to adjust the level */ 
    1449         if (cport->tx_adj_level != NORMAL_LEVEL) { 
    1450             pj_int16_t *input = buf; 
    1451             pj_int32_t adj = cport->tx_adj_level; 
    1452  
    1453             for (j=0; j<conf->samples_per_frame; ++j) { 
    1454                 pj_int32_t itemp; 
    1455  
    1456                 /* For the level adjustment, we need to store the sample to 
    1457                  * a temporary 32bit integer value to avoid overflowing the 
    1458                  * 16bit sample storage. 
    1459                  */ 
    1460                 itemp = input[j]; 
    1461                 /*itemp = itemp * adj / NORMAL_LEVEL; */ 
    1462                 itemp = (itemp * adj) >> 7; 
    1463  
    1464                 /* Clip the signal if it's too loud */ 
    1465                 if (itemp > 32767) itemp = 32767; 
    1466                 else if (itemp < -32768) itemp = -32768; 
    1467  
    1468                 input[j] = (pj_int16_t) itemp; 
    1469             } 
    1470         } 
    1471  
    1472     }  
     1392    buf = (pj_int16_t*) cport->mix_buf; 
     1393 
    14731394    /* If there are sources in the mix buffer, convert the mixed samples 
    1474      * to the mixed samples itself. This is possible because mixed sample 
    1475      * is 32bit. 
     1395     * from 32bit to 16bit in the mixed samples itself. This is possible  
     1396     * because mixed sample is 32bit. 
    14761397     * 
    14771398     * In addition to this process, if we need to change the level of 
    14781399     * TX signal, we adjust is here too. 
    14791400     */ 
    1480     else if (cport->tx_adj_level != NORMAL_LEVEL && cport->src_level) { 
    1481  
    1482         pj_int32_t adj_level = cport->tx_adj_level; 
    1483  
    1484         /* We need to adjust signal level. */ 
    1485         for (j=0; j<conf->samples_per_frame; ++j) { 
    1486             pj_int32_t itemp; 
    1487  
    1488             /* Calculate average level, and convert the sample to 
    1489              * 16bit signed integer. 
    1490              */ 
    1491             itemp = unsigned2pcm(cport->mix_buf[j] / cport->src_level); 
     1401 
     1402    /* Calculate signal level and adjust the signal when needed.  
     1403     * Two adjustments performed at once:  
     1404     * 1. user setting adjustment (tx_adj_level).  
     1405     * 2. automatic adjustment of overflowed mixed buffer (mix_adj). 
     1406     */ 
     1407 
     1408    /* Apply simple AGC to the mix_adj, the automatic adjust, to avoid  
     1409     * dramatic change in the level thus causing noise because the signal  
     1410     * is now not aligned with the signal from the previous frame. 
     1411     */ 
     1412    SIMPLE_AGC(cport->last_mix_adj, cport->mix_adj); 
     1413    cport->last_mix_adj = cport->mix_adj; 
     1414 
     1415    adj_level = cport->tx_adj_level * cport->mix_adj / NORMAL_LEVEL; 
     1416    tx_level = 0; 
     1417 
     1418    for (j=0; j<conf->samples_per_frame; ++j) { 
     1419        if (adj_level != NORMAL_LEVEL) { 
     1420            pj_int32_t itemp = cport->mix_buf[j]; 
    14921421 
    14931422            /* Adjust the level */ 
     
    14961425 
    14971426            /* Clip the signal if it's too loud */ 
    1498             if (itemp > 32767) itemp = 32767; 
    1499             else if (itemp < -32768) itemp = -32768; 
     1427            if (itemp > MAX_LEVEL) itemp = MAX_LEVEL; 
     1428            else if (itemp < MIN_LEVEL) itemp = MIN_LEVEL; 
    15001429 
    15011430            /* Put back in the buffer. */ 
    15021431            buf[j] = (pj_int16_t) itemp; 
     1432        } else { 
     1433            buf[j] = (pj_int16_t) cport->mix_buf[j]; 
    15031434        } 
    15041435 
    1505     } else if (cport->src_level) { 
    1506         /* No need to adjust signal level. */ 
    1507         for (j=0; j<conf->samples_per_frame; ++j) { 
    1508             buf[j] = unsigned2pcm(cport->mix_buf[j] / cport->src_level); 
    1509         } 
    1510     } else { 
    1511         // Not necessarry. Buffer has been zeroed before. 
    1512         // pjmedia_zero_samples(buf, conf->samples_per_frame); 
    1513         //pj_assert(buf[0] == 0); 
    1514  
    1515         // This shouldn't happen. Function should've already bailed out when 
    1516         // cport->src_level == 0. 
    1517         pj_assert(0); 
    1518     } 
    1519  
    1520     /* Calculate TX level if we need to do so.  
    1521      * This actually is not the most correct place to calculate TX signal  
    1522      * level of the port; it should calculate the level of the actual 
    1523      * frame just before put_frame() is called. 
    1524      * But doing so would make the code more complicated than it is 
    1525      * necessary, since the purpose of level calculation mostly is just 
    1526      * for VU meter display. By doing it here, it should give the acceptable 
    1527      * indication of the signal level of the port. 
    1528      */ 
    1529     if (cport->src_cnt) { 
    1530         cport->tx_level = cport->src_level / cport->src_cnt; 
    1531     } else { 
    1532         cport->tx_level = 0; 
    1533     } 
     1436        tx_level += (buf[j]>0? buf[j] : -buf[j]); 
     1437    } 
     1438 
     1439    tx_level /= conf->samples_per_frame; 
     1440 
     1441    /* Convert level to 8bit complement ulaw */ 
     1442    tx_level = pjmedia_linear2ulaw(tx_level) ^ 0xff; 
     1443 
     1444    cport->tx_level = tx_level; 
    15341445 
    15351446    /* If port has the same clock_rate and samples_per_frame settings as 
     
    15431454 
    15441455            frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
    1545             frame.buf = (pj_int16_t*)cport->mix_buf; 
     1456            frame.buf = buf; 
    15461457            frame.size = conf->samples_per_frame * BYTES_PER_SAMPLE; 
    15471458            /* No need to adjust timestamp, port has the same 
     
    16401551    pjmedia_frame_type speaker_frame_type = PJMEDIA_FRAME_TYPE_NONE; 
    16411552    unsigned ci, cj, i, j; 
     1553    pj_int16_t *p_in; 
    16421554     
    16431555    TRACE_((THIS_FILE, "- clock -")); 
     
    16621574        ++ci; 
    16631575 
    1664         /* Reset sources */ 
    1665         conf_port->src_level = 0; 
    1666         conf_port->src_cnt = 0; 
     1576        /* Reset buffer & auto adjustment level for mixed signal */ 
     1577        conf_port->mix_adj = NORMAL_LEVEL; 
     1578        if (conf_port->transmitter_cnt) { 
     1579            pj_bzero(conf_port->mix_buf, 
     1580                     conf->samples_per_frame*sizeof(conf_port->mix_buf[0])); 
     1581        } 
    16671582    } 
    16681583 
     
    16721587    for (i=0, ci=0; i<conf->max_ports && ci<conf->port_cnt; ++i) { 
    16731588        struct conf_port *conf_port = conf->ports[i]; 
    1674         pj_int32_t level; 
     1589        pj_int32_t level = 0; 
    16751590 
    16761591        /* Skip empty port. */ 
     
    17471662        } 
    17481663 
    1749         /* If we need to adjust the RX level from this port, adjust the level 
     1664        p_in = (pj_int16_t*) frame->buf; 
     1665 
     1666        /* Adjust the RX level from this port 
    17501667         * and calculate the average level at the same time. 
    1751          * Otherwise just calculate the averate level. 
    17521668         */ 
    1753         if (conf_port->rx_adj_level != NORMAL_LEVEL) { 
    1754             pj_int16_t *input = (pj_int16_t*) frame->buf; 
    1755             pj_int32_t adj = conf_port->rx_adj_level; 
    1756  
    1757             level = 0; 
    1758             for (j=0; j<conf->samples_per_frame; ++j) { 
    1759                 pj_int32_t itemp; 
    1760  
     1669        for (j=0; j<conf->samples_per_frame; ++j) { 
     1670            if (conf_port->rx_adj_level != NORMAL_LEVEL) { 
    17611671                /* For the level adjustment, we need to store the sample to 
    17621672                 * a temporary 32bit integer value to avoid overflowing the 
    17631673                 * 16bit sample storage. 
    17641674                 */ 
    1765                 itemp = input[j]; 
     1675                pj_int32_t itemp; 
     1676 
     1677                itemp = p_in[j]; 
    17661678                /*itemp = itemp * adj / NORMAL_LEVEL;*/ 
    1767                 itemp = (itemp * adj) >> 7; 
     1679                itemp = (itemp * conf_port->rx_adj_level) >> 7; 
    17681680 
    17691681                /* Clip the signal if it's too loud */ 
    1770                 if (itemp > 32767) itemp = 32767; 
    1771                 else if (itemp < -32768) itemp = -32768; 
    1772  
    1773                 input[j] = (pj_int16_t) itemp; 
    1774  
    1775                 if (itemp >=0 ) level += itemp; 
    1776                 else level -= itemp; 
     1682                if (itemp > MAX_LEVEL) itemp = MAX_LEVEL; 
     1683                else if (itemp < MIN_LEVEL) itemp = MIN_LEVEL; 
     1684 
     1685                p_in[j] = (pj_int16_t) itemp; 
    17771686            } 
    17781687 
    1779             level /= conf->samples_per_frame; 
    1780  
    1781         } else { 
    1782             level = pjmedia_calc_avg_signal((pj_int16_t*) frame->buf,  
    1783                                             conf->samples_per_frame); 
    1784         } 
    1785  
    1786         /* Apply simple AGC to the level, to avoid dramatic change in the 
    1787          * level thus causing noise because the signal now is not aligned 
    1788          * with the signal from the previous frame. 
    1789          */ 
    1790         if (level >= conf_port->last_level) { 
    1791             level = (conf_port->last_level * ATTACK_A + level * ATTACK_B) /  
    1792                     (ATTACK_A + ATTACK_B); 
    1793         } else { 
    1794             level = (conf_port->last_level * DECAY_A + level * DECAY_B) /  
    1795                     (DECAY_A + DECAY_B); 
    1796         } 
    1797         conf_port->last_level = level; 
    1798  
     1688            level += (p_in[j]>0? p_in[j] : -p_in[j]); 
     1689        } 
     1690 
     1691        level /= conf->samples_per_frame; 
    17991692 
    18001693        /* Convert level to 8bit complement ulaw */ 
     
    18071700        if (level == 0) 
    18081701            continue; 
    1809  
    1810         /* Convert the buffer to unsigned 16bit value */ 
    1811         for (j=0; j<conf->samples_per_frame; ++j) 
    1812             conf->uns_buf[j] = pcm2unsigned(((pj_int16_t*)frame->buf)[j]); 
    18131702 
    18141703        /* Add the signal to all listeners. */ 
     
    18161705        { 
    18171706            struct conf_port *listener; 
    1818             pj_uint32_t *mix_buf; 
     1707            pj_int32_t *mix_buf; 
    18191708            unsigned k; 
    18201709 
     
    18251714                continue; 
    18261715 
    1827             /* Mix the buffer. If this is the first source for target port, 
    1828              * zero the mix buffer of target port first. 
     1716            mix_buf = listener->mix_buf; 
     1717 
     1718            /* Mixing signals, 
     1719             * and calculate appropriate level adjustment if there is 
     1720             * any overflowed level in the mixed signal. 
    18291721             */ 
    1830             mix_buf = listener->mix_buf; 
    1831             if (listener->src_level == 0) { 
    1832                 pj_bzero( mix_buf, conf->samples_per_frame*sizeof(mix_buf[0])); 
    1833             } 
    1834  
    1835             /* A little bit of optimization: 
    1836              *  When "conf_port" is the only transmitter to "listener", 
    1837              *  just add copy the frame directly from the original 
    1838              *  16bit frame (avoiding unsigned2pcm() conversion). 
    1839              *  But write_port() needs to be aware of this trick! 
    1840              */ 
    1841             if (listener->transmitter_cnt == 1) { 
    1842                 pjmedia_copy_samples((pj_int16_t*)mix_buf,  
    1843                                      (const pj_int16_t*)frame->buf,  
    1844                                      conf->samples_per_frame); 
    1845                 listener->src_level = level; 
    1846             } else { 
    1847                 for (k=0; k<conf->samples_per_frame; ++k) 
    1848                     mix_buf[k] += (conf->uns_buf[k] * level); 
    1849  
    1850                 listener->src_level += level; 
    1851             } 
    1852             listener->src_cnt++; 
    1853         } 
    1854     } 
     1722            for (k=0; k<conf->samples_per_frame; ++k) { 
     1723                mix_buf[k] += p_in[k]; 
     1724                /* Check if normalization adjustment needed. */ 
     1725                if (IS_OVERFLOW(mix_buf[k])) { 
     1726                    /* NORMAL_LEVEL * MAX_LEVEL / mix_buf[k]; */ 
     1727                    int tmp_adj = (MAX_LEVEL<<7) / mix_buf[k]; 
     1728                    if (tmp_adj<0) tmp_adj = -tmp_adj; 
     1729 
     1730                    if (tmp_adj<listener->mix_adj) 
     1731                        listener->mix_adj = tmp_adj; 
     1732 
     1733                } /* if any overflow in the mixed signals */ 
     1734            } /* loop mixing signals */ 
     1735        } /* loop the listeners of conf port */ 
     1736    } /* loop of all conf ports */ 
    18551737 
    18561738    /* Time for all ports to transmit whetever they have in their 
     
    18951777 
    18961778    /* Return sound playback frame. */ 
    1897     if (conf->ports[0]->src_level) { 
     1779    if (conf->ports[0]->tx_level) { 
    18981780        TRACE_((THIS_FILE, "write to audio, count=%d",  
    18991781                           conf->samples_per_frame)); 
    1900  
    19011782        pjmedia_copy_samples( (pj_int16_t*)frame->buf,  
    19021783                              (const pj_int16_t*)conf->ports[0]->mix_buf,  
    19031784                              conf->samples_per_frame); 
    19041785    } else { 
    1905         pjmedia_zero_samples((pj_int16_t*)frame->buf, conf->samples_per_frame);  
     1786        /* Force frame type NONE */ 
     1787        speaker_frame_type = PJMEDIA_FRAME_TYPE_NONE; 
    19061788    } 
    19071789 
Note: See TracChangeset for help on using the changeset viewer.