Index: channels/iax2-parser.h
===================================================================
--- channels/iax2-parser.h	(revision 100533)
+++ channels/iax2-parser.h	(working copy)
@@ -109,6 +109,8 @@
 	unsigned int sentyet:1;
 	/* Non-zero if should be sent to transfer peer */
 	unsigned int transfer:1;
+	/* Non-zero if should be sent to media peer */
+	int media;
 	/* Non-zero if this is the final message */
 	unsigned int final:1;
 	/* Ingress or outgres */
Index: channels/chan_iax2.c
===================================================================
--- channels/chan_iax2.c	(revision 100533)
+++ channels/chan_iax2.c	(working copy)
@@ -415,13 +415,9 @@
 	TRANSFER_BEGIN,
 	TRANSFER_READY,
 	TRANSFER_RELEASED,
-	TRANSFER_PASSTHROUGH,
 	TRANSFER_MBEGIN,
 	TRANSFER_MREADY,
-	TRANSFER_MRELEASED,
-	TRANSFER_MPASSTHROUGH,
-	TRANSFER_MEDIA,
-	TRANSFER_MEDIAPASS
+	TRANSFER_MRELEASED
 };
 
 struct iax2_registry {
@@ -608,6 +604,13 @@
 	unsigned short transfercallno;
 	/*! Transfer encrypt AES-128 Key */
 	ast_aes_encrypt_key tdcx;
+	
+	/*! If transfer has been attempted */
+	int triedtransfer;
+	/*! Whether media is released */
+	int mediareleased;
+	/*! If media released, the peer to send media to */
+	struct sockaddr_in media;
 
 	/*! Status of knowledge of peer ADSI capability */
 	int peeradsicpe;
@@ -875,7 +878,7 @@
 static int iax2_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen);
 static int iax2_poke_peer(struct iax2_peer *peer, int heldcall);
 static int iax2_provision(struct sockaddr_in *end, int sockfd, char *dest, const char *template, int force);
-static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final);
+static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final,int media);
 static int iax2_sendhtml(struct ast_channel *c, int subclass, const char *data, int datalen);
 static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img);
 static int iax2_sendtext(struct ast_channel *c, const char *text);
@@ -888,6 +891,7 @@
 static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
 static int send_command_locked(unsigned short callno, char, int, unsigned int, const unsigned char *, int, int);
 static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int);
+static int send_command_media(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int);
 static struct ast_channel *iax2_request(const char *type, int format, void *data, int *cause);
 static struct ast_frame *iax2_read(struct ast_channel *c);
 static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly);
@@ -1337,7 +1341,10 @@
 	tmp->autoid = -1;
 	tmp->authid = -1;
 	tmp->initid = -1;
+	tmp->mediareleased = 0;
+	tmp->triedtransfer = 0; 
 
+
 	ast_string_field_set(tmp,exten, "s");
 	ast_string_field_set(tmp,host, host);
 
@@ -1388,7 +1395,7 @@
 	if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
 	    (cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
 		/* We're transferring */
-		if ((dcallno == cur->callno) || (cur->transferring == TRANSFER_MEDIAPASS && cur->transfercallno == callno))
+		if ((dcallno == cur->callno) || (cur->transferring == TRANSFER_NONE && cur->transfercallno == callno))
 			return 1;
 	}
 	return 0;
@@ -1999,8 +2006,14 @@
 	/* Called with iaxsl held */
 	if (iaxdebug)
 		ast_debug(3, "Sending %d on %d/%d to %s:%d\n", f->ts, callno, iaxs[callno]->peercallno, ast_inet_ntoa(iaxs[callno]->addr.sin_addr), ntohs(iaxs[callno]->addr.sin_port));
-	if (f->transfer) {
+  	if (f->media) {
 		if (iaxdebug)
+			iax_showframe(f, NULL, 0, &iaxs[callno]->media, f->datalen - sizeof(struct ast_iax2_full_hdr));
+		res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->media, 
+			sizeof(iaxs[callno]->media));
+	} else if (f->transfer) {
+
+		if (iaxdebug)
 			iax_showframe(f, NULL, 0, &iaxs[callno]->transfer, f->datalen - sizeof(struct ast_iax2_full_hdr));
 		res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->transfer,
 					sizeof(iaxs[callno]->transfer));
