diff --git a/app.c b/app.c
index 5f96478e3349abb96aef04ecc98e3316e3215240..866d5530ea5482a20efaa3a1c92800c2529c3b79 100755
--- a/app.c
+++ b/app.c
@@ -408,7 +408,6 @@ int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, in
 
 int ast_control_streamfile(struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *pause, int skipms) 
 {
-	struct timeval started, ended;
 	long elapsed = 0,last_elapsed =0;
 	char *breaks=NULL;
 	char *end=NULL;
@@ -443,7 +442,7 @@ int ast_control_streamfile(struct ast_channel *chan, const char *file, const cha
 	}
 
 	for (;;) {
-		gettimeofday(&started,NULL);
+		struct timeval started = ast_tvnow();
 
 		if (chan)
 			ast_stopstream(chan);
@@ -468,8 +467,7 @@ int ast_control_streamfile(struct ast_channel *chan, const char *file, const cha
 			break;
 
 		if (pause != NULL && strchr(pause, res)) {
-			gettimeofday(&ended, NULL);
-			elapsed = (((ended.tv_sec * 1000) + ended.tv_usec / 1000) - ((started.tv_sec * 1000) + started.tv_usec / 1000) + last_elapsed);
+			elapsed = ast_tvdiff_ms(ast_tvnow(), started) + last_elapsed;
 			for(;;) {
 				if (chan)
 					ast_stopstream(chan);
diff --git a/apps/app_alarmreceiver.c b/apps/app_alarmreceiver.c
index da6db49d25e96e08e3a51fcb3d0c83d182441b12..9fead22da568d3384550a313a65643479e30ae68 100755
--- a/apps/app_alarmreceiver.c
+++ b/apps/app_alarmreceiver.c
@@ -235,14 +235,12 @@ static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int
 	int i = 0;
 	int r;
 	struct ast_frame *f;
-	struct timeval now, lastdigittime;
+	struct timeval lastdigittime;
 	
-	gettimeofday(&lastdigittime,NULL);
+	lastdigittime = ast_tvnow();
 	for(;;){
-		gettimeofday(&now,NULL);
-		
 		  /* if outa time, leave */
-		if (ast_tvdiff_ms(&now, &lastdigittime) > 
+		if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) >
 		    ((i > 0) ? sdto : fdto)){
 			if(option_verbose >= 4)
 				ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: DTMF Digit Timeout on %s\n", chan->name);
@@ -287,7 +285,7 @@ static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int
 		if(i >= length)
 			break;
 		
-		gettimeofday(&lastdigittime,NULL);
+		lastdigittime = ast_tvnow();
 	}
 	
 	digit_string[i] = '\0'; /* Nul terminate the end of the digit string */
diff --git a/apps/app_disa.c b/apps/app_disa.c
index dadb4d17ccaefedef471ec29b5a9f6bdc2d7335a..8b934638d05719d680f7219a5967f43b299ea886 100755
--- a/apps/app_disa.c
+++ b/apps/app_disa.c
@@ -90,15 +90,6 @@ STANDARD_LOCAL_USER;
 
 LOCAL_USER_DECL;
 
-static int ms_diff(struct timeval *tv1, struct timeval *tv2)
-{
-int	ms;
-	
-	ms = (tv1->tv_sec - tv2->tv_sec) * 1000;
-	ms += (tv1->tv_usec - tv2->tv_usec) / 1000;
-	return(ms);
-}
-
 static void play_dialtone(struct ast_channel *chan, char *mailbox)
 {
 	const struct tone_zone_sound *ts = NULL;
@@ -121,7 +112,7 @@ static int disa_exec(struct ast_channel *chan, void *data)
 	char tmp[256],arg2[256]="",exten[AST_MAX_EXTENSION],acctcode[20]="";
 	char *ourcontext,*ourcallerid,ourcidname[256],ourcidnum[256],*mailbox;
 	struct ast_frame *f;
-	struct timeval lastout, now, lastdigittime;
+	struct timeval lastdigittime;
 	int res;
 	time_t rstart;
 	FILE *fp;
@@ -142,7 +133,6 @@ static int disa_exec(struct ast_channel *chan, void *data)
 		ast_log(LOG_WARNING, "Unable to set read format to Mu-law on %s\n",chan->name);
 		return -1;
 	}
-	lastout.tv_sec = lastout.tv_usec = 0;
 	if (!data || !strlen((char *)data)) {
 		ast_log(LOG_WARNING, "disa requires an argument (passcode/passcode file)\n");
 		return -1;
@@ -187,15 +177,14 @@ static int disa_exec(struct ast_channel *chan, void *data)
 		k |= 1; /* We have the password */
 		ast_log(LOG_DEBUG, "DISA no-password login success\n");
 	}
-	gettimeofday(&lastdigittime,NULL);
+	lastdigittime = ast_tvnow();
 
 	play_dialtone(chan, mailbox);
 
 	for(;;)
 	{
-		gettimeofday(&now,NULL);
 		  /* if outa time, give em reorder */
-		if (ms_diff(&now,&lastdigittime) > 
+		if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > 
 		    ((k&2) ? digittimeout : firstdigittimeout))
 		{
 			ast_log(LOG_DEBUG,"DISA %s entry timeout on chan %s\n",
@@ -238,7 +227,7 @@ static int disa_exec(struct ast_channel *chan, void *data)
 			k|=2; /* We have the first digit */ 
 			ast_playtones_stop(chan);
 		}
-		gettimeofday(&lastdigittime,NULL);
+		lastdigittime = ast_tvnow();
 		  /* got a DTMF tone */
 		if (i < AST_MAX_EXTENSION) /* if still valid number of digits */
 		{
diff --git a/apps/app_dumpchan.c b/apps/app_dumpchan.c
index 6b43bfa5d05b05ecdd7d0e01afad28695a85413d..6c36aac7c6d88d2cd8414c17366edf57ff3563d0 100755
--- a/apps/app_dumpchan.c
+++ b/apps/app_dumpchan.c
@@ -51,7 +51,7 @@ static int ast_serialize_showchan(struct ast_channel *c, char *buf, size_t size)
 	char cgrp[256];
 	char pgrp[256];
 	
-	gettimeofday(&now, NULL);
+	now = ast_tvnow();
 	memset(buf,0,size);
 	if (!c)
 		return 0;
diff --git a/apps/app_forkcdr.c b/apps/app_forkcdr.c
index 1452b0e4b0e72efd52c24319d50f2220aacef725..9300dc257ccff4eae3abda0de7ece311bd7dc06b 100755
--- a/apps/app_forkcdr.c
+++ b/apps/app_forkcdr.c
@@ -46,7 +46,7 @@ static void ast_cdr_clone(struct ast_cdr *cdr)
 	struct ast_cdr *newcdr = ast_cdr_alloc();
 	memcpy(newcdr,cdr,sizeof(struct ast_cdr));
 	ast_cdr_append(cdr,newcdr);
-	gettimeofday(&newcdr->start, NULL);
+	newcdr->start = ast_tvnow();
 	memset(&newcdr->answer, 0, sizeof(newcdr->answer));
 	memset(&newcdr->varshead, 0, sizeof(newcdr->varshead));
 	ast_cdr_copy_vars(newcdr, cdr);
diff --git a/apps/app_mp3.c b/apps/app_mp3.c
index 1b21d333fccc27395de62698a3505f7f7fce44b1..b4d7a1f6bb239193eb3bcd911d07b60118fabaae 100755
--- a/apps/app_mp3.c
+++ b/apps/app_mp3.c
@@ -109,7 +109,7 @@ static int mp3_exec(struct ast_channel *chan, void *data)
 	int pid = -1;
 	int owriteformat;
 	int timeout = 2000;
-	struct timeval now, next;
+	struct timeval next;
 	struct ast_frame *f;
 	struct myframe {
 		struct ast_frame f;
@@ -134,35 +134,20 @@ static int mp3_exec(struct ast_channel *chan, void *data)
 		return -1;
 	}
 	
-	gettimeofday(&now, NULL);
 	res = mp3play((char *)data, fds[1]);
 	if (!strncasecmp((char *)data, "http://", 7)) {
 		timeout = 10000;
 	}
 	/* Wait 1000 ms first */
-	next = now;
+	next = ast_tvnow();
 	next.tv_sec += 1;
 	if (res >= 0) {
 		pid = res;
 		/* Order is important -- there's almost always going to be mp3...  we want to prioritize the
 		   user */
 		for (;;) {
-			gettimeofday(&now, NULL);
-			ms = (next.tv_sec - now.tv_sec) * 1000;
-			ms += (next.tv_usec - now.tv_usec) / 1000;
-#if 0
-			printf("ms: %d\n", ms);
-#endif			
+			ms = ast_tvdiff_ms(next, ast_tvnow());
 			if (ms <= 0) {
-#if 0
-				{
-					static struct timeval last;
-					struct timeval tv;
-					gettimeofday(&tv, NULL);
-					printf("Since last: %ld\n", (tv.tv_sec - last.tv_sec) * 1000 + (tv.tv_usec - last.tv_usec) / 1000);
-					last = tv;
-				}
-#endif
 				res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout);
 				if (res > 0) {
 					myf.f.frametype = AST_FRAME_VOICE;
@@ -184,14 +169,7 @@ static int mp3_exec(struct ast_channel *chan, void *data)
 					res = 0;
 					break;
 				}
-				next.tv_usec += res / 2 * 125;
-				if (next.tv_usec >= 1000000) {
-					next.tv_usec -= 1000000;
-					next.tv_sec++;
-				}
-#if 0
-				printf("Next: %d\n", ms);
-#endif				
+				next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000));
 			} else {
 				ms = ast_waitfor(chan, ms);
 				if (ms < 0) {
diff --git a/apps/app_nbscat.c b/apps/app_nbscat.c
index aa5e44d8ecf07990c0c06d35ce5a14535366550a..9227a92ffa3cd918feaaff9345cb63dfbe9f06fc 100755
--- a/apps/app_nbscat.c
+++ b/apps/app_nbscat.c
@@ -99,7 +99,7 @@ static int NBScat_exec(struct ast_channel *chan, void *data)
 	int ms = -1;
 	int pid = -1;
 	int owriteformat;
-	struct timeval now, next;
+	struct timeval next;
 	struct ast_frame *f;
 	struct myframe {
 		struct ast_frame f;
@@ -122,29 +122,15 @@ static int NBScat_exec(struct ast_channel *chan, void *data)
 	
 	res = NBScatplay(fds[1]);
 	/* Wait 1000 ms first */
-	next = now;
+	next = ast_tvnow();
 	next.tv_sec += 1;
 	if (res >= 0) {
 		pid = res;
 		/* Order is important -- there's almost always going to be mp3...  we want to prioritize the
 		   user */
 		for (;;) {
-			gettimeofday(&now, NULL);
-			ms = (next.tv_sec - now.tv_sec) * 1000;
-			ms += (next.tv_usec - now.tv_usec) / 1000;
-#if 0
-			printf("ms: %d\n", ms);
-#endif			
+			ms = ast_tvdiff_ms(next, ast_tvnow());
 			if (ms <= 0) {
-#if 0
-				{
-					static struct timeval last;
-					struct timeval tv;
-					gettimeofday(&tv, NULL);
-					printf("Since last: %ld\n", (tv.tv_sec - last.tv_sec) * 1000 + (tv.tv_usec - last.tv_usec) / 1000);
-					last = tv;
-				}
-#endif
 				res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata));
 				if (res > 0) {
 					myf.f.frametype = AST_FRAME_VOICE;
@@ -166,14 +152,7 @@ static int NBScat_exec(struct ast_channel *chan, void *data)
 					res = 0;
 					break;
 				}
-				next.tv_usec += res / 2 * 125;
-				if (next.tv_usec >= 1000000) {
-					next.tv_usec -= 1000000;
-					next.tv_sec++;
-				}
-#if 0
-				printf("Next: %d\n", ms);
-#endif				
+				next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000));
 			} else {
 				ms = ast_waitfor(chan, ms);
 				if (ms < 0) {
diff --git a/apps/app_readfile.c b/apps/app_readfile.c
index 0930ec14ea7c73aa8f3317ef8069072b45b34c27..405ceb70a93b0f9cbbe267b9dc8f2d7f5b8b878d 100755
--- a/apps/app_readfile.c
+++ b/apps/app_readfile.c
@@ -83,7 +83,7 @@ static int readfile_exec(struct ast_channel *chan, void *data)
 		if(len < strlen(returnvar))
 			returnvar[len]='\0';
 		else
-			ast_log(LOG_WARNING,"%s is longer than %d, and %zd \n", file, len, strlen(returnvar));
+			ast_log(LOG_WARNING,"%s is longer than %d, and %d \n", file, len, (int)strlen(returnvar));
 	}
 	pbx_builtin_setvar_helper(chan, varname, returnvar);
 	free(returnvar);
diff --git a/apps/app_sayunixtime.c b/apps/app_sayunixtime.c
index a641779d422c93547587f18b25bb439f0685ba30..06091911ebffa53953c08eabfef07b1c97d62525 100755
--- a/apps/app_sayunixtime.c
+++ b/apps/app_sayunixtime.c
@@ -69,7 +69,7 @@ static int sayunixtime_exec(struct ast_channel *chan, void *data)
 	
 	LOCAL_USER_ADD(u);
 
-	gettimeofday(&tv,NULL);
+	tv = ast_tvnow();
 	unixtime = (time_t)tv.tv_sec;
 
 	if( !strcasecmp(chan->language, "da" ) ) {
diff --git a/apps/app_sms.c b/apps/app_sms.c
index c2ffa4a099df5c2ff4ca76fc4cd268cba9f40677..ad9a167bd59bad808e9d2fe021ab5c2e543f4afc 100755
--- a/apps/app_sms.c
+++ b/apps/app_sms.c
@@ -1176,7 +1176,7 @@ static int sms_generate (struct ast_channel *chan, void *data, int len, int samp
 	int i;
 
 	if (len > sizeof (buf)) {
-		ast_log (LOG_WARNING, "Only doing %zd bytes (%d bytes requested)\n", sizeof (buf) / sizeof (signed short), len);
+		ast_log (LOG_WARNING, "Only doing %d bytes (%d bytes requested)\n", (int)(sizeof (buf) / sizeof (signed short)), len);
 		len = sizeof (buf);
 #ifdef OUTALAW
 		samples = len;
diff --git a/apps/app_talkdetect.c b/apps/app_talkdetect.c
index 117b835bdcfc404e3487fd96e9afa82e6c9b30ac..e60f3a8e9bc3b177cb9eba9bb8b0aa8457000f68 100755
--- a/apps/app_talkdetect.c
+++ b/apps/app_talkdetect.c
@@ -59,7 +59,7 @@ static int background_detect_exec(struct ast_channel *chan, void *data)
 	char *stringp;
 	struct ast_frame *fr;
 	int notsilent=0;
-	struct timeval start = { 0, 0}, end = {0, 0};
+	struct timeval start = { 0, 0};
 	int sil = 1000;
 	int min = 100;
 	int max = -1;
@@ -143,9 +143,7 @@ static int background_detect_exec(struct ast_channel *chan, void *data)
 							/* We've been quiet a little while */
 							if (notsilent) {
 								/* We had heard some talking */
-								gettimeofday(&end, NULL);
-								ms = (end.tv_sec - start.tv_sec) * 1000;
-								ms += (end.tv_usec - start.tv_usec) / 1000;
+								ms = ast_tvdiff_ms(ast_tvnow(), start);
 								ms -= sil;
 								if (ms < 0)
 									ms = 0;
@@ -171,7 +169,7 @@ static int background_detect_exec(struct ast_channel *chan, void *data)
 						} else {
 							if (!notsilent) {
 								/* Heard some audio, mark the begining of the token */
-								gettimeofday(&start, NULL);
+								start = ast_tvnow();
 								ast_log(LOG_DEBUG, "Start of voice token!\n");
 								notsilent = 1;
 							}
diff --git a/apps/app_test.c b/apps/app_test.c
index bbb54c192e104201f27ae38848d6ef385d0d3ff4..44508063a6a99cc4ed5c22e28a3620cab5b0d279 100755
--- a/apps/app_test.c
+++ b/apps/app_test.c
@@ -55,7 +55,7 @@ static int measurenoise(struct ast_channel *chan, int ms, char *who)
 	int samples=0;
 	int x;
 	short *foo;
-	struct timeval start, tv;
+	struct timeval start;
 	struct ast_frame *f;
 	int rformat;
 	rformat = chan->readformat;
@@ -63,11 +63,9 @@ static int measurenoise(struct ast_channel *chan, int ms, char *who)
 		ast_log(LOG_NOTICE, "Unable to set to linear mode!\n");
 		return -1;
 	}
-	gettimeofday(&start, NULL);
+	start = ast_tvnow();
 	for(;;) {
-		gettimeofday(&tv, NULL);
-		mssofar = (tv.tv_sec - start.tv_sec) * 1000;
-		mssofar += (tv.tv_usec - start.tv_usec) / 1000;
+		mssofar = ast_tvdiff_ms(ast_tvnow(), start);
 		if (mssofar > ms)
 			break;
 		res = ast_waitfor(chan, ms - mssofar);
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index a20bf730a3df27ba8912d3dcc5510aed15b1e109..e5a52f06df3aca934b6fd780005225b53193a629 100755
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -3295,7 +3295,7 @@ static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *v
 #if 0
 	/* Set the DIFF_* variables */
 	localtime_r(&t, &time_now);
-	gettimeofday(&tv_now,NULL);
+	tv_now = ast_tvnow();
 	tnow = tv_now.tv_sec;
 	localtime_r(&tnow,&time_then);
 
diff --git a/asterisk.c b/asterisk.c
index d9d4426e563a15cbfc185016ca13de59b3fc1fa9..60a2edb5bf766318f509af523f6029976afd5e7e 100755
--- a/asterisk.c
+++ b/asterisk.c
@@ -1199,7 +1199,7 @@ static char *cli_prompt(EditLine *el)
 						break;
 					case 'd': /* date */
 						memset(&tm, 0, sizeof(struct tm));
-						gettimeofday(&tv, NULL);
+						tv = ast_tvnow();
 						if (localtime_r(&(tv.tv_sec), &tm)) {
 							strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
 						}
@@ -1256,7 +1256,7 @@ static char *cli_prompt(EditLine *el)
 #endif
 					case 't': /* time */
 						memset(&tm, 0, sizeof(struct tm));
-						gettimeofday(&tv, NULL);
+						tv = ast_tvnow();
 						if (localtime_r(&(tv.tv_sec), &tm)) {
 							strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
 						}
diff --git a/cdr.c b/cdr.c
index ac727a676ac6f11f0e9a1b9655b8d2fdfe9792a7..a77048a633c588e7bebb0f83ea754edd9724f390 100755
--- a/cdr.c
+++ b/cdr.c
@@ -419,9 +419,9 @@ void ast_cdr_free(struct ast_cdr *cdr)
 		chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
 		if (!ast_test_flag(cdr, AST_CDR_FLAG_POSTED) && !ast_test_flag(cdr, AST_CDR_FLAG_POST_DISABLED))
 			ast_log(LOG_WARNING, "CDR on channel '%s' not posted\n", chan);
-		if (!cdr->end.tv_sec && !cdr->end.tv_usec)
+		if (ast_tvzero(cdr->end))
 			ast_log(LOG_WARNING, "CDR on channel '%s' lacks end\n", chan);
-		if (!cdr->start.tv_sec && !cdr->start.tv_usec)
+		if (ast_tvzero(cdr->start))
 			ast_log(LOG_WARNING, "CDR on channel '%s' lacks start\n", chan);
 
 		ast_cdr_free_vars(cdr, 0);
@@ -450,9 +450,9 @@ void ast_cdr_start(struct ast_cdr *cdr)
 			chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
 			if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
 				ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
-			if (cdr->start.tv_sec || cdr->start.tv_usec)
+			if (!ast_tvzero(cdr->start))
 				ast_log(LOG_WARNING, "CDR on channel '%s' already started\n", chan);
-			gettimeofday(&cdr->start, NULL);
+			cdr->start = ast_tvnow();
 		}
 		cdr = cdr->next;
 	}
@@ -468,9 +468,8 @@ void ast_cdr_answer(struct ast_cdr *cdr)
 			ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
 		if (cdr->disposition < AST_CDR_ANSWERED)
 			cdr->disposition = AST_CDR_ANSWERED;
-		if (!cdr->answer.tv_sec && !cdr->answer.tv_usec) {
-			gettimeofday(&cdr->answer, NULL);
-		}
+		if (ast_tvzero(cdr->answer))
+			cdr->answer = ast_tvnow();
 		cdr = cdr->next;
 	}
 }
@@ -637,10 +636,10 @@ void ast_cdr_end(struct ast_cdr *cdr)
 		chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
 		if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
 			ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
-		if (!cdr->start.tv_sec && !cdr->start.tv_usec)
+		if (ast_tvzero(cdr->start))
 			ast_log(LOG_WARNING, "CDR on channel '%s' has not started\n", chan);
-		if (!cdr->end.tv_sec && !cdr->end.tv_usec) 
-			gettimeofday(&cdr->end, NULL);
+		if (ast_tvzero(cdr->end))
+			cdr->end = ast_tvnow();
 		cdr = cdr->next;
 	}
 }
@@ -780,12 +779,12 @@ static void post_cdr(struct ast_cdr *cdr)
 		chan = !ast_strlen_zero(cdr->channel) ? cdr->channel : "<unknown>";
 		if (ast_test_flag(cdr, AST_CDR_FLAG_POSTED))
 			ast_log(LOG_WARNING, "CDR on channel '%s' already posted\n", chan);
-		if (!cdr->end.tv_sec && !cdr->end.tv_usec)
+		if (ast_tvzero(cdr->end))
 			ast_log(LOG_WARNING, "CDR on channel '%s' lacks end\n", chan);
-		if (!cdr->start.tv_sec && !cdr->start.tv_usec)
+		if (ast_tvzero(cdr->start))
 			ast_log(LOG_WARNING, "CDR on channel '%s' lacks start\n", chan);
 		cdr->duration = cdr->end.tv_sec - cdr->start.tv_sec + (cdr->end.tv_usec - cdr->start.tv_usec) / 1000000;
-		if (cdr->answer.tv_sec || cdr->answer.tv_usec)
+		if (!ast_tvzero(cdr->answer))
 			cdr->billsec = cdr->end.tv_sec - cdr->answer.tv_sec + (cdr->end.tv_usec - cdr->answer.tv_usec) / 1000000;
 		else
 			cdr->billsec = 0;
@@ -1008,13 +1007,12 @@ void ast_cdr_detach(struct ast_cdr *cdr)
 
 static void *do_cdr(void *data)
 {
-	struct timeval now;
 	struct timespec timeout;
 	int schedms;
 	int numevents = 0;
 
 	for(;;) {
-		gettimeofday(&now, NULL);
+		struct timeval now = ast_tvnow();
 		schedms = ast_sched_wait(sched);
 		/* this shouldn't happen, but provide a 1 second default just in case */
 		if (schedms <= 0)
diff --git a/cdr/cdr_csv.c b/cdr/cdr_csv.c
index bcf20feade4614e0601b879b07fc5892cef222fc..2689a9fb61edf34c7e18652fa1086e585c49758c 100755
--- a/cdr/cdr_csv.c
+++ b/cdr/cdr_csv.c
@@ -123,7 +123,7 @@ static int append_date(char *buf, struct timeval tv, size_t bufsize)
 	t = tv.tv_sec;
 	if (strlen(buf) > bufsize - 3)
 		return -1;
-	if (!tv.tv_sec && !tv.tv_usec) {
+	if (ast_tvzero(tv)) {
 		strncat(buf, ",", bufsize - strlen(buf) - 1);
 		return 0;
 	}
diff --git a/cdr/cdr_tds.c b/cdr/cdr_tds.c
index 1cdb72f684e479ea2ffdd78a1fc88ec6363a4068..cadb9dd626dd006f7b9755fb0108b47db7c26024 100755
--- a/cdr/cdr_tds.c
+++ b/cdr/cdr_tds.c
@@ -372,7 +372,7 @@ static void get_date(char *dateField, struct timeval tv)
 	char buf[80];
 
 	/* To make sure we have date variable if not insert null to SQL */
-	if (tv.tv_sec && tv.tv_usec)
+	if (!ast_tvzero(tv))
 	{
 		t = tv.tv_sec;
 		localtime_r(&t, &tm);
diff --git a/channel.c b/channel.c
index e97ae91c30d517889fe0dbc0097ddef0ba40d0cd..60e972bd776e88b2f8553dd4239850799ac16962 100755
--- a/channel.c
+++ b/channel.c
@@ -1120,7 +1120,7 @@ int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen,
 int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
 {
 	/* Wait for x amount of time on a file descriptor to have input.  */
-	struct timeval start, now;
+	struct timeval start;
 	int res;
 	int x, y;
 	int winner = -1;
@@ -1133,7 +1133,7 @@ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
 		return -1;
 	}
 	if (*ms > 0)
-		gettimeofday(&start, NULL);
+		start = ast_tvnow();
 	y = 0;
 	for (x=0;x<n;x++) {
 		if (fds[x] > -1) {
@@ -1166,13 +1166,8 @@ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
 		}
 	}
 	if (*ms > 0) {
-		long passed;
-		gettimeofday(&now, NULL);
-		passed = (now.tv_sec - start.tv_sec) * 1000;
-		passed += (now.tv_usec - start.tv_usec) / 1000;
-		if (passed <= *ms)
-			*ms -= passed;
-		else
+		*ms -= ast_tvdiff_ms(ast_tvnow(), start);
+		if (*ms < 0)
 			*ms = 0;
 	}
 	return winner;
@@ -1182,7 +1177,7 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
 	int *exception, int *outfd, int *ms)
 {
 	/* Wait for x amount of time on a file descriptor to have input.  */
-	struct timeval start, end;
+	struct timeval start;
 	struct pollfd *pfds;
 	int res;
 	long rms;
@@ -1253,7 +1248,7 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
 		}
 	}
 	if (*ms > 0) 
-		gettimeofday(&start, NULL);
+		start = ast_tvnow();
 	res = poll(pfds, max, rms);
 	if (res < 0) {
 		for (x=0;x<n;x++) 
@@ -1315,13 +1310,8 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
 		}	
 	}
 	if (*ms > 0) {
-		long diff;
-		gettimeofday(&end, NULL);
-		diff = (end.tv_sec - start.tv_sec) * 1000;
-		diff += (end.tv_usec - start.tv_usec) / 1000;
-		if (diff < *ms)
-			*ms -= diff;
-		else
+		*ms -= ast_tvdiff_ms(ast_tvnow(), start);
+		if (*ms < 0)
 			*ms = 0;
 	}
 	return winner;
@@ -2809,15 +2799,6 @@ int ast_setstate(struct ast_channel *chan, int state)
 	return 0;
 }
 
-static long tvdiff(struct timeval *now, struct timeval *then) 
-{
-#if 0
-	return (((now->tv_sec * 1000) + now->tv_usec / 1000) - ((then->tv_sec * 1000) + then->tv_usec / 1000));
-#else
-	return (now->tv_sec - then->tv_sec) * 1000 + (now->tv_usec - then->tv_usec) / 1000;	
-#endif
-}
-
 /*--- Find bridged channel */
 struct ast_channel *ast_bridged_channel(struct ast_channel *chan)
 {
@@ -2878,7 +2859,6 @@ static int ast_generic_bridge(int *playitagain, int *playit, struct timeval *sta
 	int res=0;
 	int o0nativeformats;
 	int o1nativeformats;
-	struct timeval precise_now;
 	long elapsed_ms=0, time_left_ms=0;
 	
 	cs[0] = c0;
@@ -2899,8 +2879,7 @@ static int ast_generic_bridge(int *playitagain, int *playit, struct timeval *sta
 		/* timestamp */
 		if (config->timelimit) {
 			/* If there is a time limit, return now */
-			gettimeofday(&precise_now,NULL);
-			elapsed_ms = tvdiff(&precise_now,start_time);
+			elapsed_ms = ast_tvdiff_ms(ast_tvnow(), *start_time);
 			time_left_ms = config->timelimit - elapsed_ms;
 
 			if (*playitagain && ((ast_test_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING)) || (ast_test_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING))) && (config->play_warning && time_left_ms <= config->play_warning)) { 
@@ -3022,7 +3001,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, struct as
 	int firstpass;
 	int o0nativeformats;
 	int o1nativeformats;
-	struct timeval start_time,precise_now;
+	struct timeval start_time;
 	long elapsed_ms=0, time_left_ms=0;
 	int playit=0, playitagain=1, first_time=1;
 
@@ -3031,7 +3010,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, struct as
 	config->firstpass = 0;
 
 	/* timestamp */
-	gettimeofday(&start_time,NULL);
+	start_time = ast_tvnow();
 	time_left_ms = config->timelimit;
 
 	if ((ast_test_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING)) && config->start_sound && firstpass)
@@ -3073,8 +3052,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, struct as
 	for (/* ever */;;) {
 		/* timestamp */
 		if (config->timelimit) {
-			gettimeofday(&precise_now,NULL);
-			elapsed_ms = tvdiff(&precise_now,&start_time);
+			elapsed_ms = ast_tvdiff_ms(ast_tvnow(), start_time);
 			time_left_ms = config->timelimit - elapsed_ms;
 
 			if (playitagain && ((ast_test_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING)) || (ast_test_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING))) && (config->play_warning && time_left_ms <= config->play_warning)) { 
diff --git a/channels/chan_agent.c b/channels/chan_agent.c
index 972003ba7d60f69fbf500a623bab8bbc6230dca5..5e222b41914605fbf32d18514b4e319c981f97d3 100755
--- a/channels/chan_agent.c
+++ b/channels/chan_agent.c
@@ -316,8 +316,8 @@ static struct agent_pvt *add_agent(char *agent, int pending)
 	/* If someone reduces the wrapuptime and reloads, we want it
 	 * to change the wrapuptime immediately on all calls */
 	if (p->wrapuptime > wrapuptime) {
-		struct timeval now;
-		gettimeofday(&now, NULL);
+		struct timeval now = ast_tvnow();
+		/* XXX check what is this exactly */
 
 		/* We won't be pedantic and check the tv_usec val */
 		if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
@@ -420,15 +420,8 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
 				if (p->chan)
 					ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
 				ast_hangup(p->chan);
-				if (p->wrapuptime && p->acknowledged) {
-					gettimeofday(&p->lastdisc, NULL);
-					p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
-					if (p->lastdisc.tv_usec > 1000000) {
-						p->lastdisc.tv_usec -= 1000000;
-						p->lastdisc.tv_sec++;
-					}
-					p->lastdisc.tv_sec += (p->wrapuptime / 1000);
-				}
+				if (p->wrapuptime && p->acknowledged)
+					p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
 			}
 			p->chan = NULL;
 			p->acknowledged = 0;
@@ -699,16 +692,10 @@ static int agent_hangup(struct ast_channel *ast)
 		/* If they're dead, go ahead and hang up on the agent now */
 		if (!ast_strlen_zero(p->loginchan)) {
 			/* Store last disconnect time */
-			if (p->wrapuptime && p->acknowledged) {
-				gettimeofday(&p->lastdisc, NULL);
-				p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
-				if (p->lastdisc.tv_usec >= 1000000) {
-					p->lastdisc.tv_usec -= 1000000;
-					p->lastdisc.tv_sec++;
-				}
-				p->lastdisc.tv_sec += (p->wrapuptime / 1000);
-			} else
-				memset(&p->lastdisc, 0, sizeof(p->lastdisc));
+			if (p->wrapuptime && p->acknowledged)
+				p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
+			else
+				p->lastdisc = ast_tv(0,0);
 			if (p->chan) {
 				/* Recognize the hangup and pass it along immediately */
 				ast_hangup(p->chan);
@@ -779,7 +766,7 @@ static int agent_hangup(struct ast_channel *ast)
 			/* Not dead -- check availability now */
 			ast_mutex_lock(&p->lock);
 			/* Store last disconnect time */
-			gettimeofday(&p->lastdisc, NULL);
+			p->lastdisc = ast_tvnow();
 			ast_mutex_unlock(&p->lock);
 		}
 		/* Release ownership of the agent to other threads (presumably running the login app). */
@@ -791,7 +778,6 @@ static int agent_hangup(struct ast_channel *ast)
 static int agent_cont_sleep( void *data )
 {
 	struct agent_pvt *p;
-	struct timeval tv;
 	int res;
 
 	p = (struct agent_pvt *)data;
@@ -799,9 +785,7 @@ static int agent_cont_sleep( void *data )
 	ast_mutex_lock(&p->lock);
 	res = p->app_sleep_cond;
 	if (p->lastdisc.tv_sec) {
-		gettimeofday(&tv, NULL);
-		if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
-			(tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) 
+		if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) 
 			res = 1;
 	}
 	ast_mutex_unlock(&p->lock);
@@ -1264,12 +1248,12 @@ static struct ast_channel *agent_request(const char *type, int format, void *dat
 			if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
 				if (p->chan || !ast_strlen_zero(p->loginchan))
 					hasagent++;
-				gettimeofday(&tv, NULL);
+				tv = ast_tvnow();
 #if 0
 				ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
 #endif
 				if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
-					memset(&p->lastdisc, 0, sizeof(p->lastdisc));
+					p->lastdisc = ast_tv(0, 0);
 					/* Agent must be registered, but not have any active call, and not be in a waiting state */
 					if (!p->owner && p->chan) {
 						/* Could still get a fixed agent */
@@ -1558,7 +1542,6 @@ static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
 	int max_login_tries = maxlogintries;
 	struct agent_pvt *p;
 	struct localuser *u;
-	struct timeval tv;
 	int login_state = 0;
 	char user[AST_MAX_AGENT] = "";
 	char pass[AST_MAX_AGENT];
@@ -1883,12 +1866,10 @@ static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
 								ast_mutex_lock(&agentlock);
 								ast_mutex_lock(&p->lock);
 								if (p->lastdisc.tv_sec) {
-									gettimeofday(&tv, NULL);
-									if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
-										(tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
+									if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) {
 											if (option_debug)
 												ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
-										memset(&p->lastdisc, 0, sizeof(p->lastdisc));
+										p->lastdisc = ast_tv(0, 0);
 										if (p->ackcall > 1)
 											check_beep(p, 0);
 										else
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 14ca240ddecada6381e024b95c13ebac2b727414..22a6e03c120d4e98aa901b7aa70e5221adff886f 100755
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -2084,12 +2084,8 @@ static int get_from_jb(void *p);
 
 static void update_jbsched(struct chan_iax2_pvt *pvt) {
     int when;
-    struct timeval tv;
-
-    gettimeofday(&tv,NULL);
 
-    when = (tv.tv_sec - pvt->rxcore.tv_sec) * 1000 +
-	  (tv.tv_usec - pvt->rxcore.tv_usec) / 1000;
+    when = ast_tvdiff_ms(ast_tvnow(), pvt->rxcore);
 
     /*    fprintf(stderr, "now = %d, next=%d\n", when, jb_next(pvt->jb)); */
 
@@ -2126,8 +2122,7 @@ static int get_from_jb(void *p) {
     /* to catch up with runq's now */
     tv.tv_usec += 1000;
 
-    now = (tv.tv_sec - pvt->rxcore.tv_sec) * 1000 +
-	  (tv.tv_usec - pvt->rxcore.tv_usec) / 1000;
+    now = ast_tvdiff_ms(tv, pvt->rxcore);
 
     if(now >= (next = jb_next(pvt->jb))) {
 	ret = jb_get(pvt->jb,&frame,now,ast_codec_interp_len(pvt->voiceformat));
@@ -2152,15 +2147,8 @@ static int get_from_jb(void *p) {
 		af.mallocd  = 0;
 		af.src  = "IAX2 JB interpolation";
 		af.data  = NULL;
-		af.delivery.tv_sec = pvt->rxcore.tv_sec;
-		af.delivery.tv_usec = pvt->rxcore.tv_usec;
-		af.delivery.tv_sec += next / 1000;
-		af.delivery.tv_usec += (next % 1000) * 1000;
+		af.delivery = ast_tvadd(pvt->rxcore, ast_samp2tv(next, 1000));
 		af.offset=AST_FRIENDLY_OFFSET;
-		if (af.delivery.tv_usec >= 1000000) {
-			af.delivery.tv_usec -= 1000000;
-			af.delivery.tv_sec += 1;
-		}
 
 		/* queue the frame:  For consistency, we would call __do_deliver here, but __do_deliver wants an iax_frame,
 		 * which we'd need to malloc, and then it would free it.  That seems like a drag */
@@ -2233,8 +2221,7 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr
 				ast_log(LOG_DEBUG, "schedule_delivery: call=%d: TS jumped.  resyncing rxcore (ts=%d, last=%d)\n",
 							fr->callno, fr->ts, iaxs[fr->callno]->last);
 			/* zap rxcore - calc_rxstamp will make a new one based on this frame */
-			iaxs[fr->callno]->rxcore.tv_sec = 0;
-			iaxs[fr->callno]->rxcore.tv_usec = 0;
+			iaxs[fr->callno]->rxcore = ast_tv(0, 0);
 			/* wipe "last" if stamps have jumped backwards */
 			if (x<0)
 				iaxs[fr->callno]->last = 0;
@@ -2261,22 +2248,13 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr
 
 
 	/* delivery time is sender's sent timestamp converted back into absolute time according to our clock */
-	if ( (!fromtrunk) && (iaxs[fr->callno]->rxcore.tv_sec || iaxs[fr->callno]->rxcore.tv_usec) ) {
-		fr->af.delivery.tv_sec = iaxs[fr->callno]->rxcore.tv_sec;
-		fr->af.delivery.tv_usec = iaxs[fr->callno]->rxcore.tv_usec;
-		fr->af.delivery.tv_sec += fr->ts / 1000;
-		fr->af.delivery.tv_usec += (fr->ts % 1000) * 1000;
-		if (fr->af.delivery.tv_usec >= 1000000) {
-			fr->af.delivery.tv_usec -= 1000000;
-			fr->af.delivery.tv_sec += 1;
-		}
-	}
+	if ( !fromtrunk && !ast_tvzero(iaxs[fr->callno]->rxcore))
+		fr->af.delivery = ast_tvadd(iaxs[fr->callno]->rxcore, ast_samp2tv(fr->ts, 1000));
 	else {
 #if 0
 		ast_log(LOG_DEBUG, "schedule_delivery: set delivery to 0 as we don't have an rxcore yet, or frame is from trunk.\n");
 #endif
-		fr->af.delivery.tv_sec = 0;
-		fr->af.delivery.tv_usec = 0;
+		fr->af.delivery = ast_tv(0,0);
 	}
 
 #ifndef NEWJB
@@ -3138,9 +3116,8 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
 		if ((iaxs[callno0]->transferring == TRANSFER_RELEASED) && (iaxs[callno1]->transferring == TRANSFER_RELEASED)) {
 			/* Call has been transferred.  We're no longer involved */
 			gettimeofday(&tv, NULL);
-			if (!waittimer.tv_sec && !waittimer.tv_usec) {
-				waittimer.tv_sec = tv.tv_sec;
-				waittimer.tv_usec = tv.tv_usec;
+			if (ast_tvzero(waittimer)) {
+				waittimer = tv;
 			} else if (tv.tv_sec - waittimer.tv_sec > IAX_LINGER_TIMEOUT) {
 				c0->_softhangup |= AST_SOFTHANGUP_DEV;
 				c1->_softhangup |= AST_SOFTHANGUP_DEV;
@@ -3359,21 +3336,17 @@ static unsigned int calc_txpeerstamp(struct iax2_trunk_peer *tpeer, int sampms,
 	long int ms, pred;
 
 	tpeer->trunkact = *tv;
-	mssincetx = (tv->tv_sec - tpeer->lasttxtime.tv_sec) * 1000 +
-			(1000000 + tv->tv_usec - tpeer->lasttxtime.tv_usec) / 1000 - 1000;
-	if (mssincetx > 5000 || (!tpeer->txtrunktime.tv_sec && !tpeer->txtrunktime.tv_usec)) {
+	mssincetx = ast_tvdiff_ms(*tv, tpeer->lasttxtime);
+	if (mssincetx > 5000 || ast_tvzero(tpeer->txtrunktime)) {
 		/* If it's been at least 5 seconds since the last time we transmitted on this trunk, reset our timers */
-		tpeer->txtrunktime.tv_sec = tv->tv_sec;
-		tpeer->txtrunktime.tv_usec = tv->tv_usec;
+		tpeer->txtrunktime = *tv;
 		tpeer->lastsent = 999999;
 	}
 	/* Update last transmit time now */
-	tpeer->lasttxtime.tv_sec = tv->tv_sec;
-	tpeer->lasttxtime.tv_usec = tv->tv_usec;
+	tpeer->lasttxtime = *tv;
 	
 	/* Calculate ms offset */
-	ms = (tv->tv_sec - tpeer->txtrunktime.tv_sec) * 1000 +
-		(1000000 + tv->tv_usec - tpeer->txtrunktime.tv_usec) / 1000 - 1000;
+	ms = ast_tvdiff_ms(*tv, tpeer->txtrunktime);
 	/* Predict from last value */
 	pred = tpeer->lastsent + sampms;
 	if (abs(ms - pred) < MAX_TIMESTAMP_SKEW)
@@ -3389,34 +3362,20 @@ static unsigned int calc_txpeerstamp(struct iax2_trunk_peer *tpeer, int sampms,
 static unsigned int fix_peerts(struct timeval *tv, int callno, unsigned int ts)
 {
 	long ms;	/* NOT unsigned */
-	if (!iaxs[callno]->rxcore.tv_sec && !iaxs[callno]->rxcore.tv_usec) {
+	if (ast_tvzero(iaxs[callno]->rxcore)) {
 		/* Initialize rxcore time if appropriate */
 		gettimeofday(&iaxs[callno]->rxcore, NULL);
 		/* Round to nearest 20ms so traces look pretty */
 		iaxs[callno]->rxcore.tv_usec -= iaxs[callno]->rxcore.tv_usec % 20000;
 	}
 	/* Calculate difference between trunk and channel */
-	ms = (tv->tv_sec - iaxs[callno]->rxcore.tv_sec) * 1000 + 
-		(1000000 + tv->tv_usec - iaxs[callno]->rxcore.tv_usec) / 1000 - 1000;
+	ms = ast_tvdiff_ms(*tv, iaxs[callno]->rxcore);
 	/* Return as the sum of trunk time and the difference between trunk and real time */
 	return ms + ts;
 }
 
-static void add_ms(struct timeval *tv, int ms) {
-	tv->tv_usec += ms * 1000;
-	if(tv->tv_usec > 1000000) {
-		tv->tv_usec -= 1000000;
-		tv->tv_sec++;
-	}
-	if(tv->tv_usec < 0) {
-		tv->tv_usec += 1000000;
-		tv->tv_sec--;
-	}
-}
-
 static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, struct ast_frame *f)
 {
-	struct timeval tv;
 	int ms;
 	int voice = 0;
 	int genuine = 0;
@@ -3439,7 +3398,7 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
 			p->notsilenttx = 0;	
 		}
 	}
-	if (!p->offset.tv_sec && !p->offset.tv_usec) {
+	if (ast_tvzero(p->offset)) {
 		gettimeofday(&p->offset, NULL);
 		/* Round to nearest 20ms for nice looking traces */
 		p->offset.tv_usec -= p->offset.tv_usec % 20000;
@@ -3448,15 +3407,12 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
 	if (ts)
 		return ts;
 	/* If we have a time that the frame arrived, always use it to make our timestamp */
-	if (delivery && (delivery->tv_sec || delivery->tv_usec)) {
-		ms = (delivery->tv_sec - p->offset.tv_sec) * 1000 +
-			(1000000 + delivery->tv_usec - p->offset.tv_usec) / 1000 - 1000;
+	if (delivery && !ast_tvzero(*delivery)) {
+		ms = ast_tvdiff_ms(*delivery, p->offset);
 		if (option_debug > 2)
 			ast_log(LOG_DEBUG, "calc_timestamp: call %d/%d: Timestamp slaved to delivery time\n", p->callno, iaxs[p->callno]->peercallno);
 	} else {
-		gettimeofday(&tv, NULL);
-		ms = (tv.tv_sec - p->offset.tv_sec) * 1000 +
-			(1000000 + tv.tv_usec - p->offset.tv_usec) / 1000 - 1000;
+		ms = ast_tvdiff_ms(ast_tvnow(), p->offset);
 		if (ms < 0)
 			ms = 0;
 		if (voice) {
@@ -3464,7 +3420,8 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
 			if (p->notsilenttx && abs(ms - p->nextpred) <= MAX_TIMESTAMP_SKEW) {
 				/* Adjust our txcore, keeping voice and 
 					non-voice synchronized */
-				add_ms(&p->offset, (int)(ms - p->nextpred)/10);
+				p->offset = ast_tvadd(p->offset,
+						ast_samp2tv((ms - p->nextpred)/10, 1000)); /* XXX what scale is this ??? */
 
 				if (!p->nextpred) {
 					p->nextpred = ms; /*f->samples / 8;*/
@@ -3525,19 +3482,18 @@ static unsigned int calc_fakestamp(struct chan_iax2_pvt *p1, struct chan_iax2_pv
 	/* Receive from p1, send to p2 */
 	
 	/* Setup rxcore if necessary on outgoing channel */
-	if (!p1->rxcore.tv_sec && !p1->rxcore.tv_usec)
-		gettimeofday(&p1->rxcore, NULL);
+	if (ast_tvzero(p1->rxcore))
+		p1->rxcore = ast_tvnow();
 
 	/* Setup txcore if necessary on outgoing channel */
-	if (!p2->offset.tv_sec && !p2->offset.tv_usec)
-		gettimeofday(&p2->offset, NULL);
+	if (ast_tvzero(p2->offset))
+		p2->offset = ast_tvnow();
 	
 	/* Now, ts is the timestamp of the original packet in the orignal context.
 	   Adding rxcore to it gives us when we would want the packet to be delivered normally.
 	   Subtracting txcore of the outgoing channel gives us what we'd expect */
 	
-	ms = (p1->rxcore.tv_sec - p2->offset.tv_sec) * 1000 +
-		(1000000 + p1->rxcore.tv_usec - p2->offset.tv_usec) / 1000 - 1000;
+	ms = ast_tvdiff_ms(p1->rxcore, p2->offset);
 	fakets += ms;
 
 	/* FIXME? SLD would rather remove this and leave it to the end system to deal with */
@@ -3552,23 +3508,17 @@ static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset)
 {
 	/* Returns where in "receive time" we are.  That is, how many ms
 	   since we received (or would have received) the frame with timestamp 0 */
-	struct timeval tv;
 	int ms;
 #ifdef IAXTESTS
 	int jit;
 #endif /* IAXTESTS */
 	/* Setup rxcore if necessary */
-	if (!p->rxcore.tv_sec && !p->rxcore.tv_usec) {
-		gettimeofday(&p->rxcore, NULL);
+	if (ast_tvzero(p->rxcore)) {
+		p->rxcore = ast_tvnow();
 		if (option_debug)
 			ast_log(LOG_DEBUG, "calc_rxstamp: call=%d: rxcore set to %d.%6.6d - %dms\n",
 					p->callno, (int)(p->rxcore.tv_sec), (int)(p->rxcore.tv_usec), offset);
-		p->rxcore.tv_sec -= offset / 1000;
-		p->rxcore.tv_usec -= (offset % 1000) * 1000;
-		if (p->rxcore.tv_usec < 0) {
-			p->rxcore.tv_usec += 1000000;
-			p->rxcore.tv_sec -= 1;
-		}
+		p->rxcore = ast_tvsub(p->rxcore, ast_samp2tv(offset, 1000));
 #if 1
 		if (option_debug)
 			ast_log(LOG_DEBUG, "calc_rxstamp: call=%d: works out as %d.%6.6d\n",
@@ -3576,9 +3526,7 @@ static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset)
 #endif
 	}
 
-	gettimeofday(&tv, NULL);
-	ms = (tv.tv_sec - p->rxcore.tv_sec) * 1000 +
-		(1000000 + tv.tv_usec - p->rxcore.tv_usec) / 1000 - 1000;
+	ms = ast_tvdiff_ms(ast_tvnow(), p->rxcore);
 #ifdef IAXTESTS
 	if (test_jit) {
 		if (!test_jitpct || ((100.0 * rand() / (RAND_MAX + 1.0)) < test_jitpct)) {
@@ -3618,7 +3566,7 @@ static struct iax2_trunk_peer *find_tpeer(struct sockaddr_in *sin, int fd)
 			ast_mutex_init(&tpeer->lock);
 			tpeer->lastsent = 9999;
 			memcpy(&tpeer->addr, sin, sizeof(tpeer->addr));
-			gettimeofday(&tpeer->trunkact, NULL);
+			tpeer->trunkact = ast_tvnow();
 			ast_mutex_lock(&tpeer->lock);
 			tpeer->next = tpeers;
 			tpeer->sockfd = fd;
@@ -6225,11 +6173,9 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
 				ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s:%d': No matching peer\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
 				return 1;
 			}
-			if (!ts || (!tpeer->rxtrunktime.tv_sec && !tpeer->rxtrunktime.tv_usec)) {
-				gettimeofday(&tpeer->rxtrunktime, NULL);
-				tpeer->trunkact = tpeer->rxtrunktime;
-			} else
-				gettimeofday(&tpeer->trunkact, NULL);
+			tpeer->trunkact = ast_tvnow();
+			if (!ts || ast_tvzero(tpeer->rxtrunktime))
+				tpeer->rxtrunktime = tpeer->trunkact;
 			rxtrunktime = tpeer->rxtrunktime;
 			ast_mutex_unlock(&tpeer->lock);
 			while(res >= sizeof(struct ast_iax2_meta_trunk_entry)) {
@@ -8755,8 +8701,7 @@ static struct iax2_dpcache *find_cache(struct ast_channel *chan, const char *dat
 	while(dp) {
 		next = dp->next;
 		/* Expire old caches */
-		if ((tv.tv_sec > dp->expirey.tv_sec) ||
-				((tv.tv_sec == dp->expirey.tv_sec) && (tv.tv_usec > dp->expirey.tv_usec)))  {
+		if (ast_tvcmp(tv, dp->expirey) > 0) {
 				/* It's expired, let it disappear */
 				if (prev)
 					prev->next = dp->next;
diff --git a/channels/chan_phone.c b/channels/chan_phone.c
index 2611508b7340346789977007383b6da5c775ae2e..c307fbf4d68389b725c67da100eeab26aa68682d 100755
--- a/channels/chan_phone.c
+++ b/channels/chan_phone.c
@@ -446,8 +446,7 @@ static struct ast_frame  *phone_exception(struct ast_channel *ast)
 	p->fr.src = type;
 	p->fr.offset = 0;
 	p->fr.mallocd=0;
-	p->fr.delivery.tv_sec = 0;
-	p->fr.delivery.tv_usec = 0;
+	p->fr.delivery = ast_tv(0,0);
 	
 	phonee.bytes = ioctl(p->fd, PHONE_EXCEPTION);
 	if (phonee.bits.dtmf_ready)  {
@@ -509,8 +508,7 @@ static struct ast_frame  *phone_read(struct ast_channel *ast)
 	p->fr.src = type;
 	p->fr.offset = 0;
 	p->fr.mallocd=0;
-	p->fr.delivery.tv_sec = 0;
-	p->fr.delivery.tv_usec = 0;
+	p->fr.delivery = ast_tv(0,0);
 
 	/* Try to read some data... */
 	CHECK_BLOCKING(ast);
@@ -993,7 +991,7 @@ static void *do_monitor(void *data)
 				if (i->dialtone) {
 					/* Remember we're going to have to come back and play
 					   more dialtones */
-					if (!tv.tv_usec && !tv.tv_sec) {
+					if (ast_tvzero(tv)) {
 						/* If we're due for a dialtone, play one */
 						if (write(i->fd, DialTone + tonepos, 240) != 240)
 							ast_log(LOG_WARNING, "Dial tone write error\n");
@@ -1016,15 +1014,13 @@ static void *do_monitor(void *data)
 			tonepos += 240;
 			if (tonepos >= sizeof(DialTone))
 					tonepos = 0;
-			if (!tv.tv_usec && !tv.tv_sec) {
-				tv.tv_usec = 30000;
-				tv.tv_sec = 0;
+			if (ast_tvzero(tv)) {
+				tv = ast_tv(30000, 0);
 			}
 			res = ast_select(n + 1, &rfds, NULL, &efds, &tv);
 		} else {
 			res = ast_select(n + 1, &rfds, NULL, &efds, NULL);
-			tv.tv_usec = 0;
-			tv.tv_sec = 0;
+			tv = ast_tv(0,0);
 			tonepos = 0;
 		}
 		/* Okay, select has finished.  Let's see what happened.  */
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 16a8365079d76e134107de5591c2cf509cac39be..542a762ab6386b2d75350c798a4ee70aee323d2f 100755
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -8351,8 +8351,7 @@ static int handle_response_peerpoke(struct sip_pvt *p, int resp, char *rest, str
 		int newstate = 0;
 		peer = p->peerpoke;
 		gettimeofday(&tv, NULL);
-		pingtime = (tv.tv_sec - peer->ps.tv_sec) * 1000 +
-					(tv.tv_usec - peer->ps.tv_usec) / 1000;
+		pingtime = ast_tvdiff_ms(tv, peer->ps);
 		if (pingtime < 1)
 			pingtime = 1;
 		if ((peer->lastms < 0)  || (peer->lastms > peer->maxms)) {
diff --git a/channels/chan_vpb.c b/channels/chan_vpb.c
index e3c7b61c52dea16f564ed2dd5b227deda034a1f5..65a05723c514d68b56c4dc3c84afbe322c834806 100755
--- a/channels/chan_vpb.c
+++ b/channels/chan_vpb.c
@@ -293,7 +293,7 @@ static struct vpb_pvt {
 
 	struct ast_dsp *vad;			/* AST  Voice Activation Detection dsp */
 
-	double lastgrunt;			/* time stamp (secs since epoc) of last grunt event */
+	struct timeval lastgrunt;			/* time stamp of last grunt event */
 
 	ast_mutex_t lock;			/* This one just protects bridge ptr below */
 	vpb_bridge_t *bridge;
@@ -584,13 +584,6 @@ static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
 	return (res==VPB_OK)?0:-1;
 }
 
-static double get_time_in_ms()
-{
-	struct timeval tv;
-	gettimeofday(&tv, NULL);
-	return ((double)tv.tv_sec*1000)+((double)tv.tv_usec/1000);
-}
-
 /* Caller ID can be located in different positions between the rings depending on your Telco
  * Australian (Telstra) callerid starts 700ms after 1st ring and finishes 1.5s after first ring
  * Use ANALYSE_CID to record rings and determine location of callerid
@@ -602,7 +595,7 @@ static double get_time_in_ms()
 static void get_callerid(struct vpb_pvt *p)
 {
 	short buf[CID_MSECS*8]; /* 8kHz sampling rate */
-	double cid_record_time;
+	struct timeval cid_record_time;
 	int rc;
 	struct ast_channel *owner = p->owner;
 /*
@@ -616,7 +609,7 @@ static void get_callerid(struct vpb_pvt *p)
 
 	if( ast_mutex_trylock(&p->record_lock) == 0 ) {
 
-		cid_record_time = get_time_in_ms();
+		cid_record_time = ast_tvnow();
 		if (option_verbose>3) 
 			ast_verbose(VERBOSE_PREFIX_4 "CID record - start\n");
 
@@ -624,9 +617,9 @@ static void get_callerid(struct vpb_pvt *p)
 		vpb_sleep(RING_SKIP);
 
 		if (option_verbose>3) 
-			ast_verbose(VERBOSE_PREFIX_4 "CID record - skipped %fms trailing ring\n",
-				 get_time_in_ms() - cid_record_time);
-		cid_record_time = get_time_in_ms();
+			ast_verbose(VERBOSE_PREFIX_4 "CID record - skipped %ldms trailing ring\n",
+				 ast_tvdiff_ms(ast_tvnow(), cid_record_time));
+		cid_record_time = ast_tvnow();
 
 		/* Record bit between the rings which contains the callerid */
 		vpb_record_buf_start(p->handle, VPB_LINEAR);
@@ -639,8 +632,8 @@ static void get_callerid(struct vpb_pvt *p)
 #endif
 
 		if (option_verbose>3) 
-			ast_verbose(VERBOSE_PREFIX_4 "CID record - recorded %fms between rings\n", 
-				get_time_in_ms() - cid_record_time);
+			ast_verbose(VERBOSE_PREFIX_4 "CID record - recorded %ldms between rings\n", 
+				 ast_tvdiff_ms(ast_tvnow(), cid_record_time));
 
 		ast_mutex_unlock(&p->record_lock);
 
@@ -911,7 +904,7 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
 
 			} 
 			else if (e->data == VPB_GRUNT) {
-				if( ( get_time_in_ms() - p->lastgrunt ) > gruntdetect_timeout ) {
+				if( ( ast_tvdiff_ms(ast_tvnow(), p->lastgrunt) > gruntdetect_timeout ) {
 					/* Nothing heard on line for a very long time
 					 * Timeout connection */
 					if (option_verbose > 2) 
@@ -919,7 +912,7 @@ static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e)
 					ast_log(LOG_NOTICE,"%s: Line hangup due of lack of conversation\n",p->dev); 
 					f.subclass = AST_CONTROL_HANGUP;
 				} else {
-					p->lastgrunt = get_time_in_ms();
+					p->lastgrunt = ast_tvnow();
 					f.frametype = -1;
 				}
 			} 
@@ -2193,7 +2186,7 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame)
 {
 	struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt; 
 	int res = 0, fmt = 0;
-	struct timeval play_buf_time_start,play_buf_time_finish;
+	struct timeval play_buf_time_start;
 /*	ast_mutex_lock(&p->lock); */
 	if(option_verbose>5) 
 		ast_verbose("%s: vpb_write: Writing to channel\n", p->dev);
@@ -2249,25 +2242,14 @@ static int vpb_write(struct ast_channel *ast, struct ast_frame *frame)
 
 /*	ast_log(LOG_DEBUG, "%s: vpb_write: Applied gain..\n", p->dev); */
 
-/*	gettimeofday(&tv, NULL); */
-/*	return ((double)tv.tv_sec*1000)+((double)tv.tv_usec/1000); */
-
 	if ((p->read_state == 1)&&(p->play_buf_time<5)){
-		gettimeofday(&play_buf_time_start,NULL);
+		play_buf_time_start = ast_tvnow();
 		res = vpb_play_buf_sync(p->handle, (char*)frame->data, frame->datalen);
-		if( (res == VPB_OK) && (option_verbose > 5) ) {
+		if( res == VPB_OK && option_verbose > 5 ) {
 			short * data = (short*)frame->data;
 			ast_verbose("%s: vpb_write: Wrote chan (codec=%d) %d %d\n", p->dev, fmt, data[0],data[1]);
 		}
-		gettimeofday(&play_buf_time_finish,NULL);
-		if (play_buf_time_finish.tv_sec == play_buf_time_start.tv_sec){
-			p->play_buf_time=(int)((play_buf_time_finish.tv_usec-play_buf_time_start.tv_usec)/1000);
-	/*		ast_log(LOG_DEBUG, "%s: vpb_write: Timing start(%d) finish(%d)\n", p->dev,play_buf_time_start.tv_usec,play_buf_time_finish.tv_usec); */
-		}
-		else {
-			p->play_buf_time=(int)((play_buf_time_finish.tv_sec - play_buf_time_start.tv_sec)*100)+(int)((play_buf_time_finish.tv_usec-play_buf_time_start.tv_usec)/1000);
-		}
-	/*	ast_log(LOG_DEBUG, "%s: vpb_write: Wrote data [%d](%d=>%s) to play_buf in [%d]ms..\n", p->dev,frame->datalen,fmt,ast2vpbformatname(frame->subclass),p->play_buf_time); */
+		p->play_buf_time = ast_tvdiff_ms(ast_tvnow(), play_buf_time_start);
 	}
 	else {
 		p->chuck_count++;
@@ -2603,7 +2585,7 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, int state, char *context)
 		me->play_dtmf[0] = '\0';
 		me->faxhandled =0;
 		
-		me->lastgrunt  = get_time_in_ms(); /* Assume at least one grunt tone seen now. */
+		me->lastgrunt  = ast_tvnow(); /* Assume at least one grunt tone seen now. */
 
 		ast_mutex_lock(&usecnt_lock);
 		usecnt++;
diff --git a/channels/chan_zap.c b/channels/chan_zap.c
index 892048ad8a9e66231eac5baf9eaccb2bb0c929c6..ec20f5454ca611475c588ca755046b2b6e45e18f 100755
--- a/channels/chan_zap.c
+++ b/channels/chan_zap.c
@@ -3458,7 +3458,6 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
 							p->dialing = 1;
 						zt_ring_phone(p);
 					} else if (p->subs[SUB_THREEWAY].owner) {
-						struct timeval tv;
 						unsigned int mssinceflash;
 						/* Here we have to retain the lock on both the main channel, the 3-way channel, and
 						   the private structure -- not especially easy or clean */
@@ -3481,8 +3480,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
 							ast_log(LOG_NOTICE, "Whoa, threeway disappeared kinda randomly.\n");
 							return NULL;
 						}
-						gettimeofday(&tv, NULL);
-						mssinceflash = (tv.tv_sec - p->flashtime.tv_sec) * 1000 + (tv.tv_usec - p->flashtime.tv_usec) / 1000;
+						mssinceflash = ast_tvdiff_ms(ast_tvnow(), p->flashtime);
 						ast_log(LOG_DEBUG, "Last flash was %d ms ago\n", mssinceflash);
 						if (mssinceflash < MIN_MS_SINCE_FLASH) {
 							/* It hasn't been long enough since the last flashook.  This is probably a bounce on 
@@ -3978,10 +3976,8 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
 				(p->polarityonanswerdelay > 0) &&
 			        (p->polarity == POLARITY_REV) &&
 				(ast->_state == AST_STATE_UP)) {
-				struct timeval tv;
-				gettimeofday(&tv, NULL);
 
-				if((((tv.tv_sec - p->polaritydelaytv.tv_sec) * 1000) + ((tv.tv_usec - p->polaritydelaytv.tv_usec)/1000)) > p->polarityonanswerdelay) {
+				if(ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) > p->polarityonanswerdelay) {
 					ast_log(LOG_DEBUG, "Hangup due to Reverse Polarity on channel %d\n", p->channel);
 					ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
 					p->polarity = POLARITY_IDLE;
@@ -4018,8 +4014,7 @@ static struct ast_frame *__zt_exception(struct ast_channel *ast)
 	p->subs[index].f.mallocd = 0;
 	p->subs[index].f.offset = 0;
 	p->subs[index].f.subclass = 0;
-	p->subs[index].f.delivery.tv_sec = 0;
-	p->subs[index].f.delivery.tv_usec = 0;
+	p->subs[index].f.delivery = ast_tv(0,0);
 	p->subs[index].f.src = "zt_exception";
 	p->subs[index].f.data = NULL;
 	
@@ -4144,8 +4139,7 @@ struct ast_frame  *zt_read(struct ast_channel *ast)
 	p->subs[index].f.mallocd = 0;
 	p->subs[index].f.offset = 0;
 	p->subs[index].f.subclass = 0;
-	p->subs[index].f.delivery.tv_sec = 0;
-	p->subs[index].f.delivery.tv_usec = 0;
+	p->subs[index].f.delivery = ast_tv(0,0);
 	p->subs[index].f.src = "zt_read";
 	p->subs[index].f.data = NULL;
 	
@@ -7776,15 +7770,11 @@ static void *pri_dchannel(void *vpri)
 #if 0
 			printf("nextidle: %d, haveidles: %d, minunsed: %d\n",
 				nextidle, haveidles, minunused);
-			gettimeofday(&tv, NULL);
 			printf("nextidle: %d, haveidles: %d, ms: %ld, minunsed: %d\n",
-				nextidle, haveidles, (tv.tv_sec - lastidle.tv_sec) * 1000 +
-				    (tv.tv_usec - lastidle.tv_usec) / 1000, minunused);
+				nextidle, haveidles, ast_tvdiff_ms(ast_tvnow(), lastidle), minunused);
 #endif
 			if (nextidle > -1) {
-				gettimeofday(&tv, NULL);
-				if (((tv.tv_sec - lastidle.tv_sec) * 1000 +
-				    (tv.tv_usec - lastidle.tv_usec) / 1000) > 1000) {
+				if (ast_tvdiff_ms(ast_tvnow(), lastidle) > 1000) {
 					/* Don't create a new idle call more than once per second */
 					snprintf(idlen, sizeof(idlen), "%d/%s", pri->pvts[nextidle]->channel, pri->idledial);
 					idle = zt_request("Zap", AST_FORMAT_ULAW, idlen, &cause);
@@ -7817,49 +7807,36 @@ static void *pri_dchannel(void *vpri)
 			}
 		}
 		/* Start with reasonable max */
-		lowest.tv_sec = 60;
-		lowest.tv_usec = 0;
+		lowest = ast_tv(60, 0);
 		for (i=0; i<NUM_DCHANS; i++) {
 			/* Find lowest available d-channel */
 			if (!pri->dchannels[i])
 				break;
 			if ((next = pri_schedule_next(pri->dchans[i]))) {
 				/* We need relative time here */
-				gettimeofday(&tv, NULL);
-				tv.tv_sec = next->tv_sec - tv.tv_sec;
-				tv.tv_usec = next->tv_usec - tv.tv_usec;
-				if (tv.tv_usec < 0) {
-					tv.tv_usec += 1000000;
-					tv.tv_sec -= 1;
-				}
+				tv = ast_tvsub(*next, ast_tvnow());
 				if (tv.tv_sec < 0) {
-					tv.tv_sec = 0;
-					tv.tv_usec = 0;
+					tv = ast_tv(0,0);
 				}
 				if (doidling || pri->resetting) {
 					if (tv.tv_sec > 1) {
-						tv.tv_sec = 1;
-						tv.tv_usec = 0;
+						tv = ast_tv(1, 0);
 					}
 				} else {
 					if (tv.tv_sec > 60) {
-						tv.tv_sec = 60;
-						tv.tv_usec = 0;
+						tv = ast_tv(60, 0);
 					}
 				}
 			} else if (doidling || pri->resetting) {
 				/* Make sure we stop at least once per second if we're
 				   monitoring idle channels */
-				tv.tv_sec = 1;
-				tv.tv_usec = 0;
+				tv = ast_tv(1,0);
 			} else {
 				/* Don't poll for more than 60 seconds */
-				tv.tv_sec = 60;
-				tv.tv_usec = 0;
+				tv = ast_tv(60, 0);
 			}
-			if (!i || (tv.tv_sec < lowest.tv_sec) || ((tv.tv_sec == lowest.tv_sec) && (tv.tv_usec < lowest.tv_usec))) {
-				lowest.tv_sec = tv.tv_sec;
-				lowest.tv_usec = tv.tv_usec;
+			if (!i || ast_tvcmp(tv, lowest) < 0) {
+				lowest = tv;
 			}
 		}
 		ast_mutex_unlock(&pri->lock);
diff --git a/cli.c b/cli.c
index f539cb33a5206364ab3e87ad762a81bff2dea616..bb7b154f0300121c833ac710d801f1c727c691e6 100755
--- a/cli.c
+++ b/cli.c
@@ -668,7 +668,7 @@ static int handle_showchan(int fd, int argc, char *argv[])
 	
 	if (argc != 3)
 		return RESULT_SHOWUSAGE;
-	gettimeofday(&now, NULL);
+	now = ast_tvnow();
 	c = ast_get_channel_by_name_locked(argv[2]);
 	if (!c) {
 		ast_cli(fd, "%s is not a known channel\n", argv[2]);
diff --git a/frame.c b/frame.c
index 362890725355ab42884711d3d1a9e272ceb2f06a..c6abc0024b2b626baf2e852587b8b0613450a4db 100755
--- a/frame.c
+++ b/frame.c
@@ -144,8 +144,7 @@ int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
 	else
 		memcpy(s->data + s->len, f->data, f->datalen);
 	/* If either side is empty, reset the delivery time */
-	if (!s->len || (!f->delivery.tv_sec && !f->delivery.tv_usec) ||
-			(!s->delivery.tv_sec && !s->delivery.tv_usec))
+	if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery))	/* XXX really ? */
 		s->delivery = f->delivery;
 	s->len += f->datalen;
 	return 0;
@@ -181,7 +180,7 @@ struct ast_frame *ast_smoother_read(struct ast_smoother *s)
 	s->f.offset = AST_FRIENDLY_OFFSET;
 	s->f.datalen = len;
 	/* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
-	s->f.samples = len * s->samplesperbyte;
+	s->f.samples = len * s->samplesperbyte;	/* XXX rounding */
 	s->f.delivery = s->delivery;
 	/* Fill Data */
 	memcpy(s->f.data, s->data, len);
@@ -191,14 +190,9 @@ struct ast_frame *ast_smoother_read(struct ast_smoother *s)
 		/* In principle this should all be fine because if we are sending
 		   G.729 VAD, the next timestamp will take over anyawy */
 		memmove(s->data, s->data + len, s->len);
-		if (s->delivery.tv_sec || s->delivery.tv_usec) {
+		if (!ast_tvzero(s->delivery)) {
 			/* If we have delivery time, increment it, otherwise, leave it at 0 */
-			s->delivery.tv_sec += (len * s->samplesperbyte) / 8000.0;
-			s->delivery.tv_usec += (((int)(len * s->samplesperbyte)) % 8000) * 125;
-			if (s->delivery.tv_usec > 1000000) {
-				s->delivery.tv_usec -= 1000000;
-				s->delivery.tv_sec += 1;
-			}
+			s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, 8000));
 		}
 	}
 	/* Return frame */
diff --git a/funcs/func_strings.c b/funcs/func_strings.c
index de7015190832d95d5c396d6e1fae09762b4b5c28..7b6e072a006d7e00171212bc0bd23cb0e483fddc 100755
--- a/funcs/func_strings.c
+++ b/funcs/func_strings.c
@@ -127,7 +127,6 @@ static char *acf_strftime(struct ast_channel *chan, char *cmd, char *data, char
 {
 	char *format, *epoch, *timezone;
 	long epochi;
-	struct timeval tv;
 	struct tm time;
 
 	if (data) {
@@ -137,11 +136,9 @@ static char *acf_strftime(struct ast_channel *chan, char *cmd, char *data, char
 			timezone = strsep(&format, "|");
 
 			if (epoch && !ast_strlen_zero(epoch) && sscanf(epoch, "%ld", &epochi) == 1) {
-			} else if (!gettimeofday(&tv, NULL)) {
-				epochi = tv.tv_sec;
 			} else {
-				ast_log(LOG_ERROR, "Cannot gettimeofday() ?!!\n");
-				return "";
+				struct timeval tv = ast_tvnow();
+				epochi = tv.tv_sec;
 			}
 
 			ast_localtime(&epochi, &time, timezone);
diff --git a/include/asterisk/sched.h b/include/asterisk/sched.h
index 52d29e4e0446dd6b1d3de1a51d8e4f0a306e46fb..c64e308b421b588c59da1b6e90c2f814d04f2994 100755
--- a/include/asterisk/sched.h
+++ b/include/asterisk/sched.h
@@ -100,7 +100,7 @@ extern int ast_sched_runq(struct sched_context *con);
  * \param con Context to dump
  * Debugging: Dump the contents of the scheduler to stderr
  */
-extern void ast_sched_dump(struct sched_context *con);
+extern void ast_sched_dump(const struct sched_context *con);
 
 /*!Returns the number of seconds before an event takes place */
 /*!
diff --git a/include/asterisk/time.h b/include/asterisk/time.h
index ec7a51d8d8b58b8dfacaeb0fb2dd76d138e58107..82b781125d22b4ae5bd0fc44c694d959e3d6f661 100755
--- a/include/asterisk/time.h
+++ b/include/asterisk/time.h
@@ -23,9 +23,105 @@
  * \return the difference in milliseconds
  */
 AST_INLINE_API(
-int ast_tvdiff_ms(const struct timeval *end, const struct timeval *start),
+int ast_tvdiff_ms(struct timeval end, struct timeval start),
 {
-	return ((end->tv_sec - start->tv_sec) * 1000) + ((end->tv_usec - start->tv_usec) / 1000);
+	return ((end.tv_sec - start.tv_sec) * 1000) + ((end.tv_usec - start.tv_usec) / 1000);
+}
+)
+
+/*!
+ * \brief Returns true if the argument is 0,0
+ */
+AST_INLINE_API(
+int ast_tvzero(const struct timeval t),
+{
+	return (t.tv_sec == 0 && t.tv_usec == 0);
+}
+)
+
+/*!
+ * \brief Compres two \c struct \c timeval instances returning
+ * -1, 0, 1 if the first arg is smaller, equal or greater to the second.
+ */
+AST_INLINE_API(
+int ast_tvcmp(struct timeval _a, struct timeval _b),
+{
+	if (_a.tv_sec < _b.tv_sec)
+		return -1;
+	if (_a.tv_sec > _b.tv_sec)
+		return 1;
+	/* now seconds are equal */
+	if (_a.tv_usec < _b.tv_usec)
+		return -1;
+	if (_a.tv_usec > _b.tv_usec)
+		return 1;
+	return 0;
+}
+)
+
+/*!
+ * \brief Returns true if the two \c struct \c timeval arguments are equal.
+ */
+AST_INLINE_API(
+int ast_tveq(struct timeval _a, struct timeval _b),
+{
+	return (_a.tv_sec == _b.tv_sec && _a.tv_usec == _b.tv_usec);
+}
+)
+
+/*!
+ * \brief Returns current timeval. Meant to replace calls to gettimeofday().
+ */
+AST_INLINE_API(
+struct timeval ast_tvnow(void),
+{
+	struct timeval t;
+	gettimeofday(&t, NULL);
+	return t;
+}
+)
+
+/*!
+ * \brief Returns the sum of two timevals a + b
+ */
+struct timeval ast_tvadd(struct timeval a, struct timeval b);
+
+/*!
+ * \brief Returns the difference of two timevals a - b
+ */
+struct timeval ast_tvsub(struct timeval a, struct timeval b);
+
+/*!
+ * \brief Returns a timeval from sec, usec
+ */
+#if 0
+AST_INLINE_API(
+struct timeval ast_tv(int sec, int usec),
+{
+	struct timeval t = { sec, usec};
+	return t;
+}
+)
+#endif
+AST_INLINE_API(
+struct timeval ast_tv(int sec, int usec),
+{
+	struct timeval t;
+	t.tv_sec = sec;
+	t.tv_usec = usec;
+	return t;
+}
+)
+
+/*!
+ * \brief Returns a timeval corresponding to the duration of n samples at rate r.
+ * Useful to convert samples to timevals, or even milliseconds to timevals
+ * in the form ast_samp2tv(milliseconds, 1000)
+ */
+AST_INLINE_API(
+struct timeval ast_samp2tv(long _nsamp, long _rate),
+{
+	return ast_tv(_nsamp / _rate, (_nsamp % _rate) * (1000000 / _rate));
 }
 )
 
diff --git a/manager.c b/manager.c
index 8f39b35e2fb593b6ad4526929851ca2efe553178..1ebd22318a21d95ac82384819974a39969fad56a 100755
--- a/manager.c
+++ b/manager.c
@@ -683,11 +683,10 @@ static int action_status(struct mansession *s, struct message *m)
 	char idText[256] = "";
 	struct ast_channel *c;
 	char bridge[256];
-	struct timeval now;
+	struct timeval now = ast_tvnow();
 	long elapsed_seconds=0;
 	int all = !name || ast_strlen_zero(name); /* set if we want all channels */
 
-	gettimeofday(&now, NULL);
 	astman_send_ack(s, m, "Channel status will follow");
         if (id && !ast_strlen_zero(id))
                 snprintf(idText,256,"ActionID: %s\r\n",id);
diff --git a/pbx/pbx_dundi.c b/pbx/pbx_dundi.c
index aa4c0dbf6b70fc49ab34d204d02fd180f737faab..6122f42a30b4a5db98ed0f918804f8d476ef8616 100755
--- a/pbx/pbx_dundi.c
+++ b/pbx/pbx_dundi.c
@@ -680,13 +680,6 @@ static void *dundi_precache_thread(void *data)
 	return NULL;	
 }
 
-static inline int calc_ms(struct timeval *start)
-{
-	struct timeval tv;
-	gettimeofday(&tv, NULL);
-	return ((tv.tv_sec - start->tv_sec) * 1000 + (tv.tv_usec - start->tv_usec) / 1000);
-}
-
 static int dundi_query_eid_internal(struct dundi_entity_info *dei, const char *dcontext, dundi_eid *eid, struct dundi_hint_metadata *hmd, int ttl, int blockempty, dundi_eid *avoid[]);
 
 static void *dundi_query_thread(void *data)
@@ -2302,7 +2295,7 @@ static int dundi_do_lookup(int fd, int argc, char *argv[])
 		*context = '\0';
 		context++;
 	}
-	gettimeofday(&start, NULL);
+	start = ast_tvnow();
 	res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass);
 	
 	if (res < 0) 
@@ -2315,7 +2308,7 @@ static int dundi_do_lookup(int fd, int argc, char *argv[])
 		ast_cli(fd, "%3d. %5d %s/%s (%s)\n", x + 1, dr[x].weight, dr[x].tech, dr[x].dest, dundi_flags2str(fs, sizeof(fs), dr[x].flags));
 		ast_cli(fd, "     from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration);
 	}
-	ast_cli(fd, "DUNDi lookup completed in %d ms\n", calc_ms(&start));
+	ast_cli(fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
 	return RESULT_SUCCESS;
 }
 
@@ -2333,14 +2326,14 @@ static int dundi_do_precache(int fd, int argc, char *argv[])
 		*context = '\0';
 		context++;
 	}
-	gettimeofday(&start, NULL);
+	start = ast_tvnow();
 	res = dundi_precache(context, tmp);
 	
 	if (res < 0) 
 		ast_cli(fd, "DUNDi precache returned error.\n");
 	else if (!res) 
 		ast_cli(fd, "DUNDi precache returned no error.\n");
-	ast_cli(fd, "DUNDi lookup completed in %d ms\n", calc_ms(&start));
+	ast_cli(fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start));
 	return RESULT_SUCCESS;
 }
 
@@ -2779,7 +2772,7 @@ static struct dundi_transaction *create_transaction(struct dundi_peer *p)
 	if (trans) {
 		memset(trans, 0, sizeof(struct dundi_transaction));
 		if (global_storehistory) {
-			gettimeofday(&trans->start, NULL);
+			trans->start = ast_tvnow();
 			ast_set_flag(trans, FLAG_STOREHIST);
 		}
 		trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER;
@@ -2845,7 +2838,6 @@ static void destroy_trans(struct dundi_transaction *trans, int fromtimeout)
 {
 	struct dundi_transaction *cur, *prev;
 	struct dundi_peer *peer;
-	struct timeval tv;
 	int ms;
 	int x;
 	int cnt;
@@ -2863,9 +2855,7 @@ static void destroy_trans(struct dundi_transaction *trans, int fromtimeout)
 						ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
 					peer->lastms = -1;
 				} else {
-					gettimeofday(&tv, NULL);
-					ms = (tv.tv_sec - peer->qualtx.tv_sec) * 1000 + 
-							(tv.tv_usec - peer->qualtx.tv_usec) / 1000;
+					ms = ast_tvdiff_ms(ast_tvnow(), peer->qualtx);
 					if (ms < 1)
 						ms = 1;
 					if (ms < peer->maxms) {
@@ -2893,7 +2883,7 @@ static void destroy_trans(struct dundi_transaction *trans, int fromtimeout)
 								cnt++;
 							}
 						}
-						peer->lookuptimes[0] = calc_ms(&trans->start);
+						peer->lookuptimes[0] = ast_tvdiff_ms(ast_tvnow(), trans->start);
 						peer->lookups[0] = malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2);
 						if (peer->lookups[0]) {
 							sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext);
@@ -3577,9 +3567,10 @@ static int dundi_lookup_internal(struct dundi_result *result, int maxret, struct
 			/* Wait for the cache to populate */
 			ast_log(LOG_DEBUG, "Waiting for similar request for '%s@%s' for '%s'\n",
 				dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &pending->root_eid));
-			gettimeofday(&start, NULL);
-			while(check_request(pending) && (calc_ms(&start) < ttlms) && (!chan || !chan->_softhangup)) {
+			start = ast_tvnow();
+			while(check_request(pending) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !chan->_softhangup)) {
 				/* XXX Would be nice to have a way to poll/select here XXX */
+				/* XXX this is a busy wait loop!!! */
 				usleep(1);
 			}
 			/* Continue on as normal, our cache should kick in */
@@ -3609,8 +3600,8 @@ static int dundi_lookup_internal(struct dundi_result *result, int maxret, struct
 	/* Actually perform transactions */
 	discover_transactions(&dr);
 	/* Wait for transaction to come back */
-	gettimeofday(&start, NULL);
-	while(dr.trans && (calc_ms(&start) < ttlms) && (!chan || !chan->_softhangup)) {
+	start = ast_tvnow();
+	while(dr.trans && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !chan->_softhangup)) {
 		ms = 100;
 		ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
 	}
@@ -3767,8 +3758,8 @@ static int dundi_precache_internal(const char *context, const char *number, int
 		else
 			ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext);
 	}
-	gettimeofday(&start, NULL);
-	while(dr.trans && (calc_ms(&start) < ttlms)) {
+	start = ast_tvnow();
+	while(dr.trans && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) {
 		if (dr.pfds[0] > -1) {
 			ms = 100;
 			ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL);
@@ -3829,8 +3820,8 @@ static int dundi_query_eid_internal(struct dundi_entity_info *dei, const char *d
 	/* Actually perform transactions */
 	query_transactions(&dr);
 	/* Wait for transaction to come back */
-	gettimeofday(&start, NULL);
-	while(dr.trans && (calc_ms(&start) < ttlms))
+	start = ast_tvnow();
+	while(dr.trans && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms))
 		usleep(1);
 	res = dr.respcount;
 	return res;
@@ -4150,7 +4141,7 @@ static void qualify_peer(struct dundi_peer *peer, int schedonly)
 		if (!schedonly)
 			peer->qualtrans = create_transaction(peer);
 		if (peer->qualtrans) {
-			gettimeofday(&peer->qualtx, NULL);
+			peer->qualtx = ast_tvnow();
 			ast_set_flag(peer->qualtrans, FLAG_ISQUAL);
 			dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL);
 		}
diff --git a/pbx/pbx_gtkconsole.c b/pbx/pbx_gtkconsole.c
index f17667707b4478ebd4b8aea41aef071e17c3f531..eb9844fcf354261d0f36e1d50457cbb8bf1c94f1 100755
--- a/pbx/pbx_gtkconsole.c
+++ b/pbx/pbx_gtkconsole.c
@@ -107,12 +107,12 @@ static void __verboser(const char *stuff, int opos, int replacelast, int complet
 	if (replacelast) 
 		gtk_clist_remove(GTK_CLIST(verb), GTK_CLIST(verb)->rows - 1);
 	gtk_clist_append(GTK_CLIST(verb), s2);
-	if (last.tv_sec || last.tv_usec) {
+	if (!ast_tvzero(last)) {
 		gdk_threads_leave();
 		gettimeofday(&tv, NULL);
 		if (cleanupid > -1)
 			gtk_timeout_remove(cleanupid);
-		ms = (tv.tv_sec - last.tv_sec) * 1000 + (tv.tv_usec - last.tv_usec) / 1000;
+		ms = ast_tvdiff_ms(tv, last);
 		if (ms < 100) {
 			/* We just got a message within 100ms, so just schedule an update
 			   in the near future */
diff --git a/res/res_agi.c b/res/res_agi.c
index dd1f161c722fe202de8e210efc4e78d7cbcb0590..f31591e3eaba626548117e8f4e1e22671f93c9e7 100755
--- a/res/res_agi.c
+++ b/res/res_agi.c
@@ -787,7 +787,7 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char
 {
 	struct ast_filestream *fs;
 	struct ast_frame *f;
-	struct timeval tv, start;
+	struct timeval start;
 	long sample_offset = 0;
 	int res = 0;
 	int ms;
@@ -854,7 +854,9 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char
 
 	if (!res)
 		res = ast_waitstream(chan, argv[4]);
-	if (!res) {
+	if (res) {
+		fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
+	} else {
 		fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644);
 		if (!fs) {
 			res = -1;
@@ -870,9 +872,8 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char
 		ast_seekstream(fs, sample_offset, SEEK_SET);
 		ast_truncstream(fs);
 		
-		gettimeofday(&start, NULL);
-		gettimeofday(&tv, NULL);
-		while ((ms < 0) || (((tv.tv_sec - start.tv_sec) * 1000 + (tv.tv_usec - start.tv_usec)/1000) < ms)) {
+		start = ast_tvnow();
+		while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
 			res = ast_waitfor(chan, -1);
 			if (res < 0) {
 				ast_closestream(fs);
@@ -926,7 +927,6 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char
 				break;
 			}
 			ast_frfree(f);
-		    	gettimeofday(&tv, NULL);
 			if (gotsilence)
 				break;
         	}
@@ -938,8 +938,7 @@ static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char
 		}		
 		fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
 		ast_closestream(fs);
-	} else
-		fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
+	}
 
         if (silence > 0) {
                 res = ast_set_read_format(chan, rfmt);
diff --git a/res/res_features.c b/res/res_features.c
index c6fa6eeb5afed7f440b52770f03a5216017d553b..8d31fa70b41716513bbf51fc497281eb15521539 100755
--- a/res/res_features.c
+++ b/res/res_features.c
@@ -295,7 +295,7 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
 				ast_indicate(pu->chan, AST_CONTROL_HOLD);
 				ast_moh_start(pu->chan, NULL);
 			}
-			gettimeofday(&pu->start, NULL);
+			pu->start = ast_tvnow();
 			pu->parkingnum = x;
 			if (timeout > 0)
 				pu->parkingtime = timeout;
@@ -938,7 +938,7 @@ static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *call
 		ast_set_callerid(chan, cid_num, cid_name, cid_num);
 		
 		if (!ast_call(chan, data, timeout)) {
-			struct timeval started, ended;
+			struct timeval started;
 			int x, len = 0;
 			char *disconnect_code = NULL, *dialed_code = NULL;
 
@@ -955,7 +955,7 @@ static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *call
 				break;
 			}
 			x = 0;
-			gettimeofday(&started, NULL);
+			started = ast_tvnow();
 			to = timeout;
 			while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
 				monitor_chans[0] = caller;
@@ -963,8 +963,7 @@ static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *call
 				active_channel = ast_waitfor_n(monitor_chans, 2, &to);
 
 				/* see if the timeout has been violated */
-				gettimeofday(&ended,NULL);
-				if(ast_tvdiff_ms(&ended, &started) > timeout) {
+				if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
 					state = AST_CONTROL_UNHOLD;
 					ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
 					break; /*doh! timeout*/
@@ -1107,7 +1106,7 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
 	int hasfeatures=0;
 	int hadfeatures=0;
 	struct ast_option_header *aoh;
-	struct timeval start, end;
+	struct timeval start;
 	struct ast_bridge_config backup_config;
 	int allowdisconnect_in,allowdisconnect_out,allowredirect_in,allowredirect_out;
 	char *monitor_exec;
@@ -1157,13 +1156,11 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
 	}
 	for (;;) {
 		if (config->timelimit)
-			gettimeofday(&start, NULL);
+			start = ast_tvnow();
 		res = ast_channel_bridge(chan,peer,config,&f, &who);
 		if (config->timelimit) {
 			/* Update time limit for next pass */
-			gettimeofday(&end, NULL);
-			diff = (end.tv_sec - start.tv_sec) * 1000;
-			diff += (end.tv_usec - start.tv_usec) / 1000;
+			diff = ast_tvdiff_ms(ast_tvnow(), start);
 			config->timelimit -= diff;
 			if (hasfeatures) {
 				/* Running on backup config, meaning a feature might be being
@@ -1344,8 +1341,7 @@ static void *do_parking_thread(void *ignore)
 				pu = pu->next;
 				continue;
 			}
-			gettimeofday(&tv, NULL);
-			tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
+			tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
 			if (tms > pu->parkingtime) {
 				/* Stop music on hold */
 				ast_moh_stop(pu->chan);
@@ -1486,8 +1482,7 @@ std:					for (x=0; x<AST_MAX_FDS; x++) {
 		ast_mutex_unlock(&parking_lock);
 		rfds = nrfds;
 		efds = nefds;
-		tv.tv_sec = ms / 1000;
-		tv.tv_usec = (ms % 1000) * 1000;
+		tv = ast_samp2tv(ms, 1000);
 		/* Wait for something to happen */
 		ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
 		pthread_testcancel();
diff --git a/res/res_musiconhold.c b/res/res_musiconhold.c
index 07ba5fa08997e6717023ab47bd7d4fc688341f66..351081f46098694d41232953d58dd2c9ad04a234 100755
--- a/res/res_musiconhold.c
+++ b/res/res_musiconhold.c
@@ -444,17 +444,10 @@ static void *monmp3thread(void *data)
 	char buf[8192];
 	short sbuf[8192];
 	int res, res2;
-	struct timeval tv;
-	struct timeval tv_tmp;
-	long error_sec, error_usec;
-	long delay;
+	struct timeval tv, tv_tmp;
 
-	tv_tmp.tv_sec = 0;
-	tv_tmp.tv_usec = 0;
 	tv.tv_sec = 0;
 	tv.tv_usec = 0;
-	error_sec = 0;
-	error_usec = 0;
 	for(;/* ever */;) {
 		/* Spawn mp3 player if it's not there */
 		if (class->srcfd < 0) {
@@ -468,40 +461,20 @@ static void *monmp3thread(void *data)
 			/* Pause some amount of time */
 			res = read(class->pseudofd, buf, sizeof(buf));
 		} else {
+			long delta;
 			/* Reliable sleep */
-			if (gettimeofday(&tv_tmp, NULL) < 0) {
-				ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
-				return NULL;
-			}
-			if (((unsigned long)(tv.tv_sec) > 0)&&((unsigned long)(tv.tv_usec) > 0)) {
-				if ((unsigned long)(tv_tmp.tv_usec) < (unsigned long)(tv.tv_usec)) {
-					tv_tmp.tv_usec += 1000000;
-					tv_tmp.tv_sec -= 1;
-				}
-				error_sec = (unsigned long)(tv_tmp.tv_sec) - (unsigned long)(tv.tv_sec);
-				error_usec = (unsigned long)(tv_tmp.tv_usec) - (unsigned long)(tv.tv_usec);
-			} else {
-				error_sec = 0;
-				error_usec = 0;
-			}
-			if (error_sec * 1000 + error_usec / 1000 < MOH_MS_INTERVAL) {
-				tv.tv_sec = tv_tmp.tv_sec + (MOH_MS_INTERVAL/1000 - error_sec);
-				tv.tv_usec = tv_tmp.tv_usec + ((MOH_MS_INTERVAL % 1000) * 1000 - error_usec);
-				delay = (MOH_MS_INTERVAL/1000 - error_sec) * 1000 +
-					((MOH_MS_INTERVAL % 1000) * 1000 - error_usec) / 1000;
+			tv_tmp = ast_tvnow();
+			if (ast_tvzero(tv))
+				tv = tv_tmp;
+			delta = ast_tvdiff_ms(tv_tmp, tv);
+			if (delta < MOH_MS_INTERVAL) {	/* too early */
+				tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000));	/* next deadline */
+				usleep(1000 * (MOH_MS_INTERVAL - delta));
 			} else {
 				ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
-				tv.tv_sec = tv_tmp.tv_sec;
-				tv.tv_usec = tv_tmp.tv_usec;
-				delay = 0;
-			}
-			if (tv.tv_usec > 1000000) {
-				tv.tv_sec++;
-				tv.tv_usec-= 1000000;
+				tv = tv_tmp;
 			}
-			if (delay > 0)
-				usleep(delay * 1000);
-			res = 800;		/* 800 samples */
+			res = 8 * MOH_MS_INTERVAL;	/* 8 samples per millisecond */
 		}
 		if (!class->members)
 			continue;
diff --git a/rtp.c b/rtp.c
index 2f2cc33a509318d277db802949a1046ded8d0522..efeb65b7bc7fe75618d546af903f7f01673fff1b 100755
--- a/rtp.c
+++ b/rtp.c
@@ -42,6 +42,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/utils.h"
 #include "asterisk/cli.h"
 #include "asterisk/unaligned.h"
+#include "asterisk/utils.h"
 
 #define MAX_TIMESTAMP_SKEW	640
 
@@ -144,12 +145,10 @@ void ast_rtp_setnat(struct ast_rtp *rtp, int nat)
 
 static struct ast_frame *send_dtmf(struct ast_rtp *rtp)
 {
-	struct timeval tv;
 	static struct ast_frame null_frame = { AST_FRAME_NULL, };
 	char iabuf[INET_ADDRSTRLEN];
-	gettimeofday(&tv, NULL);
-	if ((tv.tv_sec < rtp->dtmfmute.tv_sec) ||
-	    ((tv.tv_sec == rtp->dtmfmute.tv_sec) && (tv.tv_usec < rtp->dtmfmute.tv_usec))) {
+
+	if (ast_tvcmp(ast_tvnow(), rtp->dtmfmute) < 0) {
 		if (option_debug)
 			ast_log(LOG_DEBUG, "Ignore potential DTMF echo from '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr));
 		rtp->resp = 0;
@@ -367,24 +366,13 @@ struct ast_frame *ast_rtcp_read(struct ast_rtp *rtp)
 
 static void calc_rxstamp(struct timeval *tv, struct ast_rtp *rtp, unsigned int timestamp, int mark)
 {
-	if ((!rtp->rxcore.tv_sec && !rtp->rxcore.tv_usec) || mark) {
-		gettimeofday(&rtp->rxcore, NULL);
-		rtp->rxcore.tv_sec -= timestamp / 8000;
-		rtp->rxcore.tv_usec -= (timestamp % 8000) * 125;
+	struct timeval ts = ast_samp2tv( timestamp, 8000);
+	if (ast_tvzero(rtp->rxcore) || mark) {
+		rtp->rxcore = ast_tvsub(ast_tvnow(), ts);
 		/* Round to 20ms for nice, pretty timestamps */
 		rtp->rxcore.tv_usec -= rtp->rxcore.tv_usec % 20000;
-		if (rtp->rxcore.tv_usec < 0) {
-			/* Adjust appropriately if necessary */
-			rtp->rxcore.tv_usec += 1000000;
-			rtp->rxcore.tv_sec -= 1;
-		}
-	}
-	tv->tv_sec = rtp->rxcore.tv_sec + timestamp / 8000;
-	tv->tv_usec = rtp->rxcore.tv_usec + (timestamp % 8000) * 125;
-	if (tv->tv_usec >= 1000000) {
-		tv->tv_usec -= 1000000;
-		tv->tv_sec += 1;
 	}
+	*tv = ast_tvadd(rtp->rxcore, ts);
 }
 
 struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
@@ -1033,28 +1021,19 @@ void ast_rtp_destroy(struct ast_rtp *rtp)
 
 static unsigned int calc_txstamp(struct ast_rtp *rtp, struct timeval *delivery)
 {
-	struct timeval now;
-	unsigned int ms;
-	if (!rtp->txcore.tv_sec && !rtp->txcore.tv_usec) {
-		gettimeofday(&rtp->txcore, NULL);
+	struct timeval t;
+	long ms;
+	if (ast_tvzero(rtp->txcore)) {
+		rtp->txcore = ast_tvnow();
 		/* Round to 20ms for nice, pretty timestamps */
 		rtp->txcore.tv_usec -= rtp->txcore.tv_usec % 20000;
 	}
-	if (delivery && (delivery->tv_sec || delivery->tv_usec)) {
-		/* Use previous txcore */
-		ms = (delivery->tv_sec - rtp->txcore.tv_sec) * 1000;
-		ms += (1000000 + delivery->tv_usec - rtp->txcore.tv_usec) / 1000 - 1000;
-		rtp->txcore.tv_sec = delivery->tv_sec;
-		rtp->txcore.tv_usec = delivery->tv_usec;
-	} else {
-		gettimeofday(&now, NULL);
-		ms = (now.tv_sec - rtp->txcore.tv_sec) * 1000;
-		ms += (1000000 + now.tv_usec - rtp->txcore.tv_usec) / 1000 - 1000;
-		/* Use what we just got for next time */
-		rtp->txcore.tv_sec = now.tv_sec;
-		rtp->txcore.tv_usec = now.tv_usec;
-	}
-	return ms;
+	/* Use previous txcore if available */
+	t = (delivery && !ast_tvzero(*delivery)) ? *delivery : ast_tvnow();
+	ms = ast_tvdiff_ms(t, rtp->txcore);
+	/* Use what we just got for next time */
+	rtp->txcore = t;
+	return (unsigned int) ms;
 }
 
 int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
@@ -1087,12 +1066,7 @@ int ast_rtp_senddigit(struct ast_rtp *rtp, char digit)
 	if (!rtp->them.sin_addr.s_addr)
 		return 0;
 
-	gettimeofday(&rtp->dtmfmute, NULL);
-	rtp->dtmfmute.tv_usec += (500 * 1000);
-	if (rtp->dtmfmute.tv_usec > 1000000) {
-		rtp->dtmfmute.tv_usec -= 1000000;
-		rtp->dtmfmute.tv_sec += 1;
-	}
+	rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
 	
 	/* Get a pointer to the header */
 	rtpheader = (unsigned int *)data;
@@ -1159,13 +1133,8 @@ int ast_rtp_sendcng(struct ast_rtp *rtp, int level)
 	if (!rtp->them.sin_addr.s_addr)
 		return 0;
 
-	gettimeofday(&rtp->dtmfmute, NULL);
-	rtp->dtmfmute.tv_usec += (500 * 1000);
-	if (rtp->dtmfmute.tv_usec > 1000000) {
-		rtp->dtmfmute.tv_usec -= 1000000;
-		rtp->dtmfmute.tv_sec += 1;
-	}
-	
+	rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
+
 	/* Get a pointer to the header */
 	rtpheader = (unsigned int *)data;
 	rtpheader[0] = htonl((2 << 30) | (1 << 23) | (payload << 16) | (rtp->seqno++));
@@ -1201,7 +1170,7 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
 
 		/* Re-calculate last TS */
 		rtp->lastts = rtp->lastts + ms * 8;
-		if (!f->delivery.tv_sec && !f->delivery.tv_usec) {
+		if (ast_tvzero(f->delivery)) {
 			/* If this isn't an absolute delivery time, Check if it is close to our prediction, 
 			   and if so, go with our prediction */
 			if (abs(rtp->lastts - pred) < MAX_TIMESTAMP_SKEW)
@@ -1218,7 +1187,7 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
 		/* Re-calculate last TS */
 		rtp->lastts = rtp->lastts + ms * 90;
 		/* If it's close to our prediction, go for it */
-		if (!f->delivery.tv_sec && !f->delivery.tv_usec) {
+		if (ast_tvzero(f->delivery)) {
 			if (abs(rtp->lastts - pred) < 7200) {
 				rtp->lastts = pred;
 				rtp->lastovidtimestamp += f->samples;
diff --git a/sched.c b/sched.c
index 160637e883f78525edcd236807f18f6d55d0ee68..84406f6079e28e0f9a650cb6f4ca26b803cf5282 100755
--- a/sched.c
+++ b/sched.c
@@ -31,6 +31,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/logger.h"
 #include "asterisk/channel.h"
 #include "asterisk/lock.h"
+#include "asterisk/utils.h"
 
 /* Determine if a is sooner than b */
 #define SOONER(a,b) (((b).tv_sec > (a).tv_sec) || \
@@ -148,18 +149,13 @@ int ast_sched_wait(struct sched_context *con)
 	 * Return the number of milliseconds 
 	 * until the next scheduled event
 	 */
-	struct timeval tv;
 	int ms;
 	DEBUG(ast_log(LOG_DEBUG, "ast_sched_wait()\n"));
 	ast_mutex_lock(&con->lock);
 	if (!con->schedq) {
 		ms = -1;
-	} else if (gettimeofday(&tv, NULL) < 0) {
-		/* This should never happen */
-		ms = 0;
 	} else {
-		ms = (con->schedq->when.tv_sec - tv.tv_sec) * 1000;
-		ms += (con->schedq->when.tv_usec - tv.tv_usec) / 1000;
+		ms = ast_tvdiff_ms(con->schedq->when, ast_tvnow());
 		if (ms < 0)
 			ms = 0;
 	}
@@ -194,41 +190,21 @@ static void schedule(struct sched_context *con, struct sched *s)
 	con->schedcnt++;
 }
 
-static inline int sched_settime(struct timeval *tv, int when)
+/*
+ * given the last event *tv and the offset in milliseconds 'when',
+ * computes the next value,
+ */
+static int sched_settime(struct timeval *tv, int when)
 {
-	struct timeval tv_tmp;
-	long error_sec, error_usec;
+	struct timeval now = ast_tvnow();
 
-	if (gettimeofday(&tv_tmp, NULL) < 0) {
-		/* This shouldn't ever happen, but let's be sure */
-		ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
-		return -1;
-	}
 	/*ast_log(LOG_DEBUG, "TV -> %lu,%lu\n", tv->tv_sec, tv->tv_usec);*/
-	if (((unsigned long)(tv->tv_sec) > 0)||((unsigned long)(tv->tv_usec) > 0)) {
-		if ((unsigned long)(tv_tmp.tv_usec) < (unsigned long)(tv->tv_usec)) {
-			tv_tmp.tv_usec += 1000000;
-			tv_tmp.tv_sec -= 1;
-		}
-		error_sec = (unsigned long)(tv_tmp.tv_sec) - (unsigned long)(tv->tv_sec);
-		error_usec = (unsigned long)(tv_tmp.tv_usec) - (unsigned long)(tv->tv_usec);
-	} else {
-		/*ast_log(LOG_DEBUG, "Initializing error\n");*/
-		error_sec = 0;
-		error_usec = 0;
-	}
-	/*ast_log(LOG_DEBUG, "ERROR -> %lu,%lu\n", error_sec, error_usec);*/
-	if (error_sec * 1000 + error_usec / 1000 < when) {
-		tv->tv_sec = tv_tmp.tv_sec + (when/1000 - error_sec);
-		tv->tv_usec = tv_tmp.tv_usec + ((when % 1000) * 1000 - error_usec);
-	} else {
+	if (ast_tvzero(*tv))	/* not supplied, default to now */
+		*tv = now;
+	*tv = ast_tvadd(*tv, ast_samp2tv(when, 1000));
+	if (ast_tvcmp(*tv, now) < 0) {
 		ast_log(LOG_DEBUG, "Request to schedule in the past?!?!\n");
-		tv->tv_sec = tv_tmp.tv_sec;
-		tv->tv_usec = tv_tmp.tv_usec;
-	}
-	if (tv->tv_usec > 1000000) {
-		tv->tv_sec++;
-		tv->tv_usec-= 1000000;
+		*tv = now;
 	}
 	return 0;
 }
@@ -251,8 +227,7 @@ int ast_sched_add(struct sched_context *con, int when, ast_sched_cb callback, vo
 		tmp->callback = callback;
 		tmp->data = data;
 		tmp->resched = when;
-		tmp->when.tv_sec = 0;
-		tmp->when.tv_usec = 0;
+		tmp->when = ast_tv(0, 0);
 		if (sched_settime(&tmp->when, when)) {
 			sched_release(con, tmp);
 		} else {
@@ -315,9 +290,7 @@ void ast_sched_dump(const struct sched_context *con)
 	 * stderr
 	 */
 	struct sched *q;
-	struct timeval tv;
-	time_t s, ms;
-	gettimeofday(&tv, NULL);
+	struct timeval tv = ast_tvnow();
 #ifdef SCHED_MAX_CACHE
 	ast_log(LOG_DEBUG, "Asterisk Schedule Dump (%d in Q, %d Total, %d Cache)\n", con->schedcnt, con->eventcnt - 1, con->schedccnt);
 #else
@@ -327,21 +300,15 @@ void ast_sched_dump(const struct sched_context *con)
 	ast_log(LOG_DEBUG, "=============================================================\n");
 	ast_log(LOG_DEBUG, "|ID    Callback          Data              Time  (sec:ms)   |\n");
 	ast_log(LOG_DEBUG, "+-----+-----------------+-----------------+-----------------+\n");
-	q = con->schedq;
-	while(q) {
-		s =  q->when.tv_sec - tv.tv_sec;
-		ms = q->when.tv_usec - tv.tv_usec;
-		if (ms < 0) {
-			ms += 1000000;
-			s--;
-		}
+ 	for (q = con->schedq; q; q = q->next) {
+ 		struct timeval delta =  ast_tvsub(q->when, tv);
+
 		ast_log(LOG_DEBUG, "|%.4d | %-15p | %-15p | %.6ld : %.6ld |\n", 
-				q->id,
-				q->callback,
-				q->data,
-				(long)s,
-				(long)ms);
-		q=q->next;
+			q->id,
+			q->callback,
+			q->data,
+			delta.tv_sec,
+			delta.tv_usec);
 	}
 	ast_log(LOG_DEBUG, "=============================================================\n");
 	
@@ -362,15 +329,13 @@ int ast_sched_runq(struct sched_context *con)
 	for(;;) {
 		if (!con->schedq)
 			break;
-		if (gettimeofday(&tv, NULL)) {
-			/* This should never happen */
-			ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
-			break;
-		}
-		/* We only care about millisecond accuracy anyway, so this will
-		   help us get more than one event at one time if they are very
-		   close together. */
-		tv.tv_usec += 1000;
+		
+		/* schedule all events which are going to expire within 1ms.
+		 * We only care about millisecond accuracy anyway, so this will
+		 * help us get more than one event at one time if they are very
+		 * close together.
+		 */
+		tv = ast_tvadd(ast_tvnow(), ast_tv(0, 1000));
 		if (SOONER(con->schedq->when, tv)) {
 			current = con->schedq;
 			con->schedq = con->schedq->next;
@@ -414,7 +379,6 @@ long ast_sched_when(struct sched_context *con,int id)
 {
 	struct sched *s;
 	long secs;
-	struct timeval now;
 	DEBUG(ast_log(LOG_DEBUG, "ast_sched_when()\n"));
 
 	ast_mutex_lock(&con->lock);
@@ -425,11 +389,8 @@ long ast_sched_when(struct sched_context *con,int id)
 	}
 	secs=-1;
 	if (s!=NULL) {
-		if (gettimeofday(&now, NULL)) {
-			ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
-		} else {
-			secs=s->when.tv_sec-now.tv_sec;
-		}
+		struct timeval now = ast_tvnow();
+		secs=s->when.tv_sec-now.tv_sec;
 	}
 	ast_mutex_unlock(&con->lock);
 	return secs;
diff --git a/translate.c b/translate.c
index 3ff38ee9ecfd0cfdba42751c10a24c923d7bc469..2ea1d877b5dd9f9d3a7d44fe907b1b1dd40f5b1e 100755
--- a/translate.c
+++ b/translate.c
@@ -107,10 +107,7 @@ struct ast_trans_pvt *ast_translator_build_path(int dest, int source)
 				
 			if (tmp) {
 				tmp->next = NULL;
-				tmp->nextin.tv_sec = 0;
-				tmp->nextin.tv_usec = 0;
-				tmp->nextout.tv_sec = 0;
-				tmp->nextout.tv_usec = 0;
+				tmp->nextin = tmp->nextout = ast_tv( 0, 0 );
 				tmp->step = tr_matrix[source][dest].step;
 				tmp->state = tmp->step->newpvt();
 				if (!tmp->state) {
@@ -147,47 +144,26 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f,
 	p = path;
 	/* Feed the first frame into the first translator */
 	p->step->framein(p->state, f);
-	if (f->delivery.tv_sec || f->delivery.tv_usec) {
-		if (path->nextin.tv_sec || path->nextin.tv_usec) {
+	if (!ast_tvzero(f->delivery)) {
+		if (!ast_tvzero(path->nextin)) {
 			/* Make sure this is in line with what we were expecting */
-			if ((path->nextin.tv_sec != f->delivery.tv_sec) ||
-			    (path->nextin.tv_usec != f->delivery.tv_usec)) {
+			if (!ast_tveq(path->nextin, f->delivery)) {
 				/* The time has changed between what we expected and this
 				   most recent time on the new packet.  Adjust our output
 				   time appropriately */
-				long sdiff;
-				long udiff;
-				sdiff = f->delivery.tv_sec - path->nextin.tv_sec;
-				udiff = f->delivery.tv_usec - path->nextin.tv_usec;
-				path->nextin.tv_sec = f->delivery.tv_sec;
-				path->nextin.tv_usec = f->delivery.tv_usec;
-				path->nextout.tv_sec += sdiff;
-				path->nextout.tv_usec += udiff;
-				if (path->nextout.tv_usec < 0) {
-					path->nextout.tv_usec += 1000000;
-					path->nextout.tv_sec--;
-				} else if (path->nextout.tv_usec >= 1000000) {
-					path->nextout.tv_usec -= 1000000;
-					path->nextout.tv_sec++;
-				}
+				path->nextout = ast_tvadd(path->nextout,
+					ast_tvsub(f->delivery, path->nextin));
+				path->nextin = f->delivery;
 			}
 		} else {
 			/* This is our first pass.  Make sure the timing looks good */
-			path->nextin.tv_sec = f->delivery.tv_sec;
-			path->nextin.tv_usec = f->delivery.tv_usec;
-			path->nextout.tv_sec = f->delivery.tv_sec;
-			path->nextout.tv_usec = f->delivery.tv_usec;
+			path->nextin = f->delivery;
+			path->nextout = f->delivery;
 		}
 		/* Predict next incoming sample */
-		path->nextin.tv_sec += (f->samples / 8000);
-		path->nextin.tv_usec += ((f->samples % 8000) * 125);
-		if (path->nextin.tv_usec >= 1000000) {
-			path->nextin.tv_usec -= 1000000;
-			path->nextin.tv_sec++;
-		}
+		path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, 8000));
 	}
-	delivery.tv_sec = f->delivery.tv_sec;
-	delivery.tv_usec = f->delivery.tv_usec;
+	delivery = f->delivery;
 	if (consume)
 		ast_frfree(f);
 	while(p) {
@@ -200,22 +176,15 @@ struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f,
 		if (p->next) 
 			p->next->step->framein(p->next->state, out);
 		else {
-			if (delivery.tv_sec || delivery.tv_usec) {
+			if (!ast_tvzero(delivery)) {
 				/* Use next predicted outgoing timestamp */
-				out->delivery.tv_sec = path->nextout.tv_sec;
-				out->delivery.tv_usec = path->nextout.tv_usec;
+				out->delivery = path->nextout;
 				
 				/* Predict next outgoing timestamp from samples in this
 				   frame. */
-				path->nextout.tv_sec += (out->samples / 8000);
-				path->nextout.tv_usec += ((out->samples % 8000) * 125);
-				if (path->nextout.tv_usec >= 1000000) {
-					path->nextout.tv_sec++;
-					path->nextout.tv_usec -= 1000000;
-				}
+				path->nextout = ast_tvadd(path->nextout, ast_samp2tv( out->samples, 8000));
 			} else {
-				out->delivery.tv_sec = 0;
-				out->delivery.tv_usec = 0;
+				out->delivery = ast_tv(0, 0);
 			}
 			return out;
 		}
@@ -231,7 +200,7 @@ static void calc_cost(struct ast_translator *t,int samples)
 	int sofar=0;
 	struct ast_translator_pvt *pvt;
 	struct ast_frame *f, *out;
-	struct timeval start, finish;
+	struct timeval start;
 	int cost;
 	if(!samples)
 	  samples = 1;
@@ -248,7 +217,7 @@ static void calc_cost(struct ast_translator *t,int samples)
 		t->cost = 99999;
 		return;
 	}
-	gettimeofday(&start, NULL);
+	start = ast_tvnow();
 	/* Call the encoder until we've processed one second of time */
 	while(sofar < samples * 8000) {
 		f = t->sample();
@@ -265,9 +234,8 @@ static void calc_cost(struct ast_translator *t,int samples)
 			ast_frfree(out);
 		}
 	}
-	gettimeofday(&finish, NULL);
+	cost = ast_tvdiff_ms(ast_tvnow(), start);
 	t->destroy(pvt);
-	cost = (finish.tv_sec - start.tv_sec) * 1000 + (finish.tv_usec - start.tv_usec) / 1000;
 	t->cost = cost / samples;
 	if (!t->cost)
 		t->cost = 1;
diff --git a/utils.c b/utils.c
index 1ab8c690d1cfeb2457b85ab0619c3a629cb7a1e7..2043e628603cf40ada9680ab1febece6e6861438 100755
--- a/utils.c
+++ b/utils.c
@@ -493,6 +493,55 @@ int ast_false(const char *s)
 	return 0;
 }
 
+#define ONE_MILLION	1000000
+/*
+ * put timeval in a valid range. usec is 0..999999
+ * negative values are not allowed and truncated.
+ */
+static struct timeval tvfix(struct timeval a)
+{
+	if (a.tv_usec >= ONE_MILLION) {
+		ast_log(LOG_ERROR, "warning too large timestamp %ld.%ld\n",
+			a.tv_sec, a.tv_usec);
+		a.tv_sec += a.tv_usec % ONE_MILLION;
+		a.tv_usec %= ONE_MILLION;
+	} else if (a.tv_usec < 0) {
+		ast_log(LOG_ERROR, "warning negative timestamp %ld.%ld\n",
+			a.tv_sec, a.tv_usec);
+		a.tv_usec = 0;
+	}
+	return a;
+}
+
+struct timeval ast_tvadd(struct timeval a, struct timeval b)
+{
+	/* consistency checks to guarantee usec in 0..999999 */
+	a = tvfix(a);
+	b = tvfix(b);
+	a.tv_sec += b.tv_sec;
+	a.tv_usec += b.tv_usec;
+	if (a.tv_usec >= ONE_MILLION) {
+		a.tv_sec++;
+		a.tv_usec -= ONE_MILLION;
+	}
+	return a;
+}
+
+struct timeval ast_tvsub(struct timeval a, struct timeval b)
+{
+	/* consistency checks to guarantee usec in 0..999999 */
+	a = tvfix(a);
+	b = tvfix(b);
+	a.tv_sec -= b.tv_sec;
+	a.tv_usec -= b.tv_usec;
+	if (a.tv_usec < 0) {
+		a.tv_sec-- ;
+		a.tv_usec += ONE_MILLION;
+	}
+	return a;
+}
+#undef ONE_MILLION
+
 #ifndef HAVE_STRCASESTR
 static char *upper(const char *orig, char *buf, int bufsize)
 {