Changeset 2437


Ignore:
Timestamp:
Feb 1, 2009 2:10:49 PM (15 years ago)
Author:
nanang
Message:
  • Fixed pjmedia_frame_ext helper functions, it didn't involve sizeof(bitlen) in calculating subframe address.
  • Fixed audio switch board to handle such case that transmitter of port 0 has greater ptime, so it could save the remaining data in the TX buffer.
  • Fixed audio swtich board in handling FRAME_TYPE_NONE.
  • Updated audio switch board to handle keep alive mechanism.
Location:
pjproject/branches/projects/aps-direct/pjmedia
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h

    r2436 r2437  
    265265 * are byte-aligned although its payload may not be byte-aligned. 
    266266 */ 
     267 
     268#pragma pack(1) 
    267269typedef struct pjmedia_frame_ext { 
    268270    pjmedia_frame   base;           /**< Base frame info */ 
     
    274276     */ 
    275277} pjmedia_frame_ext; 
     278#pragma pack() 
    276279 
    277280/** 
     
    279282 * pjmedia_frame_ext structure. 
    280283 */ 
     284#pragma pack(1) 
    281285typedef struct pjmedia_frame_ext_subframe { 
    282286    pj_uint16_t     bitlen;         /**< Number of bits in the data */ 
     
    284288} pjmedia_frame_ext_subframe; 
    285289 
     290#pragma pack() 
     291 
    286292 
    287293/** 
     
    305311        pjmedia_frame_ext_subframe *fsub; 
    306312        fsub = (pjmedia_frame_ext_subframe*) p; 
    307         p += fsub->bitlen / 8; 
     313        p += sizeof(fsub->bitlen) + fsub->bitlen / 8; 
    308314        if (fsub->bitlen % 8) 
    309315            ++p; 
     
    312318    tmp = bitlen / 8; 
    313319    if (bitlen % 8) ++tmp; 
     320 
    314321    pj_memcpy(p, &bitlen, sizeof(bitlen)); 
    315     pj_memcpy(p + sizeof(bitlen), src, tmp); 
     322    if (tmp) 
     323        pj_memcpy(p + sizeof(bitlen), src, tmp); 
     324 
    316325    frm->subframe_cnt++; 
    317326    frm->samples_cnt = frm->samples_cnt + samples_cnt; 
     
    339348        for (i = 0; i < n; ++i) {        
    340349            sf = (pjmedia_frame_ext_subframe*) p; 
    341             p += sf->bitlen / 8; 
     350            p += sizeof(sf->bitlen) + sf->bitlen / 8; 
    342351            if (sf->bitlen % 8) 
    343352                ++p; 
  • pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c

    r2434 r2437  
    1919 */ 
    2020#include <pjmedia/conference.h> 
     21#include <pjmedia/alaw_ulaw.h> 
    2122#include <pjmedia/errno.h> 
    2223#include <pjmedia/port.h> 
     24#include <pjmedia/silencedet.h> 
    2325#include <pjmedia/sound_port.h> 
    2426#include <pjmedia/stream.h> 
     
    4244#endif 
    4345 
    44  
    45 /* REC_FILE macro enables recording of the samples written to the sound 
    46  * device. The file contains RAW PCM data with no header, and has the 
    47  * same settings (clock rate etc) as the conference bridge. 
    48  * This should only be enabled when debugging audio quality *only*. 
    49  */ 
    50 //#define REC_FILE    "confrec.pcm" 
    51 #ifdef REC_FILE 
    52 static FILE *fhnd_rec; 
    53 #endif 
    54  
    55  
    5646#define THIS_FILE           "conf_switch.c" 
    5747 
     
    10393    pj_timestamp         ts_clock; 
    10494    pj_timestamp         ts_rx; 
     95    pj_timestamp         ts_tx; 
    10596 
    10697    /* Tx buffer is a temporary buffer to be used when there's mismatch  
     
    110101     */ 
    111102    pj_uint8_t           tx_buf[BUFFER_SIZE]; /**< Tx buffer.               */ 
    112  
    113     /* When the port is not receiving signal from any other ports (e.g. when 
    114      * no other ports is transmitting to this port), the bridge periodically 
    115      * transmit NULL frame to the port to keep the port "alive" (for example, 
    116      * a stream port needs this heart-beat to periodically transmit silence 
    117      * frame to keep NAT binding alive). 
    118      * 
    119      * This NULL frame should be sent to the port at the port's ptime rate. 
    120      * So if the port's ptime is greater than the bridge's ptime, the bridge 
    121      * needs to delay the NULL frame until it's the right time to do so. 
    122      * 
    123      * This variable keeps track of how many pending NULL samples are being 
    124      * "held" for this port. Once this value reaches samples_per_frame 
    125      * value of the port, a NULL frame is sent. The samples value on this 
    126      * variable is clocked at the port's clock rate. 
    127      */ 
    128     unsigned             tx_heart_beat; 
    129103}; 
    130104 
     
    477451    PJ_ASSERT_RETURN(conf->bits_per_sample == strm_port->info.bits_per_sample, 
    478452                     PJMEDIA_ENCBITS); 
     453 
     454    /* Port's samples per frame should be equal to or multiplication of  
     455     * conference's samples per frame. 
     456     */ 
    479457    PJ_ASSERT_RETURN((conf->samples_per_frame % 
    480458                     strm_port->info.samples_per_frame==0) || 
     
    981959} 
    982960 
    983 /* Deliver frm_src to a conference port (via frm_dst), eventually call  
    984  * port's put_frame() when samples count in the frm_dst are equal to  
    985  * port's samples_per_frame. 
    986  */ 
    987 static pj_status_t deliver_frame(struct conf_port *cport_dst, 
    988                                  pjmedia_frame *frm_dst, 
    989                                  const pjmedia_frame *frm_src) 
    990 { 
     961/* Deliver frm_src to a listener port, eventually call  port's put_frame()  
     962 * when samples count in the frm_dst are equal to port's samples_per_frame. 
     963 */ 
     964static pj_status_t write_frame(struct conf_port *cport_dst, 
     965                               const pjmedia_frame *frm_src) 
     966{ 
     967    pjmedia_frame *frm_dst = (pjmedia_frame*)cport_dst->tx_buf; 
     968     
    991969    PJ_TODO(MAKE_SURE_DEST_FRAME_HAS_ENOUGH_SPACE); 
    992970 
     971    frm_dst->type = frm_src->type; 
     972    frm_dst->timestamp = cport_dst->ts_tx; 
     973 
    993974    if (frm_src->type == PJMEDIA_FRAME_TYPE_EXTENDED) { 
     975 
    994976        pjmedia_frame_ext *f_src = (pjmedia_frame_ext*)frm_src; 
    995977        pjmedia_frame_ext *f_dst = (pjmedia_frame_ext*)frm_dst; 
    996978        unsigned i; 
    997979 
    998         /* Copy frame to listener's TX buffer. */ 
    999980        for (i = 0; i < f_src->subframe_cnt; ++i) { 
    1000981            pjmedia_frame_ext_subframe *sf; 
    1001982             
     983            /* Copy frame to listener's TX buffer. */ 
    1002984            sf = pjmedia_frame_ext_get_subframe(f_src, i); 
    1003985            pjmedia_frame_ext_append_subframe(f_dst, sf->data, sf->bitlen,  
     
    1011993            if (f_dst->samples_cnt == cport_dst->samples_per_frame) 
    1012994            { 
    1013                 f_dst->base.type = PJMEDIA_FRAME_TYPE_EXTENDED; 
    1014995                if (cport_dst->port) { 
    1015                     pjmedia_port_put_frame(cport_dst->port, (pjmedia_frame*)f_dst); 
     996                    pjmedia_port_put_frame(cport_dst->port,  
     997                                           (pjmedia_frame*)f_dst); 
     998 
     999                    /* Update TX timestamp. */ 
     1000                    pj_add_timestamp32(&cport_dst->ts_tx,  
     1001                                       cport_dst->samples_per_frame); 
    10161002 
    10171003                    /* Reset TX buffer. */ 
     
    10221008        } 
    10231009 
    1024     } else { 
    1025  
    1026         pjmedia_frame *f_dst = (pjmedia_frame*)frm_dst; 
     1010    } else if (frm_src->type == PJMEDIA_FRAME_TYPE_AUDIO) { 
     1011 
    10271012        pj_int16_t *f_start, *f_end; 
    10281013 
     
    10321017            unsigned nsamples_to_copy, nsamples_req; 
    10331018 
     1019            /* Copy frame to listener's TX buffer. */ 
    10341020            nsamples_to_copy = f_end - f_start; 
    1035             nsamples_req = cport_dst->samples_per_frame - (f_dst->size >> 1); 
     1021            nsamples_req = cport_dst->samples_per_frame - (frm_dst->size>>1); 
    10361022            if (nsamples_to_copy > nsamples_req) 
    10371023                nsamples_to_copy = nsamples_req; 
    1038             pjmedia_copy_samples((pj_int16_t*)f_dst->buf + (f_dst->size >> 1),  
     1024            pjmedia_copy_samples((pj_int16_t*)frm_dst->buf + (frm_dst->size>>1), 
    10391025                                 f_start,  
    10401026                                 nsamples_to_copy); 
    1041             f_dst->size += nsamples_to_copy << 1; 
     1027            frm_dst->size += nsamples_to_copy << 1; 
    10421028            f_start += nsamples_to_copy; 
    10431029 
     
    10461032             * samples per frame. 
    10471033             */ 
    1048             if ((f_dst->size >> 1) == cport_dst->samples_per_frame) 
     1034            if ((frm_dst->size >> 1) == cport_dst->samples_per_frame) 
    10491035            { 
    1050                 f_dst->type = PJMEDIA_FRAME_TYPE_AUDIO; 
    10511036                if (cport_dst->port) { 
    1052                     pjmedia_port_put_frame(cport_dst->port, f_dst); 
     1037                    pjmedia_port_put_frame(cport_dst->port, frm_dst); 
     1038 
     1039                    /* Update TX timestamp. */ 
     1040                    pj_add_timestamp32(&cport_dst->ts_tx,  
     1041                                       cport_dst->samples_per_frame); 
    10531042                  
    10541043                    /* Reset TX buffer. */ 
    1055                     f_dst->size = 0; 
     1044                    frm_dst->size = 0; 
    10561045                } 
    10571046            } 
    10581047        } 
    10591048 
     1049    } else if (frm_src->type == PJMEDIA_FRAME_TYPE_NONE) { 
     1050 
     1051        /* Check port format. */ 
     1052        if (cport_dst->port && (cport_dst->port->info.format.u32==0 || 
     1053            cport_dst->port->info.format.u32 == PJMEDIA_FOURCC_L16)) 
     1054        { 
     1055            /* When there is already some samples in listener's TX buffer,  
     1056             * pad the buffer with "zero samples". 
     1057             */ 
     1058            if (frm_dst->size != 0) { 
     1059                pjmedia_zero_samples((pj_int16_t*)frm_dst->buf, 
     1060                                     cport_dst->samples_per_frame -  
     1061                                     (frm_dst->size>>1)); 
     1062 
     1063                frm_dst->type = PJMEDIA_FRAME_TYPE_AUDIO; 
     1064                frm_dst->size = cport_dst->samples_per_frame << 1; 
     1065                if (cport_dst->port) 
     1066                    pjmedia_port_put_frame(cport_dst->port, frm_dst); 
     1067 
     1068                /* Update TX timestamp. */ 
     1069                pj_add_timestamp32(&cport_dst->ts_tx,  
     1070                                   cport_dst->samples_per_frame); 
     1071 
     1072                /* Reset TX buffer. */ 
     1073                frm_dst->size = 0; 
     1074            } 
     1075        } else { 
     1076            pjmedia_frame_ext *f_dst = (pjmedia_frame_ext*)frm_dst; 
     1077 
     1078            if (f_dst->samples_cnt != 0) { 
     1079                frm_dst->type = PJMEDIA_FRAME_TYPE_EXTENDED; 
     1080                pjmedia_frame_ext_append_subframe(f_dst, NULL, 0, (pj_uint16_t) 
     1081                                                  (cport_dst->samples_per_frame- 
     1082                                                  f_dst->samples_cnt)); 
     1083                if (cport_dst->port) 
     1084                    pjmedia_port_put_frame(cport_dst->port, frm_dst); 
     1085 
     1086                /* Update TX timestamp. */ 
     1087                pj_add_timestamp32(&cport_dst->ts_tx,  
     1088                                   cport_dst->samples_per_frame); 
     1089 
     1090                /* Reset TX buffer. */ 
     1091                f_dst->subframe_cnt = 0; 
     1092                f_dst->samples_cnt = 0; 
     1093            } 
     1094        } 
     1095 
     1096        /* Synchronize clock. */ 
     1097        while (pj_cmp_timestamp(&cport_dst->ts_clock,  
     1098                                &cport_dst->ts_tx) >= 0) 
     1099        { 
     1100            if (cport_dst->port) { 
     1101                frm_dst->type = PJMEDIA_FRAME_TYPE_NONE; 
     1102                frm_dst->timestamp = cport_dst->ts_tx; 
     1103                pjmedia_port_put_frame(cport_dst->port, frm_dst); 
     1104            } 
     1105            pj_add_timestamp32(&cport_dst->ts_tx, cport_dst->samples_per_frame); 
     1106        } 
    10601107    } 
    10611108 
     
    10721119    unsigned ci, i; 
    10731120     
    1074     PJ_TODO(ADJUST_AND_CALC_RX_TX_LEVEL_FOR_PCM_FRAMES); 
    1075  
    1076     TRACE_((THIS_FILE, "- clock -")); 
     1121    PJ_TODO(ADJUST_RX_TX_LEVEL_FOR_PCM_FRAMES); 
    10771122 
    10781123    /* Must lock mutex */ 
     
    10941139        ++ci; 
    10951140 
    1096         /* Skip if we're not allowed to receive from this port. */ 
    1097         if (cport->rx_setting == PJMEDIA_PORT_DISABLE) { 
     1141        /* Update clock of the port. */ 
     1142        pj_add_timestamp32(&cport->ts_clock, conf->samples_per_frame); 
     1143 
     1144        /* Skip if we're not allowed to receive from this port or  
     1145         * the port doesn't have listeners. 
     1146         */ 
     1147        if (cport->rx_setting == PJMEDIA_PORT_DISABLE ||  
     1148            cport->listener_cnt == 0) 
     1149        { 
    10981150            cport->rx_level = 0; 
    10991151            continue; 
    11001152        } 
    11011153 
    1102         /* Also skip if this port doesn't have listeners. */ 
    1103         if (cport->listener_cnt == 0) { 
    1104             cport->rx_level = 0; 
    1105             continue; 
    1106         } 
    1107  
    1108         pj_add_timestamp32(&cport->ts_clock, conf->samples_per_frame); 
    1109  
    1110         /* This loop will make sure the ptime between port & conf port  
    1111          * are synchronized. 
     1154        /* Get frame from each port, put it to the listener TX buffer, 
     1155         * and eventually call put_frame() of the listener. This loop  
     1156         * will also make sure the ptime between conf & port synchronized. 
    11121157         */ 
    11131158        while (pj_cmp_timestamp(&cport->ts_clock, &cport->ts_rx) > 0) { 
    1114             pjmedia_frame *f = (pjmedia_frame*) conf->buf; 
     1159            pjmedia_frame *f = (pjmedia_frame*)conf->buf; 
    11151160            pj_status_t status; 
    11161161            unsigned j; 
     1162            pj_int32_t level; 
    11171163 
    11181164            pj_add_timestamp32(&cport->ts_rx, cport->samples_per_frame); 
     
    11261172                continue; 
    11271173 
    1128             if (f->type == PJMEDIA_FRAME_TYPE_NONE) { 
    1129                 if (cport->port->info.format.u32 == PJMEDIA_FOURCC_L16) { 
    1130                     pjmedia_zero_samples((pj_int16_t*)f->buf, 
    1131                                          cport->samples_per_frame); 
    1132                     f->size = cport->samples_per_frame << 1; 
    1133                     f->type = PJMEDIA_FRAME_TYPE_AUDIO; 
    1134                 } else { 
    1135                     /* Handle DTX */ 
    1136                     PJ_TODO(HANDLE_DTX); 
    1137                 } 
     1174            /* Calculate RX level. */ 
     1175            if (f->type == PJMEDIA_FRAME_TYPE_AUDIO) { 
     1176                level = pjmedia_calc_avg_signal((const pj_int16_t*)f->buf, 
     1177                                                f->size >>1 ); 
     1178            } else if (f->type == PJMEDIA_FRAME_TYPE_EXTENDED) { 
     1179                /* For extended frame, TX level is unknown, so we just set  
     1180                 * it to NORMAL_LEVEL.  
     1181                 */ 
     1182                level = NORMAL_LEVEL; 
     1183            } else { /* PJMEDIA_FRAME_TYPE_NONE */ 
     1184                level = 0; 
    11381185            } 
     1186            cport->rx_level = pjmedia_linear2ulaw(level) ^ 0xff; 
    11391187 
    11401188            /* Put the frame to all listeners. */ 
     
    11421190            { 
    11431191                struct conf_port *listener; 
    1144                 pjmedia_frame *frm_dst; 
    11451192 
    11461193                listener = conf->ports[cport->listener_slots[j]]; 
    11471194 
    11481195                /* Skip if this listener doesn't want to receive audio */ 
    1149                 if (listener->tx_setting != PJMEDIA_PORT_ENABLE) 
     1196                if (listener->tx_setting == PJMEDIA_PORT_DISABLE) { 
     1197                    pj_add_timestamp32(&listener->ts_tx,  
     1198                                       listener->samples_per_frame); 
     1199                    listener->tx_level = 0; 
    11501200                    continue; 
     1201                } 
    11511202             
    1152                 if (listener->port) 
    1153                     frm_dst = frame; 
    1154                 else 
    1155                     frm_dst = (pjmedia_frame*)listener->tx_buf; 
    1156  
    1157                 status = deliver_frame(listener, frm_dst, f); 
    1158                 if (status != PJ_SUCCESS) 
     1203                status = write_frame(listener, f); 
     1204                if (status != PJ_SUCCESS) { 
     1205                    listener->tx_level = 0; 
    11591206                    continue; 
     1207                } 
     1208 
     1209                /* Set listener TX level equal to transmitter RX level. */ 
     1210                listener->tx_level = cport->rx_level; 
    11601211            } 
    11611212        } 
    1162          
    1163         /* Keep alive mechanism. */ 
    1164         PJ_TODO(SEND_KEEP_ALIVE_WHEN_NEEDED); 
    1165     } 
     1213    } 
     1214 
     1215    /* Keep alive. Update TX timestamp and send frame type NONE to all  
     1216     * underflow ports at their own clock. 
     1217     */ 
     1218    for (i=1, ci=1; i<conf->max_ports && ci<conf->port_cnt; ++i) { 
     1219        struct conf_port *cport = conf->ports[i]; 
     1220 
     1221        /* Skip empty port. */ 
     1222        if (!cport) 
     1223            continue; 
     1224 
     1225        /* Var "ci" is to count how many ports have been visited so far. */ 
     1226        ++ci; 
     1227 
     1228        if (cport->tx_setting==PJMEDIA_PORT_MUTE || cport->transmitter_cnt==0) 
     1229        { 
     1230            /* Clear left-over samples in tx_buffer, if any, so that it won't 
     1231             * be transmitted next time we have audio signal. 
     1232             */ 
     1233            pj_bzero(cport->tx_buf, sizeof(pjmedia_frame_ext)); 
     1234             
     1235            cport->tx_level = 0; 
     1236 
     1237            while (pj_cmp_timestamp(&cport->ts_clock, &cport->ts_tx) >= 0) 
     1238            { 
     1239                if (cport->tx_setting == PJMEDIA_PORT_ENABLE) { 
     1240                    pjmedia_frame tmp_f; 
     1241 
     1242                    tmp_f.timestamp = cport->ts_tx; 
     1243                    tmp_f.type = PJMEDIA_FRAME_TYPE_NONE; 
     1244                    tmp_f.buf = NULL; 
     1245                    tmp_f.size = 0; 
     1246 
     1247                    pjmedia_port_put_frame(cport->port, &tmp_f); 
     1248                    pj_add_timestamp32(&cport->ts_tx, cport->samples_per_frame); 
     1249                } 
     1250            } 
     1251        } 
     1252    } 
     1253 
     1254    /* Return sound playback frame. */ 
     1255    do { 
     1256        struct conf_port *this_cport = conf->ports[this_port->port_data.ldata]; 
     1257        pjmedia_frame *f_src = (pjmedia_frame*) this_cport->tx_buf; 
     1258 
     1259        frame->type = f_src->type; 
     1260 
     1261        if (f_src->type == PJMEDIA_FRAME_TYPE_EXTENDED) { 
     1262            pjmedia_frame_ext *f_src_ = (pjmedia_frame_ext*)f_src; 
     1263            pjmedia_frame_ext *f_dst = (pjmedia_frame_ext*)frame; 
     1264            pjmedia_frame_ext_subframe *sf; 
     1265            pj_uint16_t samples_per_subframe; 
     1266             
     1267            f_dst->samples_cnt = 0; 
     1268            f_dst->subframe_cnt = 0; 
     1269            i = 0; 
     1270            samples_per_subframe = f_src_->samples_cnt / f_src_->subframe_cnt; 
     1271 
     1272            while (f_dst->samples_cnt < this_cport->samples_per_frame) { 
     1273                sf = pjmedia_frame_ext_get_subframe(f_src_, i++); 
     1274                pjmedia_frame_ext_append_subframe(f_dst, sf->data, sf->bitlen, 
     1275                                                  samples_per_subframe); 
     1276            } 
     1277 
     1278            /* Shift left TX buffer. */ 
     1279            sf = pjmedia_frame_ext_get_subframe(f_src_, i); 
     1280            if (sf) { 
     1281                pjmedia_frame_ext_subframe *sf_end; 
     1282                unsigned len; 
     1283 
     1284                sf_end = pjmedia_frame_ext_get_subframe(f_src_,  
     1285                                                    f_src_->subframe_cnt -1); 
     1286                len = (pj_uint8_t*)sf_end - (pj_uint8_t*)sf + sf_end->bitlen/8; 
     1287                if (sf_end->bitlen % 8 != 0) 
     1288                    ++len; 
     1289                pj_memmove(this_cport->tx_buf + sizeof(pjmedia_frame_ext), sf, 
     1290                           len); 
     1291            } 
     1292            f_src_->samples_cnt = f_src_->samples_cnt -  
     1293                                  (pj_uint16_t)(i * samples_per_subframe); 
     1294            f_src_->subframe_cnt = f_src_->subframe_cnt - (pj_uint16_t)i; 
     1295 
     1296        } else if (f_src->type == PJMEDIA_FRAME_TYPE_AUDIO) { 
     1297            pjmedia_copy_samples((pj_int16_t*)frame->buf,  
     1298                                 (pj_int16_t*)f_src->buf,  
     1299                                 this_cport->samples_per_frame); 
     1300            frame->size = this_cport->samples_per_frame << 1; 
     1301 
     1302            /* Shift left TX buffer. */ 
     1303            f_src->size -= frame->size; 
     1304            if (f_src->size) 
     1305                pjmedia_move_samples((pj_int16_t*)f_src->buf, 
     1306                                     (pj_int16_t*)f_src->buf +  
     1307                                     this_cport->samples_per_frame, 
     1308                                     f_src->size >> 1); 
     1309        } 
     1310    } while (0); 
    11661311 
    11671312    /* Unlock mutex */ 
     
    11751320 */ 
    11761321static pj_status_t put_frame(pjmedia_port *this_port,  
    1177                              const pjmedia_frame *frame) 
     1322                             const pjmedia_frame *f) 
    11781323{ 
    11791324    pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata; 
    1180     struct conf_port *port = conf->ports[this_port->port_data.ldata]; 
     1325    struct conf_port *cport = conf->ports[this_port->port_data.ldata]; 
    11811326    unsigned j; 
     1327    pj_int32_t level; 
    11821328 
    11831329    /* Check for correct size. */ 
    1184     PJ_ASSERT_RETURN( frame->size == conf->samples_per_frame * 
    1185                                      conf->bits_per_sample / 8, 
     1330    PJ_ASSERT_RETURN( f->size == conf->samples_per_frame * 
     1331                                 conf->bits_per_sample / 8, 
    11861332                      PJMEDIA_ENCSAMPLESPFRAME); 
    11871333 
     1334    pj_add_timestamp32(&cport->ts_rx, cport->samples_per_frame); 
     1335     
    11881336    /* Skip if this port is muted/disabled. */ 
    1189     if (port->rx_setting != PJMEDIA_PORT_ENABLE) { 
     1337    if (cport->rx_setting == PJMEDIA_PORT_DISABLE) { 
     1338        cport->rx_level = 0; 
    11901339        return PJ_SUCCESS; 
    11911340    } 
    11921341 
    11931342    /* Skip if no port is listening to the microphone */ 
    1194     if (port->listener_cnt == 0) { 
     1343    if (cport->listener_cnt == 0) { 
     1344        cport->rx_level = 0; 
    11951345        return PJ_SUCCESS; 
    11961346    } 
    11971347 
    1198     if (frame->type == PJMEDIA_FRAME_TYPE_NONE) { 
    1199         if (this_port->info.format.u32 == PJMEDIA_FOURCC_L16) { 
    1200             pjmedia_frame *f = (pjmedia_frame*)port->tx_buf; 
    1201  
    1202             pjmedia_zero_samples((pj_int16_t*)f->buf, 
    1203                                  port->samples_per_frame); 
    1204             f->size = port->samples_per_frame << 1; 
    1205             f->type = PJMEDIA_FRAME_TYPE_AUDIO; 
    1206             frame = f; 
    1207         } else { 
    1208             /* Handle DTX */ 
    1209             PJ_TODO(HANDLE_DTX); 
    1210         } 
    1211     } 
     1348    /* Calculate RX level. */ 
     1349    if (f->type == PJMEDIA_FRAME_TYPE_AUDIO) { 
     1350        level = pjmedia_calc_avg_signal((const pj_int16_t*)f->buf, 
     1351                                        f->size >>1 ); 
     1352    } else if (f->type == PJMEDIA_FRAME_TYPE_EXTENDED) { 
     1353        /* For extended frame, TX level is unknown, so we just set  
     1354         * it to NORMAL_LEVEL.  
     1355         */ 
     1356        level = NORMAL_LEVEL; 
     1357    } else { /* PJMEDIA_FRAME_TYPE_NONE. */ 
     1358        level = 0; 
     1359    } 
     1360    cport->rx_level = pjmedia_linear2ulaw(level) ^ 0xff; 
    12121361 
    12131362    /* Put the frame to all listeners. */ 
    1214     for (j=0; j < port->listener_cnt; ++j)  
     1363    for (j=0; j < cport->listener_cnt; ++j)  
    12151364    { 
    12161365        struct conf_port *listener; 
    1217         pjmedia_frame *frm_dst; 
    12181366        pj_status_t status; 
    12191367 
    1220         listener = conf->ports[port->listener_slots[j]]; 
     1368        listener = conf->ports[cport->listener_slots[j]]; 
    12211369 
    12221370        /* Skip if this listener doesn't want to receive audio */ 
    1223         if (listener->tx_setting != PJMEDIA_PORT_ENABLE) 
     1371        if (listener->tx_setting == PJMEDIA_PORT_DISABLE) { 
     1372            pj_add_timestamp32(&listener->ts_tx,  
     1373                               listener->samples_per_frame); 
     1374            listener->tx_level = 0; 
    12241375            continue; 
     1376        } 
    12251377 
    12261378        /* Skip loopback for now. */ 
    1227         if (listener == port) 
     1379        if (listener == cport) { 
     1380            pj_add_timestamp32(&listener->ts_tx,  
     1381                               listener->samples_per_frame); 
     1382            listener->tx_level = 0; 
    12281383            continue; 
     1384        } 
    12291385             
    1230         frm_dst = (pjmedia_frame*)listener->tx_buf; 
    1231  
    1232         status = deliver_frame(listener, frm_dst, frame); 
    1233         if (status != PJ_SUCCESS) 
     1386        status = write_frame(listener, f); 
     1387        if (status != PJ_SUCCESS) { 
     1388            listener->tx_level = 0; 
    12341389            continue; 
     1390        } 
     1391 
     1392        /* Set listener TX level equal to transmitter RX level. */ 
     1393        listener->tx_level = cport->rx_level; 
    12351394    } 
    12361395 
Note: See TracChangeset for help on using the changeset viewer.