Ticket #438: ticket438.2.patch
File ticket438.2.patch, 24.2 KB (added by nanang, 17 years ago) |
---|
-
pjmedia/include/pjmedia/delaybuf.h
66 66 * from. 67 67 * @param name Optional name for the buffer for log 68 68 * identification. 69 * @param clock_rate Number of samples processed per second. 69 70 * @param samples_per_frame Number of samples per frame. 70 * @param max_ cntMaximum number of delay to be accommodated,71 * @param max_frames Maximum number of delay to be accommodated, 71 72 * in number of frames. 72 73 * @param delay The delay to be applied, in number of frames. 73 * If the value is -1 , the delay buffer will74 * If the value is -1 or 0, the delay buffer will 74 75 * learn about the delay automatically. If 75 76 * the value is greater than zero, then this 76 77 * value will be used and no learning will be … … 83 84 */ 84 85 PJ_DECL(pj_status_t) pjmedia_delay_buf_create(pj_pool_t *pool, 85 86 const char *name, 87 unsigned clock_rate, 86 88 unsigned samples_per_frame, 87 unsigned max_ cnt,89 unsigned max_frames, 88 90 int delay, 89 91 pjmedia_delay_buf **p_b); 90 92 … … 131 133 */ 132 134 PJ_DECL(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b); 133 135 136 /** 137 * Reset delay buffer. This will clear the buffer's content. But keep 138 * the learning result. 139 * 140 * @param b The delay buffer. 141 * 142 * @return PJ_SUCCESS on success or the appropriate error. 143 */ 144 PJ_DECL(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b); 134 145 146 /** 147 * Destroy delay buffer. 148 * 149 * @param b Delay buffer session. 150 * 151 * @return PJ_SUCCESS normally. 152 */ 153 PJ_DECL(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b); 154 155 135 156 PJ_END_DECL 136 157 137 158 -
pjmedia/src/pjmedia/delaybuf.c
19 19 20 20 #include <pjmedia/delaybuf.h> 21 21 #include <pjmedia/errno.h> 22 #include <pjmedia/wsola.h> 22 23 #include <pj/assert.h> 23 24 #include <pj/log.h> 24 25 #include <pj/pool.h> 25 26 27 28 #if 1 29 # define TRACE__(x) PJ_LOG(3,x) 30 #else 31 # define TRACE__(x) 32 #endif 33 34 35 /* Type of states of delay buffer */ 26 36 enum state 27 37 { 28 38 STATE_WAITING, … … 30 40 STATE_RUNNING 31 41 }; 32 42 43 /* Type of operation of delay buffer */ 33 44 enum OP 34 45 { 35 46 OP_PUT, … … 37 48 OP_UNDEFINED 38 49 }; 39 50 40 /* The following macros represent cycles of test. */ 41 /* Since there are two operations performed (get & put), */ 42 /* these macros value must be minimum 2 and should be even number */ 51 /* The following macros represent cycles of test. Since there are two 52 * operations performed (get & put), these macros minimum value must be 2 53 * and should be even number. 54 */ 43 55 #define WAITING_COUNT 4 44 56 #define LEARN_COUNT 16 45 57 46 /* Number of buffers to add to learnt level for additional stability */ 58 /* Number of buffers to add to learnt level for additional stability 59 * Please note that WSOLA discard needs minimum 3 frames, so max buffer count 60 * should be minimally 3, setting SAFE_MARGIN to 2 will guarantees this. 61 */ 47 62 #define SAFE_MARGIN 2 48 63 49 64 /* … … 66 81 67 82 struct pjmedia_delay_buf 68 83 { 69 char obj_name[PJ_MAX_OBJ_NAME];84 char obj_name[PJ_MAX_OBJ_NAME]; 70 85 71 pj_int16_t *frame_buf;72 unsigned put_pos;73 unsigned get_pos;74 unsigned buf_cnt;86 pj_int16_t *frame_buf; 87 enum state state; /**< State of delay buffer */ 88 unsigned samples_per_frame; /**< Number of samples for one frame */ 89 unsigned max_frames; /**< Buffer allocated, in frames */ 75 90 76 unsigned samples_per_frame; 77 unsigned max_cnt; 78 enum state state; 91 unsigned put_pos; /**< Position for put op, in samples */ 92 unsigned get_pos; /**< Position for get op, in samples */ 93 unsigned buf_cnt; /**< Number of buffered samples */ 94 unsigned max_cnt; /**< Max number of buffered samples */ 79 95 80 96 struct { 81 unsigned level;97 unsigned level; /**< Burst level storage of learning */ 82 98 } op[2]; 99 enum OP last_op; /**< Last op (GET or PUT) of learning*/ 100 unsigned state_count; /**< Counter of op cycles of learning*/ 83 101 84 enum OP last_op;85 unsigned max_level; 86 unsigned state_count;102 unsigned max_level; /**< Learning result: burst level */ 103 104 pjmedia_wsola *wsola; /**< Drift handler */ 87 105 }; 88 106 89 107 PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool, 90 108 const char *name, 109 unsigned clock_rate, 91 110 unsigned samples_per_frame, 92 unsigned max_ cnt,111 unsigned max_frames, 93 112 int delay, 94 113 pjmedia_delay_buf **p_b) 95 114 { 96 115 pjmedia_delay_buf *b; 116 pj_status_t status; 97 117 98 PJ_ASSERT_RETURN(pool && samples_per_frame && max_cnt && p_b, PJ_EINVAL); 118 PJ_ASSERT_RETURN(pool && samples_per_frame && max_frames && p_b, PJ_EINVAL); 119 PJ_ASSERT_RETURN((int)max_frames >= delay, PJ_EINVAL); 99 120 100 121 if (!name) { 101 122 name = "delaybuf"; … … 104 125 b = PJ_POOL_ZALLOC_T(pool, pjmedia_delay_buf); 105 126 106 127 pj_ansi_strncpy(b->obj_name, name, PJ_MAX_OBJ_NAME-1); 107 b->frame_buf = (pj_int16_t*)108 pj_pool_zalloc(pool, samples_per_frame * max_cnt *109 sizeof(pj_int16_t));110 128 b->samples_per_frame = samples_per_frame; 111 b->max_ cnt = max_cnt;129 b->max_frames = max_frames; 112 130 131 b->frame_buf = (pj_int16_t*) 132 pj_pool_zalloc(pool, samples_per_frame * max_frames * 133 sizeof(pj_int16_t)); 134 113 135 if (delay >= 0) { 114 PJ_ASSERT_RETURN(delay <= (int)max_cnt, PJ_EINVAL); 136 if (delay == 0) 137 delay = 1; 115 138 b->max_level = delay; 139 b->max_cnt = delay * samples_per_frame; 116 140 b->state = STATE_RUNNING; 117 141 } else { 142 b->max_cnt = max_frames * samples_per_frame; 118 143 b->last_op = OP_UNDEFINED; 119 144 b->state = STATE_WAITING; 120 b->buf_cnt = 0;121 145 } 122 146 147 status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 148 PJMEDIA_WSOLA_NO_PLC, &b->wsola); 149 if (status != PJ_SUCCESS) 150 return status; 151 123 152 *p_b = b; 124 153 125 PJ_LOG(5,(b->obj_name,"Delay buffer created"));154 TRACE__((b->obj_name,"Delay buffer created")); 126 155 127 156 return PJ_SUCCESS; 128 157 } 129 158 159 PJ_DEF(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b) 160 { 161 pj_status_t status; 162 163 status = pjmedia_wsola_destroy(b->wsola); 164 if (status == PJ_SUCCESS) 165 b->wsola = NULL; 166 167 return status; 168 } 169 170 /* This function will erase samples from delay buffer. 171 * The number of erased samples is guaranteed to be >= erase_cnt. 172 */ 173 static void shrink_buffer(pjmedia_delay_buf *b, unsigned erase_cnt) 174 { 175 unsigned buf1len; 176 unsigned buf2len; 177 pj_status_t status; 178 179 pj_assert(b && erase_cnt); 180 181 if (b->get_pos < b->put_pos) { 182 /* sssss .. sssss 183 * ^ ^ 184 * G P 185 */ 186 buf1len = b->put_pos - b->get_pos; 187 buf2len = 0; 188 } else { 189 /* sssss .. sssss 190 * ^ ^ 191 * P G 192 */ 193 buf1len = b->max_cnt - b->get_pos; 194 buf2len = b->put_pos; 195 } 196 197 /* Consistency checking */ 198 pj_assert((buf1len + buf2len) == b->buf_cnt); 199 200 if (buf1len != 0) 201 status = pjmedia_wsola_discard(b->wsola, 202 &b->frame_buf[b->get_pos], buf1len, 203 b->frame_buf, buf2len, 204 &erase_cnt); 205 else 206 status = pjmedia_wsola_discard(b->wsola, 207 b->frame_buf, buf2len, 208 NULL, 0, 209 &erase_cnt); 210 211 if ((status == PJ_SUCCESS) && (erase_cnt > 0)) { 212 /* WSOLA discard will shrink only the second buffer, but it may 213 * also shrink first buffer if second buffer is 'destroyed', so 214 * it is safe to just set the new put_pos. 215 */ 216 if (b->put_pos >= erase_cnt) 217 b->put_pos -= erase_cnt; 218 else 219 b->put_pos = b->max_cnt - (erase_cnt - b->put_pos); 220 221 b->buf_cnt -= erase_cnt; 222 223 TRACE__((b->obj_name,"Successfully shrinking %d samples, " 224 "buf_cnt=%d", erase_cnt, b->buf_cnt)); 225 } 226 227 /* Shrinking failed or erased count is less than requested, 228 * delay buf needs to drop eldest samples, this is bad since the voice 229 * samples may not have smooth transition. 230 */ 231 if (b->buf_cnt + b->samples_per_frame > b->max_cnt) { 232 erase_cnt = b->buf_cnt + b->samples_per_frame - b->max_cnt; 233 234 b->buf_cnt -= erase_cnt; 235 236 /* Shift get_pos forward */ 237 b->get_pos = (b->get_pos + erase_cnt) % b->max_cnt; 238 239 TRACE__((b->obj_name,"Shrinking failed or insufficient, dropping" 240 " %d eldest samples, buf_cnt=%d", erase_cnt, b->buf_cnt)); 241 } 242 } 243 244 static void set_max_cnt(pjmedia_delay_buf *b, unsigned new_max_cnt) 245 { 246 unsigned old_max_cnt = b->max_cnt; 247 248 /* nothing to adjust */ 249 if (old_max_cnt == new_max_cnt) 250 return; 251 252 /* For now, only support shrinking */ 253 pj_assert(old_max_cnt > new_max_cnt); 254 255 shrink_buffer(b, old_max_cnt - new_max_cnt); 256 257 /* Adjust buffer to accomodate the new max_cnt so the samples is secured. 258 * This is done by make get_pos = 0 259 */ 260 if (b->get_pos <= b->put_pos) { 261 /* sssss .. sssss 262 * ^ ^ 263 * G P 264 */ 265 /* Consistency checking */ 266 pj_assert((b->put_pos - b->get_pos) <= new_max_cnt); 267 pj_assert((b->put_pos - b->get_pos) == b->buf_cnt); 268 269 pjmedia_move_samples(b->frame_buf, &b->frame_buf[b->get_pos], 270 b->get_pos); 271 b->put_pos -= b->get_pos; 272 b->get_pos = 0; 273 } else { 274 /* sssss .. sssss 275 * ^ ^ 276 * P G 277 */ 278 unsigned d = old_max_cnt - b->get_pos; 279 280 /* Consistency checking */ 281 pj_assert((b->get_pos - b->put_pos) >= (old_max_cnt - new_max_cnt)); 282 283 /* Make get_pos = 0, shift right the leftmost block first */ 284 pjmedia_move_samples(&b->frame_buf[d], b->frame_buf, d); 285 pjmedia_copy_samples(b->frame_buf, &b->frame_buf[b->get_pos], d); 286 b->put_pos += d; 287 b->get_pos = 0; 288 } 289 290 b->max_cnt = new_max_cnt; 291 } 292 130 293 static void update(pjmedia_delay_buf *b, enum OP op) 131 294 { 132 295 enum OP other = (enum OP) !op; … … 157 320 /* give SAFE_MARGIN compensation for added stability */ 158 321 b->max_level += SAFE_MARGIN; 159 322 160 PJ_LOG(5,(b->obj_name,"Delay buffer start running, level=%u", 161 b->max_level)); 323 /* buffer not enough! */ 324 if (b->max_level > b->max_frames) { 325 PJ_LOG(4,(b->obj_name,"Delay buffer learning result (%d)" 326 " exceeds the maximum delay allowed (%d)", 327 b->max_level, 328 b->max_frames)); 162 329 163 /* buffer not enough! */ 164 if (b->max_level > b->max_cnt) { 165 b->max_level = b->max_cnt; 166 PJ_LOG(2,(b->obj_name,"Delay buffer %s learning result " \ 167 "exceeds the maximum delay allowed", 168 b->max_level)); 330 b->max_level = b->max_frames; 169 331 } 170 332 333 /* we need to set new max_cnt & adjust buffer */ 334 set_max_cnt(b, b->max_level * b->samples_per_frame); 335 171 336 b->state = STATE_RUNNING; 337 338 TRACE__((b->obj_name,"Delay buffer start running, level=%u", 339 b->max_level)); 172 340 } 173 341 } 174 342 b->last_op = op; … … 181 349 PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b, 182 350 pj_int16_t frame[]) 183 351 { 352 pj_status_t status; 353 184 354 update(b, OP_PUT); 185 355 186 if (b->state != STATE_RUNNING) 187 return PJ_EPENDING; 356 status = pjmedia_wsola_save(b->wsola, frame, PJ_FALSE); 357 if (status != PJ_SUCCESS) 358 return status; 188 359 189 pj_memcpy(&b->frame_buf[b->put_pos * b->samples_per_frame], frame, 190 b->samples_per_frame*sizeof(pj_int16_t)); 360 /* Overflow checking */ 361 if (b->buf_cnt + b->samples_per_frame > b->max_cnt) 362 { 363 /* shrink one frame or just the diff? */ 364 //unsigned erase_cnt = b->samples_per_frame; 365 unsigned erase_cnt = b->buf_cnt + b->samples_per_frame - b->max_cnt; 191 366 192 /* overflow case */ 193 if (b->put_pos == b->get_pos && b->buf_cnt) { 194 if (++b->get_pos == b->max_level) 195 b->get_pos = 0; 367 shrink_buffer(b, erase_cnt); 368 } 196 369 197 b->put_pos = b->get_pos; 370 /* put the frame on put_pos */ 371 if (b->put_pos + b->samples_per_frame <= b->max_cnt) { 372 pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame, 373 b->samples_per_frame); 374 } else { 375 int remainder = b->put_pos + b->samples_per_frame - b->max_cnt; 198 376 199 PJ_LOG(5,(b->obj_name,"Warning: buffer overflow")); 200 201 return PJ_ETOOMANY; 377 pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame, 378 b->samples_per_frame - remainder); 379 pjmedia_copy_samples(&b->frame_buf[0], 380 &frame[b->samples_per_frame - remainder], 381 remainder); 202 382 } 203 383 204 ++b->buf_cnt; 384 /* Update put_pos & buf_cnt */ 385 b->put_pos = (b->put_pos + b->samples_per_frame) % b->max_cnt; 386 b->buf_cnt += b->samples_per_frame; 205 387 206 if (++b->put_pos == b->max_level)207 b->put_pos = 0;208 209 388 return PJ_SUCCESS; 210 389 } 211 390 212 391 PJ_DEF(pj_status_t) pjmedia_delay_buf_get(pjmedia_delay_buf *b, 213 392 pj_int16_t frame[]) 214 393 { 394 pj_status_t status; 395 215 396 update(b, OP_GET); 216 397 217 if (b->state != STATE_RUNNING || !b->buf_cnt) { 218 if (b->state == STATE_RUNNING) 219 PJ_LOG(5,(b->obj_name,"Warning: delay buffer empty")); 398 /* Starvation checking */ 399 if (b->buf_cnt < b->samples_per_frame) { 220 400 221 pj_bzero(frame, b->samples_per_frame*sizeof(pj_int16_t)); 222 return PJ_EPENDING; 401 TRACE__((b->obj_name,"Warning: buffer lack of samples, buf_cnt=%d", 402 b->buf_cnt)); 403 404 status = pjmedia_wsola_generate(b->wsola, frame); 405 406 if (status == PJ_SUCCESS) { 407 TRACE__((b->obj_name,"Successfully generate frame")); 408 if (b->buf_cnt == 0) 409 return PJ_SUCCESS; 410 411 /* Put generated frame into buffer */ 412 if (b->put_pos + b->samples_per_frame <= b->max_cnt) { 413 pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame, 414 b->samples_per_frame); 415 } else { 416 int remainder = b->put_pos + b->samples_per_frame - b->max_cnt; 417 418 pjmedia_copy_samples(&b->frame_buf[b->put_pos], &frame[0], 419 b->samples_per_frame - remainder); 420 pjmedia_copy_samples(&b->frame_buf[0], 421 &frame[b->samples_per_frame - remainder], 422 remainder); 423 } 424 425 b->put_pos = (b->put_pos + b->samples_per_frame) % b->max_cnt; 426 b->buf_cnt += b->samples_per_frame; 427 428 } else { 429 /* Give all what delay buffer has, then pad zeroes */ 430 TRACE__((b->obj_name,"Failed generate frame")); 431 432 pjmedia_copy_samples(frame, &b->frame_buf[b->get_pos], b->buf_cnt); 433 pjmedia_zero_samples(&frame[b->buf_cnt], 434 b->samples_per_frame - b->buf_cnt); 435 b->get_pos += b->buf_cnt; 436 b->buf_cnt = 0; 437 438 /* Consistency checking */ 439 pj_assert(b->get_pos == b->put_pos); 440 441 return PJ_SUCCESS; 442 } 223 443 } 224 444 225 pj _memcpy(frame, &b->frame_buf[b->get_pos * b->samples_per_frame],226 b->samples_per_frame*sizeof(pj_int16_t));445 pjmedia_copy_samples(frame, &b->frame_buf[b->get_pos], 446 b->samples_per_frame); 227 447 228 if (++b->get_pos == b->max_level)229 b->get_pos = 0;448 b->get_pos = (b->get_pos + b->samples_per_frame) % b->max_cnt; 449 b->buf_cnt -= b->samples_per_frame; 230 450 231 --b->buf_cnt;232 233 451 return PJ_SUCCESS; 234 452 } 235 453 236 PJ_DE CL(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b)454 PJ_DEF(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b) 237 455 { 238 456 PJ_ASSERT_RETURN(b, PJ_EINVAL); 239 457 … … 242 460 b->state = STATE_LEARNING; 243 461 b->state_count = 0; 244 462 b->max_level = 0; 463 b->max_cnt = b->max_frames * b->samples_per_frame; 245 464 465 pjmedia_delay_buf_reset(b); 466 467 TRACE__((b->obj_name,"Delay buffer start learning")); 468 469 return PJ_SUCCESS; 470 } 471 472 PJ_DEF(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b) 473 { 474 PJ_ASSERT_RETURN(b, PJ_EINVAL); 475 246 476 /* clean up buffer */ 247 477 b->buf_cnt = 0; 248 478 b->put_pos = b->get_pos = 0; 479 pjmedia_wsola_reset(b->wsola, 0); 249 480 250 PJ_LOG(5,(b->obj_name,"Delay buffer start learning"));481 TRACE__((b->obj_name,"Delay buffer resetted")); 251 482 252 483 return PJ_SUCCESS; 253 484 } -
pjmedia/src/pjmedia/conference.c
18 18 */ 19 19 #include <pjmedia/conference.h> 20 20 #include <pjmedia/alaw_ulaw.h> 21 #include <pjmedia/delaybuf.h> 21 22 #include <pjmedia/errno.h> 22 23 #include <pjmedia/port.h> 23 24 #include <pjmedia/resample.h> … … 56 57 57 58 #define THIS_FILE "conference.c" 58 59 59 /* When delay buffer is used, we only need 1 frame buffering */ 60 #if defined(PJMEDIA_SOUND_USE_DELAYBUF) && PJMEDIA_SOUND_USE_DELAYBUF!=0 61 # define RX_BUF_COUNT 1 62 #else 63 # define RX_BUF_COUNT PJMEDIA_SOUND_BUFFER_COUNT 64 #endif 60 #define RX_BUF_COUNT PJMEDIA_SOUND_BUFFER_COUNT 65 61 66 62 #define BYTES_PER_SAMPLE 2 67 63 … … 183 179 unsigned tx_buf_cap; /**< Max size, in samples. */ 184 180 unsigned tx_buf_count; /**< # of samples in the buffer. */ 185 181 186 /* Snd buffersis a special buffer for sound device port (port 0, master187 * port) . It's not used by other ports.182 /* Delay buffer is a special buffer for sound device port (port 0, master 183 * port) and other passive ports (sound device port is also passive port). 188 184 * 189 * There are multiple numbers of this buffer, because we can not expect 190 * the mic and speaker thread to run equally after one another. In most 191 * systems, each thread will run multiple times before the other thread 192 * gains execution time. For example, in my system, mic thread is called 193 * three times, then speaker thread is called three times, and so on. 185 * We need the delay buffer because we can not expect the mic and speaker 186 * thread to run equally after one another. In most systems, each thread 187 * will run multiple times before the other thread gains execution time. 188 * For example, in my system, mic thread is called three times, then 189 * speaker thread is called three times, and so on. This we call burst. 190 * 191 * There is also possibility of drift, unbalanced rate between put_frame 192 * and get_frame operation, in passive ports. If drift happens, snd_buf 193 * needs to be expanded or shrinked. 194 * 195 * Burst and drift are handled by delay buffer. 194 196 */ 195 int snd_write_pos, snd_read_pos; 196 pj_int16_t *snd_buf[RX_BUF_COUNT]; /**< Buffer */ 197 pjmedia_delay_buf *delay_buf; 197 198 }; 198 199 199 200 … … 226 227 static pj_status_t get_frame_pasv(pjmedia_port *this_port, 227 228 pjmedia_frame *frame); 228 229 static pj_status_t destroy_port(pjmedia_port *this_port); 230 static pj_status_t destroy_port_pasv(pjmedia_port *this_port); 229 231 230 232 231 233 /* … … 377 379 struct conf_port **p_conf_port) 378 380 { 379 381 struct conf_port *conf_port; 380 unsigned i;381 382 pj_status_t status; 382 383 383 384 /* Create port */ … … 385 386 if (status != PJ_SUCCESS) 386 387 return status; 387 388 388 /* Passive port has rx buffers. */ 389 for (i=0; i<RX_BUF_COUNT; ++i) { 390 conf_port->snd_buf[i] = (pj_int16_t*) 391 pj_pool_zalloc(pool, conf->samples_per_frame * 392 sizeof(conf_port->snd_buf[0][0])); 393 if (conf_port->snd_buf[i] == NULL) { 394 return PJ_ENOMEM; 395 } 396 } 397 conf_port->snd_write_pos = 0; 398 conf_port->snd_read_pos = 0; 389 /* Passive port has delay buf. */ 390 status = pjmedia_delay_buf_create(pool, name->ptr, 391 conf->clock_rate, 392 conf->samples_per_frame, 393 RX_BUF_COUNT, /* max */ 394 -1, /* delay */ 395 &conf_port->delay_buf); 396 if (status != PJ_SUCCESS) 397 return status; 399 398 400 399 *p_conf_port = conf_port; 401 400 … … 444 443 conf->bits_per_sample, 445 444 0, /* Options */ 446 445 &conf->snd_dev_port); 446 447 447 } 448 448 449 449 if (status != PJ_SUCCESS) … … 606 606 return pjmedia_conf_destroy(conf); 607 607 } 608 608 609 static pj_status_t destroy_port_pasv(pjmedia_port *this_port) { 610 pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata; 611 struct conf_port *port = conf->ports[this_port->port_data.ldata]; 612 pj_status_t status; 609 613 614 status = pjmedia_delay_buf_destroy(port->delay_buf); 615 if (status == PJ_SUCCESS) 616 port->delay_buf = NULL; 617 618 return status; 619 } 620 610 621 /* 611 622 * Get port zero interface. 612 623 */ … … 785 796 786 797 port->get_frame = &get_frame_pasv; 787 798 port->put_frame = &put_frame; 788 port->on_destroy = NULL;799 port->on_destroy = &destroy_port_pasv; 789 800 790 801 791 802 /* Create conf port structure. */ … … 954 965 (int)dst_port->name.slen, 955 966 dst_port->name.ptr)); 956 967 957 968 /* if source port is passive port and has no listener, reset delaybuf */ 969 if (src_port->delay_buf && src_port->listener_cnt == 0) 970 pjmedia_delay_buf_reset(src_port->delay_buf); 958 971 } 959 972 960 973 pj_mutex_unlock(conf->mutex); … … 1616 1629 continue; 1617 1630 } 1618 1631 1619 /* Get frame from this port. 1620 * For p ort zero (sound port) and passive ports, get the frame from1621 * the rx_buffer instead.1632 /* Get frame from this port. 1633 * For passive ports, get the frame from the delay_buf. 1634 * For other ports, get the frame from the port. 1622 1635 */ 1623 if (conf_port->port == NULL) { 1624 pj_int16_t *snd_buf; 1625 1626 if (conf_port->snd_read_pos == conf_port->snd_write_pos) { 1627 conf_port->snd_read_pos = 1628 (conf_port->snd_write_pos+RX_BUF_COUNT-RX_BUF_COUNT/2) % 1629 RX_BUF_COUNT; 1630 } 1631 1632 /* Skip if this port is muted/disabled. */ 1633 if (conf_port->rx_setting != PJMEDIA_PORT_ENABLE) { 1634 conf_port->rx_level = 0; 1636 if (conf_port->delay_buf != NULL) { 1637 pj_status_t status; 1638 1639 status = pjmedia_delay_buf_get(conf_port->delay_buf, 1640 (pj_int16_t*)frame->buf); 1641 if (status != PJ_SUCCESS) 1635 1642 continue; 1636 }1637 1643 1638 snd_buf = conf_port->snd_buf[conf_port->snd_read_pos];1639 pjmedia_copy_samples((pj_int16_t*)frame->buf, snd_buf,1640 conf->samples_per_frame);1641 conf_port->snd_read_pos = (conf_port->snd_read_pos+1) % RX_BUF_COUNT;1642 1643 1644 } else { 1644 1645 1645 1646 pj_status_t status; … … 1830 1831 1831 1832 1832 1833 /* 1833 * Recorder callback.1834 * Recorder (or passive port) callback. 1834 1835 */ 1835 1836 static pj_status_t put_frame(pjmedia_port *this_port, 1836 1837 const pjmedia_frame *frame) 1837 1838 { 1838 1839 pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata; 1839 1840 struct conf_port *port = conf->ports[this_port->port_data.ldata]; 1840 const pj_int16_t *input = (const pj_int16_t*) frame->buf; 1841 pj_int16_t *target_snd_buf; 1841 pj_status_t status; 1842 1842 1843 1843 /* Check for correct size. */ 1844 1844 PJ_ASSERT_RETURN( frame->size == conf->samples_per_frame * 1845 1845 conf->bits_per_sample / 8, 1846 1846 PJMEDIA_ENCSAMPLESPFRAME); 1847 1847 1848 /* Check existance of delay_buf instance */ 1849 PJ_ASSERT_RETURN( port->delay_buf, PJ_EBUG ); 1850 1848 1851 /* Skip if this port is muted/disabled. */ 1849 1852 if (port->rx_setting != PJMEDIA_PORT_ENABLE) { 1850 1853 return PJ_SUCCESS; … … 1855 1858 return PJ_SUCCESS; 1856 1859 } 1857 1860 1861 status = pjmedia_delay_buf_put(port->delay_buf, (pj_int16_t*)frame->buf); 1858 1862 1859 /* Determine which rx_buffer to fill in */ 1860 target_snd_buf = port->snd_buf[port->snd_write_pos]; 1861 1862 /* Copy samples from audio device to target rx_buffer */ 1863 pjmedia_copy_samples(target_snd_buf, input, conf->samples_per_frame); 1864 1865 /* Switch buffer */ 1866 port->snd_write_pos = (port->snd_write_pos+1)%RX_BUF_COUNT; 1867 1868 1869 return PJ_SUCCESS; 1863 return status; 1870 1864 } 1871 1865 -
pjmedia/src/pjmedia/sound_port.c
32 32 33 33 #define THIS_FILE "sound_port.c" 34 34 35 #define TEST_OVERFLOW_UNDERFLOW 36 35 37 enum 36 38 { 37 39 PJMEDIA_PLC_ENABLED = 1, … … 101 103 #if PJMEDIA_SOUND_USE_DELAYBUF 102 104 if (snd_port->delay_buf) { 103 105 status = pjmedia_delay_buf_get(snd_port->delay_buf, (pj_int16_t*)output); 104 if (status != PJ_SUCCESS) {106 if (status != PJ_SUCCESS) 105 107 pj_bzero(output, size); 106 }107 108 108 109 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 109 110 pjmedia_port_put_frame(port, &frame); 111 112 #ifdef TEST_OVERFLOW_UNDERFLOW 113 { 114 static int count = 1; 115 if (++count % 10 == 0) { 116 status = pjmedia_delay_buf_get(snd_port->delay_buf, 117 (pj_int16_t*)output); 118 if (status != PJ_SUCCESS) 119 pj_bzero(output, size); 120 121 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 122 pjmedia_port_put_frame(port, &frame); 123 } 124 } 125 #endif 126 110 127 } 111 128 #endif 112 129 … … 371 388 snd_port->bits_per_sample = bits_per_sample; 372 389 373 390 #if PJMEDIA_SOUND_USE_DELAYBUF 374 status = pjmedia_delay_buf_create(pool, "snd_buff", samples_per_frame, 391 status = pjmedia_delay_buf_create(pool, "snd_buff", 392 clock_rate, samples_per_frame, 375 393 PJMEDIA_SOUND_BUFFER_COUNT, -1, 376 394 &snd_port->delay_buf); 377 395 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);