Changeset 2437
- Timestamp:
- Feb 1, 2009 2:10:49 PM (14 years ago)
- 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 265 265 * are byte-aligned although its payload may not be byte-aligned. 266 266 */ 267 268 #pragma pack(1) 267 269 typedef struct pjmedia_frame_ext { 268 270 pjmedia_frame base; /**< Base frame info */ … … 274 276 */ 275 277 } pjmedia_frame_ext; 278 #pragma pack() 276 279 277 280 /** … … 279 282 * pjmedia_frame_ext structure. 280 283 */ 284 #pragma pack(1) 281 285 typedef struct pjmedia_frame_ext_subframe { 282 286 pj_uint16_t bitlen; /**< Number of bits in the data */ … … 284 288 } pjmedia_frame_ext_subframe; 285 289 290 #pragma pack() 291 286 292 287 293 /** … … 305 311 pjmedia_frame_ext_subframe *fsub; 306 312 fsub = (pjmedia_frame_ext_subframe*) p; 307 p += fsub->bitlen / 8;313 p += sizeof(fsub->bitlen) + fsub->bitlen / 8; 308 314 if (fsub->bitlen % 8) 309 315 ++p; … … 312 318 tmp = bitlen / 8; 313 319 if (bitlen % 8) ++tmp; 320 314 321 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 316 325 frm->subframe_cnt++; 317 326 frm->samples_cnt = frm->samples_cnt + samples_cnt; … … 339 348 for (i = 0; i < n; ++i) { 340 349 sf = (pjmedia_frame_ext_subframe*) p; 341 p += s f->bitlen / 8;350 p += sizeof(sf->bitlen) + sf->bitlen / 8; 342 351 if (sf->bitlen % 8) 343 352 ++p; -
pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c
r2434 r2437 19 19 */ 20 20 #include <pjmedia/conference.h> 21 #include <pjmedia/alaw_ulaw.h> 21 22 #include <pjmedia/errno.h> 22 23 #include <pjmedia/port.h> 24 #include <pjmedia/silencedet.h> 23 25 #include <pjmedia/sound_port.h> 24 26 #include <pjmedia/stream.h> … … 42 44 #endif 43 45 44 45 /* REC_FILE macro enables recording of the samples written to the sound46 * device. The file contains RAW PCM data with no header, and has the47 * 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_FILE52 static FILE *fhnd_rec;53 #endif54 55 56 46 #define THIS_FILE "conf_switch.c" 57 47 … … 103 93 pj_timestamp ts_clock; 104 94 pj_timestamp ts_rx; 95 pj_timestamp ts_tx; 105 96 106 97 /* Tx buffer is a temporary buffer to be used when there's mismatch … … 110 101 */ 111 102 pj_uint8_t tx_buf[BUFFER_SIZE]; /**< Tx buffer. */ 112 113 /* When the port is not receiving signal from any other ports (e.g. when114 * no other ports is transmitting to this port), the bridge periodically115 * transmit NULL frame to the port to keep the port "alive" (for example,116 * a stream port needs this heart-beat to periodically transmit silence117 * 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 bridge121 * 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 being124 * "held" for this port. Once this value reaches samples_per_frame125 * value of the port, a NULL frame is sent. The samples value on this126 * variable is clocked at the port's clock rate.127 */128 unsigned tx_heart_beat;129 103 }; 130 104 … … 477 451 PJ_ASSERT_RETURN(conf->bits_per_sample == strm_port->info.bits_per_sample, 478 452 PJMEDIA_ENCBITS); 453 454 /* Port's samples per frame should be equal to or multiplication of 455 * conference's samples per frame. 456 */ 479 457 PJ_ASSERT_RETURN((conf->samples_per_frame % 480 458 strm_port->info.samples_per_frame==0) || … … 981 959 } 982 960 983 /* Deliver frm_src to a conference port (via frm_dst), eventually call984 * port's put_frame() when samples count in the frm_dst are equal to985 * 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 */ 964 static 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 991 969 PJ_TODO(MAKE_SURE_DEST_FRAME_HAS_ENOUGH_SPACE); 992 970 971 frm_dst->type = frm_src->type; 972 frm_dst->timestamp = cport_dst->ts_tx; 973 993 974 if (frm_src->type == PJMEDIA_FRAME_TYPE_EXTENDED) { 975 994 976 pjmedia_frame_ext *f_src = (pjmedia_frame_ext*)frm_src; 995 977 pjmedia_frame_ext *f_dst = (pjmedia_frame_ext*)frm_dst; 996 978 unsigned i; 997 979 998 /* Copy frame to listener's TX buffer. */999 980 for (i = 0; i < f_src->subframe_cnt; ++i) { 1000 981 pjmedia_frame_ext_subframe *sf; 1001 982 983 /* Copy frame to listener's TX buffer. */ 1002 984 sf = pjmedia_frame_ext_get_subframe(f_src, i); 1003 985 pjmedia_frame_ext_append_subframe(f_dst, sf->data, sf->bitlen, … … 1011 993 if (f_dst->samples_cnt == cport_dst->samples_per_frame) 1012 994 { 1013 f_dst->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;1014 995 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); 1016 1002 1017 1003 /* Reset TX buffer. */ … … 1022 1008 } 1023 1009 1024 } else { 1025 1026 pjmedia_frame *f_dst = (pjmedia_frame*)frm_dst; 1010 } else if (frm_src->type == PJMEDIA_FRAME_TYPE_AUDIO) { 1011 1027 1012 pj_int16_t *f_start, *f_end; 1028 1013 … … 1032 1017 unsigned nsamples_to_copy, nsamples_req; 1033 1018 1019 /* Copy frame to listener's TX buffer. */ 1034 1020 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); 1036 1022 if (nsamples_to_copy > nsamples_req) 1037 1023 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), 1039 1025 f_start, 1040 1026 nsamples_to_copy); 1041 f _dst->size += nsamples_to_copy << 1;1027 frm_dst->size += nsamples_to_copy << 1; 1042 1028 f_start += nsamples_to_copy; 1043 1029 … … 1046 1032 * samples per frame. 1047 1033 */ 1048 if ((f _dst->size >> 1) == cport_dst->samples_per_frame)1034 if ((frm_dst->size >> 1) == cport_dst->samples_per_frame) 1049 1035 { 1050 f_dst->type = PJMEDIA_FRAME_TYPE_AUDIO;1051 1036 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); 1053 1042 1054 1043 /* Reset TX buffer. */ 1055 f _dst->size = 0;1044 frm_dst->size = 0; 1056 1045 } 1057 1046 } 1058 1047 } 1059 1048 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 } 1060 1107 } 1061 1108 … … 1072 1119 unsigned ci, i; 1073 1120 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); 1077 1122 1078 1123 /* Must lock mutex */ … … 1094 1139 ++ci; 1095 1140 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 { 1098 1150 cport->rx_level = 0; 1099 1151 continue; 1100 1152 } 1101 1153 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. 1112 1157 */ 1113 1158 while (pj_cmp_timestamp(&cport->ts_clock, &cport->ts_rx) > 0) { 1114 pjmedia_frame *f = (pjmedia_frame*) 1159 pjmedia_frame *f = (pjmedia_frame*)conf->buf; 1115 1160 pj_status_t status; 1116 1161 unsigned j; 1162 pj_int32_t level; 1117 1163 1118 1164 pj_add_timestamp32(&cport->ts_rx, cport->samples_per_frame); … … 1126 1172 continue; 1127 1173 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; 1138 1185 } 1186 cport->rx_level = pjmedia_linear2ulaw(level) ^ 0xff; 1139 1187 1140 1188 /* Put the frame to all listeners. */ … … 1142 1190 { 1143 1191 struct conf_port *listener; 1144 pjmedia_frame *frm_dst;1145 1192 1146 1193 listener = conf->ports[cport->listener_slots[j]]; 1147 1194 1148 1195 /* 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; 1150 1200 continue; 1201 } 1151 1202 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; 1159 1206 continue; 1207 } 1208 1209 /* Set listener TX level equal to transmitter RX level. */ 1210 listener->tx_level = cport->rx_level; 1160 1211 } 1161 1212 } 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); 1166 1311 1167 1312 /* Unlock mutex */ … … 1175 1320 */ 1176 1321 static pj_status_t put_frame(pjmedia_port *this_port, 1177 const pjmedia_frame *f rame)1322 const pjmedia_frame *f) 1178 1323 { 1179 1324 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]; 1181 1326 unsigned j; 1327 pj_int32_t level; 1182 1328 1183 1329 /* Check for correct size. */ 1184 PJ_ASSERT_RETURN( f rame->size == conf->samples_per_frame *1185 1330 PJ_ASSERT_RETURN( f->size == conf->samples_per_frame * 1331 conf->bits_per_sample / 8, 1186 1332 PJMEDIA_ENCSAMPLESPFRAME); 1187 1333 1334 pj_add_timestamp32(&cport->ts_rx, cport->samples_per_frame); 1335 1188 1336 /* 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; 1190 1339 return PJ_SUCCESS; 1191 1340 } 1192 1341 1193 1342 /* 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; 1195 1345 return PJ_SUCCESS; 1196 1346 } 1197 1347 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; 1212 1361 1213 1362 /* Put the frame to all listeners. */ 1214 for (j=0; j < port->listener_cnt; ++j)1363 for (j=0; j < cport->listener_cnt; ++j) 1215 1364 { 1216 1365 struct conf_port *listener; 1217 pjmedia_frame *frm_dst;1218 1366 pj_status_t status; 1219 1367 1220 listener = conf->ports[ port->listener_slots[j]];1368 listener = conf->ports[cport->listener_slots[j]]; 1221 1369 1222 1370 /* 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; 1224 1375 continue; 1376 } 1225 1377 1226 1378 /* 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; 1228 1383 continue; 1384 } 1229 1385 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; 1234 1389 continue; 1390 } 1391 1392 /* Set listener TX level equal to transmitter RX level. */ 1393 listener->tx_level = cport->rx_level; 1235 1394 } 1236 1395
Note: See TracChangeset
for help on using the changeset viewer.