summaryrefslogtreecommitdiff
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
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
-rw-r--r--pjmedia/include/pjmedia/silencedet.h74
-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
8 files changed, 306 insertions, 117 deletions
diff --git a/pjmedia/include/pjmedia/silencedet.h b/pjmedia/include/pjmedia/silencedet.h
index 4e823979..e6cb55c5 100644
--- a/pjmedia/include/pjmedia/silencedet.h
+++ b/pjmedia/include/pjmedia/silencedet.h
@@ -36,43 +36,83 @@ typedef struct pjmedia_silence_det pjmedia_silence_det;
/**
+ * Suggested or default threshold to be set for fixed silence detection
+ * or as starting threshold for adaptive silence detection. The threshold
+ * has the range from zero to 255.
+ */
+#define PJMEDIA_SILENCE_DET_THRESHOLD 4
+
+
+/**
* Create voice activity detector with default settings. The default settings
- * are to perform adaptive silence detection, which adjusts the noise level
- * dynamically based on current input level.
+ * are set to adaptive silence detection with the default threshold.
*
- * @param pool Pool for allocating the structure.
- * @param p_sd Pointer to receive the silence detector instance.
+ * @param pool Pool for allocating the structure.
+ * @param clock_rate Clock rate.
+ * @param samples_per_frame Number of samples per frame. The clock_rate and
+ * samples_per_frame is only used to calculate the
+ * frame time, from which some timing parameters
+ * are calculated from.
+ * @param p_sd Pointer to receive the silence detector instance.
*
- * @return PJ_SUCCESS on success.
+ * @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pjmedia_silence_det_create( pj_pool_t *pool,
+ unsigned clock_rate,
+ unsigned samples_per_frame,
pjmedia_silence_det **p_sd );
/**
- * Set the sd to operate in adaptive mode.
+ * Set the sd to operate in fixed threshold mode. With fixed threshold mode,
+ * the threshold will not be changed adaptively.
*
- * @param sd The silence detector
- * @param frame_size Number of samples per frame.
+ * @param sd The silence detector
+ * @param threshold The silence threshold, or -1 to use default
+ * threshold.
*
- * @return PJ_SUCCESS on success.
+ * @return PJ_SUCCESS on success.
*/
-PJ_DECL(pj_status_t) pjmedia_silence_det_set_adaptive( pjmedia_silence_det *sd,
- unsigned frame_size);
+PJ_DECL(pj_status_t) pjmedia_silence_det_set_fixed( pjmedia_silence_det *sd,
+ int threshold );
+/**
+ * Set the sd to operate in adaptive mode. This is the default mode
+ * when the silence detector is created.
+ *
+ * @param sd The silence detector
+ * @param threshold Initial threshold to be set, or -1 to use default
+ * threshold.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_silence_det_set_adaptive(pjmedia_silence_det *sd,
+ int threshold);
/**
- * Set the sd to operate in fixed threshold mode.
+ * Set other silence detector parameters.
*
* @param sd The silence detector
- * @param frame_size Number of samplse per frame.
- * @param threshold The silence threshold.
+ * @param min_silence Minimum duration of silence (in msec) before
+ * silence is reported. If -1 is specified, then
+ * the default value will be used. The default is
+ * 400 msec.
+ * @param min_signal Minimum duration of signal (in msec) before
+ * signal is reported. If -1 is specified, then
+ * the default value will be used. The default is
+ * one frame.
+ * @param recalc_time The interval to recalculate signal and silence
+ * proportion and to readjust the silence threshold
+ * when adaptive silence detection is set. If -1
+ * is specified, then the default value will be used.
+ * The default value is 5000 (msec).
*
* @return PJ_SUCCESS on success.
*/
-PJ_DECL(pj_status_t) pjmedia_silence_det_set_fixed( pjmedia_silence_det *sd,
- unsigned frame_size,
- unsigned threshold );
+PJ_DECL(pj_status_t) pjmedia_silence_det_set_params( pjmedia_silence_det *sd,
+ int min_silence,
+ int min_signal,
+ int recalc_time);
/**
* Disable the silence detector.
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);