Changeset 408 for pjproject/trunk/pjmedia/src/pjmedia/stream.c
- Timestamp:
- Apr 24, 2006 11:13:00 PM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia/stream.c
r402 r408 38 38 #define THIS_FILE "stream.c" 39 39 #define ERRLEVEL 1 40 #define TRACE_(expr) stream_perror expr41 #define TRC_(expr) PJ_LOG( 4,expr)40 #define LOGERR_(expr) stream_perror expr 41 #define TRC_(expr) PJ_LOG(5,expr) 42 42 43 43 /** … … 107 107 pj_size_t rtcp_pkt_size; /**< Size of RTCP packet buf. */ 108 108 char rtcp_pkt[512]; /**< RTCP packet buffer. */ 109 pj_uint32_t rtcp_tx_time; /**< RTCP tx time in timestamp */ 109 pj_uint32_t rtcp_last_tx; /**< RTCP tx time in timestamp */ 110 pj_uint32_t rtcp_interval; /**< Interval, in timestamp. */ 110 111 int rtcp_addrlen; /**< Address length. */ 111 112 … … 184 185 channel->pcm_buf_size, &frame_out); 185 186 if (status != 0) { 186 TRACE_((THIS_FILE, "codec decode() error", status));187 LOGERR_((port->info.name.ptr, "codec decode() error", status)); 187 188 188 189 frame->type = PJMEDIA_FRAME_TYPE_NONE; … … 192 193 /* Put in sound buffer. */ 193 194 if (frame_out.size > frame->size) { 194 PJ_LOG(4,(THIS_FILE, "Sound playout buffer truncated %d bytes", 195 PJ_LOG(4,(port->info.name.ptr, 196 "Sound playout buffer truncated %d bytes", 195 197 frame_out.size - frame->size)); 196 198 frame_out.size = frame->size; … … 240 242 241 243 if (stream->tx_dtmf_count) 242 PJ_LOG(5,(THIS_FILE,"Sending DTMF digit id %c", 244 PJ_LOG(5,(stream->port.info.name.ptr, 245 "Sending DTMF digit id %c", 243 246 digitmap[stream->tx_dtmf_buf[0].event])); 244 247 245 248 } else if (duration == 0) { 246 PJ_LOG(5,( THIS_FILE,"Sending DTMF digit id %c",249 PJ_LOG(5,(stream->port.info.name.ptr, "Sending DTMF digit id %c", 247 250 digitmap[digit->event])); 248 251 } … … 252 255 } 253 256 257 254 258 /** 255 * rec_callback()259 * check_tx_rtcp() 256 260 * 257 * This callback is called when the mic device has gathered 258 * enough audio samples. We will encode the audio samples and 259 * send it to remote. 260 */ 261 static pj_status_t put_frame( pjmedia_port *port, 262 const pjmedia_frame *frame ) 263 { 264 pjmedia_stream *stream = port->user_data; 265 pjmedia_channel *channel = stream->enc; 266 pj_status_t status = 0; 267 struct pjmedia_frame frame_out; 268 int ts_len; 269 pj_bool_t has_tx; 270 void *rtphdr; 271 int rtphdrlen; 272 pj_ssize_t sent; 273 274 /* Number of samples in the frame */ 275 ts_len = frame->size / 2; 276 277 /* Init frame_out buffer. */ 278 frame_out.buf = ((char*)channel->out_pkt) + sizeof(pjmedia_rtp_hdr); 279 280 /* Make compiler happy */ 281 frame_out.size = 0; 282 283 /* If we have DTMF digits in the queue, transmit the digits. 284 * Otherwise encode the PCM buffer. 261 * This function is can be called by either put_frame() or get_frame(), 262 * to transmit periodic RTCP SR/RR report. 263 */ 264 static void check_tx_rtcp(pjmedia_stream *stream, pj_uint32_t timestamp) 265 { 266 /* Note that timestamp may represent local or remote timestamp, 267 * depending on whether this function is called from put_frame() 268 * or get_frame(). 285 269 */ 286 if (stream->tx_dtmf_count) { 287 288 has_tx = PJ_TRUE; 289 create_dtmf_payload(stream, &frame_out); 290 291 /* Encapsulate. */ 292 status = pjmedia_rtp_encode_rtp( &channel->rtp, 293 stream->tx_event_pt, 0, 294 frame_out.size, ts_len, 295 (const void**)&rtphdr, 296 &rtphdrlen); 297 298 } else if (frame->type != PJMEDIA_FRAME_TYPE_NONE) { 299 unsigned max_size; 300 301 has_tx = PJ_TRUE; 302 max_size = channel->out_pkt_size - sizeof(pjmedia_rtp_hdr); 303 status = stream->codec->op->encode( stream->codec, frame, 304 max_size, 305 &frame_out); 306 if (status != 0) { 307 TRACE_((THIS_FILE, "Codec encode() error", status)); 308 return status; 309 } 310 311 //printf("p"); fflush(stdout); 312 313 /* Encapsulate. */ 314 status = pjmedia_rtp_encode_rtp( &channel->rtp, 315 channel->pt, 0, 316 frame_out.size, ts_len, 317 (const void**)&rtphdr, 318 &rtphdrlen); 319 } else { 320 321 /* Just update RTP session's timestamp. */ 322 has_tx = PJ_FALSE; 323 status = pjmedia_rtp_encode_rtp( &channel->rtp, 324 0, 0, 325 0, ts_len, 326 (const void**)&rtphdr, 327 &rtphdrlen); 328 329 } 330 331 if (status != PJ_SUCCESS) { 332 TRACE_((THIS_FILE, "RTP encode_rtp() error", status)); 333 return status; 334 } 335 336 /* Check if this is the time to transmit RTCP packet */ 337 if (stream->rtcp_tx_time == 0) { 338 unsigned first_interval; 339 340 first_interval = PJMEDIA_RTCP_INTERVAL + (pj_rand() % 2000); 341 stream->rtcp_tx_time = pj_ntohl(channel->rtp.out_hdr.ts) + 342 first_interval* stream->port.info.sample_rate / 343 1000; 344 } else if (pj_ntohl(channel->rtp.out_hdr.ts) >= stream->rtcp_tx_time) { 270 271 272 if (stream->rtcp_last_tx == 0) { 273 274 stream->rtcp_last_tx = timestamp; 275 276 } else if (timestamp - stream->rtcp_last_tx >= stream->rtcp_interval) { 345 277 346 278 pjmedia_rtcp_pkt *rtcp_pkt; 347 279 pj_ssize_t size; 348 unsigned interval;349 280 int len; 281 pj_status_t status; 350 282 351 283 pjmedia_rtcp_build_rtcp(&stream->rtcp, &rtcp_pkt, &len); … … 359 291 360 292 pj_strerror(status, errmsg, sizeof(errmsg)); 361 PJ_LOG(4,( THIS_FILE, "Error sending RTCP: %s [%d]",293 PJ_LOG(4,(port->info.name.ptr, "Error sending RTCP: %s [%d]", 362 294 errmsg, status)); 363 295 } 364 296 #endif 365 297 366 interval = PJMEDIA_RTCP_INTERVAL + (pj_rand() % 500); 367 stream->rtcp_tx_time = pj_ntohl(channel->rtp.out_hdr.ts) + 368 interval * stream->port.info.sample_rate / 369 1000; 298 stream->rtcp_last_tx = timestamp; 299 } 300 301 } 302 303 304 /** 305 * put_frame() 306 * 307 * This callback is called by upstream component when it has PCM frame 308 * to transmit. This function encodes the PCM frame, pack it into 309 * RTP packet, and transmit to peer. 310 */ 311 static pj_status_t put_frame( pjmedia_port *port, 312 const pjmedia_frame *frame ) 313 { 314 pjmedia_stream *stream = port->user_data; 315 pjmedia_channel *channel = stream->enc; 316 pj_status_t status = 0; 317 struct pjmedia_frame frame_out; 318 int ts_len; 319 pj_bool_t has_tx; 320 void *rtphdr; 321 int rtphdrlen; 322 pj_ssize_t sent; 323 324 /* Number of samples in the frame */ 325 ts_len = frame->size / 2; 326 327 /* Init frame_out buffer. */ 328 frame_out.buf = ((char*)channel->out_pkt) + sizeof(pjmedia_rtp_hdr); 329 330 /* Make compiler happy */ 331 frame_out.size = 0; 332 333 /* If we have DTMF digits in the queue, transmit the digits. 334 * Otherwise encode the PCM buffer. 335 */ 336 if (stream->tx_dtmf_count) { 337 338 has_tx = PJ_TRUE; 339 create_dtmf_payload(stream, &frame_out); 340 341 /* Encapsulate. */ 342 status = pjmedia_rtp_encode_rtp( &channel->rtp, 343 stream->tx_event_pt, 0, 344 frame_out.size, ts_len, 345 (const void**)&rtphdr, 346 &rtphdrlen); 347 348 } else if (frame->type != PJMEDIA_FRAME_TYPE_NONE) { 349 unsigned max_size; 350 351 has_tx = PJ_TRUE; 352 max_size = channel->out_pkt_size - sizeof(pjmedia_rtp_hdr); 353 status = stream->codec->op->encode( stream->codec, frame, 354 max_size, 355 &frame_out); 356 if (status != 0) { 357 LOGERR_((stream->port.info.name.ptr, 358 "Codec encode() error", status)); 359 return status; 360 } 361 362 //printf("p"); fflush(stdout); 363 364 /* Encapsulate. */ 365 status = pjmedia_rtp_encode_rtp( &channel->rtp, 366 channel->pt, 0, 367 frame_out.size, ts_len, 368 (const void**)&rtphdr, 369 &rtphdrlen); 370 } else { 371 372 /* Just update RTP session's timestamp. */ 373 has_tx = PJ_FALSE; 374 status = pjmedia_rtp_encode_rtp( &channel->rtp, 375 0, 0, 376 0, ts_len, 377 (const void**)&rtphdr, 378 &rtphdrlen); 379 380 } 381 382 if (status != PJ_SUCCESS) { 383 LOGERR_((stream->port.info.name.ptr, 384 "RTP encode_rtp() error", status)); 385 return status; 386 } 387 388 /* Check if now is the time to transmit RTCP SR/RR report. 389 * We only do this when stream direction is not "decoding only", because 390 * when it is, check_tx_rtcp() will be handled by get_frame(). 391 */ 392 if (stream->dir != PJMEDIA_DIR_DECODING) { 393 check_tx_rtcp(stream, pj_ntohl(channel->rtp.out_hdr.ts)); 370 394 } 371 395 … … 450 474 /* Ignore unknown event. */ 451 475 if (event->event > 15) { 452 PJ_LOG(5,(THIS_FILE, "Ignored RTP pkt with bad DTMF event %d", 453 event->event)); 476 PJ_LOG(5,(stream->port.info.name.ptr, 477 "Ignored RTP pkt with bad DTMF event %d", 478 event->event)); 454 479 return; 455 480 } 456 481 457 482 /* New event! */ 458 PJ_LOG(5,( THIS_FILE, "Received DTMF digit %c, vol=%d",459 460 483 PJ_LOG(5,(stream->port.info.name.ptr, "Received DTMF digit %c, vol=%d", 484 digitmap[event->event], 485 (event->e_vol & 0x3F))); 461 486 462 487 stream->last_dtmf = event->event; … … 517 542 &hdr, &payload, &payloadlen); 518 543 if (status != PJ_SUCCESS) { 519 TRACE_((THIS_FILE, "RTP decode error", status));544 LOGERR_((stream->port.info.name.ptr, "RTP decode error", status)); 520 545 goto read_next_packet; 521 546 } … … 537 562 */ 538 563 pjmedia_rtp_session_update(&channel->rtp, hdr, &seq_st); 539 if (seq_st.status. flag.bad) {540 TRC_ (( THIS_FILE,541 "RTP s ession_update error: badpt=%d, dup=%d, outorder=%d, "542 " probation=%d, restart=%d",564 if (seq_st.status.value) { 565 TRC_ ((stream->port.info.name.ptr, 566 "RTP status: badpt=%d, badssrc=%d, dup=%d, " 567 "outorder=%d, probation=%d, restart=%d", 543 568 seq_st.status.flag.badpt, 569 seq_st.status.flag.badssrc, 544 570 seq_st.status.flag.dup, 545 571 seq_st.status.flag.outorder, 546 572 seq_st.status.flag.probation, 547 573 seq_st.status.flag.restart)); 574 575 if (seq_st.status.flag.badpt) { 576 PJ_LOG(4,(stream->port.info.name.ptr, 577 "Bad RTP pt %d (expecting %d)", 578 hdr->pt, channel->rtp.out_pt)); 579 } 580 } 581 582 /* Skip bad RTP packet */ 583 if (seq_st.status.flag.bad) 548 584 goto read_next_packet; 549 }550 585 551 586 … … 564 599 stream->rtp_src_cnt = 0; 565 600 566 PJ_LOG(4,(THIS_FILE,"Remote RTP address switched to %s:%d", 601 PJ_LOG(4,(stream->port.info.name.ptr, 602 "Remote RTP address switched to %s:%d", 567 603 pj_inet_ntoa(stream->rtp_src_addr.sin_addr), 568 604 pj_ntohs(stream->rtp_src_addr.sin_port))); … … 571 607 572 608 573 /* Put to jitter buffer. */ 609 610 /* Put "good" packet to jitter buffer, or reset the jitter buffer 611 * when RTP session is restarted. 612 */ 574 613 pj_mutex_lock( stream->jb_mutex ); 575 status = pjmedia_jbuf_put_frame(stream->jb, payload, payloadlen, 576 pj_ntohs(hdr->seq)); 614 if (seq_st.status.flag.restart) { 615 status = pjmedia_jbuf_reset(stream->jb); 616 PJ_LOG(4,(stream->port.info.name.ptr, "Jitter buffer reset")); 617 618 } else { 619 status = pjmedia_jbuf_put_frame(stream->jb, payload, payloadlen, 620 pj_ntohs(hdr->seq)); 621 } 577 622 pj_mutex_unlock( stream->jb_mutex ); 578 623 624 625 /* Check if now is the time to transmit RTCP SR/RR report. 626 * We only do this when stream direction is "decoding only", 627 * because otherwise check_tx_rtcp() will be handled by put_frame() 628 */ 629 if (stream->dir == PJMEDIA_DIR_DECODING) { 630 check_tx_rtcp(stream, pj_ntohl(hdr->ts)); 631 } 632 579 633 if (status != 0) { 580 TRACE_((THIS_FILE, "Jitter buffer put() error", status)); 634 LOGERR_((stream->port.info.name.ptr, "Jitter buffer put() error", 635 status)); 581 636 goto read_next_packet; 582 637 } 638 583 639 584 640 read_next_packet: … … 603 659 604 660 pj_strerror(status, errmsg, sizeof(errmsg)); 605 PJ_LOG(4,(THIS_FILE, "Error reading RTP packet: %s [status=%d]. " 606 "RTP stream thread quitting!", 607 errmsg, status)); 661 PJ_LOG(4,(stream->port.info.name.ptr, 662 "Error reading RTP packet: %s [status=%d]. " 663 "RTP stream thread quitting!", 664 errmsg, status)); 608 665 } 609 666 } … … 644 701 645 702 pj_strerror(status, errmsg, sizeof(errmsg)); 646 PJ_LOG(4,(THIS_FILE, "Error reading RTCP packet: %s [status=%d]", 647 errmsg, status)); 703 PJ_LOG(4,(stream->port.info.name.ptr, 704 "Error reading RTCP packet: %s [status=%d]", 705 errmsg, status)); 648 706 } 649 707 … … 743 801 PJ_ASSERT_RETURN(stream != NULL, PJ_ENOMEM); 744 802 803 /* Init stream/port name */ 804 stream->port.info.name.ptr = pj_pool_alloc(pool, 24); 805 pj_ansi_sprintf(stream->port.info.name.ptr, 806 "strm%p", stream); 807 stream->port.info.name.slen = pj_ansi_strlen(stream->port.info.name.ptr); 808 745 809 /* Init port. */ 746 stream->port.info.name = pj_str("stream");747 810 stream->port.info.signature = ('S'<<3 | 'T'<<2 | 'R'<<1 | 'M'); 748 811 stream->port.info.type = PJMEDIA_TYPE_AUDIO; … … 768 831 stream->rem_rtcp_addr = stream->rem_rtp_addr; 769 832 stream->rem_rtcp_addr.sin_port = pj_htons(rtcp_port); 770 stream->tx_event_pt = info->tx_event_pt; 771 stream->rx_event_pt = info->rx_event_pt; 833 stream->rtcp_interval = (PJMEDIA_RTCP_INTERVAL + (pj_rand() % 8000)) * 834 info->fmt.sample_rate / 1000; 835 836 stream->tx_event_pt = info->tx_event_pt ? info->tx_event_pt : -1; 837 stream->rx_event_pt = info->rx_event_pt ? info->rx_event_pt : -1; 772 838 stream->last_dtmf = -1; 839 773 840 774 841 /* Create mutex to protect jitter buffer: */ … … 813 880 /* Init RTCP session: */ 814 881 815 pjmedia_rtcp_init(&stream->rtcp, info->fmt.sample_rate, 882 pjmedia_rtcp_init(&stream->rtcp, stream->port.info.name.ptr, 883 info->fmt.sample_rate, 816 884 stream->port.info.samples_per_frame, 817 885 info->ssrc); … … 820 888 /* Create jitter buffer: */ 821 889 822 status = pjmedia_jbuf_create(pool, stream->frame_size, 15, 100, 890 status = pjmedia_jbuf_create(pool, &stream->port.info.name, 891 stream->frame_size, 15, 100, 823 892 &stream->jb); 824 893 if (status != PJ_SUCCESS) … … 883 952 /* Success! */ 884 953 *p_stream = stream; 954 955 PJ_LOG(5,(THIS_FILE, "Stream %s created", stream->port.info.name.ptr)); 885 956 return PJ_SUCCESS; 886 957 … … 958 1029 stream->enc->paused = 0; 959 1030 //pjmedia_snd_stream_start(stream->enc->snd_stream); 960 PJ_LOG(4,( THIS_FILE, "Encoder stream started"));1031 PJ_LOG(4,(stream->port.info.name.ptr, "Encoder stream started")); 961 1032 } else { 962 PJ_LOG(4,( THIS_FILE, "Encoder stream paused"));1033 PJ_LOG(4,(stream->port.info.name.ptr, "Encoder stream paused")); 963 1034 } 964 1035 … … 966 1037 stream->dec->paused = 0; 967 1038 //pjmedia_snd_stream_start(stream->dec->snd_stream); 968 PJ_LOG(4,( THIS_FILE, "Decoder stream started"));1039 PJ_LOG(4,(stream->port.info.name.ptr, "Decoder stream started")); 969 1040 } else { 970 PJ_LOG(4,( THIS_FILE, "Decoder stream paused"));1041 PJ_LOG(4,(stream->port.info.name.ptr, "Decoder stream paused")); 971 1042 } 972 1043 … … 998 1069 if ((dir & PJMEDIA_DIR_ENCODING) && stream->enc) { 999 1070 stream->enc->paused = 1; 1000 PJ_LOG(4,( THIS_FILE, "Encoder stream paused"));1071 PJ_LOG(4,(stream->port.info.name.ptr, "Encoder stream paused")); 1001 1072 } 1002 1073 1003 1074 if ((dir & PJMEDIA_DIR_DECODING) && stream->dec) { 1004 1075 stream->dec->paused = 1; 1005 PJ_LOG(4,( THIS_FILE, "Decoder stream paused"));1076 PJ_LOG(4,(stream->port.info.name.ptr, "Decoder stream paused")); 1006 1077 } 1007 1078 … … 1020 1091 if ((dir & PJMEDIA_DIR_ENCODING) && stream->enc) { 1021 1092 stream->enc->paused = 1; 1022 PJ_LOG(4,( THIS_FILE, "Encoder stream resumed"));1093 PJ_LOG(4,(stream->port.info.name.ptr, "Encoder stream resumed")); 1023 1094 } 1024 1095 1025 1096 if ((dir & PJMEDIA_DIR_DECODING) && stream->dec) { 1026 1097 stream->dec->paused = 1; 1027 PJ_LOG(4,( THIS_FILE, "Decoder stream resumed"));1098 PJ_LOG(4,(stream->port.info.name.ptr, "Decoder stream resumed")); 1028 1099 } 1029 1100
Note: See TracChangeset
for help on using the changeset viewer.