diff options
author | markster <markster@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-05-10 09:09:16 +0000 |
---|---|---|
committer | markster <markster@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-05-10 09:09:16 +0000 |
commit | 9e8603c06dc57ac8be815bb92a152ad5aa175f23 (patch) | |
tree | 4844a6d447394e3b7fd09ee597a19835acd526c1 | |
parent | c400f24164b9bd4d9e417ae964d120ebaccb28ca (diff) |
Allow media to go directly between IAX endpoints while signalling still
goes through the existing path.
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@26314 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r-- | channels/chan_iax2.c | 136 | ||||
-rw-r--r-- | channels/iax2.h | 1 | ||||
-rw-r--r-- | configs/iax.conf.sample | 4 | ||||
-rw-r--r-- | include/asterisk/utils.h | 8 |
4 files changed, 113 insertions, 36 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index d284e702e..2f16f5557 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -282,7 +282,8 @@ enum { IAX_RTAUTOCLEAR = (1 << 19), /*!< erase me on expire */ IAX_FORCEJITTERBUF = (1 << 20), /*!< Force jitterbuffer, even when bridged to a channel that can take jitter */ IAX_RTIGNOREREGEXPIRE = (1 << 21), /*!< When using realtime, ignore registration expiration */ - IAX_TRUNKTIMESTAMPS = (1 << 22) /*!< Send trunk timestamps */ + IAX_TRUNKTIMESTAMPS = (1 << 22), /*!< Send trunk timestamps */ + IAX_TRANSFERMEDIA = (1 << 23) /*!< When doing IAX2 transfers, transfer media only */ } iax2_flags; static int global_rtautoclear = 120; @@ -406,7 +407,13 @@ enum iax_transfer_state { TRANSFER_BEGIN, TRANSFER_READY, TRANSFER_RELEASED, - TRANSFER_PASSTHROUGH + TRANSFER_PASSTHROUGH, + TRANSFER_MBEGIN, + TRANSFER_MREADY, + TRANSFER_MRELEASED, + TRANSFER_MPASSTHROUGH, + TRANSFER_MEDIA, + TRANSFER_MEDIAPASS }; struct iax2_registry { @@ -1258,7 +1265,7 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc iaxs[x]->pingid = ast_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x); iaxs[x]->lagid = ast_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x); iaxs[x]->amaflags = amaflags; - ast_copy_flags(iaxs[x], (&globalflags), IAX_NOTRANSFER | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); + ast_copy_flags(iaxs[x], (&globalflags), IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); ast_copy_string(iaxs[x]->accountcode, accountcode, sizeof(iaxs[x]->accountcode)); } else { ast_log(LOG_WARNING, "Out of resources\n"); @@ -2944,7 +2951,7 @@ static int create_addr(const char *peername, struct sockaddr_in *sin, struct cre return -1; } - ast_copy_flags(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); + ast_copy_flags(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); cai->maxtime = peer->maxms; cai->capability = peer->capability; cai->encmethods = peer->encmethods; @@ -3291,7 +3298,7 @@ static struct ast_frame *iax2_read(struct ast_channel *c) return &ast_null_frame; } -static int iax2_start_transfer(unsigned short callno0, unsigned short callno1) +static int iax2_start_transfer(unsigned short callno0, unsigned short callno1, int mediaonly) { int res; struct iax_ie_data ied0; @@ -3313,8 +3320,8 @@ static int iax2_start_transfer(unsigned short callno0, unsigned short callno1) res = send_command(iaxs[callno1], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos, -1); if (res) return -1; - iaxs[callno0]->transferring = TRANSFER_BEGIN; - iaxs[callno1]->transferring = TRANSFER_BEGIN; + iaxs[callno0]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN; + iaxs[callno1]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN; return 0; } @@ -3391,10 +3398,10 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha return AST_BRIDGE_FAILED_NOWARN; } /* check if transfered and if we really want native bridging */ - if (!transferstarted && !ast_test_flag(iaxs[callno0], IAX_NOTRANSFER) && !ast_test_flag(iaxs[callno1], IAX_NOTRANSFER) && - !(flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) { + if (!transferstarted && !ast_test_flag(iaxs[callno0], IAX_NOTRANSFER) && !ast_test_flag(iaxs[callno1], IAX_NOTRANSFER)) { /* Try the transfer */ - if (iax2_start_transfer(callno0, callno1)) + if (iax2_start_transfer(callno0, callno1, (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1)) || + ast_test_flag(iaxs[callno0], IAX_TRANSFERMEDIA) | ast_test_flag(iaxs[callno1], IAX_TRANSFERMEDIA))) ast_log(LOG_WARNING, "Unable to start the transfer\n"); transferstarted = 1; } @@ -4123,7 +4130,9 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in return 0; - if ((ast_test_flag(pvt, IAX_TRUNK) || ((fts & 0xFFFF0000L) == (lastsent & 0xFFFF0000L))) + if ((ast_test_flag(pvt, IAX_TRUNK) || + (((fts & 0xFFFF0000L) == (lastsent & 0xFFFF0000L)) || + ((fts & 0xFFFF0000L) == ((lastsent + 0x10000) & 0xFFFF0000L)))) /* High two bytes are the same on timestamp, or sending on a trunk */ && (f->frametype == AST_FRAME_VOICE) /* is a voice frame */ && @@ -4244,6 +4253,8 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_mini_hdr); fr->data = mh; fr->retries = -1; + if (pvt->transferring == TRANSFER_MEDIAPASS) + fr->transfer = 1; if (ast_test_flag(pvt, IAX_ENCRYPTED)) { if (ast_test_flag(pvt, IAX_KEYPOPULATED)) { encrypt_frame(&pvt->ecx, (struct ast_iax2_full_hdr *)mh, pvt->semirand, &fr->datalen); @@ -5116,7 +5127,7 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies iaxs[callno]->amaflags = user->amaflags; if (!ast_strlen_zero(user->language)) ast_copy_string(iaxs[callno]->language, user->language, sizeof(iaxs[callno]->language)); - ast_copy_flags(iaxs[callno], user, IAX_NOTRANSFER | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); + ast_copy_flags(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); /* Keep this check last */ if (!ast_strlen_zero(user->dbsecret)) { char *family, *key=NULL; @@ -7761,32 +7772,53 @@ retryowner2: } break; case IAX_COMMAND_TXREADY: - if (iaxs[fr.callno]->transferring == TRANSFER_BEGIN) { - iaxs[fr.callno]->transferring = TRANSFER_READY; + if ((iaxs[fr.callno]->transferring == TRANSFER_BEGIN) || + (iaxs[fr.callno]->transferring == TRANSFER_MBEGIN)) { + if (iaxs[fr.callno]->transferring == TRANSFER_MBEGIN) + iaxs[fr.callno]->transferring = TRANSFER_MREADY; + else + iaxs[fr.callno]->transferring = TRANSFER_READY; if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Channel '%s' ready to transfer\n", iaxs[fr.callno]->owner ? iaxs[fr.callno]->owner->name : "<Unknown>"); if (iaxs[fr.callno]->bridgecallno) { - if (iaxs[iaxs[fr.callno]->bridgecallno]->transferring == TRANSFER_READY) { - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Releasing %s and %s\n", iaxs[fr.callno]->owner ? iaxs[fr.callno]->owner->name : "<Unknown>", + if ((iaxs[iaxs[fr.callno]->bridgecallno]->transferring == TRANSFER_READY) || + (iaxs[iaxs[fr.callno]->bridgecallno]->transferring == TRANSFER_MREADY)) { + /* They're both ready, now release them. */ + if (iaxs[fr.callno]->transferring == TRANSFER_MREADY) { + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Attempting media bridge of %s and %s\n", iaxs[fr.callno]->owner ? iaxs[fr.callno]->owner->name : "<Unknown>", iaxs[iaxs[fr.callno]->bridgecallno]->owner ? iaxs[iaxs[fr.callno]->bridgecallno]->owner->name : "<Unknown>"); - /* They're both ready, now release them. */ - iaxs[iaxs[fr.callno]->bridgecallno]->transferring = TRANSFER_RELEASED; - iaxs[fr.callno]->transferring = TRANSFER_RELEASED; - ast_set_flag(iaxs[iaxs[fr.callno]->bridgecallno], IAX_ALREADYGONE); - ast_set_flag(iaxs[fr.callno], IAX_ALREADYGONE); + iaxs[iaxs[fr.callno]->bridgecallno]->transferring = TRANSFER_MEDIA; + iaxs[fr.callno]->transferring = TRANSFER_MEDIA; + + memset(&ied0, 0, sizeof(ied0)); + memset(&ied1, 0, sizeof(ied1)); + iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[iaxs[fr.callno]->bridgecallno]->peercallno); + iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr.callno]->peercallno); + send_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied0.buf, ied0.pos, -1); + send_command(iaxs[iaxs[fr.callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied1.buf, ied1.pos, -1); + } else { + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Releasing %s and %s\n", iaxs[fr.callno]->owner ? iaxs[fr.callno]->owner->name : "<Unknown>", + iaxs[iaxs[fr.callno]->bridgecallno]->owner ? iaxs[iaxs[fr.callno]->bridgecallno]->owner->name : "<Unknown>"); - /* Stop doing lag & ping requests */ - stop_stuff(fr.callno); - stop_stuff(iaxs[fr.callno]->bridgecallno); + iaxs[iaxs[fr.callno]->bridgecallno]->transferring = TRANSFER_RELEASED; + iaxs[fr.callno]->transferring = TRANSFER_RELEASED; + ast_set_flag(iaxs[iaxs[fr.callno]->bridgecallno], IAX_ALREADYGONE); + ast_set_flag(iaxs[fr.callno], IAX_ALREADYGONE); - memset(&ied0, 0, sizeof(ied0)); - memset(&ied1, 0, sizeof(ied1)); - iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[iaxs[fr.callno]->bridgecallno]->peercallno); - iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr.callno]->peercallno); - send_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied0.buf, ied0.pos, -1); - send_command(iaxs[iaxs[fr.callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied1.buf, ied1.pos, -1); + /* Stop doing lag & ping requests */ + stop_stuff(fr.callno); + stop_stuff(iaxs[fr.callno]->bridgecallno); + + memset(&ied0, 0, sizeof(ied0)); + memset(&ied1, 0, sizeof(ied1)); + iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[iaxs[fr.callno]->bridgecallno]->peercallno); + iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr.callno]->peercallno); + send_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied0.buf, ied0.pos, -1); + send_command(iaxs[iaxs[fr.callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied1.buf, ied1.pos, -1); + } } } @@ -7805,6 +7837,12 @@ retryowner2: complete_transfer(fr.callno, &ies); stop_stuff(fr.callno); /* for attended transfer to work with libiax */ break; + case IAX_COMMAND_TXMEDIA: + if (iaxs[fr.callno]->transferring == TRANSFER_READY) { + /* Start sending our media to the transfer address, but otherwise leave the call as-is */ + iaxs[fr.callno]->transferring = TRANSFER_MEDIAPASS; + } + break; case IAX_COMMAND_DPREP: complete_dpreply(iaxs[fr.callno], &ies); break; @@ -8279,7 +8317,7 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data memset(&cai, 0, sizeof(cai)); cai.capability = iax2_capability; - ast_copy_flags(&cai, &globalflags, IAX_NOTRANSFER | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); + ast_copy_flags(&cai, &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); if (!pds.peer) { ast_log(LOG_WARNING, "No peer given\n"); @@ -8306,7 +8344,7 @@ static struct ast_channel *iax2_request(const char *type, int format, void *data ast_mutex_lock(&iaxsl[callno]); /* If this is a trunk, update it now */ - ast_copy_flags(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); + ast_copy_flags(iaxs[callno], &cai, IAX_TRUNK | IAX_SENDANI | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF); if (ast_test_flag(&cai, IAX_TRUNK)) callno = make_trunk(callno, 1); iaxs[callno]->maxtime = cai.maxtime; @@ -8630,7 +8668,16 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in } else if (!strcasecmp(v->name, "encryption")) { peer->encmethods = get_encrypt_methods(v->value); } else if (!strcasecmp(v->name, "notransfer")) { + ast_log(LOG_NOTICE, "The option 'notransfer' is deprecated in favor of 'transfer' which has options 'yes', 'no', and 'mediaonly'\n"); + ast_clear_flag(peer, IAX_TRANSFERMEDIA); ast_set2_flag(peer, ast_true(v->value), IAX_NOTRANSFER); + } else if (!strcasecmp(v->name, "transfer")) { + if (!strcasecmp(v->value, "mediaonly")) { + ast_set_flags_to(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA); + } else if (ast_true(v->value)) { + ast_set_flags_to(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0); + } else + ast_set_flags_to(peer, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER); } else if (!strcasecmp(v->name, "jitterbuffer")) { ast_set2_flag(peer, ast_true(v->value), IAX_USEJITTERBUF); } else if (!strcasecmp(v->name, "forcejitterbuffer")) { @@ -8823,7 +8870,16 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in } else if (!strcasecmp(v->name, "encryption")) { user->encmethods = get_encrypt_methods(v->value); } else if (!strcasecmp(v->name, "notransfer")) { + ast_log(LOG_NOTICE, "The option 'notransfer' is deprecated in favor of 'transfer' which has options 'yes', 'no', and 'mediaonly'\n"); + ast_clear_flag(user, IAX_TRANSFERMEDIA); ast_set2_flag(user, ast_true(v->value), IAX_NOTRANSFER); + } else if (!strcasecmp(v->name, "transfer")) { + if (!strcasecmp(v->value, "mediaonly")) { + ast_set_flags_to(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA); + } else if (ast_true(v->value)) { + ast_set_flags_to(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0); + } else + ast_set_flags_to(user, IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER); } else if (!strcasecmp(v->name, "codecpriority")) { if(!strcasecmp(v->value, "caller")) ast_set_flag(user, IAX_CODEC_USER_FIRST); @@ -9144,9 +9200,18 @@ static int set_config(char *config_file, int reload) authdebug = ast_true(v->value); else if (!strcasecmp(v->name, "encryption")) iax2_encryption = get_encrypt_methods(v->value); - else if (!strcasecmp(v->name, "notransfer")) + else if (!strcasecmp(v->name, "notransfer")) { + ast_log(LOG_NOTICE, "The option 'notransfer' is deprecated in favor of 'transfer' which has options 'yes', 'no', and 'mediaonly'\n"); + ast_clear_flag((&globalflags), IAX_TRANSFERMEDIA); ast_set2_flag((&globalflags), ast_true(v->value), IAX_NOTRANSFER); - else if (!strcasecmp(v->name, "codecpriority")) { + } else if (!strcasecmp(v->name, "transfer")) { + if (!strcasecmp(v->value, "mediaonly")) { + ast_set_flags_to((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_TRANSFERMEDIA); + } else if (ast_true(v->value)) { + ast_set_flags_to((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, 0); + } else + ast_set_flags_to((&globalflags), IAX_NOTRANSFER|IAX_TRANSFERMEDIA, IAX_NOTRANSFER); + } else if (!strcasecmp(v->name, "codecpriority")) { if(!strcasecmp(v->value, "caller")) ast_set_flag((&globalflags), IAX_CODEC_USER_FIRST); else if(!strcasecmp(v->value, "disabled")) @@ -9295,6 +9360,7 @@ static int reload_config(void) amaflags = 0; delayreject = 0; ast_clear_flag((&globalflags), IAX_NOTRANSFER); + ast_clear_flag((&globalflags), IAX_TRANSFERMEDIA); ast_clear_flag((&globalflags), IAX_USEJITTERBUF); ast_clear_flag((&globalflags), IAX_FORCEJITTERBUF); delete_users(); diff --git a/channels/iax2.h b/channels/iax2.h index c6b44628d..2b0c8bb99 100644 --- a/channels/iax2.h +++ b/channels/iax2.h @@ -67,6 +67,7 @@ #define IAX_COMMAND_PROVISION 35 /* Provision device */ #define IAX_COMMAND_FWDOWNL 36 /* Download firmware */ #define IAX_COMMAND_FWDATA 37 /* Firmware Data */ +#define IAX_COMMAND_TXMEDIA 38 /* Transfer media only */ #define IAX_DEFAULT_REG_EXPIRE 60 /* By default require re-registration once per minute */ diff --git a/configs/iax.conf.sample b/configs/iax.conf.sample index 3eeb760e5..83889306b 100644 --- a/configs/iax.conf.sample +++ b/configs/iax.conf.sample @@ -343,7 +343,9 @@ inkeys=freeworlddialup ;secret=markpasswd ;setvar=foo=bar ;dbsecret=mysecrets/place ; Secrets can be stored in astdb, too -;notransfer=yes ; Disable IAX native transfer +;transfer=no ; Disable IAX native transfer +;transfer=mediaonly ; When doing IAX native transfers, transfer + ; only media stream ;jitterbuffer=yes ; Override global setting an enable jitter buffer ; ; for this user ;callerid="Mark Spencer" <(256) 428-6275> diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index d2db42e07..134caa8dc 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -102,6 +102,14 @@ extern unsigned int __unsigned_int_flags_dummy; (p)->flags &= ~(flag); \ } while (0) +#define ast_set_flags_to(p,flag,value) do { \ + typeof ((p)->flags) __p = (p)->flags; \ + typeof (__unsigned_int_flags_dummy) __x = 0; \ + (void) (&__p == &__x); \ + (p)->flags &= ~(flag); \ + (p)->flags |= (value); \ + } while (0) + /* Non-type checking variations for non-unsigned int flags. You should only use non-unsigned int flags where required by protocol etc and if you know what you're doing :) */ |