@@ -2172,7 +2185,13 @@
 				if (f->retries >= max_retries) {
 					if (f->transfer) {
 						/* Transfer timeout */
-						send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
+						struct iax_ie_data ied;
+						memset(&ied, 0, sizeof(ied));
+						iax_ie_append_int(&ied, IAX_IE_TRANSFERID, iaxs[callno]->transferid);
+						if (iaxs[callno]->mediareleased)
+							send_command_media(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied.buf, ied.pos);
+						else
+							send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied.buf, ied.pos, -1);
 					} else if (f->final) {
 						if (f->final) 
 							iax2_destroy(callno);
@@ -3592,23 +3611,37 @@
 	struct iax_ie_data ied1;
 	unsigned int transferid = (unsigned int)ast_random();
 	memset(&ied0, 0, sizeof(ied0));
+	iaxs[callno0]->transferid = transferid;
 	iax_ie_append_addr(&ied0, IAX_IE_APPARENT_ADDR, &iaxs[callno1]->addr);
 	iax_ie_append_short(&ied0, IAX_IE_CALLNO, iaxs[callno1]->peercallno);
 	iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, transferid);
 
 	memset(&ied1, 0, sizeof(ied1));
+	iaxs[callno1]->transferid = transferid;
 	iax_ie_append_addr(&ied1, IAX_IE_APPARENT_ADDR, &iaxs[callno0]->addr);
 	iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[callno0]->peercallno);
 	iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, transferid);
 	
-	res = send_command(iaxs[callno0], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos, -1);
+	if (iaxs[callno0]->mediareleased)
+		res = send_command_media(iaxs[callno0], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos);
+	else
+		res = send_command(iaxs[callno0], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied0.buf, ied0.pos, -1);
+
 	if (res)
 		return -1;
-	res = send_command(iaxs[callno1], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos, -1);
+	
+	if (iaxs[callno1]->mediareleased)
+		res = send_command_media(iaxs[callno1], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos);
+	else
+		res = send_command(iaxs[callno1], AST_FRAME_IAX, IAX_COMMAND_TXREQ, 0, ied1.buf, ied1.pos, -1);
+	
 	if (res)
 		return -1;
 	iaxs[callno0]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN;
 	iaxs[callno1]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN;
+	iaxs[callno0]->triedtransfer = 1;
+	iaxs[callno1]->triedtransfer = 1;
+
 	return 0;
 }
 
@@ -3634,7 +3667,6 @@
 	struct ast_channel *who, *other;
 	int to = -1;
 	int res = -1;
-	int transferstarted=0;
 	struct ast_frame *f;
 	unsigned short callno0 = PTR_TO_CALLNO(c0->tech_pvt);
 	unsigned short callno1 = PTR_TO_CALLNO(c1->tech_pvt);
