Esempio n. 1
0
static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag)
{
	/* Initialize the file if not already done so */
	char *ext = NULL;
	char *last_slash = NULL;
	if (!ast_strlen_zero(filename)) {
		if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
			*oflags = O_CREAT | O_WRONLY;
			*oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;

			last_slash = strrchr(filename, '/');

			if ((ext = strrchr(filename, '.')) && (ext > last_slash)) {
				*(ext++) = '\0';
			} else {
				ext = "raw";
			}

			if (!(*fs = ast_writefile(filename, ext, NULL, *oflags, 0, 0666))) {
				ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, ext);
				*errflag = 1;
			} else {
				struct ast_filestream *tmp = *fs;
				mixmonitor->mixmonitor_ds->samp_rate = MAX(mixmonitor->mixmonitor_ds->samp_rate, ast_format_rate(&tmp->fmt->format));
			}
		}
	}
}
/*! \brief Start monitoring a channel
 * \param chan ast_channel struct to record
 * \param format_spec file format to use for recording
 * \param fname_base filename base to record to
 * \param need_lock whether to lock the channel mutex
 * \param stream_action whether to record the input and/or output streams.  X_REC_IN | X_REC_OUT is most often used
 * Creates the file to record, if no format is specified it assumes WAV
 * It also sets channel variable __MONITORED=yes
 * \retval 0 on success
 * \retval -1 on failure
 */
