summaryrefslogtreecommitdiff
path: root/pjmedia/src/pjmedia/stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjmedia/src/pjmedia/stream.c')
-rw-r--r--pjmedia/src/pjmedia/stream.c104
1 files changed, 86 insertions, 18 deletions
diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c
index 5c7c873..840b06c 100644
--- a/pjmedia/src/pjmedia/stream.c
+++ b/pjmedia/src/pjmedia/stream.c
@@ -1,4 +1,4 @@
-/* $Id: stream.c 4120 2012-05-12 07:18:09Z ming $ */
+/* $Id: stream.c 4336 2013-01-29 08:15:02Z ming $ */
/*
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
@@ -73,6 +73,8 @@
# define PJMEDIA_STREAM_INC 1000
#endif
+/* Number of DTMF E bit transmissions */
+#define DTMF_EBIT_RETRANSMIT_CNT 3
/**
* Media channel.
@@ -94,6 +96,7 @@ struct dtmf
{
int event;
pj_uint32_t duration;
+ int ebit_cnt; /**< # of E bit transmissions */
};
/**
@@ -876,7 +879,7 @@ static pj_status_t get_frame_ext( pjmedia_port *port, pjmedia_frame *frame)
*/
static void create_dtmf_payload(pjmedia_stream *stream,
struct pjmedia_frame *frame_out,
- int *first, int *last)
+ int forced_last, int *first, int *last)
{
pjmedia_rtp_dtmf_event *event;
struct dtmf *digit = &stream->tx_dtmf_buf[0];
@@ -896,25 +899,33 @@ static void create_dtmf_payload(pjmedia_stream *stream,
}
digit->duration += PJMEDIA_PIA_SPF(&stream->port.info);
+ if (digit->duration >= PJMEDIA_DTMF_DURATION)
+ digit->duration = PJMEDIA_DTMF_DURATION;
event->event = (pj_uint8_t)digit->event;
event->e_vol = 10;
event->duration = pj_htons((pj_uint16_t)digit->duration);
+ if (forced_last) {
+ digit->duration = PJMEDIA_DTMF_DURATION;
+ }
if (digit->duration >= PJMEDIA_DTMF_DURATION) {
event->e_vol |= 0x80;
- *last = 1;
- /* Prepare next digit. */
- pj_mutex_lock(stream->jb_mutex);
+ if (++digit->ebit_cnt >= DTMF_EBIT_RETRANSMIT_CNT) {
+ *last = 1;
- pj_array_erase(stream->tx_dtmf_buf, sizeof(stream->tx_dtmf_buf[0]),
- stream->tx_dtmf_count, 0);
- --stream->tx_dtmf_count;
+ /* Prepare next digit. */
+ pj_mutex_lock(stream->jb_mutex);
- pj_mutex_unlock(stream->jb_mutex);
+ pj_array_erase(stream->tx_dtmf_buf, sizeof(stream->tx_dtmf_buf[0]),
+ stream->tx_dtmf_count, 0);
+ --stream->tx_dtmf_count;
+
+ pj_mutex_unlock(stream->jb_mutex);
+ }
}
frame_out->size = 4;
@@ -1217,7 +1228,7 @@ static pj_status_t put_frame_imp( pjmedia_port *port,
if (stream->tx_dtmf_count) {
int first=0, last=0;
- create_dtmf_payload(stream, &frame_out, &first, &last);
+ create_dtmf_payload(stream, &frame_out, 0, &first, &last);
/* Encapsulate into RTP packet. Note that:
* - RTP marker should be set on the beginning of a new event
@@ -1235,7 +1246,9 @@ static pj_status_t put_frame_imp( pjmedia_port *port,
* Increment the RTP timestamp of the RTP session, for next
* RTP packets.
*/
- inc_timestamp = PJMEDIA_DTMF_DURATION - rtp_ts_len;
+ inc_timestamp = PJMEDIA_DTMF_DURATION +
+ ((DTMF_EBIT_RETRANSMIT_CNT-1) * samples_per_frame)
+ - rtp_ts_len;
}
@@ -1765,7 +1778,11 @@ static void on_rx_rtp( void *data,
peer_frm_ts_diff == (frm_ts_span>>1)))
{
if (peer_frm_ts_diff < stream->rtp_rx_ts_len_per_frame)
+ {
stream->rtp_rx_ts_len_per_frame = peer_frm_ts_diff;
+ /* Done, stop the check immediately */
+ stream->rtp_rx_check_cnt = 1;
+ }
if (--stream->rtp_rx_check_cnt == 0) {
PJ_LOG(4, (THIS_FILE, "G722 codec used, remote"
@@ -1985,6 +2002,8 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
PJ_ASSERT_RETURN(stream != NULL, PJ_ENOMEM);
stream->own_pool = own_pool;
pj_memcpy(&stream->si, info, sizeof(*info));
+ stream->si.param = pjmedia_codec_param_clone(pool, info->param);
+ pj_strdup(pool, &stream->si.fmt.encoding_name, &info->fmt.encoding_name);
/* Init stream/port name */
name.ptr = (char*) pj_pool_alloc(pool, M);
@@ -2159,12 +2178,16 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
}
/* Get the frame size */
- stream->frame_size = stream->codec_param.info.max_bps *
- stream->codec_param.info.frm_ptime / 8 / 1000;
- if ((stream->codec_param.info.max_bps * stream->codec_param.info.frm_ptime)
- % 8000 != 0)
- {
- ++stream->frame_size;
+ if (stream->codec_param.info.max_rx_frame_size > 0) {
+ stream->frame_size = stream->codec_param.info.max_rx_frame_size;
+ } else {
+ stream->frame_size = stream->codec_param.info.max_bps *
+ stream->codec_param.info.frm_ptime / 8 / 1000;
+ if ((stream->codec_param.info.max_bps *
+ stream->codec_param.info.frm_ptime) % 8000 != 0)
+ {
+ ++stream->frame_size;
+ }
}
/* How many consecutive PLC frames can be generated */
@@ -2172,7 +2195,7 @@ PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
stream->codec_param.info.frm_ptime;
#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG!=0)
- stream->rtp_rx_check_cnt = 5;
+ stream->rtp_rx_check_cnt = 50;
stream->has_g722_mpeg_bug = PJ_FALSE;
stream->rtp_rx_last_ts = 0;
stream->rtp_rx_last_cnt = 0;
@@ -2410,6 +2433,8 @@ err_cleanup:
*/
PJ_DEF(pj_status_t) pjmedia_stream_destroy( pjmedia_stream *stream )
{
+ pj_status_t status;
+
PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
/* Send RTCP BYE (also SDES & XR) */
@@ -2417,6 +2442,48 @@ PJ_DEF(pj_status_t) pjmedia_stream_destroy( pjmedia_stream *stream )
send_rtcp(stream, PJ_TRUE, PJ_TRUE, PJ_TRUE);
}
+ /* If we're in the middle of transmitting DTMF digit, send one last
+ * RFC 2833 RTP packet with 'End' flag set.
+ */
+ if (stream->tx_dtmf_count && stream->tx_dtmf_buf[0].duration != 0) {
+ pjmedia_frame frame_out;
+ pjmedia_channel *channel = stream->enc;
+ int first=0, last=0;
+ void *rtphdr;
+ int rtphdrlen;
+
+ pj_bzero(&frame_out, sizeof(frame_out));
+ frame_out.buf = ((char*)channel->out_pkt) + sizeof(pjmedia_rtp_hdr);
+ frame_out.size = 0;
+
+ create_dtmf_payload(stream, &frame_out, 1, &first, &last);
+
+ /* Encapsulate into RTP packet. Note that:
+ * - RTP marker should be set on the beginning of a new event
+ * - RTP timestamp is constant for the same packet.
+ */
+ status = pjmedia_rtp_encode_rtp( &channel->rtp,
+ stream->tx_event_pt, first,
+ frame_out.size, 0,
+ (const void**)&rtphdr,
+ &rtphdrlen);
+ if (status == PJ_SUCCESS) {
+ /* Copy RTP header to the beginning of packet */
+ pj_memcpy(channel->out_pkt, rtphdr, sizeof(pjmedia_rtp_hdr));
+
+ /* Send the RTP packet to the transport. */
+ status = pjmedia_transport_send_rtp(stream->transport,
+ channel->out_pkt,
+ frame_out.size +
+ sizeof(pjmedia_rtp_hdr));
+ }
+
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(4,(stream->port.info.name.ptr, status,
+ "Error sending RTP/DTMF end packet"));
+ }
+ }
+
/* Detach from transport
* MUST NOT hold stream mutex while detaching from transport, as
* it may cause deadlock. See ticket #460 for the details.
@@ -2692,6 +2759,7 @@ PJ_DEF(pj_status_t) pjmedia_stream_dial_dtmf( pjmedia_stream *stream,
stream->tx_dtmf_buf[stream->tx_dtmf_count+i].event = pt;
stream->tx_dtmf_buf[stream->tx_dtmf_count+i].duration = 0;
+ stream->tx_dtmf_buf[stream->tx_dtmf_count+i].ebit_cnt = 0;
}
if (status != PJ_SUCCESS)