diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index 9d04f2336a86d65f437daf5cf89bdc2a24271885..e54108c3b45f5fcc7620bb5e63a52fdd669bd14b 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -2006,6 +2006,20 @@ static struct ast_variable *add_var(const char *buf, struct ast_variable *list)
 	return list;
 }
 
+static void skinny_locksub(struct skinny_subchannel *sub)
+{
+	if (sub && sub->owner) {
+		ast_channel_lock(sub->owner);
+	}
+}
+
+static void skinny_unlocksub(struct skinny_subchannel *sub)
+{
+	if (sub && sub->owner) {
+		ast_channel_unlock(sub->owner);
+	}
+}
+
 static int skinny_sched_del(int sched_id, struct skinny_subchannel *sub)
 {
 	SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - Deleting SCHED %d\n",
@@ -4921,8 +4935,10 @@ static int skinny_dialer_cb(const void *data)
 static int skinny_autoanswer_cb(const void *data)
 {
 	struct skinny_subchannel *sub = (struct skinny_subchannel *)data;
+	skinny_locksub(sub);
 	sub->aa_sched = 0;
 	setsubstate(sub, SKINNY_CONNECTED);
+	skinny_unlocksub(sub);
 	return 0;
 }
 
@@ -4969,6 +4985,7 @@ static int skinny_call(struct ast_channel *ast, const char *dest, int timeout)
 		return -1;
 	}
 
+	skinny_locksub(sub);
 	AST_LIST_TRAVERSE(ast_channel_varshead(ast), current, entries) {
 		if (!(strcmp(ast_var_name(current), "SKINNY_AUTOANSWER"))) {
 			if (d->hookstate == SKINNY_ONHOOK && !sub->aa_sched) {
@@ -5001,6 +5018,7 @@ static int skinny_call(struct ast_channel *ast, const char *dest, int timeout)
 	if (doautoanswer) {
 		setsubstate(sub, SUBSTATE_CONNECTED);
 	}
+	skinny_unlocksub(sub);
 	return res;
 }
 
@@ -5573,6 +5591,8 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 		return;
 	}
 
+	skinny_locksub(sub);
+
 	if (sub->dialer_sched) {
 		skinny_sched_del(sub->dialer_sched, sub);
 		sub->dialer_sched = 0;
@@ -5590,6 +5610,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 			if (skinny_sched_del(sub->cfwd_sched, sub)) {
 				SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - trying to change state from %s to %s, but already forwarded because no answer.\n",
 					sub->callid, substate2str(sub->substate), substate2str(actualstate));
+				skinny_unlocksub(sub);
 				return;
 			}
 			sub->cfwd_sched = 0;
@@ -5666,12 +5687,11 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 
 			sub->cxmode = SKINNY_CX_RECVONLY;
 			sub->substate = SUBSTATE_ONHOOK;
-			destroy_rtp(sub);
 			sub->substate = SUBSTATE_ONHOOK;
 			if (sub->owner) {
 				ast_queue_hangup(sub->owner);
 			}
-			return;
+			break;
 		case SUBSTATE_CONNECTED:
 			transmit_activatecallplane(d, l);
 			transmit_stop_tone(d, l->instance, sub->callid);
@@ -5691,7 +5711,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 			}
 			sub->substate = SUBSTATE_CONNECTED;
 			l->activesub = sub;
-			return;
+			break;
 		case SUBSTATE_HOLD:
 			if (sub->substate != SUBSTATE_CONNECTED) {
 				ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_HOLD from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
@@ -5709,10 +5729,12 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 
 			ast_queue_hold(sub->owner, l->mohsuggest);
 
-			return;
+			break;
 		default:
 			ast_log(LOG_WARNING, "Substate handling under subline for state %d not implemented on Sub-%d\n", state, sub->callid);
 		}