int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const char *format_spec,
					     const char *fname_base, int need_lock, int stream_action)
{
	int res = 0;

	LOCK_IF_NEEDED(chan, need_lock);

	if (!(ast_channel_monitor(chan))) {
		struct ast_channel_monitor *monitor;
		char *channel_name, *p;

		/* Create monitoring directory if needed */
		ast_mkdir(ast_config_AST_MONITOR_DIR, 0777);

		if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
			UNLOCK_IF_NEEDED(chan, need_lock);
			return -1;
		}

		/* Determine file names */
		if (!ast_strlen_zero(fname_base)) {
			int directory = strchr(fname_base, '/') ? 1 : 0;
			const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
			const char *absolute_suffix = *fname_base == '/' ? "" : "/";

			snprintf(monitor->read_filename, FILENAME_MAX, "%s%s%s-in",
						absolute, absolute_suffix, fname_base);
			snprintf(monitor->write_filename, FILENAME_MAX, "%s%s%s-out",
						absolute, absolute_suffix, fname_base);
			snprintf(monitor->filename_base, FILENAME_MAX, "%s%s%s",
					 	absolute, absolute_suffix, fname_base);

			/* try creating the directory just in case it doesn't exist */
			if (directory) {
				char *name = ast_strdupa(monitor->filename_base);
				ast_mkdir(dirname(name), 0777);
			}
		} else {
			ast_mutex_lock(&monitorlock);
			snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%lu",
						ast_config_AST_MONITOR_DIR, seq);
			snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%lu",
						ast_config_AST_MONITOR_DIR, seq);
			seq++;
			ast_mutex_unlock(&monitorlock);

			/* Replace all '/' chars from the channel name with '-' chars. */
			channel_name = ast_strdupa(ast_channel_name(chan));
			for (p = channel_name; (p = strchr(p, '/')); ) {
				*p = '-';
			}

			snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
					 ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
			monitor->filename_changed = 1;
		}

		monitor->stop = ast_monitor_stop;

		/* Determine file format */
		if (!ast_strlen_zero(format_spec)) {
			monitor->format = ast_strdup(format_spec);
		} else {
			monitor->format = ast_strdup("wav");
		}
		
		/* open files */
		if (stream_action & X_REC_IN) {
			if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0)
				ast_filedelete(monitor->read_filename, NULL);
			if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
							monitor->format, NULL,
							O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
				ast_log(LOG_WARNING, "Could not create file %s\n",
							monitor->read_filename);
				ast_free(monitor);
				UNLOCK_IF_NEEDED(chan, need_lock);
				return -1;
			}
		} else
			monitor->read_stream = NULL;

		if (stream_action & X_REC_OUT) {
			if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
				ast_filedelete(monitor->write_filename, NULL);
			}
			if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
							monitor->format, NULL,
							O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
				ast_log(LOG_WARNING, "Could not create file %s\n",
							monitor->write_filename);
				if (monitor->read_stream) {
					ast_closestream(monitor->read_stream);
				}
				ast_free(monitor);
				UNLOCK_IF_NEEDED(chan, need_lock);
				return -1;
			}
		} else
			monitor->write_stream = NULL;

		ast_channel_monitor_set(chan, monitor);
		ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
		/* so we know this call has been monitored in case we need to bill for it or something */
		pbx_builtin_setvar_helper(chan, "__MONITORED","true");

		ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStart",
			                "Channel: %s\r\n"
					        "Uniqueid: %s\r\n",
	                        ast_channel_name(chan),
			                ast_channel_uniqueid(chan));
	} else {
		ast_debug(1,"Cannot start monitoring %s, already monitored\n", ast_channel_name(chan));
		res = -1;
	}

	UNLOCK_IF_NEEDED(chan, need_lock);

	return res;
}
Esempio n. 3
0
/*! 
 * \brief Convert a file from one format to another 
 * \param e CLI entry
 * \param cmd command number
 * \param a list of cli arguments
 * \retval CLI_SUCCESS on success.
 * \retval CLI_SHOWUSAGE or CLI_FAILURE on failure.
*/
static char *handle_cli_file_convert(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
	char *ret = CLI_FAILURE;
	struct ast_filestream *fs_in = NULL, *fs_out = NULL;
	struct ast_frame *f;
	struct timeval start;
	int cost;
	char *file_in = NULL, *file_out = NULL;
	char *name_in, *ext_in, *name_out, *ext_out;

	switch (cmd) {
	case CLI_INIT:
		e->command = "file convert";
		e->usage =
			"Usage: file convert <file_in> <file_out>\n"
			"       Convert from file_in to file_out. If an absolute path\n"
			"       is not given, the default Asterisk sounds directory\n"
			"       will be used.\n\n"
			"       Example:\n"
			"           file convert tt-weasels.gsm tt-weasels.ulaw\n";
		return NULL;
	case CLI_GENERATE:
		return NULL;
	}
	
	/* ugly, can be removed when CLI entries have ast_module pointers */
	ast_module_ref(ast_module_info->self);

	if (a->argc != 4 || ast_strlen_zero(a->argv[2]) || ast_strlen_zero(a->argv[3])) {
		ret = CLI_SHOWUSAGE;
		goto fail_out;	
	}

	file_in = ast_strdupa(a->argv[2]);
	file_out = ast_strdupa(a->argv[3]);

	if (split_ext(file_in, &name_in, &ext_in)) {
		ast_cli(a->fd, "'%s' is an invalid filename!\n", a->argv[2]);
		goto fail_out;
	}
	if (!(fs_in = ast_readfile(name_in, ext_in, NULL, O_RDONLY, 0, 0))) {
		ast_cli(a->fd, "Unable to open input file: %s\n", a->argv[2]);
		goto fail_out;
	}
	
	if (split_ext(file_out, &name_out, &ext_out)) {
		ast_cli(a->fd, "'%s' is an invalid filename!\n", a->argv[3]);
		goto fail_out;
	}
	if (!(fs_out = ast_writefile(name_out, ext_out, NULL, O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
		ast_cli(a->fd, "Unable to open output file: %s\n", a->argv[3]);
		goto fail_out;
	}

	start = ast_tvnow();
	
	while ((f = ast_readframe(fs_in))) {
		if (ast_writestream(fs_out, f)) {
			ast_frfree(f);
			ast_cli(a->fd, "Failed to convert %s.%s to %s.%s!\n", name_in, ext_in, name_out, ext_out);
			goto fail_out;
		}
		ast_frfree(f);
	}

	cost = ast_tvdiff_ms(ast_tvnow(), start);
	ast_cli(a->fd, "Converted %s.%s to %s.%s in %dms\n", name_in, ext_in, name_out, ext_out, cost);
	ret = CLI_SUCCESS;

fail_out:
	if (fs_out) {
		ast_closestream(fs_out);
		if (ret != CLI_SUCCESS)
			ast_filedelete(name_out, ext_out);
	}

	if (fs_in) 
		ast_closestream(fs_in);

	ast_module_unref(ast_module_info->self);

	return ret;
}
/* Start monitoring a channel */
int ast_monitor_start(	struct ast_channel *chan, const char *format_spec,
		const char *fname_base, int need_lock)
{
	int res = 0;
	char tmp[256];

	LOCK_IF_NEEDED(chan, need_lock);

	if (!(chan->monitor)) {
		struct ast_channel_monitor *monitor;
		char *channel_name, *p;

		/* Create monitoring directory if needed */
		if (mkdir(ast_config_AST_MONITOR_DIR, 0770) < 0) {
			if (errno != EEXIST) {
				ast_log(LOG_WARNING, "Unable to create audio monitor directory: %s\n",
					strerror(errno));
			}
		}

		if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
			UNLOCK_IF_NEEDED(chan, need_lock);
			return -1;
		}

		/* Determine file names */
		if (!ast_strlen_zero(fname_base)) {
			int directory = strchr(fname_base, '/') ? 1 : 0;
			/* try creating the directory just in case it doesn't exist */
			if (directory) {
				char *name = strdup(fname_base);
				snprintf(tmp, sizeof(tmp), "mkdir -p \"%s\"",dirname(name));
				free(name);
				ast_safe_system(tmp);
			}
			snprintf(monitor->read_filename, FILENAME_MAX, "%s/%s-in",
						directory ? "" : ast_config_AST_MONITOR_DIR, fname_base);
			snprintf(monitor->write_filename, FILENAME_MAX, "%s/%s-out",
						directory ? "" : ast_config_AST_MONITOR_DIR, fname_base);
			ast_copy_string(monitor->filename_base, fname_base, sizeof(monitor->filename_base));
		} else {
			ast_mutex_lock(&monitorlock);
			snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld",
						ast_config_AST_MONITOR_DIR, seq);
			snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld",
						ast_config_AST_MONITOR_DIR, seq);
			seq++;
			ast_mutex_unlock(&monitorlock);

			channel_name = ast_strdupa(chan->name);
			while ((p = strchr(channel_name, '/'))) {
				*p = '-';
			}
			snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
					 ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
			monitor->filename_changed = 1;
		}

		monitor->stop = ast_monitor_stop;

		/* Determine file format */
		if (!ast_strlen_zero(format_spec)) {
			monitor->format = strdup(format_spec);
		} else {
			monitor->format = strdup("wav");
		}
		
		/* open files */
		if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0) {
			ast_filedelete(monitor->read_filename, NULL);
		}
		if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
						monitor->format, NULL,
						O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
			ast_log(LOG_WARNING, "Could not create file %s\n",
						monitor->read_filename);
			free(monitor);
			ast_channel_unlock(chan);
			return -1;
		}
		if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
			ast_filedelete(monitor->write_filename, NULL);
		}
		if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
						monitor->format, NULL,
						O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
			ast_log(LOG_WARNING, "Could not create file %s\n",
						monitor->write_filename);
			ast_closestream(monitor->read_stream);
			free(monitor);
			ast_channel_unlock(chan);
			return -1;
		}
		chan->monitor = monitor;
		ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
		/* so we know this call has been monitored in case we need to bill for it or something */
		pbx_builtin_setvar_helper(chan, "__MONITORED","true");
	} else {
		ast_log(LOG_DEBUG,"Cannot start monitoring %s, already monitored\n",
					chan->name);
		res = -1;
	}

	UNLOCK_IF_NEEDED(chan, need_lock);

	return res;
}
/*! \brief Convert a file from one format to another */
static int cli_audio_convert(int fd, int argc, char *argv[])
{
	int ret = RESULT_FAILURE;
	struct ast_filestream *fs_in = NULL, *fs_out = NULL;
	struct ast_frame *f;
	struct timeval start;
	int cost;
	char *file_in = NULL, *file_out = NULL;
	char *name_in, *ext_in, *name_out, *ext_out;
	
	ast_atomic_fetchadd_int(&me->usecnt, +1);
	
	if (argc != 3 || ast_strlen_zero(argv[1]) || ast_strlen_zero(argv[2])) {
		ret = RESULT_SHOWUSAGE;
		goto fail_out;	
	}

	file_in = ast_strdupa(argv[1]);
	file_out = ast_strdupa(argv[2]);

	if (split_ext(file_in, &name_in, &ext_in)) {
		ast_cli(fd, "'%s' is an invalid filename!\n", argv[1]);
		goto fail_out;
	}
	if (!(fs_in = ast_readfile(name_in, ext_in, NULL, O_RDONLY, 0, 0))) {
		ast_cli(fd, "Unable to open input file: %s\n", argv[1]);
		goto fail_out;
	}
	
	if (split_ext(file_out, &name_out, &ext_out)) {
		ast_cli(fd, "'%s' is an invalid filename!\n", argv[2]);
		goto fail_out;
	}
	if (!(fs_out = ast_writefile(name_out, ext_out, NULL, O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) {
		ast_cli(fd, "Unable to open output file: %s\n", argv[2]);
		goto fail_out;
	}

	start = ast_tvnow();
	
	while ((f = ast_readframe(fs_in))) {
		if (ast_writestream(fs_out, f)) {
			ast_cli(fd, "Failed to convert %s.%s to %s.%s!\n", name_in, ext_in, name_out, ext_out);
			goto fail_out;
		}
	}

	cost = ast_tvdiff_ms(ast_tvnow(), start);
	ast_cli(fd, "Converted %s.%s to %s.%s in %dms\n", name_in, ext_in, name_out, ext_out, cost);
	ret = RESULT_SUCCESS;

fail_out:
	if (fs_out) {
		ast_closestream(fs_out);
		if (ret != RESULT_SUCCESS)
			ast_filedelete(name_out, ext_out);
	}

	if (fs_in) 
		ast_closestream(fs_in);

	ast_atomic_fetchadd_int(&me->usecnt, -1);
	
	return ret;
}
Esempio n. 6
0
static void *mixmonitor_thread(void *obj) 
{
	struct mixmonitor *mixmonitor = obj;
	struct ast_filestream **fs = NULL;
	unsigned int oflags;
	char *ext;
	int errflag = 0;

	ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);

	fs = &mixmonitor->mixmonitor_ds->fs;

	/* The audiohook must enter and exit the loop locked */
	ast_audiohook_lock(&mixmonitor->audiohook);
	while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
		struct ast_frame *fr = NULL;

		ast_audiohook_trigger_wait(&mixmonitor->audiohook);

		if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING)
			break;

		if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR)))
			continue;

		/* audiohook lock is not required for the next block.
		 * Unlock it, but remember to lock it before looping or exiting */
		ast_audiohook_unlock(&mixmonitor->audiohook);

		ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
		if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) {
			/* Initialize the file if not already done so */
			if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
				oflags = O_CREAT | O_WRONLY;
				oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;

				if ((ext = strrchr(mixmonitor->filename, '.')))
					*(ext++) = '\0';
				else
					ext = "raw";

				if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0666))) {
					ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext);
					errflag = 1;
				}
			}

			/* Write out the frame(s) */
			if (*fs) {
				struct ast_frame *cur;

				for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
					ast_writestream(*fs, cur);
				}
			}
		}
		ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);

		/* All done! free it. */
		ast_frame_free(fr, 0);
		ast_audiohook_lock(&mixmonitor->audiohook);
	}

	ast_audiohook_unlock(&mixmonitor->audiohook);

	/* Datastore cleanup.  close the filestream and wait for ds destruction */
	ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
	mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
	if (!mixmonitor->mixmonitor_ds->destruction_ok) {
		ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
	}
	ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);

	/* kill the audiohook */
	destroy_monitor_audiohook(mixmonitor);

	if (mixmonitor->post_process) {
		ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
		ast_safe_system(mixmonitor->post_process);
	}

	ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
	mixmonitor_free(mixmonitor);
	return NULL;
}
Esempio n. 7
0
static void *mixmonitor_thread(void *obj) 
{
	struct mixmonitor *mixmonitor = obj;
	struct ast_filestream *fs = NULL;
	unsigned int oflags;
	char *ext;
	int errflag = 0;

	if (option_verbose > 1)
		ast_verbose(VERBOSE_PREFIX_2 "Begin MixMonitor Recording %s\n", mixmonitor->name);
	
	ast_audiohook_lock(&mixmonitor->audiohook);

	while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
		struct ast_frame *fr = NULL;
		
		ast_audiohook_trigger_wait(&mixmonitor->audiohook);
		
		if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING)
			break;
		
		if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR)))
			continue;

		ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
		if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) {
			ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
			/* Initialize the file if not already done so */
			if (!fs && !errflag) {
				oflags = O_CREAT | O_WRONLY;
				oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
				
				if ((ext = strrchr(mixmonitor->filename, '.')))
					*(ext++) = '\0';
				else
					ext = "raw";
				
				if (!(fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0644))) {
					ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext);
					errflag = 1;
				}
			}

			/* Write out the frame */
			if (fs)
				ast_writestream(fs, fr);
		} else {
			ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
		}

		/* All done! free it. */
		ast_frame_free(fr, 0);
	}

	ast_audiohook_detach(&mixmonitor->audiohook);
	ast_audiohook_unlock(&mixmonitor->audiohook);
	ast_audiohook_destroy(&mixmonitor->audiohook);
	
	if (option_verbose > 1)
		ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name);

	if (fs)
		ast_closestream(fs);

	if (mixmonitor->post_process) {
		if (option_verbose > 2)
			ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", mixmonitor->post_process);
		ast_safe_system(mixmonitor->post_process);
	}

	ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
	if (!mixmonitor->mixmonitor_ds->destruction_ok) {
		ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
	}
	ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
	ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
	ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
	ast_free(mixmonitor->mixmonitor_ds);
	free(mixmonitor);

	return NULL;
}
Esempio n. 8
0
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence)
{
    int d = 0;
    char *fmts;
    char comment[256];
    int x, fmtcnt=1, res=-1,outmsg=0;
    struct ast_frame *f;
    struct ast_filestream *others[MAX_OTHER_FORMATS];
    struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
    char *sfmt[MAX_OTHER_FORMATS];
    char *stringp=NULL;
    time_t start, end;
    struct ast_dsp *sildet;   	/* silence detector dsp */
    int totalsilence = 0;
    int dspsilence = 0;
    int gotsilence = 0;		/* did we timeout for silence? */
    int rfmt=0;
    char prependfile[80];

    if (silencethreshold < 0)
        silencethreshold = global_silence_threshold;

    if (maxsilence < 0)
        maxsilence = global_maxsilence;

    /* barf if no pointer passed to store duration in */
    if (duration == NULL) {
        ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
        return -1;
    }

    ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
    snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);

    if (playfile || beep) {
        if (!beep)
            d = ast_play_and_wait(chan, playfile);
        if (d > -1)
            d = ast_streamfile(chan, "beep",chan->language);
        if (!d)
            d = ast_waitstream(chan,"");
        if (d < 0)
            return -1;
    }
    strncpy(prependfile, recordfile, sizeof(prependfile) -1);
    strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);

    fmts = ast_strdupa(fmt);

    stringp=fmts;
    strsep(&stringp, "|");
    ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
    sfmt[0] = ast_strdupa(fmts);

    while((fmt = strsep(&stringp, "|"))) {
        if (fmtcnt > MAX_OTHER_FORMATS - 1) {
            ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
            break;
        }
        sfmt[fmtcnt++] = ast_strdupa(fmt);
    }

    time(&start);
    end=start;  /* pre-initialize end to be same as start in case we never get into loop */
    for (x=0; x<fmtcnt; x++) {
        others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
        ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing:  %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
        if (!others[x]) {
            break;
        }
    }

    sildet = ast_dsp_new(); /* Create the silence detector */
    if (!sildet) {
        ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
        return -1;
    }
    ast_dsp_set_threshold(sildet, silencethreshold);

    if (maxsilence > 0) {
        rfmt = chan->readformat;
        res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
        if (res < 0) {
            ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
            return -1;
        }
    }

    if (x == fmtcnt) {
        /* Loop forever, writing the packets we read to the writer(s), until
           we read a # or get a hangup */
        f = NULL;
        for(;;) {
            res = ast_waitfor(chan, 2000);
            if (!res) {
                ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
                /* Try one more time in case of masq */
                res = ast_waitfor(chan, 2000);
                if (!res) {
                    ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
                    res = -1;
                }
            }

            if (res < 0) {
                f = NULL;
                break;
            }
            f = ast_read(chan);
            if (!f)
                break;
            if (f->frametype == AST_FRAME_VOICE) {
                /* write each format */
                for (x=0; x<fmtcnt; x++) {
                    if (!others[x])
                        break;
                    res = ast_writestream(others[x], f);
                }

                /* Silence Detection */
                if (maxsilence > 0) {
                    dspsilence = 0;
                    ast_dsp_silence(sildet, f, &dspsilence);
                    if (dspsilence)
                        totalsilence = dspsilence;
                    else
                        totalsilence = 0;

                    if (totalsilence > maxsilence) {
                        /* Ended happily with silence */
                        if (option_verbose > 2)
                            ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
                        ast_frfree(f);
                        gotsilence = 1;
                        outmsg=2;
                        break;
                    }
                }
                /* Exit on any error */
                if (res) {
                    ast_log(LOG_WARNING, "Error writing frame\n");
                    ast_frfree(f);
                    break;
                }
            } else if (f->frametype == AST_FRAME_VIDEO) {
                /* Write only once */
                ast_writestream(others[0], f);
            } else if (f->frametype == AST_FRAME_DTMF) {
                /* stop recording with any digit */
                if (option_verbose > 2)
                    ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
                res = 't';
                outmsg = 2;
                ast_frfree(f);
                break;
            }
            if (maxtime) {
                time(&end);
                if (maxtime < (end - start)) {
                    if (option_verbose > 2)
                        ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
                    res = 't';
                    outmsg=2;
                    ast_frfree(f);
                    break;
                }
            }
            ast_frfree(f);
        }
        if (end == start) time(&end);
        if (!f) {
            if (option_verbose > 2)
                ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
            res = -1;
            outmsg=1;
#if 0
            /* delete all the prepend files */
            for (x=0; x<fmtcnt; x++) {
                if (!others[x])
                    break;
                ast_closestream(others[x]);
                ast_filedelete(prependfile, sfmt[x]);
            }
#endif
        }
    } else {
        ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]);
    }
    *duration = end - start;
