Changeset 1833 for pjproject/trunk
- Timestamp:
- Feb 29, 2008 5:19:42 PM (17 years ago)
- Location:
- pjproject/trunk/pjmedia
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/include/pjmedia/delaybuf.h
r1664 r1833 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 77 78 * performed. 79 * @param option Option flags, must be zero for now. 78 80 * @param p_b Pointer to receive the delay buffer instance. 79 81 * … … 84 86 PJ_DECL(pj_status_t) pjmedia_delay_buf_create(pj_pool_t *pool, 85 87 const char *name, 88 unsigned clock_rate, 86 89 unsigned samples_per_frame, 87 unsigned max_ cnt,90 unsigned max_frames, 88 91 int delay, 92 unsigned options, 89 93 pjmedia_delay_buf **p_b); 90 94 … … 132 136 PJ_DECL(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b); 133 137 138 /** 139 * Reset delay buffer. This will clear the buffer's content. But keep 140 * the learning result. 141 * 142 * @param b The delay buffer. 143 * 144 * @return PJ_SUCCESS on success or the appropriate error. 145 */ 146 PJ_DECL(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b); 147 148 /** 149 * Destroy delay buffer. 150 * 151 * @param b Delay buffer session. 152 * 153 * @return PJ_SUCCESS normally. 154 */ 155 PJ_DECL(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b); 156 134 157 135 158 PJ_END_DECL -
pjproject/trunk/pjmedia/src/pjmedia/conference.c
r1715 r1833 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> … … 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 … … 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. 194 */ 195 int snd_write_pos, snd_read_pos; 196 pj_int16_t *snd_buf[RX_BUF_COUNT]; /**< Buffer */ 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. 196 */ 197 pjmedia_delay_buf *delay_buf; 197 198 }; 198 199 … … 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 … … 378 380 { 379 381 struct conf_port *conf_port; 380 unsigned i;381 382 pj_status_t status; 382 383 … … 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 0, /* options */ 396 &conf_port->delay_buf); 397 if (status != PJ_SUCCESS) 398 return status; 399 399 400 400 *p_conf_port = conf_port; … … 445 445 0, /* Options */ 446 446 &conf->snd_dev_port); 447 447 448 } 448 449 … … 607 608 } 608 609 610 static pj_status_t destroy_port_pasv(pjmedia_port *this_port) { 611 pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata; 612 struct conf_port *port = conf->ports[this_port->port_data.ldata]; 613 pj_status_t status; 614 615 status = pjmedia_delay_buf_destroy(port->delay_buf); 616 if (status == PJ_SUCCESS) 617 port->delay_buf = NULL; 618 619 return status; 620 } 609 621 610 622 /* … … 786 798 port->get_frame = &get_frame_pasv; 787 799 port->put_frame = &put_frame; 788 port->on_destroy = NULL;800 port->on_destroy = &destroy_port_pasv; 789 801 790 802 … … 955 967 dst_port->name.ptr)); 956 968 957 969 /* if source port is passive port and has no listener, reset delaybuf */ 970 if (src_port->delay_buf && src_port->listener_cnt == 0) 971 pjmedia_delay_buf_reset(src_port->delay_buf); 958 972 } 959 973 … … 1617 1631 } 1618 1632 1619 /* Get frame from this port. 1620 * For p ort zero (sound port) and passive ports, get the frame from1621 * the rx_buffer instead.1633 /* Get frame from this port. 1634 * For passive ports, get the frame from the delay_buf. 1635 * For other ports, get the frame from the port. 1622 1636 */ 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; 1637 if (conf_port->delay_buf != NULL) { 1638 pj_status_t status; 1639 1640 status = pjmedia_delay_buf_get(conf_port->delay_buf, 1641 (pj_int16_t*)frame->buf); 1642 if (status != PJ_SUCCESS) 1635 1643 continue; 1636 }1637 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 1644 1643 1645 } else { … … 1831 1833 1832 1834 /* 1833 * Recorder callback.1835 * Recorder (or passive port) callback. 1834 1836 */ 1835 1837 static pj_status_t put_frame(pjmedia_port *this_port, … … 1838 1840 pjmedia_conf *conf = (pjmedia_conf*) this_port->port_data.pdata; 1839 1841 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; 1842 pj_status_t status; 1842 1843 1843 1844 /* Check for correct size. */ … … 1846 1847 PJMEDIA_ENCSAMPLESPFRAME); 1847 1848 1849 /* Check existance of delay_buf instance */ 1850 PJ_ASSERT_RETURN( port->delay_buf, PJ_EBUG ); 1851 1848 1852 /* Skip if this port is muted/disabled. */ 1849 1853 if (port->rx_setting != PJMEDIA_PORT_ENABLE) { … … 1856 1860 } 1857 1861 1858 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; 1870 } 1871 1862 status = pjmedia_delay_buf_put(port->delay_buf, (pj_int16_t*)frame->buf); 1863 1864 return status; 1865 } 1866 -
pjproject/trunk/pjmedia/src/pjmedia/delaybuf.c
r1716 r1833 20 20 #include <pjmedia/delaybuf.h> 21 21 #include <pjmedia/errno.h> 22 #include <pjmedia/wsola.h> 22 23 #include <pj/assert.h> 24 #include <pj/lock.h> 23 25 #include <pj/log.h> 24 26 #include <pj/pool.h> 25 27 28 29 #if 0 30 # define TRACE__(x) PJ_LOG(3,x) 31 #else 32 # define TRACE__(x) 33 #endif 34 35 36 /* Type of states of delay buffer */ 26 37 enum state 27 38 { … … 31 42 }; 32 43 44 /* Type of operation of delay buffer */ 33 45 enum OP 34 46 { … … 38 50 }; 39 51 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 */ 52 /* The following macros represent cycles of test. Since there are two 53 * operations performed (get & put), these macros minimum value must be 2 54 * and should be even number. 55 */ 43 56 #define WAITING_COUNT 4 44 57 #define LEARN_COUNT 16 45 58 46 /* Number of buffers to add to learnt level for additional stability */ 59 /* Number of buffers to add to learnt level for additional stability 60 * Please note that wsola_discard() needs minimum 3 frames, so max buffer 61 * count should be minimally 3, setting SAFE_MARGIN to 2 will guarantees 62 * this. 63 */ 47 64 #define SAFE_MARGIN 2 48 65 … … 67 84 struct pjmedia_delay_buf 68 85 { 69 char obj_name[PJ_MAX_OBJ_NAME]; 70 71 pj_int16_t *frame_buf; 72 unsigned put_pos; 73 unsigned get_pos; 74 unsigned buf_cnt; 75 76 unsigned samples_per_frame; 77 unsigned max_cnt; 78 enum state state; 86 char obj_name[PJ_MAX_OBJ_NAME]; 87 88 pj_lock_t *lock; /**< Lock object. */ 89 90 pj_int16_t *frame_buf; 91 enum state state; /**< State of delay buffer */ 92 unsigned samples_per_frame; /**< Number of samples in one frame */ 93 unsigned max_frames; /**< Buffer allocated, in frames */ 94 95 unsigned put_pos; /**< Position for put op, in samples */ 96 unsigned get_pos; /**< Position for get op, in samples */ 97 unsigned buf_cnt; /**< Number of buffered samples */ 98 unsigned max_cnt; /**< Max number of buffered samples */ 79 99 80 100 struct { 81 unsigned level;101 unsigned level; /**< Burst level storage on learning */ 82 102 } op[2]; 83 84 enum OP last_op; 85 unsigned max_level; 86 unsigned state_count; 103 enum OP last_op; /**< Last op (GET or PUT) of learning*/ 104 unsigned state_count; /**< Counter of op cycles of learning*/ 105 106 unsigned max_level; /**< Learning result: burst level */ 107 108 pjmedia_wsola *wsola; /**< Drift handler */ 87 109 }; 88 110 89 111 PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool, 90 112 const char *name, 113 unsigned clock_rate, 91 114 unsigned samples_per_frame, 92 unsigned max_ cnt,115 unsigned max_frames, 93 116 int delay, 117 unsigned options, 94 118 pjmedia_delay_buf **p_b) 95 119 { 96 120 pjmedia_delay_buf *b; 97 98 PJ_ASSERT_RETURN(pool && samples_per_frame && max_cnt && p_b, PJ_EINVAL); 121 pj_status_t status; 122 123 PJ_ASSERT_RETURN(pool && samples_per_frame && max_frames && p_b, PJ_EINVAL); 124 PJ_ASSERT_RETURN((int)max_frames >= delay, PJ_EINVAL); 125 PJ_ASSERT_RETURN(options==0, PJ_EINVAL); 126 127 PJ_UNUSED_ARG(options); 99 128 100 129 if (!name) { … … 105 134 106 135 pj_ansi_strncpy(b->obj_name, name, PJ_MAX_OBJ_NAME-1); 136 b->samples_per_frame = samples_per_frame; 137 b->max_frames = max_frames; 138 139 status = pj_lock_create_recursive_mutex(pool, b->obj_name, 140 &b->lock); 141 if (status != PJ_SUCCESS) 142 return status; 143 107 144 b->frame_buf = (pj_int16_t*) 108 pj_pool_zalloc(pool, samples_per_frame * max_cnt * 109 sizeof(pj_int16_t)); 110 b->samples_per_frame = samples_per_frame; 111 b->max_cnt = max_cnt; 145 pj_pool_zalloc(pool, samples_per_frame * max_frames * 146 sizeof(pj_int16_t)); 112 147 113 148 if (delay >= 0) { 114 PJ_ASSERT_RETURN(delay <= (int)max_cnt, PJ_EINVAL); 149 if (delay == 0) 150 delay = 1; 115 151 b->max_level = delay; 152 b->max_cnt = delay * samples_per_frame; 116 153 b->state = STATE_RUNNING; 117 154 } else { 155 b->max_cnt = max_frames * samples_per_frame; 118 156 b->last_op = OP_UNDEFINED; 119 157 b->state = STATE_WAITING; 120 b->buf_cnt = 0; 121 } 158 } 159 160 status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 161 PJMEDIA_WSOLA_NO_PLC, &b->wsola); 162 if (status != PJ_SUCCESS) 163 return status; 122 164 123 165 *p_b = b; 124 166 125 PJ_LOG(5,(b->obj_name,"Delay buffer created"));167 TRACE__((b->obj_name,"Delay buffer created")); 126 168 127 169 return PJ_SUCCESS; 170 } 171 172 PJ_DEF(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b) 173 { 174 pj_status_t status; 175 176 PJ_ASSERT_RETURN(b, PJ_EINVAL); 177 178 pj_lock_acquire(b->lock); 179 180 status = pjmedia_wsola_destroy(b->wsola); 181 if (status == PJ_SUCCESS) 182 b->wsola = NULL; 183 184 pj_lock_release(b->lock); 185 pj_lock_destroy(b->lock); 186 b->lock = NULL; 187 188 return status; 189 } 190 191 /* This function will erase samples from delay buffer. 192 * The number of erased samples is guaranteed to be >= erase_cnt. 193 */ 194 static void shrink_buffer(pjmedia_delay_buf *b, unsigned erase_cnt) 195 { 196 unsigned buf1len; 197 unsigned buf2len; 198 pj_status_t status; 199 200 pj_assert(b && erase_cnt); 201 202 if (b->get_pos < b->put_pos) { 203 /* sssss .. sssss 204 * ^ ^ 205 * G P 206 */ 207 buf1len = b->put_pos - b->get_pos; 208 buf2len = 0; 209 } else { 210 /* sssss .. sssss 211 * ^ ^ 212 * P G 213 */ 214 buf1len = b->max_cnt - b->get_pos; 215 buf2len = b->put_pos; 216 } 217 218 /* Consistency checking */ 219 pj_assert((buf1len + buf2len) == b->buf_cnt); 220 221 if (buf1len != 0) 222 status = pjmedia_wsola_discard(b->wsola, 223 &b->frame_buf[b->get_pos], buf1len, 224 b->frame_buf, buf2len, 225 &erase_cnt); 226 else 227 status = pjmedia_wsola_discard(b->wsola, 228 b->frame_buf, buf2len, 229 NULL, 0, 230 &erase_cnt); 231 232 if ((status == PJ_SUCCESS) && (erase_cnt > 0)) { 233 /* WSOLA discard will shrink only the second buffer, but it may 234 * also shrink first buffer if second buffer is 'destroyed', so 235 * it is safe to just set the new put_pos. 236 */ 237 if (b->put_pos >= erase_cnt) 238 b->put_pos -= erase_cnt; 239 else 240 b->put_pos = b->max_cnt - (erase_cnt - b->put_pos); 241 242 b->buf_cnt -= erase_cnt; 243 244 PJ_LOG(5,(b->obj_name,"Successfully shrinking %d samples, " 245 "buf_cnt=%d", erase_cnt, b->buf_cnt)); 246 } 247 248 /* Shrinking failed or erased count is less than requested, 249 * delaybuf needs to drop eldest samples, this is bad since the voice 250 * samples may not have smooth transition. 251 */ 252 if (b->buf_cnt + b->samples_per_frame > b->max_cnt) { 253 erase_cnt = b->buf_cnt + b->samples_per_frame - b->max_cnt; 254 255 b->buf_cnt -= erase_cnt; 256 257 /* Shift get_pos forward */ 258 b->get_pos = (b->get_pos + erase_cnt) % b->max_cnt; 259 260 PJ_LOG(4,(b->obj_name,"Shrinking failed or insufficient, dropping" 261 " %d eldest samples, buf_cnt=%d", erase_cnt, b->buf_cnt)); 262 } 263 } 264 265 static void set_max_cnt(pjmedia_delay_buf *b, unsigned new_max_cnt) 266 { 267 unsigned old_max_cnt = b->max_cnt; 268 269 /* nothing to adjust */ 270 if (old_max_cnt == new_max_cnt) 271 return; 272 273 /* For now, only support shrinking */ 274 pj_assert(old_max_cnt > new_max_cnt); 275 276 shrink_buffer(b, old_max_cnt - new_max_cnt); 277 278 /* Adjust buffer to accomodate the new max_cnt so the samples is secured. 279 * This is done by make get_pos = 0 280 */ 281 if (b->get_pos <= b->put_pos) { 282 /* sssss .. sssss 283 * ^ ^ 284 * G P 285 */ 286 /* Consistency checking */ 287 pj_assert((b->put_pos - b->get_pos) <= new_max_cnt); 288 pj_assert((b->put_pos - b->get_pos) == b->buf_cnt); 289 290 pjmedia_move_samples(b->frame_buf, &b->frame_buf[b->get_pos], 291 b->get_pos); 292 b->put_pos -= b->get_pos; 293 b->get_pos = 0; 294 } else { 295 /* sssss .. sssss 296 * ^ ^ 297 * P G 298 */ 299 unsigned d = old_max_cnt - b->get_pos; 300 301 /* Consistency checking */ 302 pj_assert((b->get_pos - b->put_pos) >= (old_max_cnt - new_max_cnt)); 303 304 /* Make get_pos = 0, shift right the leftmost block first */ 305 pjmedia_move_samples(&b->frame_buf[d], b->frame_buf, d); 306 pjmedia_copy_samples(b->frame_buf, &b->frame_buf[b->get_pos], d); 307 b->put_pos += d; 308 b->get_pos = 0; 309 } 310 311 b->max_cnt = new_max_cnt; 128 312 } 129 313 … … 158 342 b->max_level += SAFE_MARGIN; 159 343 160 PJ_LOG(5,(b->obj_name,"Delay buffer start running, level=%u",161 b->max_level));162 163 344 /* 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)); 345 if (b->max_level > b->max_frames) { 346 PJ_LOG(4,(b->obj_name,"Delay buffer learning result (%d)" 347 " exceeds the maximum delay allowed (%d)", 348 b->max_level, 349 b->max_frames)); 350 351 b->max_level = b->max_frames; 169 352 } 170 353 354 /* we need to set new max_cnt & adjust buffer */ 355 set_max_cnt(b, b->max_level * b->samples_per_frame); 356 171 357 b->state = STATE_RUNNING; 358 359 PJ_LOG(4,(b->obj_name,"Delay buffer start running, level=%u", 360 b->max_level)); 172 361 } 173 362 } … … 182 371 pj_int16_t frame[]) 183 372 { 373 pj_status_t status; 374 375 PJ_ASSERT_RETURN(b && frame, PJ_EINVAL); 376 377 pj_lock_acquire(b->lock); 378 184 379 update(b, OP_PUT); 185 380 186 if (b->state != STATE_RUNNING) 187 return PJ_EPENDING; 188 189 pj_memcpy(&b->frame_buf[b->put_pos * b->samples_per_frame], frame, 190 b->samples_per_frame*sizeof(pj_int16_t)); 191 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; 196 197 b->put_pos = b->get_pos; 198 199 PJ_LOG(5,(b->obj_name,"Warning: buffer overflow")); 200 201 return PJ_ETOOMANY; 202 } 203 204 ++b->buf_cnt; 205 206 if (++b->put_pos == b->max_level) 207 b->put_pos = 0; 208 381 status = pjmedia_wsola_save(b->wsola, frame, PJ_FALSE); 382 if (status != PJ_SUCCESS) { 383 pj_lock_release(b->lock); 384 return status; 385 } 386 387 /* Overflow checking */ 388 if (b->buf_cnt + b->samples_per_frame > b->max_cnt) 389 { 390 /* shrink one frame or just the diff? */ 391 //unsigned erase_cnt = b->samples_per_frame; 392 unsigned erase_cnt = b->buf_cnt + b->samples_per_frame - b->max_cnt; 393 394 shrink_buffer(b, erase_cnt); 395 } 396 397 /* put the frame on put_pos */ 398 if (b->put_pos + b->samples_per_frame <= b->max_cnt) { 399 pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame, 400 b->samples_per_frame); 401 } else { 402 int remainder = b->put_pos + b->samples_per_frame - b->max_cnt; 403 404 pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame, 405 b->samples_per_frame - remainder); 406 pjmedia_copy_samples(&b->frame_buf[0], 407 &frame[b->samples_per_frame - remainder], 408 remainder); 409 } 410 411 /* Update put_pos & buf_cnt */ 412 b->put_pos = (b->put_pos + b->samples_per_frame) % b->max_cnt; 413 b->buf_cnt += b->samples_per_frame; 414 415 pj_lock_release(b->lock); 209 416 return PJ_SUCCESS; 210 417 } 211 418 212 PJ_DEF(pj_status_t) pjmedia_delay_buf_get( pjmedia_delay_buf *b,419 PJ_DEF(pj_status_t) pjmedia_delay_buf_get( pjmedia_delay_buf *b, 213 420 pj_int16_t frame[]) 214 421 { 422 pj_status_t status; 423 424 PJ_ASSERT_RETURN(b && frame, PJ_EINVAL); 425 426 pj_lock_acquire(b->lock); 427 215 428 update(b, OP_GET); 216 429 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)); 222 return PJ_EPENDING; 223 } 224 225 pj_memcpy(frame, &b->frame_buf[b->get_pos * b->samples_per_frame], 226 b->samples_per_frame*sizeof(pj_int16_t)); 227 228 if (++b->get_pos == b->max_level) 229 b->get_pos = 0; 230 231 --b->buf_cnt; 430 /* Starvation checking */ 431 if (b->buf_cnt < b->samples_per_frame) { 432 433 PJ_LOG(5,(b->obj_name,"Underflow, buf_cnt=%d, will generate 1 frame", 434 b->buf_cnt)); 435 436 status = pjmedia_wsola_generate(b->wsola, frame); 437 438 if (status == PJ_SUCCESS) { 439 TRACE__((b->obj_name,"Successfully generate 1 frame")); 440 if (b->buf_cnt == 0) { 441 pj_lock_release(b->lock); 442 return PJ_SUCCESS; 443 } 444 445 /* Put generated frame into buffer */ 446 if (b->put_pos + b->samples_per_frame <= b->max_cnt) { 447 pjmedia_copy_samples(&b->frame_buf[b->put_pos], frame, 448 b->samples_per_frame); 449 } else { 450 int remainder = b->put_pos + b->samples_per_frame - b->max_cnt; 451 452 pjmedia_copy_samples(&b->frame_buf[b->put_pos], &frame[0], 453 b->samples_per_frame - remainder); 454 pjmedia_copy_samples(&b->frame_buf[0], 455 &frame[b->samples_per_frame - remainder], 456 remainder); 457 } 458 459 b->put_pos = (b->put_pos + b->samples_per_frame) % b->max_cnt; 460 b->buf_cnt += b->samples_per_frame; 461 462 } else { 463 /* Give all what delay buffer has, then pad zeroes */ 464 PJ_LOG(4,(b->obj_name,"Error generating frame, status=%d", 465 status)); 466 467 pjmedia_copy_samples(frame, &b->frame_buf[b->get_pos], b->buf_cnt); 468 pjmedia_zero_samples(&frame[b->buf_cnt], 469 b->samples_per_frame - b->buf_cnt); 470 b->get_pos += b->buf_cnt; 471 b->buf_cnt = 0; 472 473 /* Consistency checking */ 474 pj_assert(b->get_pos == b->put_pos); 475 476 pj_lock_release(b->lock); 477 478 return PJ_SUCCESS; 479 } 480 } 481 482 pjmedia_copy_samples(frame, &b->frame_buf[b->get_pos], 483 b->samples_per_frame); 484 485 b->get_pos = (b->get_pos + b->samples_per_frame) % b->max_cnt; 486 b->buf_cnt -= b->samples_per_frame; 487 488 pj_lock_release(b->lock); 232 489 233 490 return PJ_SUCCESS; 234 491 } 235 492 236 PJ_DE CL(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b)493 PJ_DEF(pj_status_t) pjmedia_delay_buf_learn(pjmedia_delay_buf *b) 237 494 { 238 495 PJ_ASSERT_RETURN(b, PJ_EINVAL); 496 497 pj_lock_acquire(b->lock); 239 498 240 499 b->last_op = OP_UNDEFINED; … … 243 502 b->state_count = 0; 244 503 b->max_level = 0; 504 b->max_cnt = b->max_frames * b->samples_per_frame; 505 506 pjmedia_delay_buf_reset(b); 507 508 pj_lock_release(b->lock); 509 510 PJ_LOG(5,(b->obj_name,"Delay buffer start learning")); 511 512 return PJ_SUCCESS; 513 } 514 515 PJ_DEF(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b) 516 { 517 PJ_ASSERT_RETURN(b, PJ_EINVAL); 518 519 pj_lock_acquire(b->lock); 245 520 246 521 /* clean up buffer */ 247 522 b->buf_cnt = 0; 248 523 b->put_pos = b->get_pos = 0; 249 250 PJ_LOG(5,(b->obj_name,"Delay buffer start learning")); 524 pjmedia_wsola_reset(b->wsola, 0); 525 526 pj_lock_release(b->lock); 527 528 PJ_LOG(5,(b->obj_name,"Delay buffer resetted")); 251 529 252 530 return PJ_SUCCESS; 253 531 } 532 -
pjproject/trunk/pjmedia/src/pjmedia/sound_port.c
r1825 r1833 33 33 #define THIS_FILE "sound_port.c" 34 34 35 #define TEST_OVERFLOW_UNDERFLOW 36 35 37 enum 36 38 { … … 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 … … 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); -
pjproject/trunk/pjmedia/src/test/wsola_test.c
r1832 r1833 328 328 pool = pj_pool_create(&cp.factory, "", 1000, 1000, NULL); 329 329 330 mem_test(pool);331 return 0;332 333 330 srand(2); 334 331 335 rc = expand(pool, "beet44.pcm", "output.pcm", 1, 0, 0);332 rc = expand(pool, "beet44.pcm", "output.pcm", 0, 0, 0); 336 333 //rc = compress(pool, "beet44.pcm", "output.pcm", 2); 337 334
Note: See TracChangeset
for help on using the changeset viewer.