[Asterisk-Dev] Asterisk crashes on voicemail timeout

Jim Gottlieb jimmy-ml at nccom.com
Sun Apr 27 19:07:09 MST 2003


On 2003-04-27 at 12:34, Mark Spencer (markster at digium.com) wrote:

> The "right thing to do" (on my list) is to listen for silence, and when a
> certain amount of silence has occured, *rewind* the stream by that amount
> of silence, and truncate it, to remove the silence from the recording.
> This is totally doable, I just haven't had the time yet t o do it.

In case it helps, here is our routine for recording to a file,
including silence timeout (with rewind) and DTMF interrupt.

#define SILENCE_LEVEL   32
#define SILENCE_COUNT   40000 /* five seconds */
-------------- next part --------------
/* Beep and then record a file. filename and format are null-terminated
strings which are the file name and format of the desired file. Timeout is
the maximum length of the recording in milliseconds (specify 0 for infinite).
flags are: NEWT_FLAG_COMMONINT to allow common section interrupt.

Returns 0 if time-out, 1 if hang-up, 2 if common interrupt, or the
received DTMF char if one received.
*/

int newt_dep_recordfile(void *newtch, char *filename, char *format, 
	int timeout, int flags)
{
struct newt_channel *newt;  /* pointer to our channel structure */
struct ast_filestream *fs;  /* file stream for writing the file */
struct ast_frame *f;  /* frames for reading (f) and writing (wf) */
struct timeval tv, start, lastout = { 0,0 } ; /* time vars */
int i,j,res,sil; /* scratch vars */
short samp; /* holder for linear-ized sample */
unsigned char *cp; /* pointer for mu-law data block */

	/* point it to the channel structure passed by the user */
	newt = (struct newt_channel *) newtch; 
 	/* beep at the user to prompt for recording */
	i = 0; /* start at 0 index into tone generation */
	/* i is now value for 3rd arg of make_tone_block call */
	/* initialize last out time */
	lastout.tv_sec = lastout.tv_usec = 0;
	/* output recording beep */
	if (ast_streamfile(newt->chan,"beep",newt->chan->language) == -1) return -1;
	(void) newt_waitstream(newt->chan,"",newt,NEWT_FLAG_COMMONINT,0); /* for normal channel */
	ast_stopstream(newt->chan);

	/* suck in 5 voice frames to make up for echo of beep, etc */
	for(i = 0; i < 5; i++) {
		/* check for soft hangup flag */
		if (ast_check_hangup(newt->chan)) return -1;
		/* if got a common section interrupt, return as such */
		if ((flags & NEWT_FLAG_COMMONINT) && 
			(newt_iscommonint(newt->channo))) return 2;
		/* wait for something on fd */
		res = ast_waitfor(newt->chan,-1);
		if (res == -1) return -1;
		/* read a frame */
		f = ast_read(newt->chan);
		if (!f) { /* if hangup */
			return 1; /* return indicating hangup */
		}
		switch(f->frametype) {
		case AST_FRAME_DTMF:  /* if we got a DTMF frame */
			res = f->subclass; /* get received char */
			/* free frame */
			ast_frfree(f);
			return res; /* return received char */
		}
		/* free the alloc'ed frame */
		ast_frfree(f);
	}
	/* now we actually record the voice stream into the file */
	/* use the asterisk call to open a file stream */
	/* start with normal flags */
	i = O_CREAT | O_TRUNC | O_WRONLY;
	/* if they want to append, set flags this way */
	if (flags & NEWT_FLAG_APPEND) i = O_CREAT | O_WRONLY | O_APPEND; 
	fs = ast_writefile(filename, format, NULL, i, 0, 0644);
	if (!fs) { /* if unable to open */
		/* log error */
		ast_log(LOG_WARNING, "ast_writefile failed on %s for %s\n", newt->chan->name, filename);
		return -1; /* return indicating error */
	}
	gettimeofday(&start, NULL);  /* get recording start time */
	gettimeofday(&tv, NULL);  /* get current time */
	sil = 0; /* initialize contiguous silence counter to zero */
	/* loop while time left (or no time specified) */
	while ((!timeout) || (((tv.tv_sec - start.tv_sec) * 1000 + (tv.tv_usec - start.tv_usec)/1000) < timeout)) {
		/* check for soft hangup flag */
		if (ast_check_hangup(newt->chan)) return -1;
		/* if got a common section interrupt, return as such */
		if ((flags & NEWT_FLAG_COMMONINT) && 
			(newt_iscommonint(newt->channo))) return 2;
		/* wait for activity on channel */
		res = ast_waitfor(newt->chan, 250);
		if (res < 0) { /* if timeout */
			continue; /* do it again */
		}
		/* read a frame */
		f = ast_read(newt->chan);
		if (!f) { /* if hangup */
			ast_closestream(fs);  /* close stream */
			return 1;
		}


		switch(f->frametype) {
		case AST_FRAME_DTMF:  /* DTMF found */
			res = f->subclass;  /* get received char */
			ast_closestream(fs);  /* close stream */
			/* free frame */
			ast_frfree(f);

			if (newt_truncate_vfile(filename, format, NEWT_DTMF_TRUNCATE_SIZE) == -1) return -1;
			return res;

		case AST_FRAME_VOICE:  /* voice frame */
			/* if we are to check for silence */
			if (flags & NEWT_FLAG_SILENCEINT) { 
			/* go through the received block and count the 
			   contiguous samples that qualify as silence */
				/* set pointer to data block in frame */
				cp = (unsigned char *) f->data;
				/* loop through the block */
				for(j = 0; j < f->datalen; j++) {
					/* get this sample in linear form */
					samp = AST_MULAW(cp[j]);
					/* within silence parameters, add to
					   count, otherwise clear count */
					if ((samp <= SILENCE_LEVEL) &&
					  (samp >= -SILENCE_LEVEL)) {
						sil++;
					} else sil = 0;
				}
				/* if we have enough contiguous silence, 
				   exit as interrupted by it */
				if (sil >= SILENCE_COUNT) {
				/* free frame */
				ast_frfree(f);
				ast_closestream(fs);  /* close stream */

				if (newt_truncate_vfile(filename, format, SILENCE_COUNT) == -1) return -1;
				return 0; /* return same as timeout */
				}
			}
			ast_writestream(fs, f);  /* write to file */
			break;
		}
		/* free frame */
		ast_frfree(f);
		/* save current time */
		gettimeofday(&tv, NULL);
	}
	ast_closestream(fs); /* close file stream */
	return 0;  /* return indicating timeout */
}


More information about the asterisk-dev mailing list