Ticket #438: ticket438.patch
File ticket438.patch, 21.7 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 * Destroy delay buffer. 138 * 139 * @param b Delay buffer session. 140 * 141 * @return PJ_SUCCESS normally. 142 */ 143 PJ_DECL(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b); 134 144 145 135 146 PJ_END_DECL 136 147 137 148 -
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 130 171 static void update(pjmedia_delay_buf *b, enum OP op) 131 172 { 132 173 enum OP other = (enum OP) !op; … … 157 198 /* give SAFE_MARGIN compensation for added stability */ 158 199 b->max_level += SAFE_MARGIN; 159 200 160 PJ_LOG(5,(b->obj_name,"Delay buffer start running, level=%u",161 201 TRACE__((b->obj_name,"Delay buffer start running, level=%u", 202 b->max_level)); 162 203 163 204 /* 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)); 205 if (b->max_level > b->max_frames) { 206 PJ_LOG(4,(b->obj_name,"Delay buffer learning result (%d)" 207 " exceeds the maximum delay allowed (%d)", 208 b->max_level, 209 b->max_frames)); 210 211 b->max_level = b->max_frames; 169 212 } 170 213 214 b->max_cnt = b->max_level * b->samples_per_frame; 171 215 b->state = STATE_RUNNING; 172 216 } 173 217 } … … 181 225 PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b, 182 226 pj_int16_t frame[]) 183 227 { 228 pj_status_t status; 229 184 230 update(b, OP_PUT); 185 231 232 status = pjmedia_wsola_save(b->wsola, frame, PJ_FALSE); 233 if (status != PJ_SUCCESS) 234 return status; 235 186 236 if (b->state != STATE_RUNNING) 187 237 return PJ_EPENDING; 238 239 /* Overflow checking */ 240 if (b->buf_cnt + b->samples_per_frame > b->max_cnt) 241 { 242 /* shrink one frame or just the diff? */ 243 //unsigned erase_cnt = b->samples_per_frame; 244 unsigned erase_cnt = b->buf_cnt + b->samples_per_frame - b->max_cnt; 188 245 189 pj_memcpy(&b->frame_buf[b->put_pos * b->samples_per_frame], frame, 190 b->samples_per_frame*sizeof(pj_int16_t));246 unsigned buf1len; 247 unsigned buf2len; 191 248 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; 249 TRACE__((b->obj_name,"Warning: buffer overflow, buf_cnt=%d, " 250 "trying to shrink %d samples", b->buf_cnt, erase_cnt)); 196 251 197 b->put_pos = b->get_pos; 252 if (b->get_pos < b->put_pos) { 253 /* sssss .. sssss 254 * ^ ^ 255 * G P 256 */ 257 buf1len = b->put_pos - b->get_pos; 258 buf2len = 0; 259 } else { 260 /* sssss .. sssss 261 * ^ ^ 262 * P G 263 */ 264 buf1len = b->max_cnt - b->get_pos; 265 buf2len = b->put_pos; 266 } 198 267 199 PJ_LOG(5,(b->obj_name,"Warning: buffer overflow")); 268 if (buf1len != 0) 269 status = pjmedia_wsola_discard(b->wsola, 270 &b->frame_buf[b->get_pos], buf1len, 271 b->frame_buf, buf2len, 272 &erase_cnt); 273 else 274 status = pjmedia_wsola_discard(b->wsola, 275 b->frame_buf, buf2len, 276 NULL, 0, 277 &erase_cnt); 200 278 201 return PJ_ETOOMANY; 279 if ((status == PJ_SUCCESS) && (erase_cnt > 0)) { 280 /* WSOLA discard will shrink only the second buffer, but it may 281 * also shrink first buffer if second buffer is 'destroyed', so 282 * it is safe to just set the new put_pos. 283 */ 284 if (b->put_pos >= erase_cnt) 285 b->put_pos -= erase_cnt; 286 else 287 b->put_pos = b->max_cnt - (erase_cnt - b->put_pos); 288 289 b->buf_cnt -= erase_cnt; 290 291 TRACE__((b->obj_name,"Successfully shrinking %d samples, " 292 "buf_cnt=%d", erase_cnt, b->buf_cnt)); 293 } 294 295 /* Shrinking failed or erased count is less than requested, 296 * delay buf needs to drop eldest samples, this is bad since the voice 297 * samples may not have smooth transition. 298 */ 299 if (b->buf_cnt + b->samples_per_frame > b->max_cnt) { 300 erase_cnt = b->buf_cnt + b->samples_per_frame - b->max_cnt; 301 302 b->buf_cnt -= erase_cnt; 303 304 /* Shift get_pos forward */ 305 b->get_pos = (b->get_pos + erase_cnt) % b->max_cnt; 306 307 TRACE__((b->obj_name,"Shrinking failed or insufficient, dropping" 308 " %d eldest samples, buf_cnt=%d", erase_cnt, b->buf_cnt)); 309 } 202 310 } 203 311 204 ++b->buf_cnt; 312 /* put the frame on put_pos */ 313 if (b->put_pos + b->samples_per_frame <= b->max_cnt) { 314 pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame, 315 b->samples_per_frame); 316 } else { 317 int remainder = b->put_pos + b->samples_per_frame - b->max_cnt; 205 318 206 if (++b->put_pos == b->max_level) 207 b->put_pos = 0; 319 pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame, 320 b->samples_per_frame - remainder); 321 pjmedia_copy_samples(&b->frame_buf[0], 322 &frame[b->samples_per_frame - remainder], 323 remainder); 324 } 208 325 326 /* Update put_pos & buf_cnt */ 327 b->put_pos = (b->put_pos + b->samples_per_frame) % b->max_cnt; 328 b->buf_cnt += b->samples_per_frame; 329 209 330 return PJ_SUCCESS; 210 331 } 211 332 212 333 PJ_DEF(pj_status_t) pjmedia_delay_buf_get(pjmedia_delay_buf *b, 213 334 pj_int16_t frame[]) 214 335 { 336 pj_status_t status; 215 337 update(b, OP_GET); 216 338 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")); 220 221 pj_bzero(frame, b->samples_per_frame*sizeof(pj_int16_t)); 339 if (b->state != STATE_RUNNING) { 340 pjmedia_zero_samples(frame, b->samples_per_frame); 222 341 return PJ_EPENDING; 223 342 } 224 343 225 pj_memcpy(frame, &b->frame_buf[b->get_pos * b->samples_per_frame],226 b->samples_per_frame*sizeof(pj_int16_t)); 344 /* Starvation checking */ 345 if (b->buf_cnt < b->samples_per_frame) { 227 346 228 if (++b->get_pos == b->max_level) 229 b->get_pos = 0;347 TRACE__((b->obj_name,"Warning: buffer lack of samples, buf_cnt=%d", 348 b->buf_cnt)); 230 349 231 --b->buf_cnt;350 status = pjmedia_wsola_generate(b->wsola, frame); 232 351 352 if (status == PJ_SUCCESS) { 353 TRACE__((b->obj_name,"Successfully generate frame")); 354 if (b->buf_cnt == 0) 355 return PJ_SUCCESS; 356 357 /* put generated frame into buffer */ 358 if (b->put_pos + b->samples_per_frame <= b->max_cnt) { 359 pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame, 360 b->samples_per_frame); 361 } else { 362 int remainder = b->put_pos + b->samples_per_frame - b->max_cnt; 363 364 pjmedia_copy_samples(&b->frame_buf[b->put_pos], &frame[0], 365 b->samples_per_frame - remainder); 366 pjmedia_copy_samples(&b->frame_buf[0], 367 &frame[b->samples_per_frame - remainder], 368 remainder); 369 } 370 371 b->put_pos = (b->put_pos + b->samples_per_frame) % b->max_cnt; 372 b->buf_cnt += b->samples_per_frame; 373 374 } else { 375 /* Give all what delay buffer has, then pad zeroes */ 376 TRACE__((b->obj_name,"Failed generate frame")); 377 378 pjmedia_copy_samples(frame, &b->frame_buf[b->get_pos], b->buf_cnt); 379 pjmedia_zero_samples(&frame[b->buf_cnt], 380 b->samples_per_frame - b->buf_cnt); 381 b->get_pos += b->buf_cnt; 382 b->buf_cnt = 0; 383 384 /* Consistency checking */ 385 pj_assert(b->get_pos == b->put_pos); 386 387 return PJ_SUCCESS; 388 } 389 } 390 391 pjmedia_copy_samples(frame, &b->frame_buf[b->get_pos], 392 b->samples_per_frame); 393 394 b->get_pos = (b->get_pos + b->samples_per_frame) % b->max_cnt; 395 b->buf_cnt -= b->samples_per_frame; 396 233 397 return PJ_SUCCESS; 234 398 } 235 399 … … 242 406 b->state = STATE_LEARNING; 243 407 b->state_count = 0; 244 408 b->max_level = 0; 409 b->max_cnt = 0; 245 410 246 411 /* clean up buffer */ 247 412 b->buf_cnt = 0; 248 413 b->put_pos = b->get_pos = 0; 249 414 250 PJ_LOG(5,(b->obj_name,"Delay buffer start learning"));415 TRACE__((b->obj_name,"Delay buffer start learning")); 251 416 252 417 return PJ_SUCCESS; 253 418 } -
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. */ … … 1616 1627 continue; 1617 1628 } 1618 1629 1619 /* Get frame from this port. 1620 * For p ort zero (sound port) and passive ports, get the frame from1621 * the rx_buffer instead.1630 /* Get frame from this port. 1631 * For passive ports, get the frame from the delay_buf. 1632 * For other ports, get the frame from the port. 1622 1633 */ 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; 1634 if (conf_port->delay_buf != NULL) { 1635 pj_status_t status; 1636 1637 status = pjmedia_delay_buf_get(conf_port->delay_buf, 1638 (pj_int16_t*)frame->buf); 1639 if (status != PJ_SUCCESS) 1635 1640 continue; 1636 }1637 1641 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 1642 } else { 1644 1643 1645 1644 pj_status_t status; … … 1830 1829 1831 1830 1832 1831 /* 1833 * Recorder callback.1832 * Recorder (or passive port) callback. 1834 1833 */ 1835 1834 static pj_status_t put_frame(pjmedia_port *this_port, 1836 1835 const pjmedia_frame *frame) 1837 1836 { 1838 1837 pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata; 1839 1838 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; 1839 pj_status_t status; 1842 1840 1843 1841 /* Check for correct size. */ 1844 1842 PJ_ASSERT_RETURN( frame->size == conf->samples_per_frame * 1845 1843 conf->bits_per_sample / 8, 1846 1844 PJMEDIA_ENCSAMPLESPFRAME); 1847 1845 1846 /* Check existance of delay_buf instance */ 1847 PJ_ASSERT_RETURN( port->delay_buf, PJ_EBUG ); 1848 1848 1849 /* Skip if this port is muted/disabled. */ 1849 1850 if (port->rx_setting != PJMEDIA_PORT_ENABLE) { 1850 1851 return PJ_SUCCESS; … … 1855 1856 return PJ_SUCCESS; 1856 1857 } 1857 1858 1859 status = pjmedia_delay_buf_put(port->delay_buf, (pj_int16_t*)frame->buf); 1858 1860 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; 1861 return status; 1870 1862 } 1871 1863 -
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);