summaryrefslogtreecommitdiff
path: root/pjmedia/src
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-05-19 15:58:13 +0000
committerBenny Prijono <bennylp@teluu.com>2006-05-19 15:58:13 +0000
commit1c28ac165c9a24bc00ae6563fd87dcb05f8524b3 (patch)
treef8d03e735436381996fb2c0e5be02a83052e2699 /pjmedia/src
parentbf8079559cb3435731580d57b243f12a68863a05 (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.c83
-rw-r--r--pjmedia/src/pjmedia-codec/speex_codec.c27
-rw-r--r--pjmedia/src/pjmedia/conference.c7
-rw-r--r--pjmedia/src/pjmedia/g711.c43
-rw-r--r--pjmedia/src/pjmedia/silencedet.c111
-rw-r--r--pjmedia/src/pjmedia/stream.c73
-rw-r--r--pjmedia/src/pjmedia/transport_udp.c5
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);