diff options
author | Benny Prijono <bennylp@teluu.com> | 2006-05-19 15:58:13 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2006-05-19 15:58:13 +0000 |
commit | 1c28ac165c9a24bc00ae6563fd87dcb05f8524b3 (patch) | |
tree | f8d03e735436381996fb2c0e5be02a83052e2699 /pjmedia/src | |
parent | bf8079559cb3435731580d57b243f12a68863a05 (diff) |
Install VAD in g711, gsm, and speex, and add the DTX support in stream.c. Also changed the way the silence detector works, and changed default speex quality/complexity to 10
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@457 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia/src')
-rw-r--r-- | pjmedia/src/pjmedia-codec/gsm.c | 83 | ||||
-rw-r--r-- | pjmedia/src/pjmedia-codec/speex_codec.c | 27 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/conference.c | 7 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/g711.c | 43 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/silencedet.c | 111 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/stream.c | 73 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/transport_udp.c | 5 |
7 files changed, 249 insertions, 100 deletions
diff --git a/pjmedia/src/pjmedia-codec/gsm.c b/pjmedia/src/pjmedia-codec/gsm.c index 8689960f..48e8ae13 100644 --- a/pjmedia/src/pjmedia-codec/gsm.c +++ b/pjmedia/src/pjmedia-codec/gsm.c @@ -20,7 +20,9 @@ #include <pjmedia/codec.h> #include <pjmedia/errno.h> #include <pjmedia/endpoint.h> +#include <pjmedia/plc.h> #include <pjmedia/port.h> +#include <pjmedia/silencedet.h> #include <pj/assert.h> #include <pj/pool.h> #include <pj/string.h> @@ -68,6 +70,9 @@ static pj_status_t gsm_codec_decode( pjmedia_codec *codec, const struct pjmedia_frame *input, unsigned output_buf_len, struct pjmedia_frame *output); +static pj_status_t gsm_codec_recover(pjmedia_codec *codec, + unsigned output_buf_len, + struct pjmedia_frame *output); /* Definition for GSM codec operations. */ static pjmedia_codec_op gsm_op = @@ -77,7 +82,8 @@ static pjmedia_codec_op gsm_op = &gsm_codec_close, &gsm_codec_parse, &gsm_codec_encode, - &gsm_codec_decode + &gsm_codec_decode, + &gsm_codec_recover }; /* Definition for GSM codec factory operations. */ @@ -100,11 +106,16 @@ static struct gsm_codec_factory pjmedia_codec codec_list; } gsm_codec_factory; + /* GSM codec private data. */ struct gsm_data { - void *encoder; - void *decoder; + void *encoder; + void *decoder; + pj_bool_t plc_enabled; + pjmedia_plc *plc; + pj_bool_t vad_enabled; + pjmedia_silence_det *vad; }; @@ -239,8 +250,10 @@ static pj_status_t gsm_default_attr (pjmedia_codec_factory *factory, attr->info.pt = PJMEDIA_RTP_PT_GSM; attr->setting.frm_per_pkt = 1; + attr->setting.vad = 1; + attr->setting.plc = 1; - /* Default all flag bits disabled. */ + /* Default all other flag bits disabled. */ return PJ_SUCCESS; } @@ -276,6 +289,7 @@ static pj_status_t gsm_alloc_codec( pjmedia_codec_factory *factory, { pjmedia_codec *codec; struct gsm_data *gsm_data; + pj_status_t status; PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL); PJ_ASSERT_RETURN(factory == &gsm_codec_factory.base, PJ_EINVAL); @@ -297,6 +311,23 @@ static pj_status_t gsm_alloc_codec( pjmedia_codec_factory *factory, gsm_data = pj_pool_zalloc(gsm_codec_factory.pool, sizeof(struct gsm_data)); codec->codec_data = gsm_data; + + /* Create PLC */ + status = pjmedia_plc_create(gsm_codec_factory.pool, 8000, + 160, 0, &gsm_data->plc); + if (status != PJ_SUCCESS) { + pj_mutex_unlock(gsm_codec_factory.mutex); + return status; + } + + /* Create silence detector */ + status = pjmedia_silence_det_create(gsm_codec_factory.pool, + 8000, 160, + &gsm_data->vad); + if (status != PJ_SUCCESS) { + pj_mutex_unlock(gsm_codec_factory.mutex); + return status; + } } pj_mutex_unlock(gsm_codec_factory.mutex); @@ -361,6 +392,9 @@ static pj_status_t gsm_codec_open( pjmedia_codec *codec, if (!gsm_data->decoder) return PJMEDIA_CODEC_EFAILED; + gsm_data->vad_enabled = (attr->setting.vad != 0); + gsm_data->plc_enabled = (attr->setting.plc != 0); + return PJ_SUCCESS; } @@ -437,6 +471,24 @@ static pj_status_t gsm_codec_encode( pjmedia_codec *codec, if (input->size < 320) return PJMEDIA_CODEC_EPCMTOOSHORT; + /* Detect silence */ + if (gsm_data->vad_enabled) { + pj_bool_t is_silence; + + is_silence = pjmedia_silence_det_detect(gsm_data->vad, + input->buf, + input->size / 2, + NULL); + if (is_silence) { + output->type = PJMEDIA_FRAME_TYPE_NONE; + output->buf = NULL; + output->size = 0; + output->timestamp.u64 = input->timestamp.u64; + return PJ_SUCCESS; + } + } + + /* Encode */ gsm_encode(gsm_data->encoder, (short*)input->buf, (unsigned char*)output->buf); @@ -472,6 +524,29 @@ static pj_status_t gsm_codec_decode( pjmedia_codec *codec, output->size = 320; output->type = PJMEDIA_FRAME_TYPE_AUDIO; + if (gsm_data->plc_enabled) + pjmedia_plc_save( gsm_data->plc, output->buf); + + return PJ_SUCCESS; +} + + +/* + * Recover lost frame. + */ +static pj_status_t gsm_codec_recover(pjmedia_codec *codec, + unsigned output_buf_len, + struct pjmedia_frame *output) +{ + struct gsm_data *gsm_data = codec->codec_data; + + PJ_ASSERT_RETURN(gsm_data->plc_enabled, PJ_EINVALIDOP); + + PJ_ASSERT_RETURN(output_buf_len >= 320, PJMEDIA_CODEC_EPCMTOOSHORT); + + pjmedia_plc_generate(gsm_data->plc, output->buf); + output->size = 320; + return PJ_SUCCESS; } diff --git a/pjmedia/src/pjmedia-codec/speex_codec.c b/pjmedia/src/pjmedia-codec/speex_codec.c index 1bf161b6..b1bb8df4 100644 --- a/pjmedia/src/pjmedia-codec/speex_codec.c +++ b/pjmedia/src/pjmedia-codec/speex_codec.c @@ -37,8 +37,8 @@ #define THIS_FILE "speex_codec.c" -#define DEFAULT_QUALITY 4 -#define DEFAULT_COMPLEXITY -1 +#define DEFAULT_QUALITY 10 +#define DEFAULT_COMPLEXITY 10 /* Prototypes for Speex factory */ static pj_status_t spx_test_alloc( pjmedia_codec_factory *factory, @@ -255,8 +255,8 @@ PJ_DEF(pj_status_t) pjmedia_codec_speex_init( pjmedia_endpt *endpt, spx_factory.speex_param[PARAM_UWB].complexity = complexity; /* Somehow quality <=4 is broken in linux. */ - if (quality <= 4) { - PJ_LOG(4,(THIS_FILE, "Adjusting quality to 5 for uwb")); + if (quality <= 4 && quality >= 0) { + PJ_LOG(5,(THIS_FILE, "Adjusting quality to 5 for uwb")); spx_factory.speex_param[PARAM_UWB].quality = 5; } @@ -411,9 +411,7 @@ static pj_status_t spx_default_attr (pjmedia_codec_factory *factory, attr->setting.hpf = 1; attr->setting.lpf =1 ; attr->setting.penh =1 ; - - /* Default, set VAD off as it caused voice chip off */ - attr->setting.vad = 0; + attr->setting.vad = 1; return PJ_SUCCESS; } @@ -571,8 +569,9 @@ static pj_status_t spx_codec_open( pjmedia_codec *codec, &spx_factory.speex_param[id].clock_rate); /* VAD */ - tmp = attr->setting.vad; + tmp = (attr->setting.vad != 0); speex_encoder_ctl(spx->enc, SPEEX_SET_VAD, &tmp); + speex_encoder_ctl(spx->enc, SPEEX_SET_DTX, &tmp); /* Complexity */ if (spx_factory.speex_param[id].complexity != -1) { @@ -687,6 +686,7 @@ static pj_status_t spx_codec_encode( pjmedia_codec *codec, float tmp[642]; /* 20ms at 32KHz + 2 */ pj_int16_t *samp_in; unsigned i, samp_count, sz; + int tx; spx = (struct spx_private*) codec->codec_data; @@ -710,7 +710,16 @@ static pj_status_t spx_codec_encode( pjmedia_codec *codec, speex_bits_reset(&spx->enc_bits); /* Encode the frame */ - speex_encode(spx->enc, tmp, &spx->enc_bits); + tx = speex_encode(spx->enc, tmp, &spx->enc_bits); + + /* Check if we need not to transmit the frame (DTX) */ + if (tx == 0) { + output->buf = NULL; + output->size = 0; + output->timestamp.u64 = input->timestamp.u64; + output->type = PJMEDIA_FRAME_TYPE_NONE; + return PJ_SUCCESS; + } /* Check size. */ sz = speex_bits_nbytes(&spx->enc_bits); diff --git a/pjmedia/src/pjmedia/conference.c b/pjmedia/src/pjmedia/conference.c index 60013c55..e4f29f2c 100644 --- a/pjmedia/src/pjmedia/conference.c +++ b/pjmedia/src/pjmedia/conference.c @@ -228,11 +228,14 @@ static pj_status_t create_conf_port( pj_pool_t *pool, /* Create and init vad. */ - status = pjmedia_silence_det_create( pool, &conf_port->vad); + status = pjmedia_silence_det_create( pool, + port->info.clock_rate, + port->info.samples_per_frame, + &conf_port->vad); if (status != PJ_SUCCESS) return status; - pjmedia_silence_det_set_adaptive(conf_port->vad, conf->samples_per_frame); + pjmedia_silence_det_set_fixed(conf_port->vad, 2); /* Save some port's infos, for convenience. */ if (port) { diff --git a/pjmedia/src/pjmedia/g711.c b/pjmedia/src/pjmedia/g711.c index c9500a5f..68a3934c 100644 --- a/pjmedia/src/pjmedia/g711.c +++ b/pjmedia/src/pjmedia/g711.c @@ -24,6 +24,7 @@ #include <pjmedia/errno.h> #include <pjmedia/port.h> #include <pjmedia/plc.h> +#include <pjmedia/silencedet.h> #include <pj/pool.h> #include <pj/string.h> #include <pj/assert.h> @@ -121,9 +122,11 @@ static struct g711_factory /* G711 codec private data. */ struct g711_private { - unsigned pt; - pj_bool_t plc_enabled; - pjmedia_plc *plc; + unsigned pt; + pj_bool_t plc_enabled; + pjmedia_plc *plc; + pj_bool_t vad_enabled; + pjmedia_silence_det *vad; }; @@ -250,7 +253,10 @@ static pj_status_t g711_default_attr (pjmedia_codec_factory *factory, /* Enable plc by default. */ attr->setting.plc = 1; - /* Default all flag bits disabled. */ + /* Enable VAD by default. */ + attr->setting.vad = 1; + + /* Default all other flag bits disabled. */ return PJ_SUCCESS; } @@ -302,8 +308,8 @@ static pj_status_t g711_alloc_codec( pjmedia_codec_factory *factory, struct g711_private *codec_priv; codec = pj_pool_alloc(g711_factory.pool, sizeof(pjmedia_codec)); - codec_priv = pj_pool_alloc(g711_factory.pool, - sizeof(struct g711_private)); + codec_priv = pj_pool_zalloc(g711_factory.pool, + sizeof(struct g711_private)); if (!codec || !codec_priv) { pj_mutex_unlock(g711_factory.mutex); return PJ_ENOMEM; @@ -320,6 +326,15 @@ static pj_status_t g711_alloc_codec( pjmedia_codec_factory *factory, return status; } + /* Create VAD */ + status = pjmedia_silence_det_create(g711_factory.pool, + 8000, 80, + &codec_priv->vad); + if (status != PJ_SUCCESS) { + pj_mutex_unlock(g711_factory.mutex); + return status; + } + codec->factory = factory; codec->op = &g711_op; codec->codec_data = codec_priv; @@ -378,6 +393,7 @@ static pj_status_t g711_open(pjmedia_codec *codec, struct g711_private *priv = codec->codec_data; priv->pt = attr->info.pt; priv->plc_enabled = (attr->setting.plc != 0); + priv->vad_enabled = (attr->setting.vad != 0); return PJ_SUCCESS; } @@ -429,6 +445,21 @@ static pj_status_t g711_encode(pjmedia_codec *codec, if (output_buf_len < input->size / 2) return PJMEDIA_CODEC_EFRMTOOSHORT; + /* Detect silence if VAD is enabled */ + if (priv->vad_enabled) { + pj_bool_t is_silence; + + is_silence = pjmedia_silence_det_detect(priv->vad, input->buf, + input->size / 2, NULL); + if (is_silence) { + output->type = PJMEDIA_FRAME_TYPE_NONE; + output->buf = NULL; + output->size = 0; + output->timestamp.u64 = input->timestamp.u64; + return PJ_SUCCESS; + } + } + /* Encode */ if (priv->pt == PJMEDIA_RTP_PT_PCMA) { unsigned i; diff --git a/pjmedia/src/pjmedia/silencedet.c b/pjmedia/src/pjmedia/silencedet.c index 74c3fd44..ad456bc5 100644 --- a/pjmedia/src/pjmedia/silencedet.c +++ b/pjmedia/src/pjmedia/silencedet.c @@ -32,14 +32,14 @@ typedef enum pjmedia_silence_det_mode { } pjmedia_silence_det_mode; + /** * This structure holds the silence detector state. */ struct pjmedia_silence_det { int mode; /**< VAD mode. */ - unsigned frame_size; /**< Samples per frame. */ - + unsigned ptime; /**< Frame time, in msec. */ unsigned min_signal_cnt; /**< # of signal frames.before talk burst */ unsigned min_silence_cnt; /**< # of silence frames before silence. */ @@ -60,6 +60,8 @@ unsigned char linear2ulaw(int pcm_val); PJ_DEF(pj_status_t) pjmedia_silence_det_create( pj_pool_t *pool, + unsigned clock_rate, + unsigned samples_per_frame, pjmedia_silence_det **p_sd) { pjmedia_silence_det *sd; @@ -68,47 +70,73 @@ PJ_DEF(pj_status_t) pjmedia_silence_det_create( pj_pool_t *pool, sd = pj_pool_zalloc(pool, sizeof(struct pjmedia_silence_det)); - sd->weakest_signal = 0xFFFFFFFFUL; - sd->loudest_silence = 0; + sd->ptime = samples_per_frame * 1000 / clock_rate; sd->signal_cnt = 0; sd->silence_cnt = 0; - - /* Restart in adaptive, silent mode */ + sd->weakest_signal = 0xFFFFFFFFUL; + sd->loudest_silence = 0; + + /* Default settings */ + pjmedia_silence_det_set_params(sd, -1, -1, -1); + + /* Restart in fixed, silent mode */ sd->in_talk = PJ_FALSE; - pjmedia_silence_det_set_adaptive( sd, 160 ); + pjmedia_silence_det_set_adaptive( sd, -1 ); *p_sd = sd; return PJ_SUCCESS; } -PJ_DEF(pj_status_t) pjmedia_silence_det_set_adaptive( pjmedia_silence_det *sd, - unsigned frame_size) +PJ_DEF(pj_status_t) pjmedia_silence_det_set_adaptive(pjmedia_silence_det *sd, + int threshold) { - PJ_ASSERT_RETURN(sd && frame_size, PJ_EINVAL); + PJ_ASSERT_RETURN(sd, PJ_EINVAL); + + if (threshold < 0) + threshold = PJMEDIA_SILENCE_DET_THRESHOLD; - sd->frame_size = frame_size; sd->mode = VAD_MODE_ADAPTIVE; - sd->min_signal_cnt = 10; - sd->min_silence_cnt = 64; - sd->recalc_cnt = 250; - sd->cur_threshold = 20; + sd->cur_threshold = threshold; return PJ_SUCCESS; } PJ_DEF(pj_status_t) pjmedia_silence_det_set_fixed( pjmedia_silence_det *sd, - unsigned frame_size, - unsigned threshold ) + int threshold ) { - PJ_ASSERT_RETURN(sd && frame_size, PJ_EINVAL); + PJ_ASSERT_RETURN(sd, PJ_EINVAL); + + if (threshold < 0) + threshold = PJMEDIA_SILENCE_DET_THRESHOLD; sd->mode = VAD_MODE_FIXED; - sd->frame_size = frame_size; sd->cur_threshold = threshold; return PJ_SUCCESS; } +PJ_DEF(pj_status_t) pjmedia_silence_det_set_params( pjmedia_silence_det *sd, + int min_silence, + int min_signal, + int recalc_time) +{ + PJ_ASSERT_RETURN(sd, PJ_EINVAL); + + if (min_silence == -1) + min_silence = 500; + if (min_signal < 0) + min_signal = sd->ptime; + if (recalc_time < 0) + recalc_time = 5000; + + sd->min_signal_cnt = min_signal / sd->ptime; + sd->min_silence_cnt = min_silence / sd->ptime; + sd->recalc_cnt = recalc_time / sd->ptime; + + return PJ_SUCCESS; +} + + PJ_DEF(pj_status_t) pjmedia_silence_det_disable( pjmedia_silence_det *sd ) { PJ_ASSERT_RETURN(sd, PJ_EINVAL); @@ -184,11 +212,6 @@ PJ_DEF(pj_bool_t) pjmedia_silence_det_apply( pjmedia_silence_det *sd, sd->cur_cnt = 0; } - /* For fixed threshold sd, everything is done. */ - if (sd->mode == VAD_MODE_FIXED) { - return !sd->in_talk; - } - /* Count the number of silent and signal frames and calculate min/max */ if (have_signal) { @@ -207,39 +230,29 @@ PJ_DEF(pj_bool_t) pjmedia_silence_det_apply( pjmedia_silence_det *sd, */ if ((sd->signal_cnt + sd->silence_cnt) > sd->recalc_cnt) { - /* Adjust silence threshold by looking at the proportions of - * signal and silence frames. - */ - if (sd->signal_cnt >= sd->recalc_cnt) { - /* All frames where signal frames. - * Increase silence threshold. - */ - sd->cur_threshold += (sd->weakest_signal - sd->cur_threshold)/4; - PJ_LOG(6,(THIS_FILE, "Vad cur_threshold increased to %d", - sd->cur_threshold)); - } - else if (sd->silence_cnt >= sd->recalc_cnt) { - /* All frames where silence frames. - * Decrease silence threshold. - */ - sd->cur_threshold = (sd->cur_threshold+sd->loudest_silence)/2+1; - PJ_LOG(6,(THIS_FILE, "Vad cur_threshold decreased to %d", - sd->cur_threshold)); - } - else { + if (sd->mode == VAD_MODE_ADAPTIVE) { pj_bool_t updated = PJ_TRUE; + unsigned pct_signal; + + /* Get percentage of signal */ + pct_signal = sd->signal_cnt * 100 / + (sd->signal_cnt + sd->silence_cnt); /* Adjust according to signal/silence proportions. */ - if (sd->signal_cnt > sd->silence_cnt * 2) + if (pct_signal > 95) { + sd->cur_threshold += (sd->weakest_signal - sd->cur_threshold)/4; + } else if (pct_signal < 5) { + sd->cur_threshold = (sd->cur_threshold+sd->loudest_silence)/2+1; + } else if (pct_signal > 90) { sd->cur_threshold++; - else if (sd->silence_cnt > sd->signal_cnt* 2) + } else if (pct_signal < 10) { sd->cur_threshold--; - else + } else { updated = PJ_FALSE; + } if (updated) { - PJ_LOG(6,(THIS_FILE, - "Vad cur_threshold updated to %d", + PJ_LOG(5,(THIS_FILE, "Vad cur_threshold updated to %d", sd->cur_threshold)); } } diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c index 36acd1a4..bbf161ff 100644 --- a/pjmedia/src/pjmedia/stream.c +++ b/pjmedia/src/pjmedia/stream.c @@ -56,7 +56,6 @@ struct pjmedia_channel unsigned out_pkt_size; /**< Size of output buffer. */ void *out_pkt; /**< Output buffer. */ pjmedia_rtp_session rtp; /**< RTP session. */ - char last_frm_type; /**< Last frame type from jb */ }; @@ -90,8 +89,13 @@ struct pjmedia_stream pjmedia_codec *codec; /**< Codec instance being used. */ pjmedia_codec_param codec_param; /**< Codec param. */ unsigned frame_size; /**< Size of encoded base frame.*/ + pj_bool_t is_streaming; /**< Currently streaming?. This + is used to put RTP marker + bit. */ + pj_mutex_t *jb_mutex; pjmedia_jbuf *jb; /**< Jitter buffer. */ + char jb_last_frm; /**< Last frame type from jb */ pjmedia_rtcp_session rtcp; /**< RTCP for incoming RTP. */ @@ -209,7 +213,7 @@ static pj_status_t get_frame( pjmedia_port *port, pjmedia_frame *frame) * activate PLC to smoothen the fade-out, otherwise zero * the frame. */ - if (frame_type != channel->last_frm_type) { + if (frame_type != stream->jb_last_frm) { pjmedia_jb_state jb_state; /* Activate PLC to smoothen the missing frame */ @@ -243,9 +247,10 @@ static pj_status_t get_frame( pjmedia_port *port, pjmedia_frame *frame) if (samples_count < samples_required) { pjmedia_zero_samples(p_out_samp + samples_count, samples_required - samples_count); + samples_count = samples_required; } - channel->last_frm_type = frame_type; + stream->jb_last_frm = frame_type; break; } else if (frame_type != PJMEDIA_JB_NORMAL_FRAME) { @@ -276,7 +281,7 @@ static pj_status_t get_frame( pjmedia_port *port, pjmedia_frame *frame) } while (samples_count < samples_required); - if (channel->last_frm_type != frame_type) { + if (stream->jb_last_frm != frame_type) { PJ_LOG(5,(stream->port.info.name.ptr, "Jitter buffer is bufferring with plc (prefetch=%d)", jb_state.prefetch)); @@ -287,12 +292,13 @@ static pj_status_t get_frame( pjmedia_port *port, pjmedia_frame *frame) if (samples_count < samples_required) { pjmedia_zero_samples(p_out_samp + samples_count, samples_required - samples_count); + samples_count = samples_required; PJ_LOG(5,(stream->port.info.name.ptr, "Jitter buffer is bufferring (prefetch=%d)..", jb_state.prefetch)); } - channel->last_frm_type = frame_type; + stream->jb_last_frm = frame_type; break; } else { @@ -317,7 +323,7 @@ static pj_status_t get_frame( pjmedia_port *port, pjmedia_frame *frame) } } - channel->last_frm_type = frame_type; + stream->jb_last_frm = frame_type; } @@ -437,10 +443,8 @@ static pj_status_t put_frame( pjmedia_port *port, pj_status_t status = 0; struct pjmedia_frame frame_out; unsigned ts_len; - pj_bool_t has_tx; void *rtphdr; int rtphdrlen; - pj_ssize_t sent; /* Don't do anything if stream is paused */ @@ -453,16 +457,14 @@ static pj_status_t put_frame( pjmedia_port *port, /* Init frame_out buffer. */ frame_out.buf = ((char*)channel->out_pkt) + sizeof(pjmedia_rtp_hdr); - - /* Make compiler happy */ frame_out.size = 0; + /* If we have DTMF digits in the queue, transmit the digits. * Otherwise encode the PCM buffer. */ if (stream->tx_dtmf_count) { - has_tx = PJ_TRUE; create_dtmf_payload(stream, &frame_out); /* Encapsulate. */ @@ -475,8 +477,6 @@ static pj_status_t put_frame( pjmedia_port *port, } else if (frame->type != PJMEDIA_FRAME_TYPE_NONE) { unsigned ts, samples_per_frame; - has_tx = PJ_TRUE; - /* Repeatedly call encode if there are multiple frames to be * sent. */ @@ -489,17 +489,21 @@ static pj_status_t put_frame( pjmedia_port *port, pjmedia_frame tmp_out_frame, tmp_in_frame; unsigned bytes_per_sample, max_size; + /* Nb of bytes in PCM sample */ bytes_per_sample = stream->codec_param.info.pcm_bits_per_sample/8; + /* Split original PCM input frame into base frame size */ tmp_in_frame.buf = ((char*)frame->buf) + ts * bytes_per_sample; tmp_in_frame.size = samples_per_frame * bytes_per_sample; tmp_in_frame.type = PJMEDIA_FRAME_TYPE_AUDIO; + /* Set output frame position */ tmp_out_frame.buf = ((char*)frame_out.buf) + frame_out.size; max_size = channel->out_pkt_size - sizeof(pjmedia_rtp_hdr) - frame_out.size; + /* Encode! */ status = stream->codec->op->encode( stream->codec, &tmp_in_frame, max_size, &tmp_out_frame); if (status != PJ_SUCCESS) { @@ -508,10 +512,19 @@ static pj_status_t put_frame( pjmedia_port *port, return status; } + /* tmp_out_frame.size may be zero for silence frame. */ frame_out.size += tmp_out_frame.size; - } - //printf("p"); fflush(stdout); + /* Stop processing next PCM frame when encode() returns either + * CNG frame or NULL frame. + */ + if (tmp_out_frame.type!=PJMEDIA_FRAME_TYPE_AUDIO || + tmp_out_frame.size==0) + { + break; + } + + } /* Encapsulate. */ status = pjmedia_rtp_encode_rtp( &channel->rtp, @@ -522,7 +535,6 @@ static pj_status_t put_frame( pjmedia_port *port, } else { /* Just update RTP session's timestamp. */ - has_tx = PJ_FALSE; status = pjmedia_rtp_encode_rtp( &channel->rtp, 0, 0, 0, ts_len, @@ -546,23 +558,34 @@ static pj_status_t put_frame( pjmedia_port *port, } /* Do nothing if we have nothing to transmit */ - if (!has_tx) - return PJ_SUCCESS; - - if (rtphdrlen != sizeof(pjmedia_rtp_hdr)) { - /* We don't support RTP with extended header yet. */ - PJ_TODO(SUPPORT_SENDING_RTP_WITH_EXTENDED_HEADER); + if (frame_out.size == 0) { + if (stream->is_streaming) { + PJ_LOG(5,(stream->port.info.name.ptr,"Starting silence")); + stream->is_streaming = PJ_FALSE; + } return PJ_SUCCESS; } + + /* Copy RTP header to the beginning of packet */ pj_memcpy(channel->out_pkt, rtphdr, sizeof(pjmedia_rtp_hdr)); - /* Send. */ - sent = frame_out.size+sizeof(pjmedia_rtp_hdr); + /* Set RTP marker bit if currently not streaming */ + if (stream->is_streaming == PJ_FALSE) { + pjmedia_rtp_hdr *rtp = channel->out_pkt; + + rtp->m = 1; + PJ_LOG(5,(stream->port.info.name.ptr,"Start talksprut..")); + } + + stream->is_streaming = PJ_TRUE; + /* Send the RTP packet to the transport. */ (*stream->transport->op->send_rtp)(stream->transport, - channel->out_pkt, sent); + channel->out_pkt, + frame_out.size + + sizeof(pjmedia_rtp_hdr)); /* Update stat */ diff --git a/pjmedia/src/pjmedia/transport_udp.c b/pjmedia/src/pjmedia/transport_udp.c index c1936cfe..edd33f3f 100644 --- a/pjmedia/src/pjmedia/transport_udp.c +++ b/pjmedia/src/pjmedia/transport_udp.c @@ -397,11 +397,6 @@ static pj_status_t transport_attach( pjmedia_transport *tp, /* Validate arguments */ PJ_ASSERT_RETURN(tp && strm && rem_addr && addr_len, PJ_EINVAL); - /* Remote address must be Internet address */ - PJ_ASSERT_RETURN(addr_len == sizeof(pj_sockaddr_in) && - ((pj_sockaddr_in*)rem_addr)->sin_family == PJ_AF_INET, - PJ_EINVAL); - /* Must not be "attached" to existing stream */ PJ_ASSERT_RETURN(udp->stream == NULL, PJ_EINVALIDOP); |