Changeset 203 for pjproject/trunk/pjmedia/src/pjmedia/vad.c
- Timestamp:
- Feb 20, 2006 1:28:25 AM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia/vad.c
r202 r203 19 19 #include <pjmedia/vad.h> 20 20 #include <pjmedia/errno.h> 21 21 #include <pj/assert.h> 22 #include <pj/log.h> 23 #include <pj/pool.h> 24 25 26 #define THIS_FILE "vad.c" 27 28 typedef enum pjmedia_vad_mode { 29 VAD_MODE_NONE, 30 VAD_MODE_FIXED, 31 VAD_MODE_ADAPTIVE 32 } pjmedia_vad_mode; 33 34 35 /** 36 * This structure holds the vad state. 37 */ 38 struct pjmedia_vad 39 { 40 int mode; /**< VAD mode. */ 41 unsigned frame_size; /**< Samples per frame. */ 42 43 44 unsigned min_signal_cnt; /**< # of signal frames.before talk burst */ 45 unsigned min_silence_cnt; /**< # of silence frames before silence. */ 46 unsigned recalc_cnt; /**< # of frames before adaptive recalc. */ 47 48 pj_bool_t in_talk; /**< In talk burst? */ 49 unsigned cur_cnt; /**< # of frames in current mode. */ 50 unsigned signal_cnt; /**< # of signal frames received. */ 51 unsigned silence_cnt; /**< # of silence frames received */ 52 unsigned cur_threshold; /**< Current silence threshold. */ 53 unsigned weakest_signal; /**< Weakest signal detected. */ 54 unsigned loudest_silence; /**< Loudest silence detected. */ 55 }; 56 57 58 59 unsigned char linear2ulaw(int pcm_val); 22 60 23 61 PJ_DEF(pj_status_t) pjmedia_vad_create( pj_pool_t *pool, 24 62 pjmedia_vad **p_vad) 25 63 { 26 return PJ_EINVALIDOP; 27 } 28 29 PJ_DEF(pj_uint32_t) pjmedia_vad_calc_avg_signal_level(pj_int16_t samples[], 30 pj_size_t count) 31 { 32 return PJ_EINVALIDOP; 33 } 34 35 PJ_DEF(pj_status_t) pjmedia_vad_detect_silence( pjmedia_vad *vad, 36 pj_int16_t samples[], 37 pj_size_t count, 38 pj_bool_t *p_silence) 39 { 40 return PJ_EINVALIDOP; 41 } 42 64 pjmedia_vad *vad; 65 66 PJ_ASSERT_RETURN(pool && p_vad, PJ_EINVAL); 67 68 vad = pj_pool_zalloc(pool, sizeof(struct pjmedia_vad)); 69 70 vad->weakest_signal = 0xFFFFFFFFUL; 71 vad->loudest_silence = 0; 72 vad->signal_cnt = 0; 73 vad->silence_cnt = 0; 74 75 /* Restart in adaptive, silent mode */ 76 vad->in_talk = PJ_FALSE; 77 pjmedia_vad_set_adaptive( vad, 160 ); 78 79 *p_vad = vad; 80 return PJ_SUCCESS; 81 } 82 83 PJ_DEF(pj_status_t) pjmedia_vad_set_adaptive( pjmedia_vad *vad, 84 unsigned frame_size) 85 { 86 PJ_ASSERT_RETURN(vad && frame_size, PJ_EINVAL); 87 88 vad->frame_size = frame_size; 89 vad->mode = VAD_MODE_ADAPTIVE; 90 vad->min_signal_cnt = 3; 91 vad->min_silence_cnt = 20; 92 vad->recalc_cnt = 30; 93 vad->cur_threshold = 20; 94 95 return PJ_SUCCESS; 96 } 97 98 PJ_DEF(pj_status_t) pjmedia_vad_set_fixed( pjmedia_vad *vad, 99 unsigned frame_size, 100 unsigned threshold ) 101 { 102 PJ_ASSERT_RETURN(vad && frame_size, PJ_EINVAL); 103 104 vad->mode = VAD_MODE_FIXED; 105 vad->frame_size = frame_size; 106 vad->cur_threshold = threshold; 107 108 return PJ_SUCCESS; 109 } 110 111 PJ_DEF(pj_status_t) pjmedia_vad_disable( pjmedia_vad *vad ) 112 { 113 PJ_ASSERT_RETURN(vad, PJ_EINVAL); 114 115 vad->mode = VAD_MODE_NONE; 116 117 return PJ_SUCCESS; 118 } 119 120 121 PJ_DEF(pj_int32_t) pjmedia_vad_calc_avg_signal(const pj_int16_t samples[], 122 pj_size_t count) 123 { 124 pj_uint32_t sum = 0; 125 126 const pj_int16_t * pcm = samples; 127 const pj_int16_t * end = samples + count; 128 129 if (count==0) 130 return 0; 131 132 while (pcm != end) { 133 if (*pcm < 0) 134 sum -= *pcm++; 135 else 136 sum += *pcm++; 137 } 138 139 return (pj_int32_t)(sum / count); 140 } 141 142 PJ_DEF(pj_bool_t) pjmedia_vad_detect_silence( pjmedia_vad *vad, 143 const pj_int16_t samples[], 144 pj_size_t count, 145 pj_int32_t *p_level) 146 { 147 pj_uint32_t level; 148 pj_bool_t have_signal; 149 150 /* Always return false if VAD is disabled */ 151 if (vad->mode == VAD_MODE_NONE) { 152 if (p_level) 153 *p_level = -1; 154 return PJ_FALSE; 155 } 156 157 /* Calculate average signal level. */ 158 level = pjmedia_vad_calc_avg_signal(samples, count); 159 160 /* Report to caller, if required. */ 161 if (p_level) 162 *p_level = level; 163 164 /* Convert PCM level to ulaw */ 165 level = linear2ulaw(level) ^ 0xff; 166 167 /* Do we have signal? */ 168 have_signal = level > vad->cur_threshold; 169 170 /* We we're in transition between silence and signel, increment the 171 * current frame counter. We will only switch mode when we have enough 172 * frames. 173 */ 174 if (vad->in_talk != have_signal) { 175 unsigned limit; 176 177 vad->cur_cnt++; 178 179 limit = (vad->in_talk ? vad->min_silence_cnt : 180 vad->min_signal_cnt); 181 182 if (vad->cur_cnt > limit) { 183 184 /* Swap mode */ 185 vad->in_talk = !vad->in_talk; 186 187 /* Restart adaptive cur_threshold measurements */ 188 vad->weakest_signal = 0xFFFFFFFFUL; 189 vad->loudest_silence = 0; 190 vad->signal_cnt = 0; 191 vad->silence_cnt = 0; 192 } 193 194 } else { 195 /* Reset frame count */ 196 vad->cur_cnt = 0; 197 } 198 199 /* For fixed threshold vad, everything is done. */ 200 if (vad->mode == VAD_MODE_FIXED) { 201 return !vad->in_talk; 202 } 203 204 205 /* Count the number of silent and signal frames and calculate min/max */ 206 if (have_signal) { 207 if (level < vad->weakest_signal) 208 vad->weakest_signal = level; 209 vad->signal_cnt++; 210 } 211 else { 212 if (level > vad->loudest_silence) 213 vad->loudest_silence = level; 214 vad->silence_cnt++; 215 } 216 217 /* See if we have had enough frames to look at proportions of 218 * silence/signal frames. 219 */ 220 if ((vad->signal_cnt + vad->silence_cnt) > vad->recalc_cnt) { 221 222 /* Adjust silence threshold by looking at the proportions of 223 * signal and silence frames. 224 */ 225 if (vad->signal_cnt >= vad->recalc_cnt) { 226 /* All frames where signal frames. 227 * Increase silence threshold. 228 */ 229 vad->cur_threshold += (vad->weakest_signal - vad->cur_threshold)/4; 230 PJ_LOG(5,(THIS_FILE, "Vad cur_threshold increased to %d", 231 vad->cur_threshold)); 232 } 233 else if (vad->silence_cnt >= vad->recalc_cnt) { 234 /* All frames where silence frames. 235 * Decrease silence threshold. 236 */ 237 vad->cur_threshold = (vad->cur_threshold+vad->loudest_silence)/2+1; 238 PJ_LOG(5,(THIS_FILE, "Vad cur_threshold decreased to %d", 239 vad->cur_threshold)); 240 } 241 else { 242 pj_bool_t updated = PJ_TRUE; 243 244 /* Adjust according to signal/silence proportions. */ 245 if (vad->signal_cnt > vad->silence_cnt * 2) 246 vad->cur_threshold++; 247 else if (vad->silence_cnt > vad->signal_cnt* 2) 248 vad->cur_threshold--; 249 else 250 updated = PJ_FALSE; 251 252 if (updated) { 253 PJ_LOG(5,(THIS_FILE, 254 "Vad cur_threshold updated to %d", 255 vad->cur_threshold)); 256 } 257 } 258 259 /* Reset. */ 260 vad->weakest_signal = 0xFFFFFFFFUL; 261 vad->loudest_silence = 0; 262 vad->signal_cnt = 0; 263 vad->silence_cnt = 0; 264 } 265 266 return !vad->in_talk; 267 } 268
Note: See TracChangeset
for help on using the changeset viewer.