SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file, const char *func, int line,
															  switch_file_handle_t *fh,
															  const char *file_path,
															  uint32_t channels, uint32_t rate, unsigned int flags, switch_memory_pool_t *pool)
{
	char *ext;
	switch_status_t status = SWITCH_STATUS_FALSE;
	char stream_name[128] = "";
	char *rhs = NULL;
	const char *spool_path = NULL;
	int is_stream = 0;
	char *fp = NULL;
	int to = 0;

	if (switch_test_flag(fh, SWITCH_FILE_OPEN)) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Handle already open\n");
		return SWITCH_STATUS_FALSE;
	}

	fh->samples_in = 0;

	if (!fh->samplerate) {
		if (!(fh->samplerate = rate)) {
			fh->samplerate = 8000;
		}
	}

	if (zstr(file_path)) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Filename\n");
		return SWITCH_STATUS_FALSE;
	}

	fh->flags = flags;

	if (pool) {
		fh->memory_pool = pool;
	} else {
		if ((status = switch_core_new_memory_pool(&fh->memory_pool)) != SWITCH_STATUS_SUCCESS) {
			UNPROTECT_INTERFACE(fh->file_interface);
			return status;
		}
		switch_set_flag(fh, SWITCH_FILE_FLAG_FREE_POOL);
	}

	if (*file_path == '{') {
		char *timeout;
		char *new_fp;
		fp = switch_core_strdup(fh->memory_pool, file_path);

		if (switch_event_create_brackets(fp, '{', '}', ',', &fh->params, &new_fp, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
			if ((timeout = switch_event_get_header(fh->params, "timeout"))) {
				if ((to = atoi(timeout)) < 1) {
					to = 0;
				}
			}
		} else {
			new_fp = fp;
		}

		file_path = new_fp;
	}

	if (switch_directory_exists(file_path, fh->memory_pool) == SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File [%s] is a directory not a file.\n", file_path);
		status = SWITCH_STATUS_GENERR;
		goto fail;
	}

	if ((rhs = strstr(file_path, SWITCH_URL_SEPARATOR))) {
		switch_copy_string(stream_name, file_path, (rhs + 1) - file_path);
		ext = stream_name;
		file_path = rhs + 3;
		fh->file_path = switch_core_strdup(fh->memory_pool, file_path);
		is_stream = 1;
	} else {
		if ((flags & SWITCH_FILE_FLAG_WRITE)) {

			char *p, *e;

			fh->file_path = switch_core_strdup(fh->memory_pool, file_path);
			p = fh->file_path;

			if (*p == '[' && *(p + 1) == *SWITCH_PATH_SEPARATOR) {
				e = switch_find_end_paren(p, '[', ']');

				if (e) {
					*e = '\0';
					spool_path = p + 1;
					fh->file_path = e + 1;
				}
			}

			if (!spool_path) {
				spool_path = switch_core_get_variable_pdup(SWITCH_AUDIO_SPOOL_PATH_VARIABLE, fh->memory_pool);
			}

			file_path = fh->file_path;
		}

		if ((ext = strrchr(file_path, '.')) == 0) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown file Format [%s]\n", file_path);
			switch_goto_status(SWITCH_STATUS_FALSE, fail);
		}
		ext++;
		fh->file_path = switch_core_strdup(fh->memory_pool, file_path);
	}



	if ((fh->file_interface = switch_loadable_module_get_file_interface(ext)) == 0) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid file format [%s] for [%s]!\n", ext, file_path);
		switch_goto_status(SWITCH_STATUS_GENERR, fail);
	}

	fh->file = file;
	fh->func = func;
	fh->line = line;


	if (spool_path) {
		char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
		switch_uuid_t uuid;
		switch_uuid_get(&uuid);
		switch_uuid_format(uuid_str, &uuid);

		fh->spool_path = switch_core_sprintf(fh->memory_pool, "%s%s%s.%s", spool_path, SWITCH_PATH_SEPARATOR, uuid_str, ext);
	} else {
		fh->spool_path = NULL;
	}

	if (rhs) {
		fh->handler = switch_core_strdup(fh->memory_pool, rhs);
	} else {
		fh->handler = NULL;
	}

	if (channels) {
		fh->channels = channels;
	} else {
		fh->channels = 1;
	}

	file_path = fh->spool_path ? fh->spool_path : fh->file_path;

	if ((status = fh->file_interface->file_open(fh, file_path)) != SWITCH_STATUS_SUCCESS) {
		if (fh->spool_path) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Spool dir is set.  Make sure [%s] is also a valid path\n", fh->spool_path);
		}
		UNPROTECT_INTERFACE(fh->file_interface);
		switch_goto_status(status, fail);
	}

	fh->real_channels = fh->channels;

	if (channels) {
		fh->channels = channels;
	}

	if ((flags & SWITCH_FILE_FLAG_WRITE) && !is_stream && (status = switch_file_exists(file_path, fh->memory_pool)) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File [%s] not created!\n", file_path);
		fh->file_interface->file_close(fh);
		UNPROTECT_INTERFACE(fh->file_interface);
		switch_goto_status(status, fail);
	}

	if (to) {
		fh->max_samples = (fh->samplerate / 1000) * to;
	}


	if ((flags & SWITCH_FILE_FLAG_READ)) {
		fh->native_rate = fh->samplerate;
	} else {
		fh->native_rate = rate;
	}

	if (fh->samplerate && rate && fh->samplerate != rate) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "File %s sample rate %d doesn't match requested rate %d\n", file_path, fh->samplerate, rate);
		if ((flags & SWITCH_FILE_FLAG_READ)) {
			fh->samplerate = rate;
		}
	}

	if (fh->pre_buffer_datalen) {
		//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Prebuffering %d bytes\n", (int)fh->pre_buffer_datalen);
		switch_buffer_create_dynamic(&fh->pre_buffer, fh->pre_buffer_datalen * fh->channels, fh->pre_buffer_datalen * fh->channels, 0);
		fh->pre_buffer_data = switch_core_alloc(fh->memory_pool, fh->pre_buffer_datalen * fh->channels);
	}


	if (fh->real_channels != fh->channels && (flags & SWITCH_FILE_FLAG_READ) && !(fh->flags & SWITCH_FILE_NOMUX)) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "File has %d channels, muxing to %d channel%s will occur.\n", fh->real_channels, fh->channels, fh->channels == 1 ? "" : "s");
	}

	switch_set_flag(fh, SWITCH_FILE_OPEN);
	return status;

  fail:

	switch_clear_flag(fh, SWITCH_FILE_OPEN);

	if (fh->params) {
		switch_event_destroy(&fh->params);
	}

	fh->samples_in = 0;
	fh->max_samples = 0;
	
	if (switch_test_flag(fh, SWITCH_FILE_FLAG_FREE_POOL)) {
		switch_core_destroy_memory_pool(&fh->memory_pool);
	}

	return status;
}
示例#2
0
/**
 * Encode log as GELF
 */
