Changeset 2198 for pjproject/trunk/pjmedia/src/pjmedia/echo_common.c
- Timestamp:
- Aug 9, 2008 5:40:22 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia/echo_common.c
r2039 r2198 18 18 */ 19 19 20 #include <pjmedia/config.h>21 20 #include <pjmedia/echo.h> 21 #include <pjmedia/delaybuf.h> 22 #include <pjmedia/errno.h> 22 23 #include <pj/assert.h> 24 #include <pj/list.h> 25 #include <pj/log.h> 23 26 #include <pj/pool.h> 24 27 #include "echo_internal.h" 25 28 29 #define THIS_FILE "echo_common.c" 30 26 31 typedef struct ec_operations ec_operations; 27 32 33 struct frame 34 { 35 PJ_DECL_LIST_MEMBER(struct frame); 36 short buf[1]; 37 }; 38 28 39 struct pjmedia_echo_state 29 40 { 41 pj_pool_t *pool; 42 char *obj_name; 43 unsigned samples_per_frame; 30 44 void *state; 31 45 ec_operations *op; 46 47 pj_bool_t lat_ready; /* lat_buf has been filled in. */ 48 unsigned lat_target_cnt;/* Target number of frames in lat_buf */ 49 unsigned lat_buf_cnt; /* Actual number of frames in lat_buf */ 50 struct frame lat_buf; /* Frame queue for delayed playback */ 51 struct frame lat_free; /* Free frame list. */ 52 53 pjmedia_delay_buf *delay_buf; 32 54 }; 33 55 … … 35 57 struct ec_operations 36 58 { 59 const char *name; 60 37 61 pj_status_t (*ec_create)(pj_pool_t *pool, 38 unsigned clock_rate,39 unsigned samples_per_frame,40 unsigned tail_ms,41 unsigned latency_ms,42 unsigned options,43 void **p_state );62 unsigned clock_rate, 63 unsigned channel_count, 64 unsigned samples_per_frame, 65 unsigned tail_ms, 66 unsigned options, 67 void **p_state ); 44 68 pj_status_t (*ec_destroy)(void *state ); 45 pj_status_t (*ec_playback)(void *state, 46 pj_int16_t *play_frm ); 47 pj_status_t (*ec_capture)(void *state, 48 pj_int16_t *rec_frm, 49 unsigned options ); 69 void (*ec_reset)(void *state ); 50 70 pj_status_t (*ec_cancel)(void *state, 51 71 pj_int16_t *rec_frm, … … 58 78 static struct ec_operations echo_supp_op = 59 79 { 80 "Echo suppressor", 60 81 &echo_supp_create, 61 82 &echo_supp_destroy, 62 &echo_supp_playback, 63 &echo_supp_capture, 83 &echo_supp_reset, 64 84 &echo_supp_cancel_echo 65 85 }; … … 71 91 */ 72 92 #if defined(PJMEDIA_HAS_SPEEX_AEC) && PJMEDIA_HAS_SPEEX_AEC!=0 73 static struct ec_operations aec_op = 74 { 93 static struct ec_operations speex_aec_op = 94 { 95 "AEC", 75 96 &speex_aec_create, 76 97 &speex_aec_destroy, 77 &speex_aec_playback, 78 &speex_aec_capture, 98 &speex_aec_reset, 79 99 &speex_aec_cancel_echo 80 100 }; 81 82 #else83 #define aec_op echo_supp_op84 101 #endif 85 102 86 103 104 /* 105 * IPP AEC prototypes 106 */ 107 #if defined(PJMEDIA_HAS_INTEL_IPP_AEC) && PJMEDIA_HAS_INTEL_IPP_AEC!=0 108 static struct ec_operations ipp_aec_op = 109 { 110 "IPP AEC", 111 &ipp_aec_create, 112 &ipp_aec_destroy, 113 &ipp_aec_reset, 114 &ipp_aec_cancel_echo 115 }; 116 #endif 87 117 88 118 /* … … 97 127 pjmedia_echo_state **p_echo ) 98 128 { 129 return pjmedia_echo_create2(pool, clock_rate, 1, samples_per_frame, 130 tail_ms, latency_ms, options, p_echo); 131 } 132 133 /* 134 * Create the echo canceller. 135 */ 136 PJ_DEF(pj_status_t) pjmedia_echo_create2(pj_pool_t *pool, 137 unsigned clock_rate, 138 unsigned channel_count, 139 unsigned samples_per_frame, 140 unsigned tail_ms, 141 unsigned latency_ms, 142 unsigned options, 143 pjmedia_echo_state **p_echo ) 144 { 145 unsigned ptime; 99 146 pjmedia_echo_state *ec; 100 147 pj_status_t status; 101 148 102 /* Force to use simple echo suppressor if AEC is not available */ 103 #if !defined(PJMEDIA_HAS_SPEEX_AEC) || PJMEDIA_HAS_SPEEX_AEC==0 104 options |= PJMEDIA_ECHO_SIMPLE; 149 /* Create new pool and instantiate and init the EC */ 150 pool = pj_pool_create(pool->factory, "ec%p", 256, 256, NULL); 151 ec = PJ_POOL_ZALLOC_T(pool, struct pjmedia_echo_state); 152 ec->pool = pool; 153 ec->obj_name = pool->obj_name; 154 pj_list_init(&ec->lat_buf); 155 pj_list_init(&ec->lat_free); 156 157 /* Select the backend algorithm */ 158 if (0) { 159 /* Dummy */ 160 ; 161 #if defined(PJMEDIA_HAS_SPEEX_AEC) && PJMEDIA_HAS_SPEEX_AEC!=0 162 } else if ((options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_SPEEX || 163 (options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_DEFAULT) 164 { 165 ec->op = &speex_aec_op; 105 166 #endif 106 167 107 ec = PJ_POOL_ZALLOC_T(pool, struct pjmedia_echo_state); 108 109 if (options & PJMEDIA_ECHO_SIMPLE) { 168 #if defined(PJMEDIA_HAS_INTEL_IPP_AEC) && PJMEDIA_HAS_INTEL_IPP_AEC!=0 169 } else if ((options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_IPP || 170 (options & PJMEDIA_ECHO_ALGO_MASK) == PJMEDIA_ECHO_DEFAULT) 171 { 172 ec->op = &ipp_aec_op; 173 174 #endif 175 176 } else { 110 177 ec->op = &echo_supp_op; 111 status = (*echo_supp_op.ec_create)(pool, clock_rate, samples_per_frame, 112 tail_ms, latency_ms, options, 113 &ec->state); 178 } 179 180 PJ_LOG(5,(ec->obj_name, "Creating %s", ec->op->name)); 181 182 /* Instantiate EC object */ 183 status = (*ec->op->ec_create)(pool, clock_rate, channel_count, 184 samples_per_frame, tail_ms, 185 options, &ec->state); 186 if (status != PJ_SUCCESS) { 187 pj_pool_release(pool); 188 return status; 189 } 190 191 /* Create latency buffers */ 192 ptime = samples_per_frame * 1000 / clock_rate; 193 if (latency_ms == 0) { 194 /* Give at least one frame delay to simplify programming */ 195 latency_ms = ptime; 196 } 197 ec->lat_target_cnt = latency_ms / ptime; 198 if (ec->lat_target_cnt != 0) { 199 unsigned i; 200 for (i=0; i < ec->lat_target_cnt; ++i) { 201 struct frame *frm; 202 203 frm = (struct frame*) pj_pool_alloc(pool, (samples_per_frame<<1) + 204 sizeof(struct frame)); 205 pj_list_push_back(&ec->lat_free, frm); 206 } 114 207 } else { 115 ec->op = &aec_op; 116 status = (*aec_op.ec_create)(pool, clock_rate, 117 samples_per_frame, 118 tail_ms, latency_ms, options, 119 &ec->state); 120 } 121 122 if (status != PJ_SUCCESS) 208 ec->lat_ready = PJ_TRUE; 209 } 210 211 /* Create delay buffer to compensate drifts */ 212 status = pjmedia_delay_buf_create(ec->pool, ec->obj_name, clock_rate, 213 samples_per_frame, channel_count, 214 (PJMEDIA_SOUND_BUFFER_COUNT+1) * ptime, 215 0, &ec->delay_buf); 216 if (status != PJ_SUCCESS) { 217 pj_pool_release(pool); 123 218 return status; 124 125 pj_assert(ec->state != NULL); 126 219 } 220 221 PJ_LOG(4,(ec->obj_name, 222 "%s created, clock_rate=%d, channel=%d, " 223 "samples per frame=%d, tail length=%d ms, " 224 "latency=%d ms", 225 ec->op->name, clock_rate, channel_count, samples_per_frame, 226 tail_ms, latency_ms)); 227 228 /* Done */ 127 229 *p_echo = ec; 128 230 … … 136 238 PJ_DEF(pj_status_t) pjmedia_echo_destroy(pjmedia_echo_state *echo ) 137 239 { 138 return (*echo->op->ec_destroy)(echo->state); 139 } 140 141 142 143 /* 144 * Let the Echo Canceller knows that a frame has been played to the speaker. 240 (*echo->op->ec_destroy)(echo->state); 241 pj_pool_release(echo->pool); 242 return PJ_SUCCESS; 243 } 244 245 246 /* 247 * Reset the echo canceller. 248 */ 249 PJ_DEF(pj_status_t) pjmedia_echo_reset(pjmedia_echo_state *echo ) 250 { 251 while (!pj_list_empty(&echo->lat_buf)) { 252 struct frame *frm; 253 frm = echo->lat_buf.next; 254 pj_list_erase(frm); 255 pj_list_push_back(&echo->lat_free, frm); 256 } 257 echo->lat_ready = PJ_FALSE; 258 pjmedia_delay_buf_reset(echo->delay_buf); 259 echo->op->ec_reset(echo->state); 260 return PJ_SUCCESS; 261 } 262 263 264 /* 265 * Let the Echo Canceller know that a frame has been played to the speaker. 145 266 */ 146 267 PJ_DEF(pj_status_t) pjmedia_echo_playback( pjmedia_echo_state *echo, 147 268 pj_int16_t *play_frm ) 148 269 { 149 return (*echo->op->ec_playback)(echo->state, play_frm); 270 if (!echo->lat_ready) { 271 /* We've not built enough latency in the buffer, so put this frame 272 * in the latency buffer list. 273 */ 274 struct frame *frm; 275 276 if (pj_list_empty(&echo->lat_free)) { 277 echo->lat_ready = PJ_TRUE; 278 PJ_LOG(5,(echo->obj_name, "Latency bufferring complete")); 279 pjmedia_delay_buf_put(echo->delay_buf, play_frm); 280 return PJ_SUCCESS; 281 } 282 283 frm = echo->lat_free.prev; 284 pj_list_erase(frm); 285 286 pjmedia_copy_samples(frm->buf, play_frm, echo->samples_per_frame); 287 pj_list_push_back(&echo->lat_buf, frm); 288 289 } else { 290 /* Latency buffer is ready (full), so we put this frame in the 291 * delay buffer. 292 */ 293 pjmedia_delay_buf_put(echo->delay_buf, play_frm); 294 } 295 296 return PJ_SUCCESS; 150 297 } 151 298 … … 159 306 unsigned options ) 160 307 { 161 return (*echo->op->ec_capture)(echo->state, rec_frm, options); 308 struct frame *oldest_frm; 309 pj_status_t status, rc; 310 311 if (!echo->lat_ready) { 312 /* Prefetching to fill in the desired latency */ 313 PJ_LOG(5,(echo->obj_name, "Prefetching..")); 314 return PJ_SUCCESS; 315 } 316 317 /* Retrieve oldest frame from the latency buffer */ 318 oldest_frm = echo->lat_buf.next; 319 pj_list_erase(oldest_frm); 320 321 /* Cancel echo using this reference frame */ 322 status = pjmedia_echo_cancel(echo, rec_frm, oldest_frm->buf, 323 options, NULL); 324 325 /* Move one frame from delay buffer to the latency buffer. */ 326 rc = pjmedia_delay_buf_get(echo->delay_buf, oldest_frm->buf); 327 if (rc != PJ_SUCCESS) { 328 /* Ooops.. no frame! */ 329 PJ_LOG(5,(echo->obj_name, 330 "No frame from delay buffer. This will upset EC later")); 331 pjmedia_zero_samples(oldest_frm->buf, echo->samples_per_frame); 332 } 333 pj_list_push_back(&echo->lat_buf, oldest_frm); 334 335 return status; 162 336 } 163 337
Note: See TracChangeset
for help on using the changeset viewer.