+		skinny_unlocksub(sub);
+		return;
 	}
 
 	if ((d->hookstate == SKINNY_ONHOOK) && ((actualstate == SUBSTATE_OFFHOOK) || (actualstate == SUBSTATE_DIALING)
@@ -5726,6 +5748,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 		sub->callid, substate2str(sub->substate), substate2str(actualstate));
 
 	if (actualstate == sub->substate) {
+		skinny_unlocksub(sub);
 		return;
 	}
 
@@ -5766,10 +5789,10 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 		}
 
 		sub->cxmode = SKINNY_CX_RECVONLY;
-		destroy_rtp(sub);
 		if (sub->owner) {
 			if (sub->substate == SUBSTATE_OFFHOOK) {
 				sub->substate = SUBSTATE_ONHOOK;
+				skinny_unlocksub(sub);
 				ast_hangup(sub->owner);
 			} else {
 				sub->substate = SUBSTATE_ONHOOK;
@@ -5782,7 +5805,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 	case SUBSTATE_DIALING:
 		if (ast_strlen_zero(sub->exten) || !ast_exists_extension(c, ast_channel_context(c), sub->exten, 1, l->cid_num)) {
 			ast_log(LOG_WARNING, "Exten (%s)@(%s) does not exist, unable to set substate DIALING on sub %d\n", sub->exten, ast_channel_context(c), sub->callid);
-			return;
+			break;
 		}
 
 		if (d->hookstate == SKINNY_ONHOOK) {
@@ -5825,7 +5848,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 	case SUBSTATE_RINGOUT:
 		if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS)) {
 			ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_RINGOUT from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
-			return;
+			break;
 		}
 		if (sub->substate != SUBSTATE_PROGRESS) {
 			transmit_callstate(d, l->instance, sub->callid, SKINNY_PROGRESS);
@@ -5923,7 +5946,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 	case SUBSTATE_BUSY:
 		if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS || sub->substate == SUBSTATE_RINGOUT)) {
 			ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_BUSY from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
-			return;
+			break;
 		}
 
 		if (!d->earlyrtp) {
@@ -5937,7 +5960,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 	case SUBSTATE_CONGESTION:
 		if (!(sub->substate == SUBSTATE_DIALING || sub->substate == SUBSTATE_PROGRESS || sub->substate == SUBSTATE_RINGOUT)) {
 			ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_CONGESTION from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
-			return;
+			break;
 		}
 
 		if (!d->earlyrtp) {
@@ -5951,7 +5974,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 	case SUBSTATE_PROGRESS:
 		if (sub->substate != SUBSTATE_DIALING) {
 			ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_PROGRESS from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
-			return;
+			break;
 		}
 
 		if (!d->earlyrtp) {
@@ -5965,7 +5988,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 	case SUBSTATE_HOLD:
 		if (sub->substate != SUBSTATE_CONNECTED) {
 			ast_log(LOG_WARNING, "Cannot set substate to SUBSTATE_HOLD from %s (on call-%d)\n", substate2str(sub->substate), sub->callid);
-			return;
+			break;
 		}
 		ast_queue_hold(sub->owner, l->mohsuggest);
 
@@ -5981,6 +6004,7 @@ static void setsubstate(struct skinny_subchannel *sub, int state)
 	default:
 		ast_log(LOG_WARNING, "Was asked to change to nonexistant substate %d on Sub-%d\n", state, sub->callid);
 	}
+	skinny_unlocksub(sub);
 }
 
 static void dumpsub(struct skinny_subchannel *sub, int forcehangup)
@@ -6042,8 +6066,6 @@ static void activatesub(struct skinny_subchannel *sub, int state)
 	SKINNY_DEBUG(DEBUG_SUB, 3, "Sub %d - Activating, and deactivating sub %d\n",
 		sub->callid, l->activesub ? l->activesub->callid : 0);
 
-	ast_channel_lock(sub->owner);
-
 	if (sub == l->activesub) {
 		setsubstate(sub, state);
 	} else {
@@ -6057,8 +6079,6 @@ static void activatesub(struct skinny_subchannel *sub, int state)
 		l->activesub = sub;
 		setsubstate(sub, state);
 	}
-
-	ast_channel_unlock(sub->owner);
 }
 
 static void dialandactivatesub(struct skinny_subchannel *sub, char exten[AST_MAX_EXTENSION])