diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/abstract_jb.c | 31 | ||||
-rw-r--r-- | main/app.c | 26 | ||||
-rw-r--r-- | main/astobj2.c | 14 | ||||
-rw-r--r-- | main/channel.c | 23 | ||||
-rw-r--r-- | main/fixedjitterbuf.c | 6 | ||||
-rw-r--r-- | main/fixedjitterbuf.h | 3 | ||||
-rw-r--r-- | main/format_compatibility.c | 4 | ||||
-rw-r--r-- | main/frame.c | 69 | ||||
-rw-r--r-- | main/jitterbuf.c | 5 |
9 files changed, 129 insertions, 52 deletions
diff --git a/main/abstract_jb.c b/main/abstract_jb.c index c703c6872..bd5b3c042 100644 --- a/main/abstract_jb.c +++ b/main/abstract_jb.c @@ -67,6 +67,7 @@ static long jb_next_fixed(void *jb); static int jb_remove_fixed(void *jb, struct ast_frame **fout); static void jb_force_resynch_fixed(void *jb); static void jb_empty_and_reset_fixed(void *jb); +static int jb_is_late_fixed(void *jb, long ts); /* adaptive */ static void * jb_create_adaptive(struct ast_jb_conf *general_config); static void jb_destroy_adaptive(void *jb); @@ -77,6 +78,7 @@ static long jb_next_adaptive(void *jb); static int jb_remove_adaptive(void *jb, struct ast_frame **fout); static void jb_force_resynch_adaptive(void *jb); static void jb_empty_and_reset_adaptive(void *jb); +static int jb_is_late_adaptive(void *jb, long ts); /* Available jb implementations */ static const struct ast_jb_impl avail_impl[] = { @@ -92,6 +94,7 @@ static const struct ast_jb_impl avail_impl[] = { .remove = jb_remove_fixed, .force_resync = jb_force_resynch_fixed, .empty_and_reset = jb_empty_and_reset_fixed, + .is_late = jb_is_late_fixed, }, { .name = "adaptive", @@ -105,6 +108,7 @@ static const struct ast_jb_impl avail_impl[] = { .remove = jb_remove_adaptive, .force_resync = jb_force_resynch_adaptive, .empty_and_reset = jb_empty_and_reset_adaptive, + .is_late = jb_is_late_adaptive, } }; @@ -706,6 +710,11 @@ static void jb_empty_and_reset_fixed(void *jb) } } +static int jb_is_late_fixed(void *jb, long ts) +{ + return fixed_jb_is_late(jb, ts); +} + /* adaptive */ static void *jb_create_adaptive(struct ast_jb_conf *general_config) @@ -812,6 +821,11 @@ const struct ast_jb_impl *ast_jb_get_impl(enum ast_jb_type type) return NULL; } +static int jb_is_late_adaptive(void *jb, long ts) +{ + return jb_is_late(jb, ts); +} + #define DEFAULT_TIMER_INTERVAL 20 #define DEFAULT_SIZE 200 #define DEFAULT_TARGET_EXTRA 40 @@ -895,7 +909,22 @@ static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_fram } } - if (!frame) { + /* + * If the frame has been requeued (for instance when the translate core returns + * more than one frame) then if the frame is late we want to immediately return + * it. Otherwise attempt to insert it into the jitterbuffer. + * + * If the frame is requeued and late then in all likely hood it's a frame that + * that was previously retrieved from the jitterbuffer, passed to the translate + * core, and then put back into the channel read queue. Even if it had not been + * in the jitterbuffer prior to now it needs to be the next frame "out". + * + * However late arriving frames that have not been requeued (i.e. regular frames) + * need to be passed to the jitterbuffer so they can be appropriately dropped. As + * well any requeued frames that are not late should be put into the jitterbuffer. + */ + if (!frame || (ast_test_flag(frame, AST_FRFLAG_REQUEUED) && + framedata->jb_impl->is_late(framedata->jb_obj, frame->ts))) { return frame; } diff --git a/main/app.c b/main/app.c index d5e331472..53b97cdda 100644 --- a/main/app.c +++ b/main/app.c @@ -1424,22 +1424,20 @@ static struct ast_frame *make_silence(const struct ast_frame *orig) size_t size; size_t datalen; size_t samples = 0; - struct ast_frame *next; if (!orig) { return NULL; } + do { + if (ast_format_cmp(orig->subclass.format, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) { + ast_log(LOG_WARNING, "Attempting to silence non-slin frame\n"); + return NULL; + } - if (ast_format_cmp(orig->subclass.format, ast_format_slin) == AST_FORMAT_CMP_NOT_EQUAL) { - ast_log(LOG_WARNING, "Attempting to silence non-slin frame\n"); - return NULL; - } - - for (next = AST_LIST_NEXT(orig, frame_list); - orig; - orig = next, next = orig ? AST_LIST_NEXT(orig, frame_list) : NULL) { samples += orig->samples; - } + + orig = AST_LIST_NEXT(orig, frame_list); + } while (orig); ast_verb(4, "Silencing %zu samples\n", samples); @@ -1457,7 +1455,7 @@ static struct ast_frame *make_silence(const struct ast_frame *orig) silence->samples = samples; silence->datalen = datalen; - silence->subclass.format = ast_format_slin; + silence->subclass.format = ao2_bump(ast_format_slin); return silence; } @@ -1663,14 +1661,13 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, /* It's all good */ res = 0; } else { - RAII_VAR(struct ast_frame *, silence, NULL, ast_frame_dtor); + struct ast_frame *silence = NULL; struct ast_frame *orig = f; if (muted) { silence = make_silence(orig); if (!silence) { - ast_log(LOG_WARNING, - "Error creating silence\n"); + ast_log(LOG_WARNING, "Error creating silence\n"); break; } f = silence; @@ -1681,6 +1678,7 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile, } res = ast_writestream(others[x], f); } + ast_frame_dtor(silence); f = orig; } diff --git a/main/astobj2.c b/main/astobj2.c index 314bedda2..71a81eacf 100644 --- a/main/astobj2.c +++ b/main/astobj2.c @@ -526,6 +526,20 @@ int __ao2_ref(void *user_data, int delta, if (0 < current_value) { /* The object still lives. */ +#define EXCESSIVE_REF_COUNT 100000 + + if (EXCESSIVE_REF_COUNT <= current_value && ret < EXCESSIVE_REF_COUNT) { + char excessive_ref_buf[100]; + + /* We just reached or went over the excessive ref count trigger */ + snprintf(excessive_ref_buf, sizeof(excessive_ref_buf), + "Excessive refcount %d reached on ao2 object %p", + current_value, user_data); + ast_log(__LOG_ERROR, file, line, func, "%s\n", excessive_ref_buf); + + __ast_assert_failed(0, excessive_ref_buf, file, line, func); + } + if (ref_log && tag) { fprintf(ref_log, "%p,%s%d,%d,%s,%d,%s,%d,%s\n", user_data, (delta < 0 ? "" : "+"), delta, ast_get_tid(), diff --git a/main/channel.c b/main/channel.c index c9d260897..63838d7d3 100644 --- a/main/channel.c +++ b/main/channel.c @@ -4335,12 +4335,19 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio) * at the end of the queue. */ if (AST_LIST_NEXT(f, frame_list)) { + struct ast_frame *cur, *multi_frame = AST_LIST_NEXT(f, frame_list); + + /* Mark these frames as being re-queued */ + for (cur = multi_frame; cur; cur = AST_LIST_NEXT(cur, frame_list)) { + ast_set_flag(cur, AST_FRFLAG_REQUEUED); + } + if (!readq_tail) { - ast_queue_frame_head(chan, AST_LIST_NEXT(f, frame_list)); + ast_queue_frame_head(chan, multi_frame); } else { - __ast_queue_frame(chan, AST_LIST_NEXT(f, frame_list), 0, readq_tail); + __ast_queue_frame(chan, multi_frame, 0, readq_tail); } - ast_frfree(AST_LIST_NEXT(f, frame_list)); + ast_frfree(multi_frame); AST_LIST_NEXT(f, frame_list) = NULL; } @@ -4882,16 +4889,18 @@ int ast_sendtext(struct ast_channel *chan, const char *text) if (ast_channel_tech(chan)->write_text && (ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_TEXT))) { struct ast_frame f; + memset(&f, 0, sizeof(f)); f.frametype = AST_FRAME_TEXT; f.src = "DIALPLAN"; f.mallocd = AST_MALLOCD_DATA; f.datalen = strlen(text); f.data.ptr = ast_strdup(text); - f.offset = 0; - f.seqno = 0; - f.subclass.format = ast_format_t140; - res = ast_channel_tech(chan)->write_text(chan, &f); + + if (f.data.ptr) { + res = ast_channel_tech(chan)->write_text(chan, &f); + ast_frfree(&f); + } } else if (ast_channel_tech(chan)->send_text) { res = ast_channel_tech(chan)->send_text(chan, text); } diff --git a/main/fixedjitterbuf.c b/main/fixedjitterbuf.c index db7c157c3..5fcaa22d9 100644 --- a/main/fixedjitterbuf.c +++ b/main/fixedjitterbuf.c @@ -196,7 +196,6 @@ int fixed_jb_put_first(struct fixed_jb *jb, void *data, long ms, long ts, long n return fixed_jb_put(jb, data, ms, ts, now); } - int fixed_jb_put(struct fixed_jb *jb, void *data, long ms, long ts, long now) { struct fixed_jb_frame *frame, *next, *newframe; @@ -349,3 +348,8 @@ int fixed_jb_remove(struct fixed_jb *jb, struct fixed_jb_frame *frameout) return FIXED_JB_OK; } + +int fixed_jb_is_late(struct fixed_jb *jb, long ts) +{ + return jb->rxcore + jb->delay + ts < jb->next_delivery; +} diff --git a/main/fixedjitterbuf.h b/main/fixedjitterbuf.h index df9bbac55..ab8e5e2f8 100644 --- a/main/fixedjitterbuf.h +++ b/main/fixedjitterbuf.h @@ -85,6 +85,9 @@ int fixed_jb_remove(struct fixed_jb *jb, struct fixed_jb_frame *frameout); void fixed_jb_set_force_resynch(struct fixed_jb *jb); +/*! \brief Checks if the given time stamp is late */ +int fixed_jb_is_late(struct fixed_jb *jb, long ts); + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/format_compatibility.c b/main/format_compatibility.c index 9bf263b5b..0768b6717 100644 --- a/main/format_compatibility.c +++ b/main/format_compatibility.c @@ -264,10 +264,10 @@ struct ast_format *ast_format_compatibility_bitfield2format(uint64_t bitfield) /*! T.140 RED Text format RFC 4103 */ case AST_FORMAT_T140_RED: - return ast_format_t140; + return ast_format_t140_red; /*! T.140 Text format - ITU T.140, RFC 4103 */ case AST_FORMAT_T140: - return ast_format_t140_red; + return ast_format_t140; } return NULL; } diff --git a/main/frame.c b/main/frame.c index 92b92b6e2..833408089 100644 --- a/main/frame.c +++ b/main/frame.c @@ -84,9 +84,9 @@ static struct ast_frame *ast_frame_header_new(void) if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))) { if ((f = AST_LIST_REMOVE_HEAD(&frames->list, frame_list))) { size_t mallocd_len = f->mallocd_hdr_len; + memset(f, 0, sizeof(*f)); f->mallocd_hdr_len = mallocd_len; - f->mallocd = AST_MALLOCD_HDR; frames->size--; return f; } @@ -141,12 +141,12 @@ static void __frame_free(struct ast_frame *fr, int cache) #endif if (fr->mallocd & AST_MALLOCD_DATA) { - if (fr->data.ptr) + if (fr->data.ptr) { ast_free(fr->data.ptr - fr->offset); + } } if (fr->mallocd & AST_MALLOCD_SRC) { - if (fr->src) - ast_free((void *) fr->src); + ast_free((void *) fr->src); } if (fr->mallocd & AST_MALLOCD_HDR) { if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) || @@ -208,14 +208,14 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr) return NULL; } out->frametype = fr->frametype; + out->subclass = fr->subclass; if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) || (fr->frametype == AST_FRAME_IMAGE)) { - out->subclass.format = ao2_bump(fr->subclass.format); - } else { - memcpy(&out->subclass, &fr->subclass, sizeof(out->subclass)); + ao2_bump(out->subclass.format); } out->datalen = fr->datalen; out->samples = fr->samples; + out->mallocd = AST_MALLOCD_HDR; out->offset = fr->offset; /* Copy the timing data */ ast_copy_flags(out, fr, AST_FLAGS_ALL); @@ -228,47 +228,64 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr) out = fr; } - if (!(fr->mallocd & AST_MALLOCD_SRC) && fr->src) { - if (!(out->src = ast_strdup(fr->src))) { - if (out != fr) { - ast_free(out); + if (fr->src) { + /* The original frame has a source string */ + if (!(fr->mallocd & AST_MALLOCD_SRC)) { + /* + * The original frame has a non-malloced source string. + * + * Duplicate the string and put it into the isolated frame + * which may also be the original frame. + */ + newdata = ast_strdup(fr->src); + if (!newdata) { + if (out != fr) { + ast_frame_free(out, 0); + } + return NULL; } - return NULL; + out->src = newdata; + out->mallocd |= AST_MALLOCD_SRC; + } else if (out != fr) { + /* Steal the source string from the original frame. */ + out->src = fr->src; + fr->src = NULL; + fr->mallocd &= ~AST_MALLOCD_SRC; + out->mallocd |= AST_MALLOCD_SRC; } - } else { - out->src = fr->src; - fr->src = NULL; - fr->mallocd &= ~AST_MALLOCD_SRC; } if (!(fr->mallocd & AST_MALLOCD_DATA)) { + /* The original frame has a non-malloced data buffer. */ if (!fr->datalen) { + /* Actually it's just an int so we can simply copy it. */ out->data.uint32 = fr->data.uint32; - out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC; return out; } - if (!(newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET))) { - if (out->src != fr->src) { - ast_free((void *) out->src); - } + /* + * Duplicate the data buffer and put it into the isolated frame + * which may also be the original frame. + */ + newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET); + if (!newdata) { if (out != fr) { - ast_free(out); + ast_frame_free(out, 0); } return NULL; } newdata += AST_FRIENDLY_OFFSET; out->offset = AST_FRIENDLY_OFFSET; - out->datalen = fr->datalen; memcpy(newdata, fr->data.ptr, fr->datalen); out->data.ptr = newdata; - } else { + out->mallocd |= AST_MALLOCD_DATA; + } else if (out != fr) { + /* Steal the data buffer from the original frame. */ out->data = fr->data; memset(&fr->data, 0, sizeof(fr->data)); fr->mallocd &= ~AST_MALLOCD_DATA; + out->mallocd |= AST_MALLOCD_DATA; } - out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA; - return out; } diff --git a/main/jitterbuf.c b/main/jitterbuf.c index 0e93507ef..07046869f 100644 --- a/main/jitterbuf.c +++ b/main/jitterbuf.c @@ -845,4 +845,7 @@ enum jb_return_code jb_setconf(jitterbuf *jb, jb_conf *conf) return JB_OK; } - +int jb_is_late(jitterbuf *jb, long ts) +{ + return ts + jb->info.current < jb->info.next_voice_ts; +} |