@@ -3687,13 +3719,16 @@
 			unlock_both(callno0, callno1);
 			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)) {
-			/* Try the transfer */
-			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;
+		/* check if if we really want native bridging */
+		if (!ast_test_flag(iaxs[callno0], IAX_NOTRANSFER) && !ast_test_flag(iaxs[callno1], IAX_NOTRANSFER)) {
+			if (!iaxs[callno0]->triedtransfer && !iaxs[callno1]->triedtransfer &&
+			    (iaxs[callno0]->transferring == TRANSFER_NONE) &&
+			    (iaxs[callno1]->transferring == TRANSFER_NONE)) {
+				/* Try the transfer */
+				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");
+			}
 		}
 		if ((iaxs[callno0]->transferring == TRANSFER_RELEASED) && (iaxs[callno1]->transferring == TRANSFER_RELEASED)) {
 			/* Call has been transferred.  We're no longer involved */
@@ -4405,7 +4440,7 @@
 	return res;
 }
 
-static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final)
+static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final,int media)
 {
 	/* Queue a packet for delivery on a given private structure.  Use "ts" for
 	   timestamp, or calculate if ts is 0.  Send immediately without retransmission
@@ -4476,6 +4511,7 @@
 	fr->ts = fts;
 	fr->callno = pvt->callno;
 	fr->transfer = transfer;
+	fr->media = media;
 	fr->final = final;
 	if (!sendmini) {
 		/* We need a full frame */
@@ -4488,12 +4524,12 @@
 		fh->scallno = htons(fr->callno | IAX_FLAG_FULL);
 		fh->ts = htonl(fr->ts);
 		fh->oseqno = fr->oseqno;
-		if (transfer) {
+		if (transfer || media) {
 			fh->iseqno = 0;
 		} else
 			fh->iseqno = fr->iseqno;
 		/* Keep track of the last thing we've acknowledged */
-		if (!transfer)
+		if (!transfer || media)
 			pvt->aseqno = fr->iseqno;
 		fh->type = fr->af.frametype & 0xFF;
 		if (fr->af.frametype == AST_FRAME_VIDEO)
@@ -4526,6 +4562,9 @@
 				if (iaxdebug) {
 					if (fr->transfer)
 						iax_showframe(fr, NULL, 2, &pvt->transfer, fr->datalen - sizeof(struct ast_iax2_full_hdr));
+					else if (fr->media)
+						iax_showframe(fr, NULL, 2, &pvt->media, fr->datalen - sizeof(struct ast_iax2_full_hdr));
+
 					else
 						iax_showframe(fr, NULL, 2, &pvt->addr, fr->datalen - sizeof(struct ast_iax2_full_hdr));
 				}
@@ -4553,6 +4592,8 @@
 			fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_video_hdr);
 			fr->data = vh;
 			fr->retries = -1;
+			if(pvt->mediareleased)
+				fr->media = 1;
 			res = send_packet(fr);			
 		} else {
 			/* Mini-frames have no sequence number */
@@ -4565,8 +4606,8 @@
 			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 (pvt->mediareleased)
+				fr->media = 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);
@@ -5388,7 +5429,7 @@
 				res = 0;
 			else
 			/* Simple, just queue for transmission */
-				res = iax2_send(iaxs[callno], f, 0, -1, 0, 0, 0);
+				res = iax2_send(iaxs[callno], f, 0, -1, 0, 0, 0, 0);
 		} else {
 			ast_debug(1, "Write error: %s\n", strerror(errno));
 		}
@@ -5399,7 +5440,7 @@
 }
 
 static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno, 
-		int now, int transfer, int final)
+		int now, int transfer, int final, int media)
 {
 	struct ast_frame f = { 0, };
 
@@ -5409,12 +5450,12 @@
 	f.src = __FUNCTION__;
 	f.data = (void *) data;
 
-	return iax2_send(i, &f, ts, seqno, now, transfer, final);
+	return iax2_send(i, &f, ts, seqno, now, transfer, final, media);
 }
 
 static int send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
 {
-	return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0);
+	return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0, 0);
 }
 
 static int send_command_locked(unsigned short callno, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
@@ -5438,19 +5479,24 @@
 	iax2_predestroy(i->callno);
 	if (!iaxs[call_num])
 		return -1;
-	return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1);
+	return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1, 0);
 }
 
 static int send_command_immediate(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
 {
-	return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0);
+	return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0, 0);
 }
 
 static int send_command_transfer(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen)
 {
-	return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0);
+	return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0, 0);
 }
 
