Index: pjproject/trunk/pjmedia/include/pjmedia/tonegen.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/tonegen.h	(revision 1675)
+++ pjproject/trunk/pjmedia/include/pjmedia/tonegen.h	(revision 1676)
@@ -108,5 +108,10 @@
      * the last tone has been played.
      */
-    PJMEDIA_TONEGEN_LOOP    = 1
+    PJMEDIA_TONEGEN_LOOP    = 1,
+
+    /**
+     * Disable mutex protection to the tone generator.
+     */
+    PJMEDIA_TONEGEN_NO_LOCK = 2
 };
 
Index: pjproject/trunk/pjmedia/src/pjmedia/tonegen.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/tonegen.c	(revision 1675)
+++ pjproject/trunk/pjmedia/src/pjmedia/tonegen.c	(revision 1676)
@@ -19,6 +19,9 @@
 #include <pjmedia/tonegen.h>
 #include <pjmedia/errno.h>
+#include <pjmedia/silencedet.h>
 #include <pj/assert.h>
 #include <pj/ctype.h>
+#include <pj/lock.h>
+#include <pj/log.h>
 #include <pj/pool.h>
 
@@ -229,4 +232,11 @@
 
 #define SIGNATURE   PJMEDIA_PORT_SIGNATURE('t', 'n', 'g', 'n')
+#define THIS_FILE   "tonegen.c"
+
+#if 0
+#   define TRACE_(expr)	PJ_LOG(4,expr)
+#else
+#   define TRACE_(expr)
+#endif
 
 struct tonegen
@@ -237,4 +247,7 @@
     unsigned		options;
     unsigned		playback_options;
+
+    /* lock */
+    pj_lock_t	       *lock;
 
     /* Digit map */
@@ -279,4 +292,5 @@
 static pj_status_t tonegen_get_frame(pjmedia_port *this_port, 
 				     pjmedia_frame *frame);
+static pj_status_t tonegen_destroy(pjmedia_port *this_port);
 
 /*
@@ -294,5 +308,5 @@
 					    pjmedia_port **p_port)
 {
-    const pj_str_t STR_TONE_GEN = pj_str("tone-gen");
+    const pj_str_t STR_TONE_GEN = pj_str("tonegen");
     struct tonegen  *tonegen;
     pj_status_t status;
@@ -316,5 +330,20 @@
     tonegen->options = options;
     tonegen->base.get_frame = &tonegen_get_frame;
+    tonegen->base.on_destroy = &tonegen_destroy;
     tonegen->digit_map = &digit_map;
+
+    /* Lock */
+    if (options & PJMEDIA_TONEGEN_NO_LOCK) {
+	status = pj_lock_create_null_mutex(pool, "tonegen", &tonegen->lock);
+    } else {
+	status = pj_lock_create_simple_mutex(pool, "tonegen", &tonegen->lock);
+    }
+
+    if (status != PJ_SUCCESS) {
+	return status;
+    }
+
+    TRACE_((THIS_FILE, "Tonegen created: %u/%u/%u/%u", clock_rate, 
+	    channel_count, samples_per_frame, bits_per_sample));
 
     /* Done */
@@ -356,10 +385,34 @@
     struct tonegen *tonegen = (struct tonegen*) port;
     PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
+
+    TRACE_((THIS_FILE, "tonegen_stop()"));
+
+    pj_lock_acquire(tonegen->lock);
     tonegen->count = 0;
     tonegen->cur_digit = 0;
     tonegen->dig_samples = 0;
+    pj_lock_release(tonegen->lock);
+
     return PJ_SUCCESS;
 }
 
+
+/*
+ * Callback to destroy tonegen
+ */
+static pj_status_t tonegen_destroy(pjmedia_port *port)
+{
+    struct tonegen *tonegen = (struct tonegen*) port;
+    PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
+
+    TRACE_((THIS_FILE, "tonegen_destroy()"));
+
+    pj_lock_acquire(tonegen->lock);
+    pj_lock_release(tonegen->lock);
+
+    pj_lock_destroy(tonegen->lock);
+
+    return PJ_SUCCESS;
+}
 
 /*
@@ -375,8 +428,10 @@
     PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
 
+    pj_lock_acquire(tonegen->lock);
+
     if (tonegen->count == 0) {
 	/* We don't have digits to play */
 	frame->type = PJMEDIA_FRAME_TYPE_NONE;
-	return PJ_SUCCESS;
+	goto on_return;
     }
 
@@ -389,8 +444,12 @@
 	    tonegen->dig_samples = 0;
 