#if 0
    if (outmsg > 1) {
#else
    if (outmsg) {
#endif
        struct ast_frame *fr;
        for (x=0; x<fmtcnt; x++) {
            snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
            realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
            if (!others[x] || !realfiles[x])
                break;
            if (totalsilence)
                ast_stream_rewind(others[x], totalsilence-200);
            else
                ast_stream_rewind(others[x], 200);
            ast_truncstream(others[x]);
            /* add the original file too */
            while ((fr = ast_readframe(realfiles[x]))) {
                ast_writestream(others[x],fr);
            }
            ast_closestream(others[x]);
            ast_closestream(realfiles[x]);
            ast_filerename(prependfile, recordfile, sfmt[x]);
#if 0
            ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
#endif
            ast_filedelete(prependfile, sfmt[x]);
        }
    }
    if (rfmt) {
        if (ast_set_read_format(chan, rfmt)) {
            ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
        }
    }
    if (outmsg) {
        if (outmsg > 1) {
            /* Let them know it worked */
            ast_streamfile(chan, "auth-thankyou", chan->language);
            ast_waitstream(chan, "");
        }
    }
    return res;
}

int ast_lock_path(const char *path)
{
    char *s;
    char *fs;
    int res;
    int fd;
    time_t start;
    s = alloca(strlen(path) + 10);
    fs = alloca(strlen(path) + 20);
    if (!fs || !s) {
        ast_log(LOG_WARNING, "Out of memory!\n");
        return -1;
    }
    snprintf(fs, strlen(path) + 19, "%s/%s-%08x", path, ".lock", rand());
    fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
    if (fd < 0) {
        fprintf(stderr, "Unable to create lock file: %s\n", strerror(errno));
        return -1;
    }
    close(fd);
    snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
    time(&start);
    while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
        usleep(1);
    if (res < 0) {
        ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
    }
    unlink(fs);
    ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
    return res;
}
Esempio n. 9
0
int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
{
    int res;
    struct ast_filestream *writer;
    int rfmt;
    int totalms=0, total;

    struct ast_frame *f;
    struct ast_dsp *sildet;
    /* Play prompt if requested */
    if (prompt) {
        res = ast_streamfile(c, prompt, c->language);
        if (res < 0)
            return res;
        res = ast_waitstream(c,"");
        if (res < 0)
            return res;
    }
    rfmt = c->readformat;
    res = ast_set_read_format(c, AST_FORMAT_SLINEAR);
    if (res < 0) {
        ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
        return -1;
    }
    sildet = ast_dsp_new();
    if (!sildet) {
        ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
        return -1;
    }
    writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666);
    if (!writer) {
        ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt);
        ast_dsp_free(sildet);
        return -1;
    }
    for(;;) {
        if ((res = ast_waitfor(c, 2000)) < 0) {
            ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt);
            break;
        }
        if (res) {
            f = ast_read(c);
            if (!f) {
                ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt);
                break;
            }
            if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
                /* Ended happily with DTMF */
                ast_frfree(f);
                break;
            } else if (f->frametype == AST_FRAME_VOICE) {
                ast_dsp_silence(sildet, f, &total);
                if (total > silence) {
                    /* Ended happily with silence */
                    ast_frfree(f);
                    break;
                }
                totalms += f->samples / 8;
                if (totalms > maxsec * 1000) {
                    /* Ended happily with too much stuff */
                    ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec);
                    ast_frfree(f);
                    break;
                }
            }
            ast_frfree(f);
        }
    }
    res = ast_set_read_format(c, rfmt);
    if (res)
        ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name);
    ast_dsp_free(sildet);
    ast_closestream(writer);
    return 0;
}
Esempio n. 10
0
int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path)
{
    char *fmts;
    int d;
    char comment[256];
    int x, fmtcnt=1, res=-1,outmsg=0;
    struct ast_frame *f;
    struct ast_filestream *others[MAX_OTHER_FORMATS];
    char *sfmt[MAX_OTHER_FORMATS];
    char *stringp=NULL;
    time_t start, end;
    struct ast_dsp *sildet=NULL;   	/* silence detector dsp */
    int totalsilence = 0;
    int dspsilence = 0;
    int gotsilence = 0;		/* did we timeout for silence? */
    int rfmt=0;

    if (silencethreshold < 0)
        silencethreshold = global_silence_threshold;

    if (maxsilence < 0)
        maxsilence = global_maxsilence;

    /* barf if no pointer passed to store duration in */
    if (duration == NULL) {
        ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
        return -1;
    }

    ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
    snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);

    if (playfile) {
        d = ast_play_and_wait(chan, playfile);
        if (d > -1)
            d = ast_streamfile(chan, "beep",chan->language);
        if (!d)
            d = ast_waitstream(chan,"");
        if (d < 0)
            return -1;
    }

    fmts = ast_strdupa(fmt);

    stringp=fmts;
    strsep(&stringp, "|");
    ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
    sfmt[0] = ast_strdupa(fmts);

    while((fmt = strsep(&stringp, "|"))) {
        if (fmtcnt > MAX_OTHER_FORMATS - 1) {
            ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app_voicemail.c\n");
            break;
        }
        sfmt[fmtcnt++] = ast_strdupa(fmt);
    }

    time(&start);
    end=start;  /* pre-initialize end to be same as start in case we never get into loop */
    for (x=0; x<fmtcnt; x++) {
        others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
        ast_verbose( VERBOSE_PREFIX_3 "x=%i, open writing:  %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);

        if (!others[x]) {
            break;
        }
    }

    if (path)
        ast_unlock_path(path);


    if (maxsilence > 0) {
        sildet = ast_dsp_new(); /* Create the silence detector */
        if (!sildet) {
            ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
            return -1;
        }
        ast_dsp_set_threshold(sildet, silencethreshold);
        rfmt = chan->readformat;
        res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
        if (res < 0) {
            ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
            ast_dsp_free(sildet);
            return -1;
        }
    }

    if (x == fmtcnt) {
        /* Loop forever, writing the packets we read to the writer(s), until
           we read a # or get a hangup */
        f = NULL;
        for(;;) {
            res = ast_waitfor(chan, 2000);
            if (!res) {
                ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
                /* Try one more time in case of masq */
                res = ast_waitfor(chan, 2000);
                if (!res) {
                    ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
                    res = -1;
                }
            }

            if (res < 0) {
                f = NULL;
                break;
            }
            f = ast_read(chan);
            if (!f)
                break;
            if (f->frametype == AST_FRAME_VOICE) {
                /* write each format */
                for (x=0; x<fmtcnt; x++) {
                    res = ast_writestream(others[x], f);
                }

                /* Silence Detection */
                if (maxsilence > 0) {
                    dspsilence = 0;
                    ast_dsp_silence(sildet, f, &dspsilence);
                    if (dspsilence)
                        totalsilence = dspsilence;
                    else
                        totalsilence = 0;

                    if (totalsilence > maxsilence) {
                        /* Ended happily with silence */
                        if (option_verbose > 2)
                            ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
                        ast_frfree(f);
                        gotsilence = 1;
                        outmsg=2;
                        break;
                    }
                }
                /* Exit on any error */
                if (res) {
                    ast_log(LOG_WARNING, "Error writing frame\n");
                    ast_frfree(f);
                    break;
                }
            } else if (f->frametype == AST_FRAME_VIDEO) {
                /* Write only once */
                ast_writestream(others[0], f);
            } else if (f->frametype == AST_FRAME_DTMF) {
                if (f->subclass == '#') {
                    if (option_verbose > 2)
                        ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
                    res = '#';
                    outmsg = 2;
                    ast_frfree(f);
                    break;
                }
            }
            if (f->subclass == '0') {
                /* Check for a '0' during message recording also, in case caller wants operator */
                if (option_verbose > 2)
                    ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass);
                res = '0';
                outmsg = 0;
                ast_frfree(f);
                break;
            }
            if (maxtime) {
                time(&end);
                if (maxtime < (end - start)) {
                    if (option_verbose > 2)
                        ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
                    outmsg = 2;
                    res = 't';
                    ast_frfree(f);
                    break;
                }
            }
            ast_frfree(f);
        }
        if (end == start) time(&end);
        if (!f) {
            if (option_verbose > 2)
                ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
            res = -1;
            outmsg=1;
        }
    } else {
        ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
    }

    *duration = end - start;

    for (x=0; x<fmtcnt; x++) {
        if (!others[x])
            break;
        if (res > 0) {
            if (totalsilence)
                ast_stream_rewind(others[x], totalsilence-200);
            else
                ast_stream_rewind(others[x], 200);
        }
        ast_truncstream(others[x]);
        ast_closestream(others[x]);
    }
    if (rfmt) {
        if (ast_set_read_format(chan, rfmt)) {
            ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
        }
    }
    if (outmsg > 1) {
        /* Let them know recording is stopped */
        if(!ast_streamfile(chan, "auth-thankyou", chan->language))
            ast_waitstream(chan, "");
    }
    if (sildet)
        ast_dsp_free(sildet);
    return res;
}
static int record_exec(struct ast_channel *chan, void *data)
{
	int res = 0;
	int count = 0;
	int percentflag = 0;
	char *filename, *ext = NULL, *silstr, *maxstr, *options;
	char *vdata, *p;
	int i = 0;
	char tmp[256];

	struct ast_filestream *s = '\0';
	struct localuser *u;
	struct ast_frame *f = NULL;
	
	struct ast_dsp *sildet = NULL;   	/* silence detector dsp */
	int totalsilence = 0;
	int dspsilence = 0;
	int silence = 0;		/* amount of silence to allow */
	int gotsilence = 0;		/* did we timeout for silence? */
	int maxduration = 0;		/* max duration of recording in milliseconds */
	int gottimeout = 0;		/* did we timeout for maxduration exceeded? */
	int option_skip = 0;
	int option_noanswer = 0;
	int option_append = 0;
	int terminator = '#';
	int option_quiet = 0;
	int rfmt = 0;
	int flags;
	int waitres;
	struct ast_silence_generator *silgen = NULL;
	
	/* The next few lines of code parse out the filename and header from the input string */
	if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */
		ast_log(LOG_WARNING, "Record requires an argument (filename)\n");
		return -1;
	}

	LOCAL_USER_ADD(u);

	/* Yay for strsep being easy */
	vdata = ast_strdupa(data);
	if (!vdata) {
		ast_log(LOG_ERROR, "Out of memory\n");
		LOCAL_USER_REMOVE(u);
		return -1;
	}

	p = vdata;
	filename = strsep(&p, "|");
	silstr = strsep(&p, "|");
	maxstr = strsep(&p, "|");	
	options = strsep(&p, "|");
	
	if (filename) {
		if (strstr(filename, "%d"))
			percentflag = 1;
		ext = strrchr(filename, '.'); /* to support filename with a . in the filename, not format */
		if (!ext)
			ext = strchr(filename, ':');
		if (ext) {
			*ext = '\0';
			ext++;
		}
	}
	if (!ext) {
		ast_log(LOG_WARNING, "No extension specified to filename!\n");
		LOCAL_USER_REMOVE(u);
		return -1;
	}
	if (silstr) {
		if ((sscanf(silstr, "%d", &i) == 1) && (i > -1)) {
			silence = i * 1000;
		} else if (!ast_strlen_zero(silstr)) {
			ast_log(LOG_WARNING, "'%s' is not a valid silence duration\n", silstr);
		}
	}
	
	if (maxstr) {
		if ((sscanf(maxstr, "%d", &i) == 1) && (i > -1))
			/* Convert duration to milliseconds */
			maxduration = i * 1000;
		else if (!ast_strlen_zero(maxstr))
			ast_log(LOG_WARNING, "'%s' is not a valid maximum duration\n", maxstr);
	}
	if (options) {
		/* Retain backwards compatibility with old style options */
		if (!strcasecmp(options, "skip"))
			option_skip = 1;
		else if (!strcasecmp(options, "noanswer"))
			option_noanswer = 1;
		else {
			if (strchr(options, 's'))
				option_skip = 1;
			if (strchr(options, 'n'))
				option_noanswer = 1;
			if (strchr(options, 'a'))
				option_append = 1;
			if (strchr(options, 't'))
				terminator = '*';
			if (strchr(options, 'q'))
				option_quiet = 1;
		}
	}
	
	/* done parsing */
	
	/* these are to allow the use of the %d in the config file for a wild card of sort to
	  create a new file with the inputed name scheme */
	if (percentflag) {
		do {
			snprintf(tmp, sizeof(tmp), filename, count);
			count++;
		} while ( ast_fileexists(tmp, ext, chan->language) != -1 );
		pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp);
	} else
		strncpy(tmp, filename, sizeof(tmp)-1);
	/* end of routine mentioned */
	
	
	
	if (chan->_state != AST_STATE_UP) {
		if (option_skip) {
			/* At the user's option, skip if the line is not up */
			LOCAL_USER_REMOVE(u);
			return 0;
		} else if (!option_noanswer) {
			/* Otherwise answer unless we're supposed to record while on-hook */
			res = ast_answer(chan);
		}
	}
	
	if (res) {
		ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
		goto out;
	}
	
	if (!option_quiet) {
		/* Some code to play a nice little beep to signify the start of the record operation */
		res = ast_streamfile(chan, "beep", chan->language);
		if (!res) {
			res = ast_waitstream(chan, "");
		} else {
			ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", chan->name);
		}
		ast_stopstream(chan);
	}
		
	/* The end of beep code.  Now the recording starts */
		
	if (silence > 0) {
		rfmt = chan->readformat;
		res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
		if (res < 0) {
			ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
			LOCAL_USER_REMOVE(u);
			return -1;
		}
		sildet = ast_dsp_new();
		if (!sildet) {
			ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
			LOCAL_USER_REMOVE(u);
			return -1;
		}
		ast_dsp_set_threshold(sildet, 256);
	} 
		
		
	flags = option_append ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY;
	s = ast_writefile( tmp, ext, NULL, flags , 0, 0644);
		
	if (!s) {
		ast_log(LOG_WARNING, "Could not create file %s\n", filename);
		goto out;
	}

	if (option_transmit_silence_during_record)
		silgen = ast_channel_start_silence_generator(chan);
	
	/* Request a video update */
	ast_indicate(chan, AST_CONTROL_VIDUPDATE);
	
	if (maxduration <= 0)
		maxduration = -1;
	
	while ((waitres = ast_waitfor(chan, maxduration)) > -1) {
		if (maxduration > 0) {
			if (waitres == 0) {
				gottimeout = 1;
				break;
			}
			maxduration = waitres;
		}
		
		f = ast_read(chan);
		if (!f) {
			res = -1;
			break;
		}
		if (f->frametype == AST_FRAME_VOICE) {
			res = ast_writestream(s, f);
			
			if (res) {
				ast_log(LOG_WARNING, "Problem writing frame\n");
				ast_frfree(f);
				break;
			}
			
			if (silence > 0) {
				dspsilence = 0;
				ast_dsp_silence(sildet, f, &dspsilence);
				if (dspsilence) {
					totalsilence = dspsilence;
				} else {
					totalsilence = 0;
				}
				if (totalsilence > silence) {
					/* Ended happily with silence */
					ast_frfree(f);
					gotsilence = 1;
					break;
				}
			}
		} else if (f->frametype == AST_FRAME_VIDEO) {
			res = ast_writestream(s, f);
			
			if (res) {
				ast_log(LOG_WARNING, "Problem writing frame\n");
				ast_frfree(f);
				break;
			}
		} else if ((f->frametype == AST_FRAME_DTMF) &&
		    (f->subclass == terminator)) {
			ast_frfree(f);
			break;
		}
		ast_frfree(f);
	}
	if (!f) {
		ast_log(LOG_DEBUG, "Got hangup\n");
		res = -1;
	}
			
	if (gotsilence) {
		ast_stream_rewind(s, silence-1000);
		ast_truncstream(s);
	} else if (!gottimeout) {
		/* Strip off the last 1/4 second of it */
		ast_stream_rewind(s, 250);
		ast_truncstream(s);
	}
	ast_closestream(s);

	if (silgen)
		ast_channel_stop_silence_generator(chan, silgen);
	
 out:
	if ((silence > 0) && rfmt) {
		res = ast_set_read_format(chan, rfmt);
		if (res)
			ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
		if (sildet)
			ast_dsp_free(sildet);
	}

	LOCAL_USER_REMOVE(u);

	return res;
}