diff options
-rw-r--r-- | include/asterisk/frame.h | 10 | ||||
-rw-r--r-- | main/frame.c | 91 | ||||
-rw-r--r-- | main/rtp.c | 48 |
3 files changed, 113 insertions, 36 deletions
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index bb547962c..62485ced6 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -523,6 +523,16 @@ int ast_smoother_get_flags(struct ast_smoother *smoother); int ast_smoother_test_flag(struct ast_smoother *s, int flag); void ast_smoother_free(struct ast_smoother *s); void ast_smoother_reset(struct ast_smoother *s, int bytes); + +/*! + * \brief Reconfigure an existing smoother to output a different number of bytes per frame + * \param s the smoother to reconfigure + * \param bytes the desired number of bytes per output frame + * \return nothing + * + */ +void ast_smoother_reconfigure(struct ast_smoother *s, int bytes); + int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap); struct ast_frame *ast_smoother_read(struct ast_smoother *s); #define ast_smoother_feed(s,f) __ast_smoother_feed(s, f, 0) diff --git a/main/frame.c b/main/frame.c index 912d6c739..956fea3e5 100644 --- a/main/frame.c +++ b/main/frame.c @@ -86,9 +86,9 @@ enum frame_type { struct ast_smoother { int size; int format; - int readdata; int flags; float samplesperbyte; + unsigned int opt_needs_swap:1; struct ast_frame f; struct timeval delivery; char data[SMOOTHER_SIZE]; @@ -128,10 +128,54 @@ static const struct ast_format_list AST_FORMAT_LIST[] = { struct ast_frame ast_null_frame = { AST_FRAME_NULL, }; -void ast_smoother_reset(struct ast_smoother *s, int size) +static int smoother_frame_feed(struct ast_smoother *s, struct ast_frame *f, int swap) +{ + if (s->flags & AST_SMOOTHER_FLAG_G729) { + if (s->len % 10) { + ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n"); + return 0; + } + } + if (swap) { + ast_swapcopy_samples(s->data + s->len, f->data.ptr, f->samples); + } else { + memcpy(s->data + s->len, f->data.ptr, f->datalen); + } + /* If either side is empty, reset the delivery time */ + if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery)) { /* XXX really ? */ + s->delivery = f->delivery; + } + s->len += f->datalen; + + return 0; +} + +void ast_smoother_reset(struct ast_smoother *s, int bytes) { memset(s, 0, sizeof(*s)); - s->size = size; + s->size = bytes; +} + +void ast_smoother_reconfigure(struct ast_smoother *s, int bytes) +{ + /* if there is no change, then nothing to do */ + if (s->size == bytes) { + return; + } + /* set the new desired output size */ + s->size = bytes; + /* if there is no 'optimized' frame in the smoother, + * then there is nothing left to do + */ + if (!s->opt) { + return; + } + /* there is an 'optimized' frame here at the old size, + * but it must now be put into the buffer so the data + * can be extracted at the new size + */ + smoother_frame_feed(s, s->opt, s->opt_needs_swap); + s->opt = NULL; } struct ast_smoother *ast_smoother_new(int size) @@ -176,33 +220,22 @@ int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap) ast_log(LOG_WARNING, "Out of smoother space\n"); return -1; } - if (((f->datalen == s->size) || ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729))) - && !s->opt && (f->offset >= AST_MIN_OFFSET)) { - if (!s->len) { - /* Optimize by sending the frame we just got - on the next read, thus eliminating the douple - copy */ - if (swap) - ast_swapcopy_samples(f->data.ptr, f->data.ptr, f->samples); - s->opt = f; - return 0; - } - } - if (s->flags & AST_SMOOTHER_FLAG_G729) { - if (s->len % 10) { - ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n"); - return 0; - } + if (((f->datalen == s->size) || + ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729))) && + !s->opt && + !s->len && + (f->offset >= AST_MIN_OFFSET)) { + /* Optimize by sending the frame we just got + on the next read, thus eliminating the douple + copy */ + if (swap) + ast_swapcopy_samples(f->data.ptr, f->data.ptr, f->samples); + s->opt = f; + s->opt_needs_swap = swap ? 1 : 0; + return 0; } - if (swap) - ast_swapcopy_samples(s->data+s->len, f->data.ptr, f->samples); - else - memcpy(s->data + s->len, f->data.ptr, f->datalen); - /* If either side is empty, reset the delivery time */ - if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery)) /* XXX really ? */ - s->delivery = f->delivery; - s->len += f->datalen; - return 0; + + return smoother_frame_feed(s, f, swap); } struct ast_frame *ast_smoother_read(struct ast_smoother *s) diff --git a/main/rtp.c b/main/rtp.c index 54f3a85ff..3e24e25bb 100644 --- a/main/rtp.c +++ b/main/rtp.c @@ -3659,14 +3659,48 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec void ast_rtp_codec_setpref(struct ast_rtp *rtp, struct ast_codec_pref *prefs) { - int x; - for (x = 0; x < 32; x++) { /* Ugly way */ - rtp->pref.order[x] = prefs->order[x]; - rtp->pref.framing[x] = prefs->framing[x]; + struct ast_format_list current_format_old, current_format_new; + + /* if no packets have been sent through this session yet, then + * changing preferences does not require any extra work + */ + if (rtp->lasttxformat == 0) { + rtp->pref = *prefs; + return; } - if (rtp->smoother) - ast_smoother_free(rtp->smoother); - rtp->smoother = NULL; + + current_format_old = ast_codec_pref_getsize(&rtp->pref, rtp->lasttxformat); + + rtp->pref = *prefs; + + current_format_new = ast_codec_pref_getsize(&rtp->pref, rtp->lasttxformat); + + /* if the framing desired for the current format has changed, we may have to create + * or adjust the smoother for this session + */ + if ((current_format_new.inc_ms != 0) && + (current_format_new.cur_ms != current_format_old.cur_ms)) { + int new_size = (current_format_new.cur_ms * current_format_new.fr_len) / current_format_new.inc_ms; + + if (rtp->smoother) { + ast_smoother_reconfigure(rtp->smoother, new_size); + if (option_debug) { + ast_log(LOG_DEBUG, "Adjusted smoother to %d ms and %d bytes\n", current_format_new.cur_ms, new_size); + } + } else { + if (!(rtp->smoother = ast_smoother_new(new_size))) { + ast_log(LOG_WARNING, "Unable to create smoother: format: %d ms: %d len: %d\n", rtp->lasttxformat, current_format_new.cur_ms, new_size); + return; + } + if (current_format_new.flags) { + ast_smoother_set_flags(rtp->smoother, current_format_new.flags); + } + if (option_debug) { + ast_log(LOG_DEBUG, "Created smoother: format: %d ms: %d len: %d\n", rtp->lasttxformat, current_format_new.cur_ms, new_size); + } + } + } + } struct ast_codec_pref *ast_rtp_codec_getpref(struct ast_rtp *rtp) |