+static int send_command_media(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen)
+{
+  return __send_command(i, type, command, ts, data, datalen, 0, 0, 0, 0, 1);
+}
+
 static int apply_context(struct iax2_context *con, const char *context)
 {
 	while(con) {
@@ -6250,6 +6296,8 @@
 	}
 	memcpy(&pvt->addr, &pvt->transfer, sizeof(pvt->addr));
 	memset(&pvt->transfer, 0, sizeof(pvt->transfer));
+	pvt->mediareleased = 0;
+	memset(&pvt->media, 0, sizeof(pvt->media));
 	/* Reset sequence numbers */
 	pvt->oseqno = 0;
 	pvt->rseqno = 0;
@@ -7745,6 +7793,7 @@
 				((f.subclass != IAX_COMMAND_TXCNT) &&
 				(f.subclass != IAX_COMMAND_TXREADY) &&		/* for attended transfer */
 				(f.subclass != IAX_COMMAND_TXREL) &&		/* for attended transfer */
+				(f.subclass != IAX_COMMAND_TXMEDIA) &&		/* for attended transfer */
 				(f.subclass != IAX_COMMAND_UNQUELCH ) &&	/* for attended transfer */
 				(f.subclass != IAX_COMMAND_TXACC)) ||
 				(f.frametype != AST_FRAME_IAX))) {
@@ -7754,6 +7803,7 @@
 			  (f.subclass != IAX_COMMAND_TXCNT) &&
 			  (f.subclass != IAX_COMMAND_TXREADY) &&		/* for attended transfer */
 			  (f.subclass != IAX_COMMAND_TXREL) &&		/* for attended transfer */
+			  (f.subclass != IAX_COMMAND_TXMEDIA) &&		/* for attended transfer */
 			  (f.subclass != IAX_COMMAND_UNQUELCH ) &&	/* for attended transfer */
 			  (f.subclass != IAX_COMMAND_TXACC) &&
 			  (f.subclass != IAX_COMMAND_VNAK)) ||
@@ -7854,7 +7904,7 @@
 				ast_debug(1, "Received iseqno %d not within window %d->%d\n", fr->iseqno, iaxs[fr->callno]->rseqno, iaxs[fr->callno]->oseqno);
 			}
 		}
-		if (inaddrcmp(&sin, &iaxs[fr->callno]->addr) && 
+		if (inaddrcmp(&sin, &iaxs[fr->callno]->addr) && inaddrcmp(&sin, &iaxs[fr->callno]->media) && 
 			((f.frametype != AST_FRAME_IAX) || 
 			 ((f.subclass != IAX_COMMAND_TXACC) &&
 			  (f.subclass != IAX_COMMAND_TXCNT)))) {
@@ -8039,18 +8089,22 @@
 				}
 				break;
 			case IAX_COMMAND_TXACC:
-				if (iaxs[fr->callno]->transferring == TRANSFER_BEGIN) {
-					/* Ack the packet with the given timestamp */
+				if ((iaxs[fr->callno]->transferring == TRANSFER_BEGIN) &&
+				    (iaxs[fr->callno]->transferid == ies.transferid)) {
+					/* Cancel any outstanding txcnt's */
 					AST_LIST_LOCK(&frame_queue);
 					AST_LIST_TRAVERSE(&frame_queue, cur, list) {
-						/* Cancel any outstanding txcnt's */
 						if ((fr->callno == cur->callno) && (cur->transfer))
 							cur->retries = -1;
 					}
 					AST_LIST_UNLOCK(&frame_queue);
 					memset(&ied1, 0, sizeof(ied1));
 					iax_ie_append_short(&ied1, IAX_IE_CALLNO, iaxs[fr->callno]->callno);
-					send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied1.buf, ied1.pos, -1);
+					iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, iaxs[fr->callno]->transferid);
+					if (iaxs[fr->callno]->mediareleased)
+						send_command_media(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied1.buf, ied1.pos);
+					else
+						send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREADY, 0, ied1.buf, ied1.pos, -1);
 					iaxs[fr->callno]->transferring = TRANSFER_READY;
 				}
 				break;
@@ -8465,7 +8519,7 @@
 				if(f.subclass == IAX_COMMAND_LAGRQ) {
 					/* Received a LAGRQ - echo back a LAGRP */
 					fr->af.subclass = IAX_COMMAND_LAGRP;
-					iax2_send(iaxs[fr->callno], &fr->af, fr->ts, -1, 0, 0, 0);
+					iax2_send(iaxs[fr->callno], &fr->af, fr->ts, -1, 0, 0, 0, 0);
 				} else {
 					/* Received LAGRP in response to our LAGRQ */
 					unsigned int ts;
@@ -8839,19 +8893,27 @@
 				}
 				break;
 			case IAX_COMMAND_TXREJ:
