mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-16 23:08:32 +00:00
Merge "Add the ability to read the media file type from HTTP header for playback"
This commit is contained in:
@@ -507,6 +507,7 @@ static struct ast_format_def alaw_f = {
|
||||
static struct ast_format_def pcm_f = {
|
||||
.name = "pcm",
|
||||
.exts = "pcm|ulaw|ul|mu|ulw",
|
||||
.mime_types = "audio/basic",
|
||||
.write = pcm_write,
|
||||
.seek = pcm_seek,
|
||||
.trunc = pcm_trunc,
|
||||
|
||||
@@ -128,6 +128,7 @@ static off_t vox_tell(struct ast_filestream *fs)
|
||||
static struct ast_format_def vox_f = {
|
||||
.name = "vox",
|
||||
.exts = "vox",
|
||||
.mime_types = "audio/x-vox",
|
||||
.write = vox_write,
|
||||
.seek = vox_seek,
|
||||
.trunc = vox_trunc,
|
||||
|
||||
@@ -532,6 +532,7 @@ static struct ast_format_def wav16_f = {
|
||||
static struct ast_format_def wav_f = {
|
||||
.name = "wav",
|
||||
.exts = "wav",
|
||||
.mime_types = "audio/wav|audio/x-wav",
|
||||
.open = wav_open,
|
||||
.rewrite = wav_rewrite,
|
||||
.write = wav_write,
|
||||
|
||||
@@ -427,6 +427,18 @@ char *ast_format_str_reduce(char *fmts);
|
||||
*/
|
||||
struct ast_format *ast_get_format_for_file_ext(const char *file_ext);
|
||||
|
||||
/*!
|
||||
* \brief Get a suitable filename extension for the given MIME type
|
||||
*
|
||||
* \param mime_type The MIME type for which to find extensions
|
||||
* \param buffer A pointer to a buffer to receive the extension
|
||||
* \param capacity The size of 'buffer' in bytes
|
||||
*
|
||||
* \retval 1 if an extension was found for the provided MIME type
|
||||
* \retval 0 if the MIME type was not found
|
||||
*/
|
||||
int ast_get_extension_for_mime_type(const char *mime_type, char *buffer, size_t capacity);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -44,6 +44,7 @@ struct ast_format_def {
|
||||
char name[80]; /*!< Name of format */
|
||||
char exts[80]; /*!< Extensions (separated by | if more than one)
|
||||
* this format can read. First is assumed for writing (e.g. .mp3) */
|
||||
char mime_types[80]; /*!< MIME Types related to the format (separated by | if more than one)*/
|
||||
struct ast_format *format; /*!< Format of frames it uses/provides (one only) */
|
||||
/*!
|
||||
* \brief Prepare an input stream for playback.
|
||||
|
||||
34
main/file.c
34
main/file.c
@@ -333,20 +333,21 @@ static char *build_filename(const char *filename, const char *ext)
|
||||
|
||||
/* compare type against the list 'exts' */
|
||||
/* XXX need a better algorithm */
|
||||
static int exts_compare(const char *exts, const char *type)
|
||||
static int type_in_list(const char *list, const char *type, int (*cmp)(const char *s1, const char *s2))
|
||||
{
|
||||
char tmp[256];
|
||||
char *stringp = tmp, *ext;
|
||||
char *stringp = ast_strdupa(list), *item;
|
||||
|
||||
ast_copy_string(tmp, exts, sizeof(tmp));
|
||||
while ((ext = strsep(&stringp, "|"))) {
|
||||
if (!strcmp(ext, type))
|
||||
while ((item = strsep(&stringp, "|"))) {
|
||||
if (!cmp(item, type)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define exts_compare(list, type) (type_in_list((list), (type), strcmp))
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Close the file stream by canceling any pending read / write callbacks
|
||||
@@ -1926,6 +1927,27 @@ struct ast_format *ast_get_format_for_file_ext(const char *file_ext)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ast_get_extension_for_mime_type(const char *mime_type, char *buffer, size_t capacity)
|
||||
{
|
||||
struct ast_format_def *f;
|
||||
SCOPED_RDLOCK(lock, &formats.lock);
|
||||
|
||||
ast_assert(buffer && capacity);
|
||||
|
||||
AST_RWLIST_TRAVERSE(&formats, f, list) {
|
||||
if (type_in_list(f->mime_types, mime_type, strcasecmp)) {
|
||||
size_t item_len = strcspn(f->exts, "|");
|
||||
size_t bytes_written = snprintf(buffer, capacity, ".%.*s", (int) item_len, f->exts);
|
||||
if (bytes_written < capacity) {
|
||||
/* Only return success if we didn't truncate */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_cli_entry cli_file[] = {
|
||||
AST_CLI_DEFINE(handle_cli_core_show_file_formats, "Displays file formats")
|
||||
};
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "asterisk/bucket.h"
|
||||
#include "asterisk/astdb.h"
|
||||
#include "asterisk/cli.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/media_cache.h"
|
||||
|
||||
/*! The name of the AstDB family holding items in the cache. */
|
||||
@@ -123,6 +124,24 @@ static void media_cache_item_del_from_astdb(struct ast_bucket_file *bucket_file)
|
||||
ast_free(hash_value);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Normalize the value of a Content-Type header
|
||||
*
|
||||
* This will trim off any optional parameters after the type/subtype.
|
||||
*/
|
||||
static void normalize_content_type_header(char *content_type)
|
||||
{
|
||||
char *params = strchr(content_type, ';');
|
||||
|
||||
if (params) {
|
||||
*params-- = 0;
|
||||
while (params > content_type && (*params == ' ' || *params == '\t')) {
|
||||
*params-- = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Update the name of the file backing a \c bucket_file
|
||||
@@ -142,9 +161,32 @@ static void bucket_file_update_path(struct ast_bucket_file *bucket_file,
|
||||
} else if (!strchr(bucket_file->path, '.') && (ext = strrchr(ast_sorcery_object_get_id(bucket_file), '.'))) {
|
||||
/* If we don't have a file extension and were provided one in the URI, use it */
|
||||
char new_path[PATH_MAX];
|
||||
char found_ext[PATH_MAX];
|
||||
|
||||
ast_bucket_file_metadata_set(bucket_file, "ext", ext);
|
||||
|
||||
/* Don't pass '.' while checking for supported extension */
|
||||
if (!ast_get_format_for_file_ext(ext + 1)) {
|
||||
/* If the file extension passed in the URI isn't supported check for the
|
||||
* extension based on the MIME type passed in the Content-Type header before
|
||||
* giving up.
|
||||
* If a match is found then retrieve the extension from the supported list
|
||||
* corresponding to the mime-type and use that to rename the file */
|
||||
struct ast_bucket_metadata *header = ast_bucket_file_metadata_get(bucket_file, "content-type");
|
||||
if (header) {
|
||||
char *mime_type = ast_strdup(header->value);
|
||||
if (mime_type) {
|
||||
normalize_content_type_header(mime_type);
|
||||
if (!ast_strlen_zero(mime_type)) {
|
||||
if (ast_get_extension_for_mime_type(mime_type, found_ext, sizeof(found_ext))) {
|
||||
ext = found_ext;
|
||||
}
|
||||
}
|
||||
ast_free(mime_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(new_path, sizeof(new_path), "%s%s", bucket_file->path, ext);
|
||||
rename(bucket_file->path, new_path);
|
||||
ast_copy_string(bucket_file->path, new_path, sizeof(bucket_file->path));
|
||||
|
||||
@@ -84,6 +84,7 @@ static size_t curl_header_callback(char *buffer, size_t size, size_t nitems, voi
|
||||
if (strcasecmp(header, "ETag")
|
||||
&& strcasecmp(header, "Cache-Control")
|
||||
&& strcasecmp(header, "Last-Modified")
|
||||
&& strcasecmp(header, "Content-Type")
|
||||
&& strcasecmp(header, "Expires")) {
|
||||
return realsize;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user