Index: channels/chan_h323.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_h323.c,v
retrieving revision 1.121
diff -u -r1.121 chan_h323.c
--- channels/chan_h323.c	10 Jul 2005 23:49:57 -0000	1.121
+++ channels/chan_h323.c	21 Jul 2005 09:55:38 -0000
@@ -140,7 +140,9 @@
 	int nativeformats;					/* Codec formats supported by a channel */
 	int needhangup;						/* Send hangup when Asterisk is ready */
 	int hangupcause;					/* Hangup cause from OpenH323 layer */
-	struct oh323_pvt *next;					/* Next channel in list */
+	int newstate;						/* Pending state change */
+	int newcontrol;						/* Pending control to send */
+	struct oh323_pvt *next;				/* Next channel in list */
 } *iflist = NULL;
 
 static struct ast_user_list {
@@ -233,6 +235,15 @@
 		c->hangupcause = pvt->hangupcause;
 		ast_queue_hangup(c);
 		pvt->needhangup = 0;
+		pvt->newstate = pvt->newcontrol = -1;
+	}
+	if (pvt->newstate >= 0) {
+		ast_setstate(c, pvt->newstate);
+		pvt->newstate = -1;
+	}
+	if (pvt->newcontrol >= 0) {
+		ast_queue_control(c, pvt->newcontrol);
+		pvt->newcontrol = -1;
 	}
 }
 
@@ -550,18 +561,22 @@
 			}	
 			/* Do in-band DTMF detection */
 			if ((pvt->options.dtmfmode & H323_DTMF_INBAND) && pvt->vad) {
-                   		f = ast_dsp_process(pvt->owner,pvt->vad,f);
+				if (!ast_mutex_trylock(&pvt->owner->lock)) {
+					f = ast_dsp_process(pvt->owner,pvt->vad,f);
+					ast_mutex_unlock(&pvt->owner->lock);
+				}
+				else
+					ast_log(LOG_NOTICE, "Unable to process inband DTMF while channel is locked\n");
 				if (f &&(f->frametype == AST_FRAME_DTMF)) {
 					ast_log(LOG_DEBUG, "Received in-band digit %c.\n", f->subclass);
-            			}
+				}
 			}
-			
 		}
 	}
 	return f;
 }
 
-static struct ast_frame  *oh323_read(struct ast_channel *c)
+static struct ast_frame *oh323_read(struct ast_channel *c)
 {
 	struct ast_frame *fr;
 	struct oh323_pvt *pvt = (struct oh323_pvt *)c->tech_pvt;
@@ -595,6 +610,7 @@
 		if (pvt->rtp) {
 			res =  ast_rtp_write(pvt->rtp, frame);
 		}
+		__oh323_update_info(c, pvt);
 		ast_mutex_unlock(&pvt->lock);
 	}
 	return res;
@@ -807,6 +823,7 @@
 		pvt->nonCodecCapability &= ~AST_RTP_DTMF;
 	}
 	strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
+	pvt->newstate = pvt->newsignal = -1;
 	/* Add to interface list */
 	ast_mutex_lock(&iflock);
 	pvt->next = iflist;
@@ -841,6 +858,26 @@
 	return NULL;
 }
 
+static int update_state(struct oh323_pvt *pvt, int state, int signal)
+{
+	if (!pvt)
+		return 0;
+	if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
+		if (state >= 0)
+			ast_setstate(pvt->owner, state);
+		if (signal >= 0)
+			ast_queue_control(pvt->owner, signal);
+		return 1;
+	}
+	else {
+		if (state >= 0)
+			pvt->newstate = state;
+		if (signal >= 0)
+			pvt->newsignal = signal;
+		return 0;
+	}
+}
+
 struct oh323_user *find_user(const call_details_t *cd)
 {
 	struct oh323_user *u;
@@ -1116,8 +1153,6 @@
 	return info;
 }
 
-int progress(unsigned call_reference, const char *token, int inband);
-
 /**
  * Definition taken from rtp.c for rtpPayloadType because we need it here.
  */