-				iaxs[fr->callno]->transferring = 0;
-				ast_verb(3, "Channel '%s' unable to transfer\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>");
-				memset(&iaxs[fr->callno]->transfer, 0, sizeof(iaxs[fr->callno]->transfer));
-				if (iaxs[fr->callno]->bridgecallno) {
-					if (iaxs[iaxs[fr->callno]->bridgecallno]->transferring) {
-						iaxs[iaxs[fr->callno]->bridgecallno]->transferring = 0;
-						send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
+				if ((iaxs[fr->callno]->transferring != TRANSFER_NONE) && 
+				    (iaxs[fr->callno]->transferid == ies.transferid)) {
+					iaxs[fr->callno]->transferring = TRANSFER_NONE;
+					ast_verb(3, "Channel '%s' transfer rejected\n", iaxs[fr->callno]->owner ? iaxs[fr->callno]->owner->name : "<Unknown>");
+					memset(&iaxs[fr->callno]->transfer, 0, sizeof(iaxs[fr->callno]->transfer));
+					if (iaxs[fr->callno]->bridgecallno &&
+					    (iaxs[fr->callno]->transferid == iaxs[iaxs[fr->callno]->bridgecallno]->transferid)) {
+						iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_NONE;
+						memset(&ied0, 0, sizeof(ied0));
+						iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, iaxs[iaxs[fr->callno]->bridgecallno]->transferid);
+						if (iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased)
+							send_command_media(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied0.buf, ied0.pos);
+						else
+							send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied0.buf, ied0.pos, -1);
 					}
 				}
 				break;
 			case IAX_COMMAND_TXREADY:
-				if ((iaxs[fr->callno]->transferring == TRANSFER_BEGIN) ||
-				    (iaxs[fr->callno]->transferring == TRANSFER_MBEGIN)) {
+				if (((iaxs[fr->callno]->transferring == TRANSFER_BEGIN) ||
+				     (iaxs[fr->callno]->transferring == TRANSFER_MBEGIN)) &&
+				    (iaxs[fr->callno]->transferid == ies.transferid)) {
 					if (iaxs[fr->callno]->transferring == TRANSFER_MBEGIN)
 						iaxs[fr->callno]->transferring = TRANSFER_MREADY;
 					else
@@ -8861,19 +8923,32 @@
 						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 a peer is media released, we must also do a media release as there may be peers in between */
+							if (iaxs[fr->callno]->mediareleased || 
+							    iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased ||
+							    (iaxs[fr->callno]->transferring == TRANSFER_MREADY)) {
+
 								ast_verb(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>");
 
-								iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_MEDIA;
-								iaxs[fr->callno]->transferring = TRANSFER_MEDIA;
+								iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_MRELEASED;
+								iaxs[fr->callno]->transferring = TRANSFER_MRELEASED;
 
 								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_int(&ied0, IAX_IE_TRANSFERID, iaxs[iaxs[fr->callno]->bridgecallno]->transferid);
 								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);
+								iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, iaxs[fr->callno]->transferid);
+								if (iaxs[fr->callno]->mediareleased)
+									send_command_media(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied0.buf, ied0.pos);
+								else
+									send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied0.buf, ied0.pos, -1);
+								if (iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased)
+									send_command_media(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied1.buf, ied1.pos);
+								else
+									send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXMEDIA, 0, ied1.buf, ied1.pos, -1);
+
 							} else {
 								ast_verb(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>");
@@ -8890,9 +8965,18 @@
 								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_int(&ied0, IAX_IE_TRANSFERID, iaxs[iaxs[fr->callno]->bridgecallno]->transferid);
 								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);
+								iax_ie_append_int(&ied1, IAX_IE_TRANSFERID, iaxs[fr->callno]->transferid);
+								if (iaxs[fr->callno]->mediareleased)
+									send_command_media(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied0.buf, ied0.pos);
+								else
+									send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied0.buf, ied0.pos, -1);
+								if (iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased)
+									send_command_media(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied1.buf, ied1.pos);
+								else
+									send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREL, 0, ied1.buf, ied1.pos, -1);
+
 							}
 
 						}
@@ -8900,20 +8984,49 @@
 				}
 				break;
 			case IAX_COMMAND_TXREQ:
