Changeset 390
- Timestamp:
- Apr 6, 2006 7:29:03 PM (19 years ago)
- Location:
- pjproject/trunk
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/include/pjmedia/rtcp.h
r385 r390 147 147 148 148 /** 149 * Unidirectional RTP stream statistics. 150 */ 151 struct pjmedia_rtcp_stream_stat 152 { 153 pj_time_val update; /**< Time of last update. */ 154 unsigned update_cnt; /**< Number of updates (to calculate avg) */ 155 pj_uint32_t pkt; /**< Total number of packets */ 156 pj_uint32_t bytes; /**< Total number of payload/bytes */ 157 unsigned discard; /**< Number of discarded packets. */ 158 unsigned loss; /**< Number of packets lost */ 159 unsigned reorder; /**< Number of out of order packets */ 160 unsigned dup; /**< Number of duplicates packets */ 161 162 struct { 163 unsigned min; /**< Minimum loss period (in usec) */ 164 unsigned avg; /**< Average loss period (in usec) */ 165 unsigned max; /**< Maximum loss period (in usec) */ 166 unsigned last; /**< Last loss period (in usec) */ 167 } loss_period; /**< Lost period history. */ 168 169 struct { 170 unsigned burst:1; /**< Burst/sequential packet lost detected */ 171 unsigned random:1; /**< Random packet lost detected. */ 172 } loss_type; /**< Types of loss detected. */ 173 174 struct { 175 unsigned min; /**< Minimum jitter (in usec) */ 176 unsigned avg; /**< Average jitter (in usec) */ 177 unsigned max; /**< Maximum jitter (in usec) */ 178 unsigned last; /**< Last jitter (in usec) */ 179 } jitter; /**< Jitter history. */ 180 }; 181 182 183 /** 184 * @see pjmedia_rtcp_stream_stat 185 */ 186 typedef struct pjmedia_rtcp_stream_stat pjmedia_rtcp_stream_stat; 187 188 189 190 /** 191 * Bidirectional RTP stream statistics. 192 */ 193 struct pjmedia_rtcp_stat 194 { 195 pjmedia_rtcp_stream_stat tx; /**< Encoder stream statistics. */ 196 pjmedia_rtcp_stream_stat rx; /**< Decoder stream statistics. */ 197 198 struct { 199 unsigned min; /**< Minimum round-trip delay (in usec) */ 200 unsigned avg; /**< Average round-trip delay (in usec) */ 201 unsigned max; /**< Maximum round-trip delay (in usec) */ 202 unsigned last; /**< Last round-trip delay (in usec) */ 203 } rtt; /**< Round trip delay history. */ 204 205 unsigned rtt_update_cnt; /**< Nb of times rtt is updated. */ 206 }; 207 208 209 /** 210 * @see pjmedia_rtcp_stat 211 */ 212 typedef struct pjmedia_rtcp_stat pjmedia_rtcp_stat; 213 214 215 /** 149 216 * RTCP session is used to monitor the RTP session of one endpoint. There 150 217 * should only be one RTCP session for a bidirectional RTP streams. … … 157 224 158 225 unsigned clock_rate; /**< Clock rate of the stream */ 226 unsigned pkt_size; /**< Avg pkt size, in samples. */ 159 227 pj_uint32_t received; /**< # pkt received */ 160 228 pj_uint32_t exp_prior; /**< # pkt expected at last interval*/ … … 167 235 pj_timestamp rx_lsr_time;/**< Time when last SR is received */ 168 236 pj_uint32_t peer_ssrc; /**< Peer SSRC */ 169 unsigned rtt_us; /**< End-to-end delay, in usec. */ 237 238 pjmedia_rtcp_stat stat; /**< Bidirectional stream stat. */ 170 239 }; 171 240 … … 179 248 * Initialize RTCP session. 180 249 * 181 * @param session The session 182 * @param ssrc The SSRC used in to identify the session. 250 * @param session The session 251 * @param clock_rate Codec clock rate in samples per second. 252 * @param samples_per_frame Average number of samples per frame. 253 * @param ssrc The SSRC used in to identify the session. 183 254 */ 184 255 PJ_DECL(void) pjmedia_rtcp_init( pjmedia_rtcp_session *session, 185 256 unsigned clock_rate, 257 unsigned samples_per_frame, 186 258 pj_uint32_t ssrc ); 187 259 … … 202 274 * @param seq The RTP packet sequence number, in host byte order. 203 275 * @param ts The RTP packet timestamp, in host byte order. 276 * @param payload Size of the payload. 204 277 */ 205 278 PJ_DECL(void) pjmedia_rtcp_rx_rtp( pjmedia_rtcp_session *session, 206 pj_uint16_t seq, 207 pj_uint32_t ts ); 279 unsigned seq, 280 unsigned ts, 281 unsigned payload); 208 282 209 283 … … 217 291 */ 218 292 PJ_DECL(void) pjmedia_rtcp_tx_rtp( pjmedia_rtcp_session *session, 219 pj_uint16_tptsize );293 unsigned ptsize ); 220 294 221 295 -
pjproject/trunk/pjmedia/include/pjmedia/rtp.h
r214 r390 181 181 182 182 /** 183 * This structure is used to receive additional information about the 184 * state of incoming RTP packet. 185 */ 186 struct pjmedia_rtp_status 187 { 188 union { 189 struct flag { 190 int bad:1; /**< General flag to indicate that sequence is 191 bad, and application should not process 192 this packet. More information will be given 193 in other flags. */ 194 int badpt:1; /**< Bad payload type. */ 195 int dup:1; /**< Indicates duplicate packet */ 196 int outorder:1; /**< Indicates out of order packet */ 197 int probation:1;/**< Indicates that session is in probation 198 until more packets are received. */ 199 int restart:1; /**< Indicates that sequence number has made 200 a large jump, and internal base sequence 201 number has been adjusted. */ 202 } flag; /**< Status flags. */ 203 204 pj_uint16_t value; /**< Status value, to conveniently address all 205 flags. */ 206 207 } status; /**< Status information union. */ 208 209 pj_uint16_t diff; /**< Sequence number difference from previous 210 packet. Normally the value should be 1. 211 Value greater than one may indicate packet 212 loss. If packet with lower sequence is 213 received, the value will be set to zero. 214 If base sequence has been restarted, the 215 value will be one. */ 216 }; 217 218 /** 219 * @see pjmedia_rtp_status 220 */ 221 typedef struct pjmedia_rtp_status pjmedia_rtp_status; 222 223 224 /** 183 225 * This function will initialize the RTP session according to given parameters. 184 226 * … … 242 284 * @param ses The session. 243 285 * @param hdr The RTP header of the incoming packet. 244 * 245 * @return PJ_SUCCESS if the packet is valid and can be processed,246 * otherwise will return the appropriate status code.247 */ 248 PJ_DECL(pj_status_t) pjmedia_rtp_session_update( pjmedia_rtp_session *ses, 249 const pjmedia_rtp_hdr *hdr);286 * @param seq_st Optional structure to receive the status of the RTP packet 287 * processing. 288 */ 289 PJ_DECL(void) pjmedia_rtp_session_update( pjmedia_rtp_session *ses, 290 const pjmedia_rtp_hdr *hdr, 291 pjmedia_rtp_status *seq_st); 250 292 251 293 … … 266 308 267 309 /** 268 * Internal function to restart the sequence number control, shared by RTCP269 * implementation.270 *271 * @param seq_ctrl The sequence control instance.272 * @param seq Sequence number to restart.273 */274 void pjmedia_rtp_seq_restart(pjmedia_rtp_seq_session *seq_ctrl,275 pj_uint16_t seq);276 277 /**278 310 * Internal function update sequence control, shared by RTCP implementation. 279 311 * 280 * @param seq_ctrl The sequence control instance. 281 * @param seq Sequence number to update. 282 * 283 * @return PJ_SUCCESS if the sequence number can be accepted. 284 */ 285 pj_status_t pjmedia_rtp_seq_update(pjmedia_rtp_seq_session *seq_ctrl, 286 pj_uint16_t seq); 312 * @param seq_ctrl The sequence control instance. 313 * @param seq Sequence number to update. 314 * @param seq_status Optional structure to receive additional information 315 * about the packet. 316 */ 317 void pjmedia_rtp_seq_update( pjmedia_rtp_seq_session *seq_ctrl, 318 pj_uint16_t seq, 319 pjmedia_rtp_status *seq_status); 287 320 288 321 /** -
pjproject/trunk/pjmedia/include/pjmedia/session.h
r374 r390 218 218 PJ_DECL(pj_status_t) pjmedia_session_get_stream_stat(pjmedia_session *session, 219 219 unsigned index, 220 pjmedia_ stream_stat *sta);220 pjmedia_rtcp_stat *stat); 221 221 222 222 /** -
pjproject/trunk/pjmedia/include/pjmedia/stream.h
r290 r390 30 30 #include <pjmedia/endpoint.h> 31 31 #include <pjmedia/port.h> 32 #include <pjmedia/rtcp.h> 32 33 #include <pj/sock.h> 33 34 … … 83 84 84 85 /** 85 * Individual channel statistic.86 */87 struct pjmedia_channel_stat88 {89 pj_uint32_t pkt; /**< Total number of packets. */90 pj_uint32_t bytes; /**< Total number of bytes, including RTP hdr. */91 pj_uint32_t lost; /**< Total number of packet lost */92 };93 94 /**95 * Stream statistic.96 */97 struct pjmedia_stream_stat98 {99 pjmedia_channel_stat enc; /**< Encoder statistics. */100 pjmedia_channel_stat dec; /**< Decoder statistics. */101 };102 103 104 105 /**106 86 * Create a media stream based on the specified stream parameter. 107 87 * All channels in the stream initially will be inactive. … … 165 145 */ 166 146 PJ_DECL(pj_status_t) pjmedia_stream_get_stat( const pjmedia_stream *stream, 167 pjmedia_ stream_stat *stat);147 pjmedia_rtcp_stat *stat); 168 148 169 149 /** -
pjproject/trunk/pjmedia/src/pjmedia/rtcp.c
r389 r390 44 44 * Get NTP time. 45 45 */ 46 static void rtcp_get_ntp_time(const pjmedia_rtcp_session *s ,46 static void rtcp_get_ntp_time(const pjmedia_rtcp_session *sess, 47 47 struct pjmedia_rtcp_ntp_rec *ntp) 48 48 { … … 57 57 58 58 /* Calculate second fractions */ 59 ts.u64 %= s ->ts_freq.u64;60 ts.u64 = (ts.u64 << 32) / s ->ts_freq.u64;59 ts.u64 %= sess->ts_freq.u64; 60 ts.u64 = (ts.u64 << 32) / sess->ts_freq.u64; 61 61 62 62 /* Fill up the low 32bit part */ … … 65 65 66 66 67 PJ_DEF(void) pjmedia_rtcp_init(pjmedia_rtcp_session *s ,67 PJ_DEF(void) pjmedia_rtcp_init(pjmedia_rtcp_session *sess, 68 68 unsigned clock_rate, 69 unsigned samples_per_frame, 69 70 pj_uint32_t ssrc) 70 71 { 71 pjmedia_rtcp_pkt *rtcp_pkt = &s ->rtcp_pkt;72 pjmedia_rtcp_pkt *rtcp_pkt = &sess->rtcp_pkt; 72 73 73 74 pj_memset(rtcp_pkt, 0, sizeof(pjmedia_rtcp_pkt)); 74 75 75 76 /* Set clock rate */ 76 s->clock_rate = clock_rate; 77 sess->clock_rate = clock_rate; 78 sess->pkt_size = samples_per_frame; 77 79 78 80 /* Init time */ 79 s ->rx_lsr = 0;80 s ->rx_lsr_time.u64 = 0;81 sess->rx_lsr = 0; 82 sess->rx_lsr_time.u64 = 0; 81 83 82 84 /* Init common RTCP header */ … … 90 92 91 93 /* Get timestamp frequency */ 92 pj_get_timestamp_freq(&s ->ts_freq);94 pj_get_timestamp_freq(&sess->ts_freq); 93 95 94 96 /* RR will be initialized on receipt of the first RTP packet. */ … … 96 98 97 99 98 PJ_DEF(void) pjmedia_rtcp_fini(pjmedia_rtcp_session *sess ion)100 PJ_DEF(void) pjmedia_rtcp_fini(pjmedia_rtcp_session *sess) 99 101 { 100 102 /* Nothing to do. */ 101 PJ_UNUSED_ARG(session); 102 } 103 104 static void rtcp_init_seq(pjmedia_rtcp_session *s, pj_uint16_t seq) 105 { 106 s->received = 0; 107 s->exp_prior = 0; 108 s->rx_prior = 0; 109 s->transit = 0; 110 s->jitter = 0; 111 112 pjmedia_rtp_seq_restart(&s->seq_ctrl, seq); 113 } 114 115 PJ_DEF(void) pjmedia_rtcp_rx_rtp(pjmedia_rtcp_session *s, 116 pj_uint16_t seq, 117 pj_uint32_t rtp_ts) 103 PJ_UNUSED_ARG(sess); 104 } 105 106 static void rtcp_init_seq(pjmedia_rtcp_session *sess) 107 { 108 sess->received = 0; 109 sess->exp_prior = 0; 110 sess->rx_prior = 0; 111 sess->transit = 0; 112 sess->jitter = 0; 113 } 114 115 PJ_DEF(void) pjmedia_rtcp_rx_rtp(pjmedia_rtcp_session *sess, 116 unsigned seq, 117 unsigned rtp_ts, 118 unsigned payload) 118 119 { 119 120 pj_timestamp ts; 120 121 pj_uint32_t arrival; 121 122 pj_int32_t transit; 122 int status; 123 124 /* Update sequence numbers (received, lost, etc). */ 125 status = pjmedia_rtp_seq_update(&s->seq_ctrl, seq); 126 if (status == PJMEDIA_RTP_ESESSRESTART) { 127 rtcp_init_seq(s, seq); 128 status = 0; 129 } 130 131 if (status != 0) 123 pjmedia_rtp_status seq_st; 124 unsigned last_seq; 125 126 sess->stat.rx.pkt++; 127 sess->stat.rx.bytes += payload; 128 129 /* Update sequence numbers. */ 130 last_seq = sess->seq_ctrl.max_seq; 131 pjmedia_rtp_seq_update(&sess->seq_ctrl, (pj_uint16_t)seq, &seq_st); 132 if (seq_st.status.flag.restart) { 133 rtcp_init_seq(sess); 134 } 135 136 if (seq_st.status.flag.dup) 137 sess->stat.rx.dup++; 138 if (seq_st.status.flag.outorder) 139 sess->stat.rx.reorder++; 140 141 if (seq_st.status.flag.bad) { 142 sess->stat.rx.discard++; 132 143 return; 133 134 ++s->received; 144 } 145 146 147 /* Only mark "good" packets */ 148 ++sess->received; 149 135 150 136 151 /* … … 140 155 /* Get arrival time and convert timestamp to samples */ 141 156 pj_get_timestamp(&ts); 142 ts.u64 = ts.u64 * s ->clock_rate /s->ts_freq.u64;157 ts.u64 = ts.u64 * sess->clock_rate / sess->ts_freq.u64; 143 158 arrival = ts.u32.lo; 144 159 145 160 transit = arrival - rtp_ts; 146 161 147 if (s->transit == 0) { 148 s->transit = transit; 162 /* Ignore the first N packets as they normally have bad jitter 163 * due to other threads working to establish the call 164 */ 165 if (sess->transit == 0 || sess->received < 25 ) { 166 sess->transit = transit; 167 sess->stat.rx.jitter.min = 2000; 149 168 } else { 150 169 pj_int32_t d; 151 152 d = transit - s->transit; 153 s->transit = transit; 170 pj_uint32_t jitter; 171 172 d = transit - sess->transit; 173 sess->transit = transit; 154 174 if (d < 0) 155 175 d = -d; 156 176 157 s->jitter += d - ((s->jitter + 8) >> 4); 158 } 159 } 160 161 PJ_DEF(void) pjmedia_rtcp_tx_rtp(pjmedia_rtcp_session *s, 162 pj_uint16_t bytes_payload_size) 163 { 164 pjmedia_rtcp_pkt *rtcp_pkt = &s->rtcp_pkt; 165 166 /* Update number of packets */ 167 rtcp_pkt->sr.sender_pcount = 168 pj_htonl( pj_ntohl(rtcp_pkt->sr.sender_pcount) + 1); 169 170 /* Update number of bytes */ 171 rtcp_pkt->sr.sender_bcount = 172 pj_htonl( pj_ntohl(rtcp_pkt->sr.sender_bcount) + bytes_payload_size ); 173 } 174 175 176 PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *session, 177 sess->jitter += d - ((sess->jitter + 8) >> 4); 178 179 /* Get jitter in usec */ 180 if (d < 4294) 181 jitter = d * 1000000 / sess->clock_rate; 182 else { 183 jitter = d * 1000 / sess->clock_rate; 184 jitter *= 1000; 185 } 186 187 /* Update jitter stat */ 188 if (jitter < sess->stat.rx.jitter.min) 189 sess->stat.rx.jitter.min = jitter; 190 if (jitter > sess->stat.rx.jitter.max) 191 sess->stat.rx.jitter.max = jitter; 192 sess->stat.rx.jitter.last = jitter; 193 } 194 } 195 196 PJ_DEF(void) pjmedia_rtcp_tx_rtp(pjmedia_rtcp_session *sess, 197 unsigned bytes_payload_size) 198 { 199 /* Update statistics */ 200 sess->stat.tx.pkt++; 201 sess->stat.tx.bytes += bytes_payload_size; 202 } 203 204 205 PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess, 177 206 const void *pkt, 178 207 pj_size_t size) … … 184 213 185 214 /* Save LSR from NTP timestamp of RTCP packet */ 186 sess ion->rx_lsr = ((pj_ntohl(rtcp->sr.ntp_sec) & 0x0000FFFF) << 16) |187 215 sess->rx_lsr = ((pj_ntohl(rtcp->sr.ntp_sec) & 0x0000FFFF) << 16) | 216 ((pj_ntohl(rtcp->sr.ntp_frac) >> 16) & 0xFFFF); 188 217 189 218 /* Calculate SR arrival time for DLSR */ 190 pj_get_timestamp(&sess ion->rx_lsr_time);219 pj_get_timestamp(&sess->rx_lsr_time); 191 220 192 221 TRACE_((THIS_FILE, "Rx RTCP SR: ntp-ts=%p, time=%p", 193 sess ion->rx_lsr,194 (pj_uint32_t)(sess ion->rx_lsr_time.u64*65536/session->ts_freq.u64)));222 sess->rx_lsr, 223 (pj_uint32_t)(sess->rx_lsr_time.u64*65536/sess->ts_freq.u64))); 195 224 196 225 /* Calculate RTT if it has RR */ 197 226 if (size >= sizeof(pjmedia_rtcp_pkt)) { 198 227 228 pj_uint32_t last_loss, jitter_samp, jitter; 229 230 last_loss = sess->stat.tx.loss; 231 232 /* Get packet loss */ 233 sess->stat.tx.loss = (rtcp->rr.total_lost_2 << 16) + 234 (rtcp->rr.total_lost_1 << 8) + 235 rtcp->rr.total_lost_0; 236 237 /* We can't calculate the exact loss period for TX, so just give the 238 * best estimation. 239 */ 240 if (sess->stat.tx.loss > last_loss) { 241 unsigned period; 242 243 /* Loss period in msec */ 244 period = (sess->stat.tx.loss - last_loss) * sess->pkt_size * 245 1000 / sess->clock_rate; 246 247 /* Loss period in usec */ 248 period *= 1000; 249 250 if (sess->stat.tx.update_cnt==0||sess->stat.tx.loss_period.min==0) 251 sess->stat.tx.loss_period.min = period; 252 if (period < sess->stat.tx.loss_period.min) 253 sess->stat.tx.loss_period.min = period; 254 if (period > sess->stat.tx.loss_period.max) 255 sess->stat.tx.loss_period.max = period; 256 257 sess->stat.tx.loss_period.avg = 258 (sess->stat.tx.loss_period.avg*sess->stat.tx.update_cnt+period) 259 / (sess->stat.tx.update_cnt + 1); 260 sess->stat.tx.loss_period.last = period; 261 } 262 263 /* Get jitter value in usec */ 264 jitter_samp = pj_ntohl(rtcp->rr.jitter); 265 /* Calculate jitter in usec, avoiding overflows */ 266 if (jitter_samp <= 4294) 267 jitter = jitter_samp * 1000000 / sess->clock_rate; 268 else { 269 jitter = jitter_samp * 1000 / sess->clock_rate; 270 jitter *= 1000; 271 } 272 273 /* Update jitter statistics */ 274 if (sess->stat.tx.update_cnt == 0) 275 sess->stat.tx.jitter.min = jitter; 276 if (jitter < sess->stat.tx.jitter.min && jitter) 277 sess->stat.tx.jitter.min = jitter; 278 if (jitter > sess->stat.tx.jitter.max) 279 sess->stat.tx.jitter.max = jitter; 280 sess->stat.tx.jitter.avg = 281 (sess->stat.tx.jitter.avg * sess->stat.tx.update_cnt + jitter) / 282 (sess->stat.tx.update_cnt + 1); 283 sess->stat.tx.jitter.last = jitter; 284 285 199 286 /* Can only calculate if LSR and DLSR is present in RR */ 200 287 if (rtcp->rr.lsr && rtcp->rr.dlsr) { … … 212 299 213 300 /* Get current time, and convert to 1/65536 resolution */ 214 rtcp_get_ntp_time(sess ion, &ntp);301 rtcp_get_ntp_time(sess, &ntp); 215 302 now = ((ntp.hi & 0xFFFF) << 16) + 216 303 (ntp.lo >> 16); … … 221 308 /* Convert end to end delay to usec (keeping the calculation in 222 309 * 64bit space):: 223 * sess ion->ee_delay = (eedelay * 1000) / 65536;310 * sess->ee_delay = (eedelay * 1000) / 65536; 224 311 */ 225 312 eedelay = (eedelay * 1000000) >> 16; … … 234 321 */ 235 322 if (now-dlsr >= lsr) { 236 session->rtt_us = (pj_uint32_t)eedelay; 323 unsigned rtt = (pj_uint32_t)eedelay; 324 325 if (sess->stat.rtt_update_cnt == 0) 326 sess->stat.rtt.min = rtt; 327 328 if (rtt < sess->stat.rtt.min && rtt) 329 sess->stat.rtt.min = rtt; 330 if (rtt > sess->stat.rtt.max) 331 sess->stat.rtt.max = rtt; 332 333 sess->stat.rtt.avg = 334 (sess->stat.rtt.avg * sess->stat.rtt_update_cnt + rtt) / 335 (sess->stat.rtt_update_cnt + 1); 336 337 sess->stat.rtt.last = rtt; 338 sess->stat.rtt_update_cnt++; 339 237 340 } else { 238 PJ_LOG(3, (THIS_FILE, "Internal NTP clock skew detected")); 341 PJ_LOG(3, (THIS_FILE, "Internal NTP clock skew detected: " 342 "lsr=%p, now=%p, dlsr=%p (%d:%03dms)", 343 lsr, now, dlsr, dlsr/65536, 344 (dlsr%65536)*1000/65536)); 239 345 } 240 346 } 241 } 242 } 243 244 245 static void rtcp_build_rtcp(pjmedia_rtcp_session *s, 246 pj_uint32_t receiver_ssrc) 247 { 248 pj_uint32_t expected; 249 pj_uint32_t u32; 250 pj_uint32_t expected_interval, received_interval, lost_interval; 251 pjmedia_rtcp_pkt *rtcp_pkt = &s->rtcp_pkt; 347 348 pj_gettimeofday(&sess->stat.tx.update); 349 sess->stat.tx.update_cnt++; 350 } 351 } 352 353 354 PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *sess, 355 pjmedia_rtcp_pkt **ret_p_pkt, 356 int *len) 357 { 358 pj_uint32_t expected, expected_interval, received_interval, lost_interval; 359 pj_uint32_t jitter_samp, jitter; 360 pjmedia_rtcp_pkt *rtcp_pkt = &sess->rtcp_pkt; 361 pjmedia_rtcp_ntp_rec ntp; 362 363 /* Packet count */ 364 rtcp_pkt->sr.sender_pcount = pj_htonl(sess->stat.tx.pkt); 365 366 /* Octets count */ 367 rtcp_pkt->sr.sender_bcount = pj_htonl(sess->stat.tx.bytes); 252 368 253 369 /* SSRC and last_seq */ 254 rtcp_pkt->rr.ssrc = pj_htonl( receiver_ssrc);255 rtcp_pkt->rr.last_seq = (s ->seq_ctrl.cycles & 0xFFFF0000L);256 rtcp_pkt->rr.last_seq += s ->seq_ctrl.max_seq;370 rtcp_pkt->rr.ssrc = pj_htonl(sess->peer_ssrc); 371 rtcp_pkt->rr.last_seq = (sess->seq_ctrl.cycles & 0xFFFF0000L); 372 rtcp_pkt->rr.last_seq += sess->seq_ctrl.max_seq; 257 373 rtcp_pkt->rr.last_seq = pj_htonl(rtcp_pkt->rr.last_seq); 258 374 375 259 376 /* Jitter */ 260 rtcp_pkt->rr.jitter = pj_htonl(s->jitter >> 4); 377 jitter_samp = (sess->jitter >> 4); 378 rtcp_pkt->rr.jitter = pj_htonl(jitter_samp); 379 380 /* Calculate jitter in usec, avoiding overflows */ 381 if (jitter_samp <= 4294) 382 jitter = jitter_samp * 1000000 / sess->clock_rate; 383 else { 384 jitter = jitter_samp * 1000 / sess->clock_rate; 385 jitter *= 1000; 386 } 387 388 /* Update jitter statistics */ 389 sess->stat.rx.jitter.avg = 390 (sess->stat.rx.jitter.avg * sess->stat.rx.update_cnt + jitter) / 391 (sess->stat.rx.update_cnt + 1); 261 392 262 393 /* Total lost. */ 263 expected = pj_ntohl(rtcp_pkt->rr.last_seq) - s->seq_ctrl.base_seq; 264 if (expected >= s->received) 265 u32 = expected - s->received; 266 else 267 u32 = 0; 268 rtcp_pkt->rr.total_lost_2 = (u32 >> 16) & 0x00FF; 269 rtcp_pkt->rr.total_lost_1 = (u32 >> 8) & 0x00FF; 270 rtcp_pkt->rr.total_lost_0 = u32 & 0x00FF; 394 expected = pj_ntohl(rtcp_pkt->rr.last_seq) - sess->seq_ctrl.base_seq; 395 if (expected >= sess->received) 396 sess->stat.rx.loss = expected - sess->received; 397 rtcp_pkt->rr.total_lost_2 = (sess->stat.rx.loss >> 16) & 0xFF; 398 rtcp_pkt->rr.total_lost_1 = (sess->stat.rx.loss >> 8) & 0xFF; 399 rtcp_pkt->rr.total_lost_0 = (sess->stat.rx.loss & 0xFF); 271 400 272 401 /* Fraction lost calculation */ 273 expected_interval = expected - s ->exp_prior;274 s ->exp_prior = expected;275 276 received_interval = s ->received -s->rx_prior;277 s ->rx_prior =s->received;402 expected_interval = expected - sess->exp_prior; 403 sess->exp_prior = expected; 404 405 received_interval = sess->received - sess->rx_prior; 406 sess->rx_prior = sess->received; 278 407 279 408 lost_interval = expected_interval - received_interval; … … 284 413 rtcp_pkt->rr.fract_lost = (lost_interval << 8) / expected_interval; 285 414 } 286 }287 288 PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *session,289 pjmedia_rtcp_pkt **ret_p_pkt,290 int *len)291 {292 pjmedia_rtcp_pkt *rtcp_pkt = &session->rtcp_pkt;293 pjmedia_rtcp_ntp_rec ntp;294 295 rtcp_build_rtcp(session, session->peer_ssrc);296 415 297 416 /* Get current NTP time. */ 298 rtcp_get_ntp_time(sess ion, &ntp);417 rtcp_get_ntp_time(sess, &ntp); 299 418 300 419 /* Fill in NTP timestamp in SR. */ … … 302 421 rtcp_pkt->sr.ntp_frac = pj_htonl(ntp.lo); 303 422 304 if (sess ion->rx_lsr_time.u64 == 0 || session->rx_lsr == 0) {423 if (sess->rx_lsr_time.u64 == 0 || sess->rx_lsr == 0) { 305 424 rtcp_pkt->rr.lsr = 0; 306 425 rtcp_pkt->rr.dlsr = 0; 307 426 } else { 308 427 pj_timestamp ts; 309 pj_uint32_t lsr = sess ion->rx_lsr;310 pj_uint64_t lsr_time = sess ion->rx_lsr_time.u64;428 pj_uint32_t lsr = sess->rx_lsr; 429 pj_uint64_t lsr_time = sess->rx_lsr_time.u64; 311 430 pj_uint32_t dlsr; 312 431 313 432 /* Convert LSR time to 1/65536 seconds resolution */ 314 lsr_time = (lsr_time << 16) / sess ion->ts_freq.u64;433 lsr_time = (lsr_time << 16) / sess->ts_freq.u64; 315 434 316 435 /* Fill in LSR. … … 325 444 326 445 /* Convert interval to 1/65536 seconds value */ 327 ts.u64 = (ts.u64 << 16) / sess ion->ts_freq.u64;446 ts.u64 = (ts.u64 << 16) / sess->ts_freq.u64; 328 447 329 448 /* Get DLSR */ … … 341 460 } 342 461 462 /* Update counter */ 463 pj_gettimeofday(&sess->stat.rx.update); 464 sess->stat.rx.update_cnt++; 465 343 466 344 467 /* Return pointer. */ -
pjproject/trunk/pjmedia/src/pjmedia/rtp.c
r223 r390 35 35 #define MIN_SEQUENTIAL ((pj_int16_t)2) 36 36 37 static void pjmedia_rtp_seq_restart(pjmedia_rtp_seq_session *seq_ctrl, 38 pj_uint16_t seq); 39 37 40 38 41 PJ_DEF(pj_status_t) pjmedia_rtp_session_init( pjmedia_rtp_session *ses, … … 162 165 163 166 164 PJ_DEF(pj_status_t) pjmedia_rtp_session_update( pjmedia_rtp_session *ses, const pjmedia_rtp_hdr *hdr) 165 { 166 int status; 167 PJ_DEF(void) pjmedia_rtp_session_update( pjmedia_rtp_session *ses, 168 const pjmedia_rtp_hdr *hdr, 169 pjmedia_rtp_status *p_seq_st) 170 { 171 pjmedia_rtp_status seq_st; 167 172 168 173 /* Check SSRC. */ … … 176 181 */ 177 182 183 /* Init status */ 184 seq_st.status.value = 0; 185 seq_st.diff = 0; 186 178 187 /* Check payload type. */ 179 188 if (hdr->pt != ses->out_pt) { 180 PJ_LOG(4, (THIS_FILE, "pjmedia_rtp_session_update: ses=%p, invalid payload type %d (!=%d)", 189 PJ_LOG(4, (THIS_FILE, 190 "pjmedia_rtp_session_update: ses=%p, invalid payload " 191 "type %d (expecting %d)", 181 192 ses, hdr->pt, ses->out_pt)); 182 return PJMEDIA_RTP_EINPT; 193 if (p_seq_st) { 194 p_seq_st->status.flag.bad = 1; 195 p_seq_st->status.flag.badpt = 1; 196 } 197 return; 183 198 } 184 199 … … 188 203 189 204 /* Check sequence number to see if remote session has been restarted. */ 190 status = pjmedia_rtp_seq_update( &ses->seq_ctrl, pj_ntohs(hdr->seq)); 191 if (status == PJMEDIA_RTP_ESESSRESTART) { 192 pjmedia_rtp_seq_restart( &ses->seq_ctrl, pj_ntohs(hdr->seq)); 205 pjmedia_rtp_seq_update( &ses->seq_ctrl, pj_ntohs(hdr->seq), &seq_st); 206 if (seq_st.status.flag.restart) { 193 207 ++ses->received; 194 } else if (status == 0 || status == PJMEDIA_RTP_ESESSPROBATION) { 208 209 } else if (!seq_st.status.flag.bad) { 195 210 ++ses->received; 196 211 } 197 212 198 199 return status; 200 } 201 202 203 void pjmedia_rtp_seq_restart(pjmedia_rtp_seq_session *sctrl, pj_uint16_t seq) 204 { 205 sctrl->base_seq = seq; 206 sctrl->max_seq = seq; 207 sctrl->bad_seq = RTP_SEQ_MOD + 1; 208 sctrl->cycles = 0; 209 } 210 211 212 void pjmedia_rtp_seq_init(pjmedia_rtp_seq_session *sctrl, pj_uint16_t seq) 213 { 214 pjmedia_rtp_seq_restart(sctrl, seq); 215 216 sctrl->max_seq = (pj_uint16_t) (seq - 1); 217 sctrl->probation = MIN_SEQUENTIAL; 218 } 219 220 221 pj_status_t pjmedia_rtp_seq_update(pjmedia_rtp_seq_session *sctrl, 222 pj_uint16_t seq) 223 { 224 pj_uint16_t udelta = (pj_uint16_t) (seq - sctrl->max_seq); 213 if (p_seq_st) { 214 p_seq_st->status.value = seq_st.status.value; 215 p_seq_st->diff = seq_st.diff; 216 } 217 } 218 219 220 void pjmedia_rtp_seq_restart(pjmedia_rtp_seq_session *sess, pj_uint16_t seq) 221 { 222 sess->base_seq = seq; 223 sess->max_seq = seq; 224 sess->bad_seq = RTP_SEQ_MOD + 1; 225 sess->cycles = 0; 226 } 227 228 229 void pjmedia_rtp_seq_init(pjmedia_rtp_seq_session *sess, pj_uint16_t seq) 230 { 231 pjmedia_rtp_seq_restart(sess, seq); 232 233 sess->max_seq = (pj_uint16_t) (seq - 1); 234 sess->probation = MIN_SEQUENTIAL; 235 } 236 237 238 void pjmedia_rtp_seq_update( pjmedia_rtp_seq_session *sess, 239 pj_uint16_t seq, 240 pjmedia_rtp_status *seq_status) 241 { 242 pj_uint16_t udelta = (pj_uint16_t) (seq - sess->max_seq); 243 pjmedia_rtp_status st; 225 244 245 /* Init status */ 246 st.status.value = 0; 247 st.diff = 0; 248 226 249 /* 227 250 * Source is not valid until MIN_SEQUENTIAL packets with 228 251 * sequential sequence numbers have been received. 229 252 */ 230 if (sctrl->probation) { 231 /* packet is in sequence */ 232 if (seq == sctrl->max_seq+ 1) { 233 sctrl->probation--; 234 sctrl->max_seq = seq; 235 if (sctrl->probation == 0) { 236 return PJMEDIA_RTP_ESESSRESTART; 253 if (sess->probation) { 254 255 st.status.flag.probation = 1; 256 257 if (seq == sess->max_seq+ 1) { 258 /* packet is in sequence */ 259 st.diff = 1; 260 sess->probation--; 261 sess->max_seq = seq; 262 if (sess->probation == 0) { 263 st.status.flag.probation = 0; 237 264 } 238 265 } else { 239 sctrl->probation = MIN_SEQUENTIAL - 1; 240 sctrl->max_seq = seq; 266 267 st.diff = 0; 268 269 st.status.flag.bad = 1; 270 if (seq == sess->max_seq) 271 st.status.flag.dup = 1; 272 else 273 st.status.flag.outorder = 1; 274 275 sess->probation = MIN_SEQUENTIAL - 1; 276 sess->max_seq = seq; 241 277 } 242 return PJMEDIA_RTP_ESESSPROBATION; 278 279 280 } else if (udelta == 0) { 281 282 st.status.flag.dup = 1; 243 283 244 284 } else if (udelta < MAX_DROPOUT) { 245 285 /* in order, with permissible gap */ 246 if (seq < s ctrl->max_seq) {286 if (seq < sess->max_seq) { 247 287 /* Sequence number wrapped - count another 64K cycle. */ 248 s ctrl->cycles += RTP_SEQ_MOD;288 sess->cycles += RTP_SEQ_MOD; 249 289 } 250 sctrl->max_seq = seq; 290 sess->max_seq = seq; 291 292 st.diff = udelta; 251 293 252 294 } else if (udelta <= (RTP_SEQ_MOD - MAX_MISORDER)) { 253 295 /* the sequence number made a very large jump */ 254 if (seq == s ctrl->bad_seq) {296 if (seq == sess->bad_seq) { 255 297 /* 256 298 * Two sequential packets -- assume that the other side … … 258 300 * (i.e., pretend this was the first packet). 259 301 */ 260 return PJMEDIA_RTP_ESESSRESTART; 302 pjmedia_rtp_seq_restart(sess, seq); 303 st.status.flag.restart = 1; 304 st.status.flag.probation = 1; 305 st.diff = 1; 261 306 } 262 307 else { 263 sctrl->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1); 264 return PJMEDIA_RTP_EBADSEQ; 308 sess->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1); 309 st.status.flag.bad = 1; 310 st.status.flag.outorder = 1; 265 311 } 266 312 } else { 267 /* duplicate or reordered packet */ 313 /* old duplicate or reordered packet. 314 * Not necessarily bad packet (?) 315 */ 316 st.status.flag.outorder = 1; 268 317 } 269 318 270 return PJ_SUCCESS; 271 } 272 273 319 320 if (seq_status) { 321 seq_status->diff = st.diff; 322 seq_status->status.value = st.status.value; 323 } 324 } 325 326 -
pjproject/trunk/pjmedia/src/pjmedia/session.c
r374 r390 526 526 PJ_DEF(pj_status_t) pjmedia_session_get_stream_stat( pjmedia_session *session, 527 527 unsigned index, 528 pjmedia_ stream_stat *stat)528 pjmedia_rtcp_stat *stat) 529 529 { 530 530 PJ_ASSERT_RETURN(session && stat && index < session->stream_cnt, -
pjproject/trunk/pjmedia/src/pjmedia/stream.c
r381 r390 38 38 #define ERRLEVEL 1 39 39 #define TRACE_(expr) stream_perror expr 40 40 #define TRC_(expr) PJ_LOG(4,expr) 41 41 #define PJMEDIA_MAX_FRAME_DURATION_MS 200 42 42 #define PJMEDIA_MAX_BUFFER_SIZE_MS 2000 … … 44 44 #define PJMEDIA_DTMF_DURATION 1600 /* in timestamp */ 45 45 #define PJMEDIA_RTP_NAT_PROBATION_CNT 10 46 #define PJMEDIA_RTCP_INTERVAL 5 /* seconds */ 46 47 47 48 … … 88 89 89 90 pjmedia_dir dir; /**< Stream direction. */ 90 pjmedia_stream_stat stat; /**< Stream statistics. */91 91 void *user_data; /**< User data. */ 92 92 … … 111 111 pj_ioqueue_key_t *rtcp_key; /**< RTCP ioqueue key. */ 112 112 pj_ioqueue_op_key_t rtcp_op_key; /**< The pending read op key. */ 113 113 pj_size_t rtcp_pkt_size; /**< Size of RTCP packet buf. */ 114 char rtcp_pkt[512]; /**< RTCP packet buffer. */ 115 pj_uint32_t rtcp_tx_time; /**< RTCP tx time in timestamp */ 116 int rtcp_addrlen; /**< Address length. */ 114 117 115 118 /* RFC 2833 DTMF transmission queue: */ … … 270 273 struct pjmedia_frame frame_out; 271 274 int ts_len; 275 pj_bool_t has_tx; 272 276 void *rtphdr; 273 277 int rtphdrlen; … … 279 283 /* Init frame_out buffer. */ 280 284 frame_out.buf = ((char*)channel->out_pkt) + sizeof(pjmedia_rtp_hdr); 285 286 /* Make compiler happy */ 287 frame_out.size = 0; 281 288 282 289 /* If we have DTMF digits in the queue, transmit the digits. … … 285 292 if (stream->tx_dtmf_count) { 286 293 294 has_tx = PJ_TRUE; 287 295 create_dtmf_payload(stream, &frame_out); 288 296 … … 297 305 unsigned max_size; 298 306 307 has_tx = PJ_TRUE; 299 308 max_size = channel->out_pkt_size - sizeof(pjmedia_rtp_hdr); 300 309 status = stream->codec->op->encode( stream->codec, frame, … … 317 326 318 327 /* Just update RTP session's timestamp. */ 328 has_tx = PJ_FALSE; 319 329 status = pjmedia_rtp_encode_rtp( &channel->rtp, 320 330 0, 0, … … 322 332 (const void**)&rtphdr, 323 333 &rtphdrlen); 324 return PJ_SUCCESS; 325 326 } 327 328 if (status != 0) { 334 335 } 336 337 if (status != PJ_SUCCESS) { 329 338 TRACE_((THIS_FILE, "RTP encode_rtp() error", status)); 330 339 return status; 331 340 } 341 342 /* Check if this is the time to transmit RTCP packet */ 343 if (stream->rtcp_tx_time == 0) { 344 stream->rtcp_tx_time = pj_ntohl(channel->rtp.out_hdr.ts) + 345 PJMEDIA_RTCP_INTERVAL * 346 stream->port.info.sample_rate; 347 } else if (pj_ntohl(channel->rtp.out_hdr.ts) >= stream->rtcp_tx_time) { 348 349 pjmedia_rtcp_pkt *rtcp_pkt; 350 pj_ssize_t size; 351 int len; 352 353 pjmedia_rtcp_build_rtcp(&stream->rtcp, &rtcp_pkt, &len); 354 size = len; 355 status = pj_sock_sendto(stream->skinfo.rtcp_sock, rtcp_pkt, &size, 0, 356 &stream->rem_rtcp_addr, 357 sizeof(stream->rem_rtcp_addr)); 358 if (status != PJ_SUCCESS) { 359 ; 360 } 361 362 stream->rtcp_tx_time = pj_ntohl(channel->rtp.out_hdr.ts) + 363 PJMEDIA_RTCP_INTERVAL * 364 stream->port.info.sample_rate; 365 } 366 367 /* Do nothing if we have nothing to transmit */ 368 if (!has_tx) 369 return PJ_SUCCESS; 332 370 333 371 if (rtphdrlen != sizeof(pjmedia_rtp_hdr)) { 334 372 /* We don't support RTP with extended header yet. */ 335 373 PJ_TODO(SUPPORT_SENDING_RTP_WITH_EXTENDED_HEADER); 336 //TRACE_((THIS_FILE, "Unsupported extended RTP header for transmission")); 337 return 0; 374 return PJ_SUCCESS; 338 375 } 339 376 … … 342 379 /* Send. */ 343 380 sent = frame_out.size+sizeof(pjmedia_rtp_hdr); 344 status = pj_sock_sendto(stream->skinfo.rtp_sock, channel->out_pkt, &sent, 0, 345 &stream->rem_rtp_addr, sizeof(stream->rem_rtp_addr)); 381 status = pj_sock_sendto(stream->skinfo.rtp_sock, channel->out_pkt, 382 &sent, 0, &stream->rem_rtp_addr, 383 sizeof(stream->rem_rtp_addr)); 346 384 if (status != PJ_SUCCESS) 347 385 return status; 348 386 349 387 /* Update stat */ 350 stream->stat.enc.pkt++; 351 stream->stat.enc.bytes += frame_out.size+sizeof(pjmedia_rtp_hdr); 388 pjmedia_rtcp_tx_rtp(&stream->rtcp, frame_out.size); 352 389 353 390 return PJ_SUCCESS; … … 460 497 const void *payload; 461 498 unsigned payloadlen; 499 pjmedia_rtp_status seq_st; 462 500 463 501 /* Go straight to read next packet if bytes_read == 0. … … 477 515 478 516 517 /* Inform RTCP session */ 518 pjmedia_rtcp_rx_rtp(&stream->rtcp, pj_ntohs(hdr->seq), 519 pj_ntohl(hdr->ts), payloadlen); 520 479 521 /* Handle incoming DTMF. */ 480 522 if (hdr->pt == stream->rx_event_pt) { … … 487 529 * the incoming packet. 488 530 */ 489 status = pjmedia_rtp_session_update(&channel->rtp, hdr); 490 if (status != 0 && 491 status != PJMEDIA_RTP_ESESSPROBATION && 492 status != PJMEDIA_RTP_ESESSRESTART) 493 { 494 TRACE_((THIS_FILE, "RTP session_update error (details follows)", 495 status)); 496 PJ_LOG(4,(THIS_FILE,"RTP packet detail: pt=%d, seq=%d", 497 hdr->pt, pj_ntohs(hdr->seq))); 531 pjmedia_rtp_session_update(&channel->rtp, hdr, &seq_st); 532 if (seq_st.status.flag.bad) { 533 TRC_ ((THIS_FILE, 534 "RTP session_update error: badpt=%d, dup=%d, outorder=%d, " 535 "probation=%d, restart=%d", 536 seq_st.status.flag.badpt, 537 seq_st.status.flag.dup, 538 seq_st.status.flag.outorder, 539 seq_st.status.flag.probation, 540 seq_st.status.flag.restart)); 498 541 goto read_next_packet; 499 542 } 500 501 502 /* Update the RTCP session. */503 pjmedia_rtcp_rx_rtp(&stream->rtcp, pj_ntohs(hdr->seq),504 pj_ntohl(hdr->ts));505 506 507 /* Update stat */508 stream->stat.dec.pkt++;509 stream->stat.dec.bytes += bytes_read;510 543 511 544 … … 572 605 pj_ssize_t bytes_read) 573 606 { 574 PJ_UNUSED_ARG(key); 607 pjmedia_stream *stream = pj_ioqueue_get_user_data(key); 608 pj_status_t status; 609 575 610 PJ_UNUSED_ARG(op_key); 576 PJ_UNUSED_ARG(bytes_read); 611 612 do { 613 if (bytes_read > 0) { 614 pjmedia_rtcp_rx_rtcp(&stream->rtcp, stream->rtcp_pkt, 615 bytes_read); 616 } 617 618 bytes_read = stream->rtcp_pkt_size; 619 stream->rtcp_addrlen = sizeof(stream->rem_rtcp_addr); 620 status = pj_ioqueue_recvfrom( stream->rtcp_key, 621 &stream->rtcp_op_key, 622 stream->rtcp_pkt, 623 &bytes_read, 0, 624 &stream->rem_rtcp_addr, 625 &stream->rtcp_addrlen); 626 627 } while (status == PJ_SUCCESS); 628 629 if (status != PJ_SUCCESS && status != PJ_EPENDING) { 630 char errmsg[PJ_ERR_MSG_SIZE]; 631 632 pj_strerror(status, errmsg, sizeof(errmsg)); 633 PJ_LOG(4,(THIS_FILE, "Error reading RTCP packet: %s [status=%d]", 634 errmsg, status)); 635 } 636 577 637 } 578 638 … … 659 719 pjmedia_codec_param codec_param; 660 720 pj_ioqueue_callback ioqueue_cb; 721 pj_uint16_t rtcp_port; 661 722 pj_status_t status; 662 723 … … 691 752 stream->skinfo = info->sock_info; 692 753 stream->rem_rtp_addr = info->rem_addr; 754 rtcp_port = (pj_uint16_t) (pj_ntohs(info->rem_addr.sin_port)+1); 755 stream->rem_rtcp_addr = stream->rem_rtp_addr; 756 stream->rem_rtcp_addr.sin_port = pj_htons(rtcp_port); 693 757 stream->tx_event_pt = info->tx_event_pt; 694 758 stream->rx_event_pt = info->rx_event_pt; 695 759 stream->last_dtmf = -1; 696 697 698 PJ_TODO(INITIALIZE_RTCP_REMOTE_ADDRESS);699 760 700 761 /* Create mutex to protect jitter buffer: */ … … 739 800 /* Init RTCP session: */ 740 801 741 pjmedia_rtcp_init(&stream->rtcp, info->fmt.sample_rate, info->ssrc); 802 pjmedia_rtcp_init(&stream->rtcp, info->fmt.sample_rate, 803 stream->port.info.samples_per_frame, 804 info->ssrc); 742 805 743 806 … … 800 863 pj_ioqueue_op_key_init(&stream->rtcp_op_key, sizeof(stream->rtcp_op_key)); 801 864 865 stream->rtcp_pkt_size = sizeof(stream->rtcp_pkt); 866 802 867 /* Bootstrap the first recvfrom() operation. */ 803 868 on_rx_rtcp( stream->rtcp_key, &stream->rtcp_op_key, 0); … … 901 966 */ 902 967 PJ_DEF(pj_status_t) pjmedia_stream_get_stat( const pjmedia_stream *stream, 903 pjmedia_ stream_stat *stat)968 pjmedia_rtcp_stat *stat) 904 969 { 905 970 PJ_ASSERT_RETURN(stream && stat, PJ_EINVAL); 906 971 907 pj_memcpy(stat, &stream->stat, sizeof(pjmedia_stream_stat)); 908 972 pj_memcpy(stat, &stream->rtcp.stat, sizeof(pjmedia_rtcp_stat)); 909 973 return PJ_SUCCESS; 910 974 } -
pjproject/trunk/pjsip-apps/src/samples/siprtp.c
r389 r390 52 52 53 53 54 /* Unidirectional media stat: */55 struct stream_stat56 {57 pj_uint32_t pkt, payload;58 pj_uint32_t discard, reorder;59 unsigned loss_min, loss_avg, loss_max;60 char *loss_type;61 unsigned jitter_min_us, jitter_avg_us, jitter_max_us;62 unsigned rtcp_cnt;63 };64 65 66 54 /* A bidirectional media stream */ 67 55 struct media_stream … … 88 76 /* RTCP stats: */ 89 77 pjmedia_rtcp_session rtcp; /* incoming RTCP session. */ 90 pjmedia_rtcp_pkt rem_rtcp; /* received RTCP stat. */91 92 /* More stats: */93 struct stream_stat rx_stat; /* incoming stream stat */94 struct stream_stat tx_stat; /* outgoing stream stat. */95 78 96 79 /* Thread: */ … … 1074 1057 } 1075 1058 1076 ++strm->rx_stat.pkt;1077 strm->rx_stat.payload += (size - 12);1078 1059 1079 1060 /* Decode RTP packet. */ … … 1084 1065 if (status != PJ_SUCCESS) { 1085 1066 app_perror(THIS_FILE, "RTP decode error", status); 1086 strm->rx_stat.discard++;1087 1067 continue; 1088 1068 } 1089 1069 1090 /* Update RTP session */1091 status = pjmedia_rtp_session_update(&strm->in_sess, hdr);1092 if (status != PJ_SUCCESS &&1093 status != PJMEDIA_RTP_ESESSPROBATION &&1094 status != PJMEDIA_RTP_ESESSRESTART)1095 {1096 app_perror(THIS_FILE, "RTP update error", status);1097 PJ_LOG(3,(THIS_FILE,"RTP packet detail: pt=%d, seq=%d",1098 hdr->pt, pj_ntohs(hdr->seq)));1099 strm->rx_stat.discard++;1100 continue;1101 }1102 1103 1070 /* Update the RTCP session. */ 1104 1071 pjmedia_rtcp_rx_rtp(&strm->rtcp, pj_ntohs(hdr->seq), 1105 pj_ntohl(hdr->ts)); 1106 1072 pj_ntohl(hdr->ts), payload_len); 1073 1074 /* Update RTP session */ 1075 pjmedia_rtp_session_update(&strm->in_sess, hdr, NULL); 1107 1076 } 1108 1077 … … 1119 1088 if (status != PJ_SUCCESS) 1120 1089 app_perror(THIS_FILE, "Error receiving RTCP packet", status); 1121 else { 1122 if (size != sizeof(strm->rem_rtcp)) { 1123 PJ_LOG(3,(THIS_FILE, "Error: RTCP packet size mismatch " 1124 "(recv %d bytes, expecting %d)", 1125 size, sizeof(strm->rem_rtcp))); 1126 status = -1; 1127 } else { 1128 pj_memcpy(&strm->rem_rtcp, packet, size); 1129 status = PJ_SUCCESS; 1130 1131 /* Report receipt of RTCP to RTCP session */ 1132 pjmedia_rtcp_rx_rtcp(&strm->rtcp, packet, size); 1133 } 1134 } 1135 1136 if (status == PJ_SUCCESS) { 1137 /* Process RTCP stats */ 1138 unsigned jitter; 1139 1140 jitter = (unsigned)(pj_ntohl(strm->rem_rtcp.rr.jitter) * 1141 1000000.0 / strm->clock_rate); 1142 if (jitter < strm->tx_stat.jitter_min_us) 1143 strm->tx_stat.jitter_min_us = jitter; 1144 if (jitter > strm->tx_stat.jitter_max_us) 1145 strm->tx_stat.jitter_max_us = jitter; 1146 strm->tx_stat.jitter_avg_us = 1147 (strm->tx_stat.jitter_avg_us * strm->tx_stat.rtcp_cnt + 1148 jitter) / (strm->tx_stat.rtcp_cnt + 1); 1149 1150 strm->tx_stat.rtcp_cnt++; 1151 } 1090 else 1091 pjmedia_rtcp_rx_rtcp(&strm->rtcp, packet, size); 1152 1092 } 1153 1093 … … 1194 1134 /* Schedule next send */ 1195 1135 next_rtp.u64 += (msec_interval * freq.u64 / 1000); 1196 1197 /* Update stats */1198 strm->tx_stat.pkt++;1199 strm->tx_stat.payload += strm->bytes_per_frame;1200 1136 } 1201 1137 … … 1229 1165 } 1230 1166 1231 1232 /* Process RTCP stats */ 1233 { 1234 unsigned jitter; 1235 1236 jitter = (unsigned) (pj_ntohl(rtcp_pkt->rr.jitter) * 1237 1000000.0 / strm->clock_rate); 1238 if (jitter < strm->rx_stat.jitter_min_us) 1239 strm->rx_stat.jitter_min_us = jitter; 1240 if (jitter > strm->rx_stat.jitter_max_us) 1241 strm->rx_stat.jitter_max_us = jitter; 1242 strm->rx_stat.jitter_avg_us = 1243 (strm->rx_stat.jitter_avg_us * strm->rx_stat.rtcp_cnt + 1244 jitter) / (strm->rx_stat.rtcp_cnt + 1); 1245 1246 strm->rx_stat.rtcp_cnt++; 1247 } 1248 1167 /* Schedule next send */ 1249 1168 next_rtcp.u64 += (freq.u64 * RTCP_INTERVAL); 1250 1169 } … … 1319 1238 pj_rand()); 1320 1239 pjmedia_rtp_session_init(&audio->in_sess, audio->si.fmt.pt, 0); 1321 pjmedia_rtcp_init(&audio->rtcp, audio->clock_rate, 0); 1322 1323 1324 /* Clear media statistics */ 1325 pj_memset(&audio->rx_stat, 0, sizeof(audio->rx_stat)); 1326 pj_memset(&audio->tx_stat, 0, sizeof(audio->tx_stat)); 1240 pjmedia_rtcp_init(&audio->rtcp, audio->clock_rate, 1241 audio->samples_per_frame, 0); 1242 1327 1243 1328 1244 … … 1411 1327 struct media_stream *audio = &call->media[0]; 1412 1328 char userinfo[128]; 1413 char duration[80] ;1329 char duration[80], last_update[80]; 1414 1330 char bps[16], ipbps[16], packets[16], bytes[16], ipbytes[16]; 1415 pj_uint32_t total_loss; 1416 1331 pj_time_val now; 1332 1333 pj_gettimeofday(&now); 1417 1334 1418 1335 /* Print duration */ 1419 1336 if (inv->state >= PJSIP_INV_STATE_CONFIRMED) { 1420 pj_time_val now; 1421 1422 pj_gettimeofday(&now); 1337 1423 1338 PJ_TIME_VAL_SUB(now, call->connect_time); 1424 1339 … … 1489 1404 good_number(ipbps, (audio->bytes_per_frame+32) * audio->clock_rate / audio->samples_per_frame)); 1490 1405 1491 total_loss = (audio->rtcp.rtcp_pkt.rr.total_lost_2 << 16) + 1492 (audio->rtcp.rtcp_pkt.rr.total_lost_1 << 8) + 1493 audio->rtcp.rtcp_pkt.rr.total_lost_0; 1494 1495 printf(" RX total %s packets %sB received (%sB +IP hdr)%s\n" 1496 " pkt discards=%d (%3.1f%%), loss=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" 1497 " loss period min=%dms, avg=%dms, max=%dms%s\n" 1498 " jitter min=%5.3fms, avg=%5.3fms, max=%5.3fms, curr=%5.3f ms%s\n", 1499 good_number(packets, audio->rx_stat.pkt), 1500 good_number(bytes, audio->rx_stat.payload), 1501 good_number(ipbytes, audio->rx_stat.payload + audio->rx_stat.pkt * 32), 1406 if (audio->rtcp.stat.rx.update_cnt == 0) 1407 strcpy(last_update, "never"); 1408 else { 1409 pj_gettimeofday(&now); 1410 PJ_TIME_VAL_SUB(now, audio->rtcp.stat.rx.update); 1411 sprintf(last_update, "%02dh:%02dm:%02d.%03ds ago", 1412 now.sec / 3600, 1413 (now.sec % 3600) / 60, 1414 now.sec % 60, 1415 now.msec); 1416 } 1417 1418 printf(" RX stat last update: %s\n" 1419 " total %s packets %sB received (%sB +IP hdr)%s\n" 1420 " pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" 1421 " loss period min=%5.3fms, avg=%5.3fms, max=%5.3fms, last=%5.3f%s\n" 1422 " jitter min=%5.3fms, avg=%5.3fms, max=%5.3fms, last=%5.3fms%s\n", 1423 last_update, 1424 good_number(packets, audio->rtcp.stat.rx.pkt), 1425 good_number(bytes, audio->rtcp.stat.rx.bytes), 1426 good_number(ipbytes, audio->rtcp.stat.rx.bytes + audio->rtcp.stat.rx.pkt * 32), 1502 1427 "", 1503 audio->rx_stat.discard, 1504 audio->rx_stat.discard * 100.0 / audio->rx_stat.pkt, 1505 total_loss, 1506 total_loss * 100.0 / audio->rx_stat.pkt, 1507 0, 0.0, 1428 audio->rtcp.stat.rx.loss, 1429 audio->rtcp.stat.rx.loss * 100.0 / audio->rtcp.stat.rx.pkt, 1430 audio->rtcp.stat.rx.dup, 1431 audio->rtcp.stat.rx.dup * 100.0 / audio->rtcp.stat.rx.pkt, 1432 audio->rtcp.stat.rx.reorder, 1433 audio->rtcp.stat.rx.reorder * 100.0 / audio->rtcp.stat.rx.pkt, 1508 1434 "", 1509 -1, -1, -1, 1435 audio->rtcp.stat.rx.loss_period.min / 1000.0, 1436 audio->rtcp.stat.rx.loss_period.avg / 1000.0, 1437 audio->rtcp.stat.rx.loss_period.max / 1000.0, 1438 audio->rtcp.stat.rx.loss_period.last / 1000.0, 1510 1439 "", 1511 (audio->rx_stat.rtcp_cnt? audio->rx_stat.jitter_min_us/1000.0 : -1.),1512 (audio->rx_stat.rtcp_cnt? audio->rx_stat.jitter_avg_us/1000.0 : -1.),1513 (audio->rx_stat.rtcp_cnt? audio->rx_stat.jitter_max_us/1000.0 : -1.),1514 (audio->rx_stat.rtcp_cnt? pj_ntohl(audio->rtcp.rtcp_pkt.rr.jitter)*1000.0/audio->clock_rate : -1.),1440 audio->rtcp.stat.rx.jitter.min / 1000.0, 1441 audio->rtcp.stat.rx.jitter.avg / 1000.0, 1442 audio->rtcp.stat.rx.jitter.max / 1000.0, 1443 audio->rtcp.stat.rx.jitter.last / 1000.0, 1515 1444 "" 1516 1445 ); 1517 1446 1518 1447 1519 total_loss = (audio->rem_rtcp.rr.total_lost_2 << 16) + 1520 (audio->rem_rtcp.rr.total_lost_1 << 8) + 1521 audio->rem_rtcp.rr.total_lost_0; 1522 1523 printf(" TX total %s packets %sB sent (%sB +IP hdr)%s\n" 1524 " pkt discards=%d (%3.1f%%), loss=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" 1525 " loss period min=%dms, avg=%dms, max=%dms%s\n" 1526 " jitter min=%5.3fms, avg=%5.3fms, max=%5.3fms, curr=%5.3f ms%s\n", 1527 good_number(packets, audio->tx_stat.pkt), 1528 good_number(bytes, audio->tx_stat.payload), 1529 good_number(ipbytes, audio->tx_stat.payload + audio->tx_stat.pkt * 32), 1448 if (audio->rtcp.stat.tx.update_cnt == 0) 1449 strcpy(last_update, "never"); 1450 else { 1451 pj_gettimeofday(&now); 1452 PJ_TIME_VAL_SUB(now, audio->rtcp.stat.tx.update); 1453 sprintf(last_update, "%02dh:%02dm:%02d.%03ds ago", 1454 now.sec / 3600, 1455 (now.sec % 3600) / 60, 1456 now.sec % 60, 1457 now.msec); 1458 } 1459 1460 printf(" TX stat last update: %s\n" 1461 " total %s packets %sB received (%sB +IP hdr)%s\n" 1462 " pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" 1463 " loss period min=%5.3fms, avg=%5.3fms, max=%5.3fms, last=%5.3f%s\n" 1464 " jitter min=%5.3fms, avg=%5.3fms, max=%5.3fms, last=%5.3fms%s\n", 1465 last_update, 1466 good_number(packets, audio->rtcp.stat.tx.pkt), 1467 good_number(bytes, audio->rtcp.stat.tx.bytes), 1468 good_number(ipbytes, audio->rtcp.stat.tx.bytes + audio->rtcp.stat.tx.pkt * 32), 1530 1469 "", 1531 audio->tx_stat.discard, 1532 audio->tx_stat.discard * 100.0 / audio->tx_stat.pkt, 1533 total_loss, 1534 total_loss * 100.0 / audio->tx_stat.pkt, 1535 0, 0.0, 1470 audio->rtcp.stat.tx.loss, 1471 audio->rtcp.stat.tx.loss * 100.0 / audio->rtcp.stat.tx.pkt, 1472 audio->rtcp.stat.tx.dup, 1473 audio->rtcp.stat.tx.dup * 100.0 / audio->rtcp.stat.tx.pkt, 1474 audio->rtcp.stat.tx.reorder, 1475 audio->rtcp.stat.tx.reorder * 100.0 / audio->rtcp.stat.tx.pkt, 1536 1476 "", 1537 -1, -1, -1, 1477 audio->rtcp.stat.tx.loss_period.min / 1000.0, 1478 audio->rtcp.stat.tx.loss_period.avg / 1000.0, 1479 audio->rtcp.stat.tx.loss_period.max / 1000.0, 1480 audio->rtcp.stat.tx.loss_period.last / 1000.0, 1538 1481 "", 1539 (audio->tx_stat.rtcp_cnt? audio->tx_stat.jitter_min_us/1000.0 : -1.),1540 (audio->tx_stat.rtcp_cnt? audio->tx_stat.jitter_avg_us/1000.0 : -1.),1541 (audio->tx_stat.rtcp_cnt? audio->tx_stat.jitter_max_us/1000.0 : -1.),1542 (audio->tx_stat.rtcp_cnt? pj_ntohl(audio->rem_rtcp.rr.jitter)*1000.0/audio->clock_rate : -1.),1482 audio->rtcp.stat.tx.jitter.min / 1000.0, 1483 audio->rtcp.stat.tx.jitter.avg / 1000.0, 1484 audio->rtcp.stat.tx.jitter.max / 1000.0, 1485 audio->rtcp.stat.tx.jitter.last / 1000.0, 1543 1486 "" 1544 1487 ); 1545 1488 1546 printf(" End to end delay: %5.3f ms\n", 1547 audio->rtcp.rtt_us / 1000.0); 1489 1490 printf(" RTT min=%5.3fms, avg=%5.3fms, max=%5.3fms, last=%5.3fms%s\n", 1491 audio->rtcp.stat.rtt.min / 1000.0, 1492 audio->rtcp.stat.rtt.avg / 1000.0, 1493 audio->rtcp.stat.rtt.max / 1000.0, 1494 audio->rtcp.stat.rtt.last / 1000.0, 1495 "" 1496 ); 1548 1497 1549 1498 } -
pjproject/trunk/pjsip/src/pjsua-lib/pjsua_settings.c
r360 r390 648 648 649 649 for (i=0; i<info.stream_cnt; ++i) { 650 pjmedia_ stream_stat strm_stat;650 pjmedia_rtcp_stat stat; 651 651 const char *rem_addr; 652 652 int rem_port; 653 653 const char *dir; 654 char stxpkt[10], stxoct[10], srxpkt[10], srxoct[10]; 655 656 pjmedia_session_get_stream_stat(session, i, &strm_stat); 654 char last_update[40]; 655 char packets[16], bytes[16], ipbytes[16]; 656 pj_time_val now; 657 658 pjmedia_session_get_stream_stat(session, i, &stat); 657 659 rem_addr = pj_inet_ntoa(info.stream_info[i].rem_addr.sin_addr); 658 660 rem_port = pj_ntohs(info.stream_info[i].rem_addr.sin_port); … … 677 679 dir, 678 680 rem_addr, rem_port)); 681 682 if (stat.rx.update_cnt == 0) 683 strcpy(last_update, "never"); 684 else { 685 pj_gettimeofday(&now); 686 PJ_TIME_VAL_SUB(now, stat.rx.update); 687 sprintf(last_update, "%02dh:%02dm:%02d.%03ds ago", 688 now.sec / 3600, 689 (now.sec % 3600) / 60, 690 now.sec % 60, 691 now.msec); 692 } 693 679 694 PJ_LOG(3,(THIS_FILE, 680 "%s tx{pt=%d,pkt=%s,oct=%s} rx{pt=%d,pkt=%s,oct=%s}", 681 " ", 682 info.stream_info[i].tx_pt, 683 good_number(stxpkt, strm_stat.enc.pkt), 684 good_number(stxoct, strm_stat.enc.bytes), 685 info.stream_info[i].fmt.pt, 686 good_number(srxpkt, strm_stat.dec.pkt), 687 good_number(srxoct, strm_stat.dec.bytes))); 695 " RX pt=%d, stat last update: %s\n" 696 " total %s packets %sB received (%sB +IP hdr)%s\n" 697 " pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" 698 " (msec) min avg max last\n" 699 " loss period: %7.3f %7.3f %7.3f %7.3f%s\n" 700 " jitter : %7.3f %7.3f %7.3f %7.3f%s", 701 info.stream_info[i].fmt.pt, 702 last_update, 703 good_number(packets, stat.rx.pkt), 704 good_number(bytes, stat.rx.bytes), 705 good_number(ipbytes, stat.rx.bytes + stat.rx.pkt * 32), 706 "", 707 stat.rx.loss, 708 stat.rx.loss * 100.0 / stat.rx.pkt, 709 stat.rx.dup, 710 stat.rx.dup * 100.0 / stat.rx.pkt, 711 stat.rx.reorder, 712 stat.rx.reorder * 100.0 / stat.rx.pkt, 713 "", 714 stat.rx.loss_period.min / 1000.0, 715 stat.rx.loss_period.avg / 1000.0, 716 stat.rx.loss_period.max / 1000.0, 717 stat.rx.loss_period.last / 1000.0, 718 "", 719 stat.rx.jitter.min / 1000.0, 720 stat.rx.jitter.avg / 1000.0, 721 stat.rx.jitter.max / 1000.0, 722 stat.rx.jitter.last / 1000.0, 723 "" 724 )); 725 726 727 if (stat.tx.update_cnt == 0) 728 strcpy(last_update, "never"); 729 else { 730 pj_gettimeofday(&now); 731 PJ_TIME_VAL_SUB(now, stat.tx.update); 732 sprintf(last_update, "%02dh:%02dm:%02d.%03ds ago", 733 now.sec / 3600, 734 (now.sec % 3600) / 60, 735 now.sec % 60, 736 now.msec); 737 } 738 739 PJ_LOG(3,(THIS_FILE, 740 " TX pt=%d, stat last update: %s\n" 741 " total %s packets %sB received (%sB +IP hdr)%s\n" 742 " pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n" 743 " (msec) min avg max last\n" 744 " loss period: %7.3f %7.3f %7.3f %7.3f%s\n" 745 " jitter : %7.3f %7.3f %7.3f %7.3f%s", 746 info.stream_info[i].tx_pt, 747 last_update, 748 good_number(packets, stat.tx.pkt), 749 good_number(bytes, stat.tx.bytes), 750 good_number(ipbytes, stat.tx.bytes + stat.tx.pkt * 32), 751 "", 752 stat.tx.loss, 753 stat.tx.loss * 100.0 / stat.tx.pkt, 754 stat.tx.dup, 755 stat.tx.dup * 100.0 / stat.tx.pkt, 756 stat.tx.reorder, 757 stat.tx.reorder * 100.0 / stat.tx.pkt, 758 "", 759 stat.tx.loss_period.min / 1000.0, 760 stat.tx.loss_period.avg / 1000.0, 761 stat.tx.loss_period.max / 1000.0, 762 stat.tx.loss_period.last / 1000.0, 763 "", 764 stat.tx.jitter.min / 1000.0, 765 stat.tx.jitter.avg / 1000.0, 766 stat.tx.jitter.max / 1000.0, 767 stat.tx.jitter.last / 1000.0, 768 "" 769 )); 770 771 772 PJ_LOG(3,(THIS_FILE, 773 " RTT msec : %7.3f %7.3f %7.3f %7.3f%s", 774 stat.rtt.min / 1000.0, 775 stat.rtt.avg / 1000.0, 776 stat.rtt.max / 1000.0, 777 stat.rtt.last / 1000.0, 778 "" 779 )); 688 780 689 781 } … … 713 805 714 806 /* Dump all invite sessions: */ 715 if (detail) { 716 PJ_LOG(3,(THIS_FILE, "Dumping invite sessions:")); 717 718 if (pjsua.call_cnt == 0) { 719 720 PJ_LOG(3,(THIS_FILE, " - no sessions -")); 721 722 } else { 723 int i; 724 725 for (i=0; i<pjsua.max_calls; ++i) { 726 727 if (pjsua.calls[i].inv == NULL) 728 continue; 729 730 print_call(" ", i, buf, sizeof(buf)); 731 PJ_LOG(3,(THIS_FILE, "%s", buf)); 732 733 if (pjsua.calls[i].session) 734 dump_media_session(pjsua.calls[i].session); 735 } 807 PJ_LOG(3,(THIS_FILE, "Dumping invite sessions:")); 808 809 if (pjsua.call_cnt == 0) { 810 811 PJ_LOG(3,(THIS_FILE, " - no sessions -")); 812 813 } else { 814 int i; 815 816 for (i=0; i<pjsua.max_calls; ++i) { 817 818 if (pjsua.calls[i].inv == NULL) 819 continue; 820 821 print_call(" ", i, buf, sizeof(buf)); 822 PJ_LOG(3,(THIS_FILE, "%s", buf)); 823 824 if (pjsua.calls[i].session) 825 dump_media_session(pjsua.calls[i].session); 736 826 } 737 827 }
Note: See TracChangeset
for help on using the changeset viewer.