@@ -1156,10 +1191,16 @@
 		pvt->owner->nativeformats = pvt->nativeformats;
 		ast_set_read_format(pvt->owner, pvt->owner->readformat);
 		ast_set_write_format(pvt->owner, pvt->owner->writeformat);
+		if (pvt->options.progress_audio)
+			ast_queue_control(pvt->owner, AST_CONTROL_PROGRESS);
 		ast_mutex_unlock(&pvt->owner->lock);
 	}
-	else if (h323debug)
-		ast_log(LOG_DEBUG, "RTP connection preparation for %s is pending...\n", token);
+	else {
+		if (pvt->options.progress_audio)
+			pvt->newcontrol = AST_CONTROL_PROGRESS;
+		if (h323debug)
+			ast_log(LOG_DEBUG, "RTP connection preparation for %s is pending...\n", token);
+	}
 
 	them.sin_family = AF_INET;
 	/* only works for IPv4 */
@@ -1167,11 +1208,7 @@
 	them.sin_port = htons(remotePort);
 	ast_rtp_set_peer(pvt->rtp, &them);
 
-	if (pvt->options.progress_audio) {
-		ast_mutex_unlock(&pvt->lock);
-		progress(call_reference, token, 1);
-	} else
-		ast_mutex_unlock(&pvt->lock);
+	ast_mutex_unlock(&pvt->lock);
 
 	if (h323debug)
 		ast_log(LOG_DEBUG, "RTP connection prepared for %s\n", token);
@@ -1202,16 +1239,8 @@
 		ast_mutex_unlock(&pvt->lock);
 		return;
 	}
-	if (!pvt->owner) {
-		ast_mutex_unlock(&pvt->lock);
-		ast_log(LOG_ERROR, "Channel has no owner\n");
-		return;
-	}
-	ast_mutex_lock(&pvt->owner->lock);
-	c = pvt->owner;	
-	ast_setstate(c, AST_STATE_UP);
-	ast_queue_control(c, AST_CONTROL_ANSWER);
-	ast_mutex_unlock(&pvt->owner->lock);
+	if (update_state(pvt, AST_STATE_UP, AST_CONTROL_ANSWER))
+		ast_mutex_unlock(&pvt->owner->lock);
 	ast_mutex_unlock(&pvt->lock);
 	return;
 }
@@ -1232,9 +1261,8 @@
 		ast_log(LOG_ERROR, "No Asterisk channel associated with private structure.\n");
 		return -1;
 	}
-	ast_mutex_lock(&pvt->owner->lock);
-	ast_queue_control(pvt->owner, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING));
-	ast_mutex_unlock(&pvt->owner->lock);
+	if (update_state(pvt, -1, (inband ? AST_CONTROL_PROGRESS : AST_CONTROL_RINGING)))
+		ast_mutex_unlock(&pvt->owner->lock);
 	ast_mutex_unlock(&pvt->lock);
 
 	return 0;
@@ -1402,20 +1430,18 @@
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Ringing on %s\n", token);
 
-        pvt = find_call_locked(call_reference, token); 
-        if (!pvt) {
-                ast_log(LOG_ERROR, "Something is wrong: ringing\n");
+	pvt = find_call_locked(call_reference, token); 
+	if (!pvt) {
+		ast_log(LOG_ERROR, "Something is wrong: ringing\n");
+		return;
 	}
 	if (!pvt->owner) {
 		ast_mutex_unlock(&pvt->lock);
 		ast_log(LOG_ERROR, "Channel has no owner\n");
 		return;
 	}
-	ast_mutex_lock(&pvt->owner->lock);
-	c = pvt->owner;
-	ast_setstate(c, AST_STATE_RINGING);
-	ast_queue_control(c, AST_CONTROL_RINGING);
-	ast_mutex_unlock(&pvt->owner->lock);
+	if (update_state(pvt, AST_STATE_RINGING, AST_CONTROL_RINGING))
+		ast_mutex_unlock(&pvt->owner->lock);
 	ast_mutex_unlock(&pvt->lock);
 	return;
 }