-				try_transfer(iaxs[fr->callno], &ies);
+				/* Try transfer only if none in progress, or use the transferid to resolve contention */
+				if ((iaxs[fr->callno]->transferring == TRANSFER_NONE) || 
+				    (iaxs[fr->callno]->transferid <= ies.transferid)) {
+					/* If there is a bridged channel and it is the same transfer, reject it */
+					if (iaxs[fr->callno]->bridgecallno &&
+					    (iaxs[fr->callno]->transferid == iaxs[iaxs[fr->callno]->bridgecallno]->transferid)) {
+						iaxs[iaxs[fr->callno]->bridgecallno]->transferring = TRANSFER_NONE;
+						memset(&ied0, 0, sizeof(ied0));
+						iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, iaxs[iaxs[fr->callno]->bridgecallno]->transferid);
+						if (iaxs[iaxs[fr->callno]->bridgecallno]->mediareleased)
+							send_command_media(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied0.buf, ied0.pos);
+						else
+							send_command(iaxs[iaxs[fr->callno]->bridgecallno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, ied0.buf, ied0.pos, -1);
+						/* Start our transfer again later */
+						iaxs[fr->callno]->triedtransfer = 0;
+						iaxs[iaxs[fr->callno]->bridgecallno]->triedtransfer = 0;
+					}
+					try_transfer(iaxs[fr->callno], &ies);
+				}
+
 				break;
 			case IAX_COMMAND_TXCNT:
-				if (iaxs[fr->callno]->transferring)
-					send_command_transfer(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXACC, 0, NULL, 0);
+				if ((iaxs[fr->callno]->transferring == TRANSFER_BEGIN) &&
+				    (iaxs[fr->callno]->transferid == ies.transferid)) {
+					memcpy(&iaxs[fr->callno]->transfer, &sin, sizeof(iaxs[fr->callno]->transfer));
+					memset(&ied0, 0, sizeof(ied0));
+					iax_ie_append_int(&ied0, IAX_IE_TRANSFERID, iaxs[fr->callno]->transferid);
+					send_command_transfer(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_TXACC, 0, ied0.buf, ied0.pos);
+				}
 				break;
 			case IAX_COMMAND_TXREL:
+				if ((iaxs[fr->callno]->transferring == TRANSFER_READY) &&
+				    (iaxs[fr->callno]->transferid == ies.transferid)) {
 				/* Send ack immediately, rather than waiting until we've changed addresses */
 				send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
 				complete_transfer(fr->callno, &ies);
-				stop_stuff(fr->callno);	/* for attended transfer to work with libiax */
+				stop_stuff(fr->callno); /* for attended transfer to work with libiax */
+				}
 				break;	
 			case IAX_COMMAND_TXMEDIA:
-				if (iaxs[fr->callno]->transferring == TRANSFER_READY) {
+				if ((iaxs[fr->callno]->transferring == TRANSFER_READY) &&
+				    (iaxs[fr->callno]->transferid == ies.transferid)) {
+
 					AST_LIST_LOCK(&frame_queue);
 					AST_LIST_TRAVERSE(&frame_queue, cur, list) {
 						/* Cancel any outstanding frames and start anew */
@@ -8922,7 +9035,10 @@
 					}
 					AST_LIST_UNLOCK(&frame_queue);
 					/* Start sending our media to the transfer address, but otherwise leave the call as-is */
-					iaxs[fr->callno]->transferring = TRANSFER_MEDIAPASS;
+					memcpy(&iaxs[fr->callno]->media, &iaxs[fr->callno]->transfer, sizeof(iaxs[fr->callno]->addr));
+					memset(&iaxs[fr->callno]->transfer, 0, sizeof(iaxs[fr->callno]->transfer));
+					iaxs[fr->callno]->transferring = TRANSFER_NONE;
+					iaxs[fr->callno]->mediareleased = 1;
 				}
 				break;	
 			case IAX_COMMAND_DPREP:
@@ -9060,7 +9176,6 @@
 			ast_debug(1, "For call=%d, set last=%d\n", fr->callno, fr->ts);
 #endif
 	}
-
 	/* Always run again */
 	ast_mutex_unlock(&iaxsl[fr->callno]);
 	return 1;