+	    TRACE_((THIS_FILE, "tonegen_get_frame(): rewind"));
+
 	} else {
 	    tonegen->count = 0;
+	    tonegen->cur_digit = 0;
 	    frame->type = PJMEDIA_FRAME_TYPE_NONE;
-	    return PJ_SUCCESS;
+	    TRACE_((THIS_FILE, "tonegen_get_frame(): no more digit"));
+	    goto on_return;
 	}
     }
@@ -403,4 +462,6 @@
 	tonegen->cur_digit++;
 	tonegen->dig_samples = 0;
+
+	TRACE_((THIS_FILE, "tonegen_get_frame(): next digit"));
     }
 
@@ -415,8 +476,12 @@
 	    tonegen->dig_samples = 0;
 
+	    TRACE_((THIS_FILE, "tonegen_get_frame(): rewind"));
+
 	} else {
 	    tonegen->count = 0;
+	    tonegen->cur_digit = 0;
 	    frame->type = PJMEDIA_FRAME_TYPE_NONE;
-	    return PJ_SUCCESS;
+	    TRACE_((THIS_FILE, "tonegen_get_frame(): no more digit"));
+	    goto on_return;
 	}
     }
@@ -463,5 +528,5 @@
 
 	/* Move to next digit if we're finished with this tone */
-	if (tonegen->dig_samples == on_samp + off_samp) {
+	if (tonegen->dig_samples >= on_samp + off_samp) {
 	    tonegen->cur_digit++;
 	    tonegen->dig_samples = 0;
@@ -486,4 +551,7 @@
     frame->size = port->info.bytes_per_frame;
 
+    TRACE_((THIS_FILE, "tonegen_get_frame(): frame created, level=%u",
+	    pjmedia_calc_avg_signal((pj_int16_t*)frame->buf, frame->size/2)));
+
     if (tonegen->cur_digit >= tonegen->count) {
 	if ((tonegen->options|tonegen->playback_options)&PJMEDIA_TONEGEN_LOOP)
@@ -493,9 +561,16 @@
 	    tonegen->dig_samples = 0;
 
+	    TRACE_((THIS_FILE, "tonegen_get_frame(): rewind"));
+
 	} else {
 	    tonegen->count = 0;
-	}
-    }
-
+	    tonegen->cur_digit = 0;
+
+	    TRACE_((THIS_FILE, "tonegen_get_frame(): no more digit"));
+	}
+    }
+
+on_return:
+    pj_lock_release(tonegen->lock);
     return PJ_SUCCESS;
 }
@@ -519,4 +594,6 @@
     PJ_ASSERT_RETURN(count+tonegen->count <= PJMEDIA_TONEGEN_MAX_DIGITS,
 		     PJ_ETOOMANY);
+
+    pj_lock_acquire(tonegen->lock);
 
     /* Set playback options */
@@ -538,4 +615,6 @@
     tonegen->count += count;
 
+    pj_lock_release(tonegen->lock);
+
     return PJ_SUCCESS;
 }
@@ -552,5 +631,5 @@
     struct tonegen *tonegen = (struct tonegen*) port;
     pjmedia_tone_desc tones[PJMEDIA_TONEGEN_MAX_DIGITS];
-    const pjmedia_tone_digit_map *map = tonegen->digit_map;
+    const pjmedia_tone_digit_map *map;
     unsigned i;
 
@@ -558,4 +637,8 @@
 		     count && digits, PJ_EINVAL);
     PJ_ASSERT_RETURN(count < PJMEDIA_TONEGEN_MAX_DIGITS, PJ_ETOOMANY);
+
+    pj_lock_acquire(tonegen->lock);
+
+    map = tonegen->digit_map;
 
     for (i=0; i<count; ++i) {
@@ -568,6 +651,8 @@
 		break;
 	}
-	if (j == map->count)
+	if (j == map->count) {
+	    pj_lock_release(tonegen->lock);
 	    return PJMEDIA_RTP_EINDTMF;
+	}
 
 	tones[i].freq1 = map->digits[j].freq1;
@@ -578,4 +663,6 @@
     }
 
+    pj_lock_release(tonegen->lock);
+
     return pjmedia_tonegen_play(port, count, tones, options);
 }
@@ -610,6 +697,10 @@
     PJ_ASSERT_RETURN(m != NULL, PJ_EINVAL);
 
+    pj_lock_acquire(tonegen->lock);
+
     tonegen->digit_map = m;
 
+    pj_lock_release(tonegen->lock);
+
     return PJ_SUCCESS;
 }
