# # Patch managed by http://www.holgerschurig.de/patcher.html # --- asterisk/channels/iax2.h~iax2-trunktimestamps +++ asterisk/channels/iax2.h @@ -138,6 +138,9 @@ #define IAX_META_TRUNK 1 /* Trunk meta-message */ #define IAX_META_VIDEO 2 /* Video frame */ +#define IAX_META_TRUNK_SUPERMINI 0 /* This trunk frame contains classic supermini frames */ +#define IAX_META_TRUNK_MINI 1 /* This trunk frame contains trunked mini frames */ + #define IAX_RATE_8KHZ (1 << 0) /* 8khz sampling (default if absent) */ #define IAX_RATE_11KHZ (1 << 1) /* 11.025khz sampling */ #define IAX_RATE_16KHZ (1 << 2) /* 16khz sampling */ @@ -209,6 +212,12 @@ unsigned short len; /* Length of data for this callno */ } __attribute__ ((__packed__)); +/* When trunktimestamps are used, we use this format instead */ +struct ast_iax2_meta_trunk_mini { + unsigned short len; + struct ast_iax2_mini_hdr mini; /* this is an actual miniframe */ +} __attribute__ ((__packed__)); + #define IAX_FIRMWARE_MAGIC 0x69617879 struct ast_iax2_firmware_header { --- asterisk/channels/chan_iax2.c~iax2-trunktimestamps +++ asterisk/channels/chan_iax2.c @@ -118,6 +118,7 @@ static int maxjitterbuffer=1000; static int jittershrinkrate=2; static int trunkfreq = 20; +static int send_trunktimestamps = 1; static int authdebug = 1; static int autokill = 0; static int iaxcompat = 0; @@ -3297,12 +3298,16 @@ return tpeer; } -static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct ast_frame *f) +static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr) { + struct ast_frame *f; struct iax2_trunk_peer *tpeer; void *tmp, *ptr; struct ast_iax2_meta_trunk_entry *met; + struct ast_iax2_meta_trunk_mini *mtm; char iabuf[INET_ADDRSTRLEN]; + + f = &fr->af; tpeer = find_tpeer(&pvt->addr, pvt->sockfd); if (tpeer) { if (tpeer->trunkdatalen + f->datalen + 4 >= tpeer->trunkdataalloc) { @@ -3324,19 +3329,29 @@ return -1; } } - + /* Append to meta frame */ ptr = tpeer->trunkdata + IAX2_TRUNK_PREFACE + tpeer->trunkdatalen; - met = (struct ast_iax2_meta_trunk_entry *)ptr; - /* Store call number and length in meta header */ - met->callno = htons(pvt->callno); - met->len = htons(f->datalen); - /* Advance pointers/decrease length past trunk entry header */ - ptr += sizeof(struct ast_iax2_meta_trunk_entry); - tpeer->trunkdatalen += sizeof(struct ast_iax2_meta_trunk_entry); + if(send_trunktimestamps) { + mtm = (struct ast_iax2_meta_trunk_mini *)ptr; + mtm->len = htons(f->datalen); + mtm->mini.callno = htons(pvt->callno); + mtm->mini.ts = htons(0xffff & fr->ts); + ptr += sizeof(struct ast_iax2_meta_trunk_mini); + tpeer->trunkdatalen += sizeof(struct ast_iax2_meta_trunk_mini); + } else { + met = (struct ast_iax2_meta_trunk_entry *)ptr; + /* Store call number and length in meta header */ + met->callno = htons(pvt->callno); + met->len = htons(f->datalen); + /* Advance pointers/decrease length past trunk entry header */ + ptr += sizeof(struct ast_iax2_meta_trunk_entry); + tpeer->trunkdatalen += sizeof(struct ast_iax2_meta_trunk_entry); + } /* Copy actual trunk data */ memcpy(ptr, f->data, f->datalen); tpeer->trunkdatalen += f->datalen; + tpeer->calls++; ast_mutex_unlock(&tpeer->lock); } @@ -3609,7 +3624,7 @@ res = iax2_transmit(fr); } else { if (ast_test_flag(pvt, IAX_TRUNK)) { - iax2_trunk_queue(pvt, &fr->af); + iax2_trunk_queue(pvt, fr); res = 0; } else if (fr->af.frametype == AST_FRAME_VIDEO) { /* Video frame have no sequence number */ @@ -5369,7 +5384,10 @@ /* We're actually sending a frame, so fill the meta trunk header and meta header */ meta->zeros = 0; meta->metacmd = IAX_META_TRUNK; - meta->cmddata = 0; + if(send_trunktimestamps) + meta->cmddata = IAX_META_TRUNK_MINI; + else + meta->cmddata = IAX_META_TRUNK_SUPERMINI; mth->ts = htonl(calc_txpeerstamp(tpeer, trunkfreq, now)); /* And the rest of the ast_iax2 header */ fr->direction = DIRECTION_OUTGRESS; @@ -5682,6 +5700,7 @@ struct ast_iax2_video_hdr *vh = (struct ast_iax2_video_hdr *)buf; struct ast_iax2_meta_trunk_hdr *mth; struct ast_iax2_meta_trunk_entry *mte; + struct ast_iax2_meta_trunk_mini *mtm; char dblbuf[4096]; /* Declaration of dblbuf must immediately *preceed* fr on the stack */ struct iax_frame fr; struct iax_frame *cur; @@ -5724,6 +5743,7 @@ fr.callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, 1, fd); minivid = 1; } else if (meta->zeros == 0) { + unsigned char metatype; /* This is a meta header */ switch(meta->metacmd) { case IAX_META_TRUNK: @@ -5733,6 +5753,7 @@ } mth = (struct ast_iax2_meta_trunk_hdr *)(meta->data); ts = ntohl(mth->ts); + metatype = meta->cmddata; res -= (sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr)); ptr = mth->data; tpeer = find_tpeer(&sin, fd); @@ -5749,14 +5770,30 @@ ast_mutex_unlock(&tpeer->lock); while(res >= sizeof(struct ast_iax2_meta_trunk_entry)) { /* Process channels */ - mte = (struct ast_iax2_meta_trunk_entry *)ptr; - ptr += sizeof(struct ast_iax2_meta_trunk_entry); - res -= sizeof(struct ast_iax2_meta_trunk_entry); - len = ntohs(mte->len); + unsigned short callno, trunked_ts, len; + + if(metatype == IAX_META_TRUNK_MINI) { + mtm = (struct ast_iax2_meta_trunk_mini *)ptr; + ptr += sizeof(struct ast_iax2_meta_trunk_mini); + res -= sizeof(struct ast_iax2_meta_trunk_mini); + len = ntohs(mtm->len); + callno = ntohs(mtm->mini.callno); + trunked_ts = ntohs(mtm->mini.ts); + } else if ( metatype == IAX_META_TRUNK_SUPERMINI ) { + mte = (struct ast_iax2_meta_trunk_entry *)ptr; + ptr += sizeof(struct ast_iax2_meta_trunk_entry); + res -= sizeof(struct ast_iax2_meta_trunk_entry); + len = ntohs(mte->len); + callno = ntohs(mte->callno); + trunked_ts = 0; + } else { + ast_log(LOG_WARNING, "Unknown meta trunk cmd from '%s:%d': dropping\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port)); + break; + } /* Stop if we don't have enough data */ if (len > res) break; - fr.callno = find_callno(ntohs(mte->callno) & ~IAX_FLAG_FULL, 0, &sin, NEW_PREVENT, 1, fd); + fr.callno = find_callno(callno & ~IAX_FLAG_FULL, 0, &sin, NEW_PREVENT, 1, fd); if (fr.callno) { ast_mutex_lock(&iaxsl[fr.callno]); /* If it's a valid call, deliver the contents. If not, we @@ -5772,7 +5809,10 @@ f.data = ptr; else f.data = NULL; - fr.ts = fix_peerts(&rxtrunktime, fr.callno, ts); + if(trunked_ts) + fr.ts = trunked_ts; + else + fr.ts = fix_peerts(&rxtrunktime, fr.callno, ts); /* Don't pass any packets until we're started */ if ((iaxs[fr.callno]->state & IAX_STATE_STARTED)) { /* Common things */ @@ -7381,6 +7421,8 @@ strncpy(peer->dbsecret, v->value, sizeof(peer->dbsecret)-1); else if (!strcasecmp(v->name, "mailboxdetail")) ast_set2_flag(peer, ast_true(v->value), IAX_MESSAGEDETAIL); + else if (!strcasecmp(v->name, "trunktimestamps")) + send_trunktimestamps = ast_true(v->value); else if (!strcasecmp(v->name, "trunk")) { ast_set2_flag(peer, ast_true(v->value), IAX_TRUNK); if (ast_test_flag(peer, IAX_TRUNK) && (timingfd < 0)) { --- asterisk/configs/iax.conf.sample~iax2-trunktimestamps +++ asterisk/configs/iax.conf.sample @@ -97,6 +97,16 @@ ;jittershrinkrate=1 ;trunkfreq=20 ; How frequently to send trunk msgs (in ms) + +; Should we send timestamps for the individual sub-frames within trunk frames? +; There is a small bandwidth use for these (less than 1kbps/call), but they ensure +; that frame timestamps get sent end-to-end properly. If both ends of all your trunks +; go directly to TDM, _and_ your trunkfreq equals the frame length for your codecs, you +; can probably suppress these. The receiver must also support this feature, although +; they do not also need to have it enabled. +; +; trunktimestamps=yes + ; ; ; We can register with another IAX server to let him know where we are