static char *to_gelf(const switch_log_node_t *node, switch_log_level_t log_level)
{
	char *gelf_text = NULL;
	cJSON *gelf = cJSON_CreateObject();
	char *hostname;
	char timestamp[32];
	char *full_message = node->content;
	char short_message[151];
	char *short_message_end = NULL;
	char *parsed_full_message = NULL;
	char *field_name = NULL;
	switch_event_t *log_fields = NULL;
	switch_core_session_t *session = NULL;

	cJSON_AddItemToObject(gelf, "version", cJSON_CreateString("1.1"));
	if ((hostname = switch_core_get_variable("hostname")) && !zstr(hostname)) {
		cJSON_AddItemToObject(gelf, "host", cJSON_CreateString(hostname));
	} else if ((hostname = switch_core_get_variable("local_ip_v4")) && !zstr(hostname)) {
		cJSON_AddItemToObject(gelf, "host", cJSON_CreateString(hostname));
	}
	switch_snprintf(timestamp, 32, "%"SWITCH_UINT64_T_FMT".%d", (uint64_t)(node->timestamp / 1000000), (node->timestamp % 1000000) / 1000);
	cJSON_AddItemToObject(gelf, "timestamp", cJSON_CreateString(timestamp));
	cJSON_AddItemToObject(gelf, "_microtimestamp", cJSON_CreateNumber(node->timestamp));
	cJSON_AddItemToObject(gelf, "level", cJSON_CreateNumber(to_graylog2_level(log_level)));
	cJSON_AddItemToObject(gelf, "_ident", cJSON_CreateString("freeswitch"));
	cJSON_AddItemToObject(gelf, "_pid", cJSON_CreateNumber((int)getpid()));
	if (!zstr(node->userdata)) {
		cJSON_AddItemToObject(gelf, "_uuid", cJSON_CreateString(node->userdata));
	}
	if (!zstr_buf(node->file)) {
		cJSON_AddItemToObject(gelf, "_file", cJSON_CreateString(node->file));
		cJSON_AddItemToObject(gelf, "_line", cJSON_CreateNumber(node->line));
	}
	if (!zstr_buf(node->func)) {
		cJSON_AddItemToObject(gelf, "_function", cJSON_CreateString(node->func));
	}

	/* skip initial space and new line */
	if (*full_message == ' ') {
		full_message++;
	}
	if (*full_message == '\n') {
		full_message++;
	}

	/* get fields from channel data, if configured */
	if (!zstr(node->userdata) && (session = switch_core_session_locate(node->userdata))) {
		switch_channel_t *channel = switch_core_session_get_channel(session);
		switch_event_header_t *hp;
		/* session_fields name mapped to variable name */
		for (hp = globals.session_fields->headers; hp; hp = hp->next) {
			if (!zstr(hp->name) && !zstr(hp->value)) {
				const char *val = switch_channel_get_variable(channel, hp->value);
				if (!zstr(val)) {
					if (!log_fields) {
						switch_event_create_plain(&log_fields, SWITCH_EVENT_CHANNEL_DATA);
					}
					switch_event_add_header_string(log_fields, SWITCH_STACK_BOTTOM, hp->name, val);
				}
			}
		}
		switch_core_session_rwunlock(session);
	}

	/* parse list of fields from message text, if any */
	if (strncmp(full_message, "LOG_FIELDS", 10) == 0) {
		switch_event_create_brackets(full_message+10, '[', ']', ',', &log_fields, &parsed_full_message, SWITCH_TRUE);
		full_message = parsed_full_message;
	}

	/* add additional fields */
	if (log_fields) {
		switch_event_header_t *hp;
		for (hp = log_fields->headers; hp; hp = hp->next) {
			if (!zstr(hp->name) && !zstr(hp->value)) {
				if (strncmp(hp->name, "@#", 2) == 0) {
					field_name = switch_mprintf("_%s", hp->name + 2);
					cJSON_AddItemToObject(gelf, field_name, cJSON_CreateNumber(strtod(hp->value, NULL)));
				} else {
					field_name = switch_mprintf("_%s", hp->name);
					cJSON_AddItemToObject(gelf, field_name, cJSON_CreateString(hp->value));
				}
				free(field_name);
			}
		}
		switch_event_destroy(&log_fields);
	}

	cJSON_AddItemToObject(gelf, "full_message", cJSON_CreateString(full_message));

	switch_snprintf(short_message, sizeof(short_message) - 1, "%s", full_message);
	if ((short_message_end = strchr(short_message, '\n'))) {
		*short_message_end = '\0';
	}
	cJSON_AddItemToObject(gelf, "short_message", cJSON_CreateString(short_message));

	gelf_text = cJSON_PrintUnformatted(gelf);
	cJSON_Delete(gelf);
	
	switch_safe_free(parsed_full_message);
	
	return gelf_text;
}