Changeset 3664 for pjproject/trunk/pjmedia/src/pjmedia/stream.c
- Timestamp:
- Jul 19, 2011 3:42:28 AM (13 years ago)
- Location:
- pjproject/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk
- Property svn:mergeinfo changed
-
pjproject/trunk/pjmedia/src/pjmedia/stream.c
r3553 r3664 23 23 #include <pjmedia/rtcp.h> 24 24 #include <pjmedia/jbuf.h> 25 #include <pjmedia/stream_common.h> 25 26 #include <pj/array.h> 26 27 #include <pj/assert.h> … … 65 66 #endif 66 67 68 #ifndef PJMEDIA_STREAM_SIZE 69 # define PJMEDIA_STREAM_SIZE 1000 70 #endif 71 72 #ifndef PJMEDIA_STREAM_INC 73 # define PJMEDIA_STREAM_INC 1000 74 #endif 67 75 68 76 … … 78 86 unsigned out_pkt_size; /**< Size of output buffer. */ 79 87 void *out_pkt; /**< Output buffer. */ 88 unsigned out_pkt_len; /**< Length of data in buffer. */ 80 89 pjmedia_rtp_session rtp; /**< RTP session. */ 81 90 }; … … 99 108 pjmedia_endpt *endpt; /**< Media endpoint. */ 100 109 pjmedia_codec_mgr *codec_mgr; /**< Codec manager instance. */ 101 110 pjmedia_stream_info si; /**< Creation parameter. */ 102 111 pjmedia_port port; /**< Port interface. */ 103 112 pjmedia_channel *enc; /**< Encoding channel. */ 104 113 pjmedia_channel *dec; /**< Decoding channel. */ 114 115 pj_pool_t *own_pool; /**< Only created if not given */ 105 116 106 117 pjmedia_dir dir; /**< Stream direction. */ … … 178 189 received according to 179 190 'erroneous' definition */ 180 pj_uint32_t rtp_rx_last_ts;/**< Last received RTP timestamp181 for timestamp checking */182 191 unsigned rtp_rx_last_cnt;/**< Nb of frames in last pkt */ 183 192 unsigned rtp_rx_check_cnt; … … 209 218 char *trace_jb_buf; /**< Jitter tracing buffer. */ 210 219 #endif 220 221 pj_uint32_t rtp_rx_last_ts; /**< Last received RTP timestamp*/ 211 222 }; 212 223 … … 472 483 pj_mutex_lock( stream->jb_mutex ); 473 484 474 samples_required = stream->port.info.samples_per_frame;485 samples_required = PJMEDIA_PIA_SPF(&stream->port.info); 475 486 samples_per_frame = stream->codec_param.info.frm_ptime * 476 487 stream->codec_param.info.clock_rate * … … 505 516 frame_out.buf = p_out_samp + samples_count; 506 517 frame_out.size = frame->size - samples_count*2; 507 status = (*stream->codec->op->recover)(stream->codec,508 509 518 status = pjmedia_codec_recover(stream->codec, 519 frame_out.size, 520 &frame_out); 510 521 511 522 ++stream->plc_cnt; … … 554 565 frame_out.buf = p_out_samp + samples_count; 555 566 frame_out.size = frame->size - samples_count*2; 556 status = (*stream->codec->op->recover)(stream->codec,557 558 567 status = pjmedia_codec_recover(stream->codec, 568 frame_out.size, 569 &frame_out); 559 570 if (status != PJ_SUCCESS) 560 571 break; … … 609 620 frame_out.buf = p_out_samp + samples_count; 610 621 frame_out.size = frame->size - samples_count*2; 611 status = (*stream->codec->op->recover)(stream->codec,612 613 622 status = pjmedia_codec_recover(stream->codec, 623 frame_out.size, 624 &frame_out); 614 625 if (status != PJ_SUCCESS) 615 626 break; … … 660 671 frame_out.buf = p_out_samp + samples_count; 661 672 frame_out.size = frame->size - samples_count*BYTES_PER_SAMPLE; 662 status = stream->codec->op->decode( stream->codec, &frame_in,663 673 status = pjmedia_codec_decode( stream->codec, &frame_in, 674 frame_out.size, &frame_out); 664 675 if (status != 0) { 665 676 LOGERR_((port->info.name.ptr, "codec decode() error", … … 726 737 */ 727 738 728 samples_required = stream->port.info.samples_per_frame;739 samples_required = PJMEDIA_PIA_SPF(&stream->port.info); 729 740 samples_per_frame = stream->codec_param.info.frm_ptime * 730 741 stream->codec_param.info.clock_rate * … … 764 775 frame_in.type = PJMEDIA_FRAME_TYPE_AUDIO; 765 776 766 status = stream->codec->op->decode( stream->codec, &frame_in,767 777 status = pjmedia_codec_decode( stream->codec, &frame_in, 778 0, frame); 768 779 if (status != PJ_SUCCESS) { 769 780 LOGERR_((port->info.name.ptr, "codec decode() error", … … 791 802 status = PJ_SUCCESS; 792 803 if (stream->codec->op->recover) { 793 status = (*stream->codec->op->recover)(stream->codec, 794 0, frame); 804 status = pjmedia_codec_recover(stream->codec, 0, frame); 795 805 } 796 806 … … 877 887 } 878 888 879 digit->duration += stream->port.info.samples_per_frame;889 digit->duration += PJMEDIA_PIA_SPF(&stream->port.info); 880 890 881 891 event->event = (pj_uint8_t)digit->event; … … 1088 1098 /* How many samples are needed */ 1089 1099 count = stream->codec_param.info.enc_ptime * 1090 stream->port.info.clock_rate/ 1000;1100 PJMEDIA_PIA_SRATE(&stream->port.info) / 1000; 1091 1101 1092 1102 /* See if we have enough samples */ … … 1111 1121 */ 1112 1122 static pj_status_t put_frame_imp( pjmedia_port *port, 1113 constpjmedia_frame *frame )1123 pjmedia_frame *frame ) 1114 1124 { 1115 1125 pjmedia_stream *stream = (pjmedia_stream*) port->port_data.pdata; … … 1152 1162 ts_len = (frame->size >> 1) / stream->codec_param.info.channel_cnt; 1153 1163 else if (frame->type == PJMEDIA_FRAME_TYPE_EXTENDED) 1154 ts_len = stream->port.info.samples_per_frame /1155 stream->port.info.channel_count;1164 ts_len = PJMEDIA_PIA_SPF(&stream->port.info) / 1165 PJMEDIA_PIA_CCNT(&stream->port.info); 1156 1166 else 1157 1167 ts_len = 0; … … 1220 1230 } else if (frame->type == PJMEDIA_FRAME_TYPE_AUDIO && 1221 1231 frame->buf == NULL && 1222 stream->port.info.f ormat.id == PJMEDIA_FORMAT_L16 &&1232 stream->port.info.fmt.id == PJMEDIA_FORMAT_L16 && 1223 1233 (stream->dir & PJMEDIA_DIR_ENCODING) && 1224 1234 stream->codec_param.info.frm_ptime * … … 1238 1248 1239 1249 /* Encode! */ 1240 status = stream->codec->op->encode( stream->codec, &silence_frame,1241 1242 1243 1250 status = pjmedia_codec_encode( stream->codec, &silence_frame, 1251 channel->out_pkt_size - 1252 sizeof(pjmedia_rtp_hdr), 1253 &frame_out); 1244 1254 if (status != PJ_SUCCESS) { 1245 1255 LOGERR_((stream->port.info.name.ptr, … … 1262 1272 { 1263 1273 /* Encode! */ 1264 status = stream->codec->op->encode( stream->codec, frame,1265 1266 1267 1274 status = pjmedia_codec_encode( stream->codec, frame, 1275 channel->out_pkt_size - 1276 sizeof(pjmedia_rtp_hdr), 1277 &frame_out); 1268 1278 if (status != PJ_SUCCESS) { 1269 1279 LOGERR_((stream->port.info.name.ptr, … … 1363 1373 */ 1364 1374 static pj_status_t put_frame( pjmedia_port *port, 1365 constpjmedia_frame *frame )1375 pjmedia_frame *frame ) 1366 1376 { 1367 1377 pjmedia_stream *stream = (pjmedia_stream*) port->port_data.pdata; … … 1411 1421 if (stream->vad_enabled != stream->codec_param.setting.vad && 1412 1422 (stream->tx_duration - stream->ts_vad_disabled) > 1413 stream->port.info.clock_rate * PJMEDIA_STREAM_VAD_SUSPEND_MSEC / 1000) 1423 PJMEDIA_PIA_SRATE(&stream->port.info) * 1424 PJMEDIA_STREAM_VAD_SUSPEND_MSEC / 1000) 1414 1425 { 1415 1426 stream->codec_param.setting.vad = stream->vad_enabled; 1416 stream->codec->op->modify(stream->codec, &stream->codec_param);1427 pjmedia_codec_modify(stream->codec, &stream->codec_param); 1417 1428 PJ_LOG(4,(stream->port.info.name.ptr,"VAD re-enabled")); 1418 1429 } … … 1574 1585 unsigned payloadlen; 1575 1586 pjmedia_rtp_status seq_st; 1576 pj_bool_t check_pt;1577 1587 pj_status_t status; 1578 1588 pj_bool_t pkt_discarded = PJ_FALSE; … … 1604 1614 * the incoming packet. 1605 1615 */ 1606 check_pt = (hdr->pt != stream->rx_event_pt) && PJMEDIA_STREAM_CHECK_RTP_PT; 1607 pjmedia_rtp_session_update2(&channel->rtp, hdr, &seq_st, check_pt); 1608 #if !PJMEDIA_STREAM_CHECK_RTP_PT 1609 if (!check_pt && hdr->pt != channel->rtp.out_pt && 1610 hdr->pt != stream->rx_event_pt) 1611 { 1612 seq_st.status.flag.badpt = 1; 1613 } 1614 #endif 1616 pjmedia_rtp_session_update2(&channel->rtp, hdr, &seq_st, 1617 hdr->pt != stream->rx_event_pt); 1615 1618 if (seq_st.status.value) { 1616 1619 TRC_ ((stream->port.info.name.ptr, … … 1672 1675 status = pjmedia_jbuf_reset(stream->jb); 1673 1676 PJ_LOG(4,(stream->port.info.name.ptr, "Jitter buffer reset")); 1674 1675 1677 } else { 1676 1678 /* … … 1689 1691 1690 1692 /* Parse the payload. */ 1691 status = (*stream->codec->op->parse)(stream->codec, 1692 (void*)payload, 1693 payloadlen, 1694 &ts, 1695 &count, 1696 frames); 1693 status = pjmedia_codec_parse(stream->codec, (void*)payload, 1694 payloadlen, &ts, &count, frames); 1697 1695 if (status != PJ_SUCCESS) { 1698 1696 LOGERR_((stream->port.info.name.ptr, … … 1722 1720 1723 1721 /* Calculate actual frame timestamp span */ 1724 frm_ts_span = stream->port.info.samples_per_frame/1722 frm_ts_span = PJMEDIA_PIA_SPF(&stream->port.info) / 1725 1723 stream->codec_param.setting.frm_per_pkt/ 1726 stream->port.info.channel_count;1724 PJMEDIA_PIA_CCNT(&stream->port.info); 1727 1725 1728 1726 /* Get remote frame timestamp span */ … … 1896 1894 /* Allocate buffer for outgoing packet. */ 1897 1895 1898 channel->out_pkt_size = sizeof(pjmedia_rtp_hdr) + 1899 stream->codec_param.info.max_bps * 1900 PJMEDIA_MAX_FRAME_DURATION_MS / 1901 8 / 1000; 1902 1903 if (channel->out_pkt_size > PJMEDIA_MAX_MTU) 1904 channel->out_pkt_size = PJMEDIA_MAX_MTU; 1896 if (param->type == PJMEDIA_TYPE_AUDIO) { 1897 channel->out_pkt_size = sizeof(pjmedia_rtp_hdr) + 1898 stream->codec_param.info.max_bps * 1899 PJMEDIA_MAX_FRAME_DURATION_MS / 1900 8 / 1000; 1901 if (channel->out_pkt_size > PJMEDIA_MAX_MTU - 1902 PJMEDIA_STREAM_RESV_PAYLOAD_LEN) 1903 { 1904 channel->out_pkt_size = PJMEDIA_MAX_MTU - 1905 PJMEDIA_STREAM_RESV_PAYLOAD_LEN; 1906 } 1907 } else { 1908 return PJ_ENOTSUP; 1909 } 1905 1910 1906 1911 /* It should big enough to hold (minimally) RTCP SR with an SDES. */ … … 1956 1961 pj_str_t name; 1957 1962 unsigned jb_init, jb_max, jb_min_pre, jb_max_pre, len; 1963 pjmedia_audio_format_detail *afd; 1964 pj_pool_t *own_pool = NULL; 1958 1965 char *p; 1959 1966 pj_status_t status; 1960 1967 1961 PJ_ASSERT_RETURN(pool && info && p_stream, PJ_EINVAL); 1962 1968 PJ_ASSERT_RETURN(endpt && info && p_stream, PJ_EINVAL); 1969 1970 if (pool == NULL) { 1971 own_pool = pjmedia_endpt_create_pool( endpt, "strm%p", 1972 PJMEDIA_STREAM_SIZE, 1973 PJMEDIA_STREAM_INC); 1974 PJ_ASSERT_RETURN(own_pool != NULL, PJ_ENOMEM); 1975 pool = own_pool; 1976 } 1963 1977 1964 1978 /* Allocate the media stream: */ … … 1966 1980 stream = PJ_POOL_ZALLOC_T(pool, pjmedia_stream); 1967 1981 PJ_ASSERT_RETURN(stream != NULL, PJ_ENOMEM); 1982 stream->own_pool = own_pool; 1983 pj_memcpy(&stream->si, info, sizeof(*info)); 1968 1984 1969 1985 /* Init stream/port name */ … … 1975 1991 */ 1976 1992 pjmedia_port_info_init(&stream->port.info, &name, 1977 PJMEDIA_PORT_SIGNATURE('S', 'T', 'R', 'M'),1993 PJMEDIA_SIG_PORT_STREAM, 1978 1994 info->fmt.clock_rate, info->fmt.channel_cnt, 1979 1995 16, 80); 1996 afd = pjmedia_format_get_audio_format_detail(&stream->port.info.fmt, 1); 1980 1997 1981 1998 /* Init port. */ 1982 1999 1983 pj_strdup(pool, &stream->port.info.encoding_name, &info->fmt.encoding_name); 1984 stream->port.info.clock_rate = info->fmt.clock_rate; 1985 stream->port.info.channel_count = info->fmt.channel_cnt; 2000 //No longer there in 2.0 2001 //pj_strdup(pool, &stream->port.info.encoding_name, &info->fmt.encoding_name); 2002 afd->clock_rate = info->fmt.clock_rate; 2003 afd->channel_count = info->fmt.channel_cnt; 1986 2004 stream->port.port_data.pdata = stream; 1987 2005 … … 2049 2067 2050 2068 /* Open the codec. */ 2051 status = stream->codec->op->open(stream->codec, &stream->codec_param);2069 status = pjmedia_codec_open(stream->codec, &stream->codec_param); 2052 2070 if (status != PJ_SUCCESS) 2053 2071 goto err_cleanup; 2054 2072 2055 2073 /* Set additional info and callbacks. */ 2056 stream->port.info.bits_per_sample = 16; 2057 stream->port.info.samples_per_frame = info->fmt.clock_rate * 2058 stream->codec_param.info.channel_cnt * 2059 stream->codec_param.info.frm_ptime * 2060 stream->codec_param.setting.frm_per_pkt / 2061 1000; 2062 stream->port.info.format.id = stream->codec_param.info.fmt_id; 2074 afd->bits_per_sample = 16; 2075 afd->frame_time_usec = stream->codec_param.info.frm_ptime * 2076 stream->codec_param.setting.frm_per_pkt * 1000; 2077 stream->port.info.fmt.id = stream->codec_param.info.fmt_id; 2063 2078 if (stream->codec_param.info.fmt_id == PJMEDIA_FORMAT_L16) { 2064 2079 /* Raw format */ 2065 stream->port.info.bytes_per_frame = stream->port.info.samples_per_frame * 2066 stream->port.info.bits_per_sample / 8; 2080 afd->avg_bps = afd->max_bps = afd->clock_rate * 2081 afd->bits_per_sample / 8; 2082 2067 2083 2068 2084 stream->port.put_frame = &put_frame; … … 2070 2086 } else { 2071 2087 /* Encoded format */ 2072 stream->port.info.bytes_per_frame = stream->codec_param.info.max_bps * 2073 stream->codec_param.info.frm_ptime * 2074 stream->codec_param.setting.frm_per_pkt / 2075 8 / 1000; 2076 if ((stream->codec_param.info.max_bps * stream->codec_param.info.frm_ptime * 2077 stream->codec_param.setting.frm_per_pkt) % 8000 != 0) 2088 afd->avg_bps = stream->codec_param.info.avg_bps; 2089 afd->max_bps = stream->codec_param.info.max_bps; 2090 2091 /* Not applicable for 2.0 2092 if ((stream->codec_param.info.max_bps * 2093 stream->codec_param.info.frm_ptime * 2094 stream->codec_param.setting.frm_per_pkt) % 8000 != 0) 2078 2095 { 2079 2096 ++stream->port.info.bytes_per_frame; … … 2081 2098 stream->port.info.format.bitrate = stream->codec_param.info.avg_bps; 2082 2099 stream->port.info.format.vad = (stream->codec_param.setting.vad != 0); 2100 */ 2083 2101 2084 2102 stream->port.put_frame = &put_frame; … … 2097 2115 stream->enc_samples_per_pkt = stream->codec_param.info.enc_ptime * 2098 2116 stream->codec_param.info.channel_cnt * 2099 stream->port.info.clock_rate / 1000;2117 afd->clock_rate / 1000; 2100 2118 2101 2119 /* Set buffer size as twice the largest ptime value between … … 2103 2121 */ 2104 2122 2105 ptime = stream->port.info.samples_per_frame * 1000 / 2106 stream->port.info.clock_rate; 2123 ptime = afd->frame_time_usec / 1000; 2107 2124 2108 2125 if (stream->codec_param.info.enc_ptime > ptime) … … 2115 2132 2116 2133 /* Allocate buffer */ 2117 stream->enc_buf_size = stream->port.info.clock_rate * ptime / 1000;2134 stream->enc_buf_size = afd->clock_rate * ptime / 1000; 2118 2135 stream->enc_buf = (pj_int16_t*) 2119 2136 pj_pool_alloc(pool, stream->enc_buf_size * 2); 2120 2137 2121 2138 } else { 2122 stream->enc_samples_per_pkt = stream->port.info.samples_per_frame;2139 stream->enc_samples_per_pkt = PJMEDIA_AFD_SPF(afd); 2123 2140 } 2124 2141 … … 2129 2146 stream->codec_param.setting.vad = 0; 2130 2147 stream->ts_vad_disabled = 0; 2131 stream->codec->op->modify(stream->codec, &stream->codec_param);2148 pjmedia_codec_modify(stream->codec, &stream->codec_param); 2132 2149 PJ_LOG(4,(stream->port.info.name.ptr,"VAD temporarily disabled")); 2133 2150 } … … 2153 2170 stream->rtp_tx_ts_len_per_pkt = stream->enc_samples_per_pkt / 2154 2171 stream->codec_param.info.channel_cnt; 2155 stream->rtp_rx_ts_len_per_frame = stream->port.info.samples_per_frame/2172 stream->rtp_rx_ts_len_per_frame = PJMEDIA_AFD_SPF(afd) / 2156 2173 stream->codec_param.setting.frm_per_pkt / 2157 2174 stream->codec_param.info.channel_cnt; … … 2227 2244 rtcp_setting.rtp_ts_base = pj_ntohl(stream->enc->rtp.out_hdr.ts); 2228 2245 rtcp_setting.clock_rate = info->fmt.clock_rate; 2229 rtcp_setting.samples_per_frame = stream->port.info.samples_per_frame;2246 rtcp_setting.samples_per_frame = PJMEDIA_AFD_SPF(afd); 2230 2247 2231 2248 #if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG!=0) … … 2433 2450 2434 2451 if (stream->codec) { 2435 stream->codec->op->close(stream->codec);2452 pjmedia_codec_close(stream->codec); 2436 2453 pjmedia_codec_mgr_dealloc_codec(stream->codec_mgr, stream->codec); 2437 2454 stream->codec = NULL; … … 2456 2473 #endif 2457 2474 2475 if (stream->own_pool) { 2476 pj_pool_t *pool = stream->own_pool; 2477 stream->own_pool = NULL; 2478 pj_pool_release(pool); 2479 } 2458 2480 return PJ_SUCCESS; 2459 2481 } … … 2516 2538 } 2517 2539 2540 2541 PJ_DEF(pj_status_t) pjmedia_stream_get_info( const pjmedia_stream *stream, 2542 pjmedia_stream_info *info) 2543 { 2544 PJ_ASSERT_RETURN(stream && info, PJ_EINVAL); 2545 2546 pj_memcpy(info, &stream->si, sizeof(pjmedia_stream_info)); 2547 return PJ_SUCCESS; 2548 } 2518 2549 2519 2550 /* … … 2761 2792 } 2762 2793 2794 2795 static const pj_str_t ID_AUDIO = { "audio", 5}; 2796 static const pj_str_t ID_IN = { "IN", 2 }; 2797 static const pj_str_t ID_IP4 = { "IP4", 3}; 2798 static const pj_str_t ID_IP6 = { "IP6", 3}; 2799 static const pj_str_t ID_RTP_AVP = { "RTP/AVP", 7 }; 2800 static const pj_str_t ID_RTP_SAVP = { "RTP/SAVP", 8 }; 2801 //static const pj_str_t ID_SDP_NAME = { "pjmedia", 7 }; 2802 static const pj_str_t ID_RTPMAP = { "rtpmap", 6 }; 2803 static const pj_str_t ID_TELEPHONE_EVENT = { "telephone-event", 15 }; 2804 2805 static const pj_str_t STR_INACTIVE = { "inactive", 8 }; 2806 static const pj_str_t STR_SENDRECV = { "sendrecv", 8 }; 2807 static const pj_str_t STR_SENDONLY = { "sendonly", 8 }; 2808 static const pj_str_t STR_RECVONLY = { "recvonly", 8 }; 2809 2810 2811 /* 2812 * Internal function for collecting codec info and param from the SDP media. 2813 */ 2814 static pj_status_t get_audio_codec_info_param(pjmedia_stream_info *si, 2815 pj_pool_t *pool, 2816 pjmedia_codec_mgr *mgr, 2817 const pjmedia_sdp_media *local_m, 2818 const pjmedia_sdp_media *rem_m) 2819 { 2820 const pjmedia_sdp_attr *attr; 2821 pjmedia_sdp_rtpmap *rtpmap; 2822 unsigned i, fmti, pt = 0; 2823 pj_status_t status; 2824 2825 /* Find the first codec which is not telephone-event */ 2826 for ( fmti = 0; fmti < local_m->desc.fmt_count; ++fmti ) { 2827 if ( !pj_isdigit(*local_m->desc.fmt[fmti].ptr) ) 2828 return PJMEDIA_EINVALIDPT; 2829 pt = pj_strtoul(&local_m->desc.fmt[fmti]); 2830 if ( PJMEDIA_RTP_PT_TELEPHONE_EVENTS == 0 || 2831 pt != PJMEDIA_RTP_PT_TELEPHONE_EVENTS ) 2832 break; 2833 } 2834 if ( fmti >= local_m->desc.fmt_count ) 2835 return PJMEDIA_EINVALIDPT; 2836 2837 /* Get codec info. 2838 * For static payload types, get the info from codec manager. 2839 * For dynamic payload types, MUST get the rtpmap. 2840 */ 2841 if (pt < 96) { 2842 pj_bool_t has_rtpmap; 2843 2844 rtpmap = NULL; 2845 has_rtpmap = PJ_TRUE; 2846 2847 attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP, 2848 &local_m->desc.fmt[fmti]); 2849 if (attr == NULL) { 2850 has_rtpmap = PJ_FALSE; 2851 } 2852 if (attr != NULL) { 2853 status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap); 2854 if (status != PJ_SUCCESS) 2855 has_rtpmap = PJ_FALSE; 2856 } 2857 2858 /* Build codec format info: */ 2859 if (has_rtpmap) { 2860 si->fmt.type = si->type; 2861 si->fmt.pt = pj_strtoul(&local_m->desc.fmt[fmti]); 2862 pj_strdup(pool, &si->fmt.encoding_name, &rtpmap->enc_name); 2863 si->fmt.clock_rate = rtpmap->clock_rate; 2864 2865 #if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0) 2866 /* The session info should have the actual clock rate, because 2867 * this info is used for calculationg buffer size, etc in stream 2868 */ 2869 if (si->fmt.pt == PJMEDIA_RTP_PT_G722) 2870 si->fmt.clock_rate = 16000; 2871 #endif 2872 2873 /* For audio codecs, rtpmap parameters denotes the number of 2874 * channels. 2875 */ 2876 if (si->type == PJMEDIA_TYPE_AUDIO && rtpmap->param.slen) { 2877 si->fmt.channel_cnt = (unsigned) pj_strtoul(&rtpmap->param); 2878 } else { 2879 si->fmt.channel_cnt = 1; 2880 } 2881 2882 } else { 2883 const pjmedia_codec_info *p_info; 2884 2885 status = pjmedia_codec_mgr_get_codec_info( mgr, pt, &p_info); 2886 if (status != PJ_SUCCESS) 2887 return status; 2888 2889 pj_memcpy(&si->fmt, p_info, sizeof(pjmedia_codec_info)); 2890 } 2891 2892 /* For static payload type, pt's are symetric */ 2893 si->tx_pt = pt; 2894 2895 } else { 2896 2897 attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP, 2898 &local_m->desc.fmt[fmti]); 2899 if (attr == NULL) 2900 return PJMEDIA_EMISSINGRTPMAP; 2901 2902 status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap); 2903 if (status != PJ_SUCCESS) 2904 return status; 2905 2906 /* Build codec format info: */ 2907 2908 si->fmt.type = si->type; 2909 si->fmt.pt = pj_strtoul(&local_m->desc.fmt[fmti]); 2910 pj_strdup(pool, &si->fmt.encoding_name, &rtpmap->enc_name); 2911 si->fmt.clock_rate = rtpmap->clock_rate; 2912 2913 /* For audio codecs, rtpmap parameters denotes the number of 2914 * channels. 2915 */ 2916 if (si->type == PJMEDIA_TYPE_AUDIO && rtpmap->param.slen) { 2917 si->fmt.channel_cnt = (unsigned) pj_strtoul(&rtpmap->param); 2918 } else { 2919 si->fmt.channel_cnt = 1; 2920 } 2921 2922 /* Determine payload type for outgoing channel, by finding 2923 * dynamic payload type in remote SDP that matches the answer. 2924 */ 2925 si->tx_pt = 0xFFFF; 2926 for (i=0; i<rem_m->desc.fmt_count; ++i) { 2927 unsigned rpt; 2928 pjmedia_sdp_attr *r_attr; 2929 pjmedia_sdp_rtpmap r_rtpmap; 2930 2931 rpt = pj_strtoul(&rem_m->desc.fmt[i]); 2932 if (rpt < 96) 2933 continue; 2934 2935 r_attr = pjmedia_sdp_media_find_attr(rem_m, &ID_RTPMAP, 2936 &rem_m->desc.fmt[i]); 2937 if (!r_attr) 2938 continue; 2939 2940 if (pjmedia_sdp_attr_get_rtpmap(r_attr, &r_rtpmap) != PJ_SUCCESS) 2941 continue; 2942 2943 if (!pj_stricmp(&rtpmap->enc_name, &r_rtpmap.enc_name) && 2944 rtpmap->clock_rate == r_rtpmap.clock_rate) 2945 { 2946 /* Found matched codec. */ 2947 si->tx_pt = rpt; 2948 2949 break; 2950 } 2951 } 2952 2953 if (si->tx_pt == 0xFFFF) 2954 return PJMEDIA_EMISSINGRTPMAP; 2955 } 2956 2957 2958 /* Now that we have codec info, get the codec param. */ 2959 si->param = PJ_POOL_ALLOC_T(pool, pjmedia_codec_param); 2960 status = pjmedia_codec_mgr_get_default_param(mgr, &si->fmt, 2961 si->param); 2962 2963 /* Get remote fmtp for our encoder. */ 2964 pjmedia_stream_info_parse_fmtp(pool, rem_m, si->tx_pt, 2965 &si->param->setting.enc_fmtp); 2966 2967 /* Get local fmtp for our decoder. */ 2968 pjmedia_stream_info_parse_fmtp(pool, local_m, si->fmt.pt, 2969 &si->param->setting.dec_fmtp); 2970 2971 /* Get the remote ptime for our encoder. */ 2972 attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr, 2973 "ptime", NULL); 2974 if (attr) { 2975 pj_str_t tmp_val = attr->value; 2976 unsigned frm_per_pkt; 2977 2978 pj_strltrim(&tmp_val); 2979 2980 /* Round up ptime when the specified is not multiple of frm_ptime */ 2981 frm_per_pkt = (pj_strtoul(&tmp_val) + 2982 si->param->info.frm_ptime/2) / 2983 si->param->info.frm_ptime; 2984 if (frm_per_pkt != 0) { 2985 si->param->setting.frm_per_pkt = (pj_uint8_t)frm_per_pkt; 2986 } 2987 } 2988 2989 /* Get remote maxptime for our encoder. */ 2990 attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr, 2991 "maxptime", NULL); 2992 if (attr) { 2993 pj_str_t tmp_val = attr->value; 2994 2995 pj_strltrim(&tmp_val); 2996 si->tx_maxptime = pj_strtoul(&tmp_val); 2997 } 2998 2999 /* When direction is NONE (it means SDP negotiation has failed) we don't 3000 * need to return a failure here, as returning failure will cause 3001 * the whole SDP to be rejected. See ticket #: 3002 * http:// 3003 * 3004 * Thanks Alain Totouom 3005 */ 3006 if (status != PJ_SUCCESS && si->dir != PJMEDIA_DIR_NONE) 3007 return status; 3008 3009 3010 /* Get incomming payload type for telephone-events */ 3011 si->rx_event_pt = -1; 3012 for (i=0; i<local_m->attr_count; ++i) { 3013 pjmedia_sdp_rtpmap r; 3014 3015 attr = local_m->attr[i]; 3016 if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0) 3017 continue; 3018 if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS) 3019 continue; 3020 if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) { 3021 si->rx_event_pt = pj_strtoul(&r.pt); 3022 break; 3023 } 3024 } 3025 3026 /* Get outgoing payload type for telephone-events */ 3027 si->tx_event_pt = -1; 3028 for (i=0; i<rem_m->attr_count; ++i) { 3029 pjmedia_sdp_rtpmap r; 3030 3031 attr = rem_m->attr[i]; 3032 if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0) 3033 continue; 3034 if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS) 3035 continue; 3036 if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) { 3037 si->tx_event_pt = pj_strtoul(&r.pt); 3038 break; 3039 } 3040 } 3041 3042 return PJ_SUCCESS; 3043 } 3044 3045 3046 3047 /* 3048 * Create stream info from SDP media line. 3049 */ 3050 PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp( 3051 pjmedia_stream_info *si, 3052 pj_pool_t *pool, 3053 pjmedia_endpt *endpt, 3054 const pjmedia_sdp_session *local, 3055 const pjmedia_sdp_session *remote, 3056 unsigned stream_idx) 3057 { 3058 pjmedia_codec_mgr *mgr; 3059 const pjmedia_sdp_attr *attr; 3060 const pjmedia_sdp_media *local_m; 3061 const pjmedia_sdp_media *rem_m; 3062 const pjmedia_sdp_conn *local_conn; 3063 const pjmedia_sdp_conn *rem_conn; 3064 int rem_af, local_af; 3065 pj_sockaddr local_addr; 3066 pj_status_t status; 3067 3068 3069 /* Validate arguments: */ 3070 PJ_ASSERT_RETURN(pool && si && local && remote, PJ_EINVAL); 3071 PJ_ASSERT_RETURN(stream_idx < local->media_count, PJ_EINVAL); 3072 PJ_ASSERT_RETURN(stream_idx < remote->media_count, PJ_EINVAL); 3073 3074 /* Keep SDP shortcuts */ 3075 local_m = local->media[stream_idx]; 3076 rem_m = remote->media[stream_idx]; 3077 3078 local_conn = local_m->conn ? local_m->conn : local->conn; 3079 if (local_conn == NULL) 3080 return PJMEDIA_SDP_EMISSINGCONN; 3081 3082 rem_conn = rem_m->conn ? rem_m->conn : remote->conn; 3083 if (rem_conn == NULL) 3084 return PJMEDIA_SDP_EMISSINGCONN; 3085 3086 /* Media type must be audio */ 3087 if (pj_stricmp(&local_m->desc.media, &ID_AUDIO) != 0) 3088 return PJMEDIA_EINVALIMEDIATYPE; 3089 3090 /* Get codec manager. */ 3091 mgr = pjmedia_endpt_get_codec_mgr(endpt); 3092 3093 /* Reset: */ 3094 3095 pj_bzero(si, sizeof(*si)); 3096 3097 #if PJMEDIA_HAS_RTCP_XR && PJMEDIA_STREAM_ENABLE_XR 3098 /* Set default RTCP XR enabled/disabled */ 3099 si->rtcp_xr_enabled = PJ_TRUE; 3100 #endif 3101 3102 /* Media type: */ 3103 si->type = PJMEDIA_TYPE_AUDIO; 3104 3105 /* Transport protocol */ 3106 3107 /* At this point, transport type must be compatible, 3108 * the transport instance will do more validation later. 3109 */ 3110 status = pjmedia_sdp_transport_cmp(&rem_m->desc.transport, 3111 &local_m->desc.transport); 3112 if (status != PJ_SUCCESS) 3113 return PJMEDIA_SDPNEG_EINVANSTP; 3114 3115 if (pj_stricmp(&local_m->desc.transport, &ID_RTP_AVP) == 0) { 3116 3117 si->proto = PJMEDIA_TP_PROTO_RTP_AVP; 3118 3119 } else if (pj_stricmp(&local_m->desc.transport, &ID_RTP_SAVP) == 0) { 3120 3121 si->proto = PJMEDIA_TP_PROTO_RTP_SAVP; 3122 3123 } else { 3124 3125 si->proto = PJMEDIA_TP_PROTO_UNKNOWN; 3126 return PJ_SUCCESS; 3127 } 3128 3129 3130 /* Check address family in remote SDP */ 3131 rem_af = pj_AF_UNSPEC(); 3132 if (pj_stricmp(&rem_conn->net_type, &ID_IN)==0) { 3133 if (pj_stricmp(&rem_conn->addr_type, &ID_IP4)==0) { 3134 rem_af = pj_AF_INET(); 3135 } else if (pj_stricmp(&rem_conn->addr_type, &ID_IP6)==0) { 3136 rem_af = pj_AF_INET6(); 3137 } 3138 } 3139 3140 if (rem_af==pj_AF_UNSPEC()) { 3141 /* Unsupported address family */ 3142 return PJ_EAFNOTSUP; 3143 } 3144 3145 /* Set remote address: */ 3146 status = pj_sockaddr_init(rem_af, &si->rem_addr, &rem_conn->addr, 3147 rem_m->desc.port); 3148 if (status != PJ_SUCCESS) { 3149 /* Invalid IP address. */ 3150 return PJMEDIA_EINVALIDIP; 3151 } 3152 3153 /* Check address family of local info */ 3154 local_af = pj_AF_UNSPEC(); 3155 if (pj_stricmp(&local_conn->net_type, &ID_IN)==0) { 3156 if (pj_stricmp(&local_conn->addr_type, &ID_IP4)==0) { 3157 local_af = pj_AF_INET(); 3158 } else if (pj_stricmp(&local_conn->addr_type, &ID_IP6)==0) { 3159 local_af = pj_AF_INET6(); 3160 } 3161 } 3162 3163 if (local_af==pj_AF_UNSPEC()) { 3164 /* Unsupported address family */ 3165 return PJ_SUCCESS; 3166 } 3167 3168 /* Set remote address: */ 3169 status = pj_sockaddr_init(local_af, &local_addr, &local_conn->addr, 3170 local_m->desc.port); 3171 if (status != PJ_SUCCESS) { 3172 /* Invalid IP address. */ 3173 return PJMEDIA_EINVALIDIP; 3174 } 3175 3176 /* Local and remote address family must match */ 3177 if (local_af != rem_af) 3178 return PJ_EAFNOTSUP; 3179 3180 /* Media direction: */ 3181 3182 if (local_m->desc.port == 0 || 3183 pj_sockaddr_has_addr(&local_addr)==PJ_FALSE || 3184 pj_sockaddr_has_addr(&si->rem_addr)==PJ_FALSE || 3185 pjmedia_sdp_media_find_attr(local_m, &STR_INACTIVE, NULL)!=NULL) 3186 { 3187 /* Inactive stream. */ 3188 3189 si->dir = PJMEDIA_DIR_NONE; 3190 3191 } else if (pjmedia_sdp_media_find_attr(local_m, &STR_SENDONLY, NULL)!=NULL) { 3192 3193 /* Send only stream. */ 3194 3195 si->dir = PJMEDIA_DIR_ENCODING; 3196 3197 } else if (pjmedia_sdp_media_find_attr(local_m, &STR_RECVONLY, NULL)!=NULL) { 3198 3199 /* Recv only stream. */ 3200 3201 si->dir = PJMEDIA_DIR_DECODING; 3202 3203 } else { 3204 3205 /* Send and receive stream. */ 3206 3207 si->dir = PJMEDIA_DIR_ENCODING_DECODING; 3208 3209 } 3210 3211 /* No need to do anything else if stream is rejected */ 3212 if (local_m->desc.port == 0) { 3213 return PJ_SUCCESS; 3214 } 3215 3216 /* If "rtcp" attribute is present in the SDP, set the RTCP address 3217 * from that attribute. Otherwise, calculate from RTP address. 3218 */ 3219 attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr, 3220 "rtcp", NULL); 3221 if (attr) { 3222 pjmedia_sdp_rtcp_attr rtcp; 3223 status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp); 3224 if (status == PJ_SUCCESS) { 3225 if (rtcp.addr.slen) { 3226 status = pj_sockaddr_init(rem_af, &si->rem_rtcp, &rtcp.addr, 3227 (pj_uint16_t)rtcp.port); 3228 } else { 3229 pj_sockaddr_init(rem_af, &si->rem_rtcp, NULL, 3230 (pj_uint16_t)rtcp.port); 3231 pj_memcpy(pj_sockaddr_get_addr(&si->rem_rtcp), 3232 pj_sockaddr_get_addr(&si->rem_addr), 3233 pj_sockaddr_get_addr_len(&si->rem_addr)); 3234 } 3235 } 3236 } 3237 3238 if (!pj_sockaddr_has_addr(&si->rem_rtcp)) { 3239 int rtcp_port; 3240 3241 pj_memcpy(&si->rem_rtcp, &si->rem_addr, sizeof(pj_sockaddr)); 3242 rtcp_port = pj_sockaddr_get_port(&si->rem_addr) + 1; 3243 pj_sockaddr_set_port(&si->rem_rtcp, (pj_uint16_t)rtcp_port); 3244 } 3245 3246 3247 /* Get the payload number for receive channel. */ 3248 /* 3249 Previously we used to rely on fmt[0] being the selected codec, 3250 but some UA sends telephone-event as fmt[0] and this would 3251 cause assert failure below. 3252 3253 Thanks Chris Hamilton <chamilton .at. cs.dal.ca> for this patch. 3254 3255 // And codec must be numeric! 3256 if (!pj_isdigit(*local_m->desc.fmt[0].ptr) || 3257 !pj_isdigit(*rem_m->desc.fmt[0].ptr)) 3258 { 3259 return PJMEDIA_EINVALIDPT; 3260 } 3261 3262 pt = pj_strtoul(&local_m->desc.fmt[0]); 3263 pj_assert(PJMEDIA_RTP_PT_TELEPHONE_EVENTS==0 || 3264 pt != PJMEDIA_RTP_PT_TELEPHONE_EVENTS); 3265 */ 3266 3267 /* Get codec info and param */ 3268 status = get_audio_codec_info_param(si, pool, mgr, local_m, rem_m); 3269 3270 /* Leave SSRC to random. */ 3271 si->ssrc = pj_rand(); 3272 3273 /* Set default jitter buffer parameter. */ 3274 si->jb_init = si->jb_max = si->jb_min_pre = si->jb_max_pre = -1; 3275 3276 return status; 3277 }
Note: See TracChangeset
for help on using the changeset viewer.