- Timestamp:
- Aug 1, 2009 9:20:59 AM (15 years ago)
- Location:
- pjproject/trunk/pjmedia
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/include/pjmedia/config.h
r2759 r2850 150 150 #ifndef PJMEDIA_WSOLA_IMP 151 151 # define PJMEDIA_WSOLA_IMP PJMEDIA_WSOLA_IMP_WSOLA 152 #endif 153 154 155 /** 156 * Specify the default maximum duration of synthetic audio that is generated 157 * by WSOLA. This value should be long enough to cover burst of packet losses. 158 * but not too long, because as the duration increases the quality would 159 * degrade considerably. 160 * 161 * Note that this limit is only applied when fading is enabled in the WSOLA 162 * session. 163 * 164 * Default: 80 165 */ 166 #ifndef PJMEDIA_WSOLA_MAX_EXPAND_MSEC 167 # define PJMEDIA_WSOLA_MAX_EXPAND_MSEC 80 168 #endif 169 170 171 /** 172 * Specify WSOLA template length, in milliseconds. The longer the template, 173 * the smoother signal to be generated at the expense of more computation 174 * needed, since the algorithm will have to compare more samples to find 175 * the most similar pitch. 176 * 177 * Default: 5 178 */ 179 #ifndef PJMEDIA_WSOLA_TEMPLATE_LENGTH_MSEC 180 # define PJMEDIA_WSOLA_TEMPLATE_LENGTH_MSEC 5 181 #endif 182 183 184 /** 185 * Specify WSOLA algorithm delay, in milliseconds. The algorithm delay is 186 * used to merge synthetic samples with real samples in the transition 187 * between real to synthetic and vice versa. The longer the delay, the 188 * smoother signal to be generated, at the expense of longer latency and 189 * a slighty more computation. 190 * 191 * Default: 5 192 */ 193 #ifndef PJMEDIA_WSOLA_DELAY_MSEC 194 # define PJMEDIA_WSOLA_DELAY_MSEC 5 195 #endif 196 197 198 /** 199 * Set this to non-zero to disable fade-out/in effect in the PLC when it 200 * instructs WSOLA to generate synthetic frames. The use of fading may 201 * or may not improve the quality of audio, depending on the nature of 202 * packet loss and the type of audio input (e.g. speech vs music). 203 * Disabling fading also implicitly remove the maximum limit of synthetic 204 * audio samples generated by WSOLA (see PJMEDIA_WSOLA_MAX_EXPAND_MSEC). 205 * 206 * Default: 0 207 */ 208 #ifndef PJMEDIA_WSOLA_PLC_NO_FADING 209 # define PJMEDIA_WSOLA_PLC_NO_FADING 0 152 210 #endif 153 211 -
pjproject/trunk/pjmedia/include/pjmedia/wsola.h
r2394 r2850 70 70 * non-contiguous buffer. 71 71 */ 72 PJMEDIA_WSOLA_NO_DISCARD = 4 72 PJMEDIA_WSOLA_NO_DISCARD = 4, 73 74 /** 75 * Disable fade-in and fade-out feature in the transition between 76 * actual and synthetic frames in WSOLA. With fade feature enabled, 77 * WSOLA will only generate a limited number of synthetic frames 78 * (configurable with #pjmedia_wsola_set_max_expand()), fading out 79 * the volume on every more samples it generates, and when it reaches 80 * the limit it will only generate silence. 81 */ 82 PJMEDIA_WSOLA_NO_FADING = 8 73 83 }; 74 84 … … 94 104 unsigned options, 95 105 pjmedia_wsola **p_wsola); 106 107 108 /** 109 * Specify maximum number of continuous synthetic frames that can be 110 * generated by WSOLA, in milliseconds. This option will only take 111 * effect if fading is not disabled via the option when the WSOLA 112 * session was created. Default value is PJMEDIA_WSOLA_MAX_EXPAND_MSEC 113 * (see also the documentation of PJMEDIA_WSOLA_MAX_EXPAND_MSEC for 114 * more information). 115 * 116 * @param wsola The WSOLA session 117 * @param msec The duration. 118 * 119 * @return PJ_SUCCESS normally. 120 */ 121 PJ_DECL(pj_status_t) pjmedia_wsola_set_max_expand(pjmedia_wsola *wsola, 122 unsigned msec); 96 123 97 124 -
pjproject/trunk/pjmedia/src/pjmedia/delaybuf.c
r2728 r2850 129 129 /* Create WSOLA */ 130 130 status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 1, 131 0, &b->wsola);131 PJMEDIA_WSOLA_NO_FADING, &b->wsola); 132 132 if (status != PJ_SUCCESS) 133 133 return status; -
pjproject/trunk/pjmedia/src/pjmedia/plc_common.c
r2394 r2850 126 126 { 127 127 struct wsola_plc *o; 128 unsigned flag; 128 129 pj_status_t status; 129 130 … … 133 134 o->prev_lost = PJ_FALSE; 134 135 136 flag = PJMEDIA_WSOLA_NO_DISCARD; 137 if (PJMEDIA_WSOLA_PLC_NO_FADING) 138 flag |= PJMEDIA_WSOLA_NO_FADING; 139 135 140 status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 1, 136 PJMEDIA_WSOLA_NO_DISCARD, &o->wsola);141 flag, &o->wsola); 137 142 if (status != PJ_SUCCESS) 138 143 return NULL; -
pjproject/trunk/pjmedia/src/pjmedia/stream.c
r2844 r2850 44 44 #define BYTES_PER_SAMPLE 2 45 45 46 /* Limit the number of synthetic audio samples that are generated by PLC. 47 * Normally PLC should have it's own means to limit the number of 48 * synthetic frames, so we need to set this to a reasonably large value 49 * just as precaution 50 */ 51 #define MAX_PLC_MSEC 240 52 46 53 /** 47 54 * Media channel. … … 99 106 unsigned enc_buf_count; /**< Number of samples in the 100 107 encoding buffer. */ 108 109 unsigned plc_cnt; /**< # of consecutive PLC frames*/ 110 unsigned max_plc_cnt; /**< Max # of PLC frames */ 101 111 102 112 unsigned vad_enabled; /**< VAD enabled in param. */ … … 198 208 } 199 209 210 #if defined(PJMEDIA_STREAM_ENABLE_KA) && PJMEDIA_STREAM_ENABLE_KA != 0 200 211 /* 201 * Send keep-alive packet .212 * Send keep-alive packet using non-codec frame. 202 213 */ 203 214 static void send_keep_alive_packet(pjmedia_stream *stream) 204 215 { 205 #if defined(PJMEDIA_STREAM_ENABLE_KA) && \ 206 PJMEDIA_STREAM_ENABLE_KA == PJMEDIA_STREAM_KA_EMPTY_RTP 216 #if PJMEDIA_STREAM_ENABLE_KA == PJMEDIA_STREAM_KA_EMPTY_RTP 207 217 208 218 /* Keep-alive packet is empty RTP */ … … 225 235 TRC_((stream->port.info.name.ptr, "Keep-alive sent (empty RTP)")); 226 236 227 #elif defined(PJMEDIA_STREAM_ENABLE_KA) && \ 228 PJMEDIA_STREAM_ENABLE_KA == PJMEDIA_STREAM_KA_USER 237 #elif PJMEDIA_STREAM_ENABLE_KA == PJMEDIA_STREAM_KA_USER 229 238 230 239 /* Keep-alive packet is defined in PJMEDIA_STREAM_KA_USER_PKT */ … … 244 253 #endif 245 254 } 255 #endif /* defined(PJMEDIA_STREAM_ENABLE_KA) */ 246 256 247 257 /* … … 295 305 /* Activate PLC */ 296 306 if (stream->codec->op->recover && 297 stream->codec_param.setting.plc) 307 stream->codec_param.setting.plc && 308 stream->plc_cnt < stream->max_plc_cnt) 298 309 { 299 310 pjmedia_frame frame_out; … … 305 316 &frame_out); 306 317 318 ++stream->plc_cnt; 319 307 320 } else { 308 321 status = -1; … … 319 332 "Lost frame recovered")); 320 333 } 321 334 322 335 } else if (frame_type == PJMEDIA_JB_ZERO_EMPTY_FRAME) { 323 336 … … 326 339 * the frame. 327 340 */ 328 if (frame_type != stream->jb_last_frm) { 341 //Using this "if" will only invoke PLC for the first packet 342 //lost and not the subsequent ones. 343 //if (frame_type != stream->jb_last_frm) { 344 if (1) { 329 345 pjmedia_jb_state jb_state; 330 346 const char *with_plc = ""; … … 332 348 /* Activate PLC to smoothen the missing frame */ 333 349 if (stream->codec->op->recover && 334 stream->codec_param.setting.plc) 350 stream->codec_param.setting.plc && 351 stream->plc_cnt < stream->max_plc_cnt) 335 352 { 336 353 pjmedia_frame frame_out; … … 344 361 if (status != PJ_SUCCESS) 345 362 break; 363 346 364 samples_count += samples_per_frame; 347 348 } while (samples_count < samples_required); 365 ++stream->plc_cnt; 366 367 } while (samples_count < samples_required && 368 stream->plc_cnt < stream->max_plc_cnt); 349 369 350 370 with_plc = ", plc invoked"; … … 380 400 /* Always activate PLC when it's available.. */ 381 401 if (stream->codec->op->recover && 382 stream->codec_param.setting.plc) 402 stream->codec_param.setting.plc && 403 stream->plc_cnt < stream->max_plc_cnt) 383 404 { 384 405 pjmedia_frame frame_out; … … 394 415 samples_count += samples_per_frame; 395 416 396 } while (samples_count < samples_required); 397 398 if (stream->jb_last_frm != frame_type) { 417 ++stream->plc_cnt; 418 419 } while (samples_count < samples_required && 420 stream->plc_cnt < stream->max_plc_cnt); 421 422 //if (stream->jb_last_frm != frame_type) { 423 if (1) { 399 424 PJ_LOG(5,(stream->port.info.name.ptr, 400 425 "Jitter buffer is bufferring with plc (prefetch=%d)", … … 419 444 /* Got "NORMAL" frame from jitter buffer */ 420 445 pjmedia_frame frame_in, frame_out; 446 447 stream->plc_cnt = 0; 421 448 422 449 /* Decode */ … … 1822 1849 ++stream->frame_size; 1823 1850 } 1851 1852 /* How many consecutive PLC frames can be generated */ 1853 stream->max_plc_cnt = (MAX_PLC_MSEC+stream->codec_param.info.frm_ptime-1)/ 1854 stream->codec_param.info.frm_ptime; 1824 1855 1825 1856 #if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG!=0) -
pjproject/trunk/pjmedia/src/pjmedia/wsola.c
r2660 r2850 71 71 72 72 /* Template size, in msec */ 73 #define TEMPLATE_PTIME 573 #define TEMPLATE_PTIME PJMEDIA_WSOLA_TEMPLATE_LENGTH_MSEC 74 74 75 75 /* Hanning window size, in msec */ 76 #define HANNING_PTIME 576 #define HANNING_PTIME PJMEDIA_WSOLA_DELAY_MSEC 77 77 78 78 /* Number of frames in erase buffer */ … … 84 84 /* Maximum distance from template for find_pitch() of expansion, in frames */ 85 85 #define EXP_MAX_DIST HIST_CNT 86 87 /* Duration of a continuous synthetic frames after which the volume 88 * of the synthetic frame will be set to zero with fading-out effect. 89 */ 90 #define MAX_EXPAND_MSEC PJMEDIA_WSOLA_MAX_EXPAND_MSEC 86 91 87 92 … … 132 137 133 138 pj_uint16_t min_extra; /* Minimum extra (const) */ 134 pj_uint16_t expand_cnt; /* Consecutive expansion count */ 139 unsigned max_expand_cnt; /* Max # of synthetic samples */ 140 unsigned fade_out_pos; /* Last fade-out position */ 135 141 pj_uint16_t expand_sr_min_dist;/* Minimum distance from template 136 142 for find_pitch() on expansion … … 147 153 148 154 pj_timestamp ts; /* Running timestamp. */ 155 149 156 }; 150 157 … … 433 440 #endif /* PJ_HAS_FLOATING_POINT */ 434 441 442 /* Apply fade-in to the buffer. 443 * - fade_cnt is the number of samples on which the volume 444 * will go from zero to 100% 445 * - fade_pos is current sample position within fade_cnt range. 446 * It is zero for the first sample, so the first sample will 447 * have zero volume. This value is increasing. 448 */ 449 static void fade_in(pj_int16_t buf[], int count, 450 int fade_in_pos, int fade_cnt) 451 { 452 #if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0 453 float fade_pos = (float)fade_in_pos; 454 #else 455 int fade_pos = fade_in_pos; 456 #endif 457 458 if (fade_cnt - fade_pos < count) { 459 for (; fade_pos < fade_cnt; ++fade_pos, ++buf) { 460 *buf = (pj_int16_t)(*buf * fade_pos / fade_cnt); 461 } 462 /* Leave the remaining samples as is */ 463 } else { 464 pj_int16_t *end = buf + count; 465 for (; buf != end; ++fade_pos, ++buf) { 466 *buf = (pj_int16_t)(*buf * fade_pos / fade_cnt); 467 } 468 } 469 } 470 471 /* Apply fade-out to the buffer. */ 472 static void wsola_fade_out(pjmedia_wsola *wsola, 473 pj_int16_t buf[], int count) 474 { 475 pj_int16_t *end = buf + count; 476 int fade_cnt = wsola->max_expand_cnt; 477 #if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0 478 float fade_pos = (float)wsola->fade_out_pos; 479 #else 480 int fade_pos = wsola->fade_out_pos; 481 #endif 482 483 if (wsola->fade_out_pos == 0) { 484 pjmedia_zero_samples(buf, count); 485 } else if (fade_pos < count) { 486 for (; fade_pos; --fade_pos, ++buf) { 487 *buf = (pj_int16_t)(*buf * fade_pos / fade_cnt); 488 } 489 if (buf != end) 490 pjmedia_zero_samples(buf, end - buf); 491 wsola->fade_out_pos = 0; 492 } else { 493 for (; buf != end; --fade_pos, ++buf) { 494 *buf = (pj_int16_t)(*buf * fade_pos / fade_cnt); 495 } 496 wsola->fade_out_pos -= count; 497 } 498 } 499 435 500 436 501 PJ_DEF(pj_status_t) pjmedia_wsola_create( pj_pool_t *pool, … … 456 521 wsola->channel_count = (pj_uint16_t) channel_count; 457 522 wsola->options = (pj_uint16_t) options; 523 wsola->max_expand_cnt = clock_rate * MAX_EXPAND_MSEC / 1000; 524 wsola->fade_out_pos = wsola->max_expand_cnt; 458 525 459 526 /* Create circular buffer */ … … 524 591 } 525 592 593 PJ_DEF(pj_status_t) pjmedia_wsola_set_max_expand(pjmedia_wsola *wsola, 594 unsigned msec) 595 { 596 PJ_ASSERT_RETURN(wsola, PJ_EINVAL); 597 wsola->max_expand_cnt = msec * wsola->clock_rate / 1000; 598 return PJ_SUCCESS; 599 } 526 600 527 601 PJ_DEF(pj_status_t) pjmedia_wsola_reset( pjmedia_wsola *wsola, … … 534 608 pjmedia_circ_buf_set_len(wsola->buf, wsola->hist_size + wsola->min_extra); 535 609 pjmedia_zero_samples(wsola->buf->start, wsola->buf->len); 610 wsola->fade_out_pos = wsola->max_expand_cnt; 536 611 537 612 return PJ_SUCCESS; … … 683 758 684 759 /* Update vars */ 685 wsola->expand_cnt = 0;686 760 wsola->ts.u64 += wsola->samples_per_frame; 687 761 … … 692 766 pj_int16_t *ola_left; 693 767 768 /* Trim excessive len */ 769 if ((int)buf_len > wsola->hist_size + (wsola->min_extra<<1)) { 770 buf_len = wsola->hist_size + (wsola->min_extra<<1); 771 pjmedia_circ_buf_set_len(wsola->buf, buf_len); 772 } 773 694 774 pjmedia_circ_buf_get_read_regions(wsola->buf, ®1, ®1_len, 695 775 ®2, ®2_len); … … 698 778 (unsigned)(wsola->hist_size + (wsola->min_extra<<1))); 699 779 780 /* Continue applying fade out to the extra samples */ 781 if ((wsola->options & PJMEDIA_WSOLA_NO_FADING)==0) { 782 if (reg2_len == 0) { 783 wsola_fade_out(wsola, reg1 + reg1_len - (wsola->min_extra<<1), 784 (wsola->min_extra<<1)); 785 } else if ((int)reg2_len >= (wsola->min_extra<<1)) { 786 wsola_fade_out(wsola, reg2 + reg2_len - (wsola->min_extra<<1), 787 (wsola->min_extra<<1)); 788 } else { 789 unsigned tmp = (wsola->min_extra<<1) - reg2_len; 790 wsola_fade_out(wsola, reg1 + reg1_len - tmp, tmp); 791 wsola_fade_out(wsola, reg2, reg2_len); 792 } 793 } 794 795 /* Get the region in buffer to be merged with the frame */ 700 796 if (reg2_len == 0) { 701 797 ola_left = reg1 + reg1_len - wsola->min_extra; … … 711 807 } 712 808 809 /* Apply fade-in to the frame before merging */ 810 if ((wsola->options & PJMEDIA_WSOLA_NO_FADING)==0) { 811 unsigned count = wsola->min_extra; 812 int fade_in_pos; 813 814 /* Scale fade_in position based on last fade-out */ 815 fade_in_pos = wsola->fade_out_pos * count / 816 wsola->max_expand_cnt; 817 818 /* Fade-in it */ 819 fade_in(frm, wsola->samples_per_frame, 820 fade_in_pos, count); 821 } 822 823 /* Merge it */ 713 824 overlapp_add_simple(frm, wsola->min_extra, ola_left, frm); 714 825 826 /* Trim len */ 715 827 buf_len -= wsola->min_extra; 716 828 pjmedia_circ_buf_set_len(wsola->buf, buf_len); 717 } 829 830 } else if ((wsola->options & PJMEDIA_WSOLA_NO_FADING)==0 && 831 wsola->fade_out_pos != wsola->max_expand_cnt) 832 { 833 unsigned count = wsola->min_extra; 834 int fade_in_pos; 835 836 /* Fade out the remaining synthetic samples */ 837 if (buf_len > wsola->hist_size) { 838 pj_int16_t *reg1, *reg2; 839 unsigned reg1_len, reg2_len; 840 841 /* Number of samples to fade out */ 842 count = buf_len - wsola->hist_size; 843 844 pjmedia_circ_buf_get_read_regions(wsola->buf, ®1, ®1_len, 845 ®2, ®2_len); 846 847 CHECK_(pjmedia_circ_buf_get_len(wsola->buf) >= 848 (unsigned)(wsola->hist_size + (wsola->min_extra<<1))); 849 850 /* Continue applying fade out to the extra samples */ 851 if (reg2_len == 0) { 852 wsola_fade_out(wsola, reg1 + reg1_len - count, count); 853 } else if ((int)reg2_len >= count) { 854 wsola_fade_out(wsola, reg2 + reg2_len - count, count); 855 } else { 856 unsigned tmp = count - reg2_len; 857 wsola_fade_out(wsola, reg1 + reg1_len - tmp, tmp); 858 wsola_fade_out(wsola, reg2, reg2_len); 859 } 860 } 861 862 /* Apply fade-in to the frame */ 863 count = wsola->min_extra; 864 865 /* Scale fade_in position based on last fade-out */ 866 fade_in_pos = wsola->fade_out_pos * count / 867 wsola->max_expand_cnt; 868 869 /* Fade it in */ 870 fade_in(frm, wsola->samples_per_frame, 871 fade_in_pos, count); 872 873 } 874 875 wsola->fade_out_pos = wsola->max_expand_cnt; 718 876 719 877 status = pjmedia_circ_buf_write(wsola->buf, frm, wsola->samples_per_frame); … … 738 896 { 739 897 unsigned samples_len, samples_req; 740 741 742 898 pj_status_t status = PJ_SUCCESS; 743 899 … … 758 914 TRACE_((THIS_FILE, "Buf size after expanded = %d", 759 915 pjmedia_circ_buf_get_len(wsola->buf))); 760 wsola->expand_cnt++;761 916 } 762 917 … … 769 924 770 925 pjmedia_circ_buf_adv_read_ptr(wsola->buf, wsola->samples_per_frame); 926 927 /* Apply fade-out to the frame */ 928 if ((wsola->options & PJMEDIA_WSOLA_NO_FADING)==0) { 929 wsola_fade_out(wsola, frm, wsola->samples_per_frame); 930 } 771 931 772 932 return PJ_SUCCESS;
Note: See TracChangeset
for help on using the changeset viewer.