[asterisk-commits] dvossel: branch dvossel/jb_ftw r311924 - in /team/dvossel/jb_ftw: funcs/ incl...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Mar 30 16:51:46 CDT 2011
Author: dvossel
Date: Wed Mar 30 16:51:40 2011
New Revision: 311924
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=311924
Log:
Prototype code creates a jitterbuffer on the read side of a channel using framehooks (awesomehooks)
This looks like it actually will work. Channels using a jitterbuffer will get read
called twice as often as those without, but it will just generate a NULL frame until
a real frame is time to be sent. In theory, this shouldn't be much more expensive
since NULL frames are just ignored.
Modified:
team/dvossel/jb_ftw/funcs/func_jitterbuffer.c
team/dvossel/jb_ftw/include/asterisk/abstract_jb.h
team/dvossel/jb_ftw/include/asterisk/channel.h
team/dvossel/jb_ftw/main/abstract_jb.c
team/dvossel/jb_ftw/main/channel.c
Modified: team/dvossel/jb_ftw/funcs/func_jitterbuffer.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/jb_ftw/funcs/func_jitterbuffer.c?view=diff&rev=311924&r1=311923&r2=311924
==============================================================================
--- team/dvossel/jb_ftw/funcs/func_jitterbuffer.c (original)
+++ team/dvossel/jb_ftw/funcs/func_jitterbuffer.c Wed Mar 30 16:51:40 2011
@@ -33,15 +33,65 @@
#include "asterisk/channel.h"
#include "asterisk/framehook.h"
#include "asterisk/pbx.h"
+#include "asterisk/abstract_jb.h"
+#include "asterisk/timing.h"
struct jb_framedata {
- /*jb stuff todohere, don't know what this is yet */
- struct ast_jb_impl *jb_impl;
- void *data;
+ const struct ast_jb_impl *jb_impl;
+ struct ast_jb_conf jb_conf;
+ void *jb_obj;
+ struct ast_timer *timer;
+ int timer_rate;
+ int timer_fd;
+
+ struct timeval start_tv;
+ /* used for debug */
+ struct timeval last_tv;
};
+
+static void jb_framedata_destroy(struct jb_framedata *framedata)
+{
+ if (framedata->timer) {
+ ast_timer_close(framedata->timer);
+ framedata->timer = NULL;
+ }
+ if (framedata->jb_impl && framedata->jb_obj) {
+ framedata->jb_impl->destroy(framedata->jb_obj);
+ framedata->jb_obj = NULL;
+ }
+ ast_free(framedata);
+}
+static int jb_framedata_init(struct jb_framedata *framedata)
+{
+//todohere eventually this should take a custom jb config, for testing this is all hardcoded at the moment.
+ framedata->timer_fd = -1;
+ if (!(framedata->jb_impl = ast_jb_get_impl(AST_JB_ADAPTIVE))) {
+ return -1;
+ }
+
+ if (!(framedata->timer = ast_timer_open())) {
+ return -1;
+ }
+ framedata->timer_fd = ast_timer_fd(framedata->timer);
+ ast_timer_set_rate(framedata->timer, 1000 / 20); //todohere move this to cb and check based on frame samples
+
+ framedata->start_tv = ast_tvnow();
+ framedata->last_tv = framedata->start_tv;
+
+//todohere setup fake conf
+ framedata->jb_conf.max_size = 200;
+ framedata->jb_conf.resync_threshold = 1000;
+ ast_copy_string(framedata->jb_conf.impl, "adaptive", sizeof(framedata->jb_conf.impl));
+ framedata->jb_conf.target_extra = 40;
+
+ framedata->jb_obj = framedata->jb_impl->create(&framedata->jb_conf, 1000);
+
+ return 0;
+}
static void datastore_destroy_cb(void *data) {
ast_free(data);
+ ast_verb(1, "JITTERBUFFER datastore destroyed\n"); //todohere change to debug
}
static const struct ast_datastore_info jb_datastore = {
@@ -51,13 +101,74 @@
static void hook_destroy_cb(void *framedata)
{
- ast_free(framedata);
+ ast_verb(1, "JITTERBUFFER hook destroyed\n"); //todohere change to debug
+ jb_framedata_destroy((struct jb_framedata *) framedata);
}
static struct ast_frame *hook_event_cb(struct ast_channel *chan, struct ast_frame *frame, enum ast_framehook_event event, void *data)
{
- //struct jb_framedata *framedata = data;
+ struct jb_framedata *framedata = data;
+ struct timeval now_tv;
+ unsigned long now;
+
+ switch (event) {
+ case AST_FRAMEHOOK_EVENT_READ:
+ break;
+ case AST_FRAMEHOOK_EVENT_ATTACHED:
+ case AST_FRAMEHOOK_EVENT_DETACHED:
+ case AST_FRAMEHOOK_EVENT_WRITE:
+ return frame;
+ }
+
+ now_tv = ast_tvnow();
+ now = ast_tvdiff_ms(now_tv, framedata->start_tv);
+
+ if (chan->fdno == AST_JITTERBUFFER_FD && framedata->timer) {
+ ast_timer_ack(framedata->timer, 1);
+ }
+
+ if (!frame) {
+ return frame;
+ }
+
/* todohere add jb logic, just passing frame through right now. */
+ if (frame->frametype == AST_FRAME_VOICE) {
+
+ // ---todohere DEBUG
+ framedata->jb_impl->put(framedata->jb_obj, frame, now);
+
+ frame = &ast_null_frame;
+ }
+
+ if (frame->frametype == AST_FRAME_NULL) {
+ int res;
+ long next = framedata->jb_impl->next(framedata->jb_obj);
+
+ if (now < next) {
+ return frame;
+ }
+ /* todohere may have to return multiple frames */
+
+ res = framedata->jb_impl->get(framedata->jb_obj, &frame, now, 20);
+ switch (res) {
+ case AST_JB_IMPL_OK:
+// printf("----- diff: %lu now: %lu next: %lu\n", ast_tvdiff_ms(now_tv, framedata->last_tv), now, next);
+// framedata->last_tv = now_tv;
+ break;
+ case AST_JB_IMPL_DROP:
+ ast_frfree(frame);
+ frame = &ast_null_frame;
+ break;
+ case AST_JB_IMPL_INTERP:
+ /* todohere */
+ ast_log(LOG_NOTICE, "got interp frame err\n");
+ /* fall through */
+ case AST_JB_IMPL_NOFRAME:
+ frame = &ast_null_frame;
+ break;
+ }
+ }
+
return frame;
}
@@ -76,6 +187,11 @@
return 0;
}
+ if (jb_framedata_init(framedata)) {
+ jb_framedata_destroy(framedata);
+ return 0;
+ }
+
interface.data = framedata;
ast_channel_lock(chan);
@@ -104,6 +220,11 @@
*id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */
datastore->data = id;
ast_channel_datastore_add(chan, datastore);
+
+ ast_channel_set_fd(chan, AST_JITTERBUFFER_FD, framedata->timer_fd);
+ } else {
+ jb_framedata_destroy(framedata);
+ framedata = NULL;
}
ast_channel_unlock(chan);
Modified: team/dvossel/jb_ftw/include/asterisk/abstract_jb.h
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/jb_ftw/include/asterisk/abstract_jb.h?view=diff&rev=311924&r1=311923&r2=311924
==============================================================================
--- team/dvossel/jb_ftw/include/asterisk/abstract_jb.h (original)
+++ team/dvossel/jb_ftw/include/asterisk/abstract_jb.h Wed Mar 30 16:51:40 2011
@@ -50,6 +50,14 @@
enum ast_jb_type {
AST_JB_FIXED,
AST_JB_ADAPTIVE,
+};
+
+/*! Abstract return codes */
+enum {
+ AST_JB_IMPL_OK,
+ AST_JB_IMPL_DROP,
+ AST_JB_IMPL_INTERP,
+ AST_JB_IMPL_NOFRAME
};
#define AST_JB_IMPL_NAME_SIZE 12
Modified: team/dvossel/jb_ftw/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/jb_ftw/include/asterisk/channel.h?view=diff&rev=311924&r1=311923&r2=311924
==============================================================================
--- team/dvossel/jb_ftw/include/asterisk/channel.h (original)
+++ team/dvossel/jb_ftw/include/asterisk/channel.h Wed Mar 30 16:51:40 2011
@@ -154,7 +154,7 @@
#define DATASTORE_INHERIT_FOREVER INT_MAX
-#define AST_MAX_FDS 10
+#define AST_MAX_FDS 11
/*
* We have AST_MAX_FDS file descriptors in a channel.
* Some of them have a fixed use:
@@ -163,6 +163,7 @@
#define AST_TIMING_FD (AST_MAX_FDS-2) /*!< used for timingfd */
#define AST_AGENT_FD (AST_MAX_FDS-3) /*!< used by agents for pass through */
#define AST_GENERATOR_FD (AST_MAX_FDS-4) /*!< used by generator */
+#define AST_JITTERBUFFER_FD (AST_MAX_FDS-5) /*!< used by generator */
enum ast_bridge_result {
AST_BRIDGE_COMPLETE = 0,
Modified: team/dvossel/jb_ftw/main/abstract_jb.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/jb_ftw/main/abstract_jb.c?view=diff&rev=311924&r1=311923&r2=311924
==============================================================================
--- team/dvossel/jb_ftw/main/abstract_jb.c (original)
+++ team/dvossel/jb_ftw/main/abstract_jb.c Wed Mar 30 16:51:40 2011
@@ -104,20 +104,11 @@
static int default_impl = 0;
-
-/*! Abstract return codes */
-enum {
- JB_IMPL_OK,
- JB_IMPL_DROP,
- JB_IMPL_INTERP,
- JB_IMPL_NOFRAME
-};
-
/* Translations between impl and abstract return codes */
static const int fixed_to_abstract_code[] =
- {JB_IMPL_OK, JB_IMPL_DROP, JB_IMPL_INTERP, JB_IMPL_NOFRAME};
+ {AST_JB_IMPL_OK, AST_JB_IMPL_DROP, AST_JB_IMPL_INTERP, AST_JB_IMPL_NOFRAME};
static const int adaptive_to_abstract_code[] =
- {JB_IMPL_OK, JB_IMPL_NOFRAME, JB_IMPL_NOFRAME, JB_IMPL_INTERP, JB_IMPL_DROP, JB_IMPL_OK};
+ {AST_JB_IMPL_OK, AST_JB_IMPL_NOFRAME, AST_JB_IMPL_NOFRAME, AST_JB_IMPL_INTERP, AST_JB_IMPL_DROP, AST_JB_IMPL_OK};
/* JB_GET actions (used only for the frames log) */
static const char * const jb_get_actions[] = {"Delivered", "Dropped", "Interpolated", "No"};
@@ -311,7 +302,7 @@
return 0;
} else {
now = get_now(jb, NULL);
- if (jbimpl->put(jbobj, frr, now) != JB_IMPL_OK) {
+ if (jbimpl->put(jbobj, frr, now) != AST_JB_IMPL_OK) {
jb_framelog("JB_PUT {now=%ld}: Dropped frame with ts=%ld and len=%ld\n", now, frr->ts, frr->len);
ast_frfree(frr);
/*return -1;*/
@@ -368,16 +359,16 @@
res = jbimpl->get(jbobj, &f, now, interpolation_len);
switch (res) {
- case JB_IMPL_OK:
+ case AST_JB_IMPL_OK:
/* deliver the frame */
ast_write(chan, f);
- case JB_IMPL_DROP:
+ case AST_JB_IMPL_DROP:
jb_framelog("\tJB_GET {now=%ld}: %s frame with ts=%ld and len=%ld\n",
now, jb_get_actions[res], f->ts, f->len);
ast_format_copy(&jb->last_format, &f->subclass.format);
ast_frfree(f);
break;
- case JB_IMPL_INTERP:
+ case AST_JB_IMPL_INTERP:
/* interpolate a frame */
f = &finterp;
ast_format_copy(&f->subclass.format, &jb->last_format);
@@ -389,9 +380,9 @@
ast_write(chan, f);
jb_framelog("\tJB_GET {now=%ld}: Interpolated frame with len=%d\n", now, interpolation_len);
break;
- case JB_IMPL_NOFRAME:
+ case AST_JB_IMPL_NOFRAME:
ast_log(LOG_WARNING,
- "JB_IMPL_NOFRAME is returned from the %s jb when now=%ld >= next=%ld, jbnext=%ld!\n",
+ "AST_JB_IMPL_NOFRAME is returned from the %s jb when now=%ld >= next=%ld, jbnext=%ld!\n",
jbimpl->name, now, jb->next, jbimpl->next(jbobj));
jb_framelog("\tJB_GET {now=%ld}: No frame for now!?\n", now);
return;
@@ -429,7 +420,7 @@
/* The result of putting the first frame should not differ from OK. However, its possible
some implementations (i.e. adaptive's when resynch_threshold is specified) to drop it. */
- if (res != JB_IMPL_OK) {
+ if (res != AST_JB_IMPL_OK) {
ast_log(LOG_WARNING, "Failed to put first frame in the jitterbuffer on channel '%s'\n", chan->name);
/*
jbimpl->destroy(jbobj);
@@ -473,7 +464,7 @@
}
}
- if (res == JB_IMPL_OK) {
+ if (res == AST_JB_IMPL_OK) {
jb_framelog("JB_PUT_FIRST {now=%ld}: Queued frame with ts=%ld and len=%ld\n",
now, frr->ts, frr->len);
} else {
@@ -485,7 +476,7 @@
ast_verb(3, "%s jitterbuffer created on channel %s\n", jbimpl->name, chan->name);
/* Free the frame if it has not been queued in the jb */
- if (res != JB_IMPL_OK) {
+ if (res != AST_JB_IMPL_OK) {
ast_frfree(frr);
}
@@ -507,7 +498,7 @@
if (ast_test_flag(jb, JB_CREATED)) {
/* Remove and free all frames still queued in jb */
- while (jbimpl->remove(jbobj, &f) == JB_IMPL_OK) {
+ while (jbimpl->remove(jbobj, &f) == AST_JB_IMPL_OK) {
ast_frfree(f);
}
Modified: team/dvossel/jb_ftw/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/dvossel/jb_ftw/main/channel.c?view=diff&rev=311924&r1=311923&r2=311924
==============================================================================
--- team/dvossel/jb_ftw/main/channel.c (original)
+++ team/dvossel/jb_ftw/main/channel.c Wed Mar 30 16:51:40 2011
@@ -3874,15 +3874,15 @@
ast_log(LOG_WARNING, "No read routine on channel %s\n", chan->name);
}
+ /* Perform the framehook read event here. After the frame enters the framehook list
+ * there is no telling what will happen, <insert mad scientist laugh here>!!! */
+ f = ast_framehook_list_read_event(chan->framehooks, f);
+
/*
* Reset the recorded file descriptor that triggered this read so that we can
* easily detect when ast_read() is called without properly using ast_waitfor().
*/
chan->fdno = -1;
-
- /* Perform the framehook read event here. After the frame enters the framehook list
- * there is no telling what will happen, <insert mad scientist laugh here>!!! */
- f = ast_framehook_list_read_event(chan->framehooks, f);
if (f) {
struct ast_frame *readq_tail = AST_LIST_LAST(&chan->readq);
More information about the asterisk-commits
mailing list